Roi Atalla avatar Roi Atalla committed 69ae7ed

Moved PNGDecoder back to util.

Comments (0)

Files changed (4)

.idea/workspace.xml

 <project version="4">
   <component name="ChangeListManager">
     <list default="true" id="3bd3582b-975a-4915-888d-8e2c52d85938" name="Default" comment="">
-      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/ra4king/opengl/arcsynthesis/gl33/chapter16/example1/example16.1.gamma_ramp.png" />
-      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/rosick/jglsdk/glimg/DdsLoader.java" />
-      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/rosick/jglsdk/glimg/DdsUtil.java" />
-      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/rosick/jglsdk/glimg/ImageCreator.java" />
-      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/rosick/jglsdk/glimg/ImageFormat.java" />
-      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/rosick/jglsdk/glimg/ImageSet.java" />
+      <change type="DELETED" beforePath="E:\Roi Atalla\Documents\Programming Files\Java Files\Personal Projects\OpenGL\src\com\ra4king\opengl\util\img\PNGDecoder.java" afterPath="" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/ra4king/opengl/arcsynthesis/gl33/chapter16/example1/Example16_1.java" afterPath="$PROJECT_DIR$/src/com/ra4king/opengl/arcsynthesis/gl33/chapter16/example1/Example16_1.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
+      <change type="MOVED" beforePath="E:\Roi Atalla\Documents\Programming Files\Java Files\Personal Projects\OpenGL\src\com\ra4king\opengl\util\img\PNGDecoder.java" afterPath="$PROJECT_DIR$/src/com/ra4king/opengl/util/PNGDecoder.java" />
     </list>
     <ignored path="OpenGL.iws" />
     <ignored path=".idea/workspace.xml" />
     <file path="/a.xml" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1361850040520" ignored="false" />
     <file path="/a.html" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1361850041808" ignored="false" />
     <file path="/a.groovy" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1361850042481" ignored="false" />
-    <file path="/Dummy.txt" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1364718742000" ignored="false" />
+    <file path="/Dummy.txt" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1364718888698" ignored="false" />
     <file path="/Example12_1.java" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1362027020824" ignored="false" />
     <file path="/example12.1.DiffuseSpecular.frag" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1361702005810" ignored="false" />
     <file path="/LightManager.java" changelist="3bd3582b-975a-4915-888d-8e2c52d85938" time="1362461124226" ignored="false" />
               <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
             </PATH_ELEMENT>
             <PATH_ELEMENT>
-              <option name="myItemId" value="util" />
-              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
-            </PATH_ELEMENT>
-            <PATH_ELEMENT>
-              <option name="myItemId" value="img" />
-              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
-            </PATH_ELEMENT>
-          </PATH>
-          <PATH>
-            <PATH_ELEMENT>
-              <option name="myItemId" value="OpenGL" />
-              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
-            </PATH_ELEMENT>
-            <PATH_ELEMENT>
-              <option name="myItemId" value="OpenGL" />
-              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
-            </PATH_ELEMENT>
-            <PATH_ELEMENT>
-              <option name="myItemId" value="src" />
-              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
-            </PATH_ELEMENT>
-            <PATH_ELEMENT>
-              <option name="myItemId" value="opengl" />
-              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
-            </PATH_ELEMENT>
-            <PATH_ELEMENT>
               <option name="myItemId" value="gl33" />
               <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
             </PATH_ELEMENT>
       <created>1364718745149</created>
       <updated>1364718745149</updated>
     </task>
-    <option name="localTasksCounter" value="28" />
+    <task id="LOCAL-00028" summary="Forgot to add files.">
+      <created>1364718893087</created>
+      <updated>1364718893087</updated>
+    </task>
+    <option name="localTasksCounter" value="29" />
     <servers />
   </component>
   <component name="TodoView" selected-index="4">
       <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29530916" sideWeight="0.51387405" order="8" side_tool="true" content_ui="tabs" />
       <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.18366013" sideWeight="0.14915694" order="2" side_tool="true" content_ui="tabs" />
       <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29104477" sideWeight="0.5" order="10" side_tool="false" content_ui="tabs" />
+      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32942432" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" />
       <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.14605543" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
       <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.18366013" sideWeight="0.17250325" order="1" side_tool="true" content_ui="tabs" />
       <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32977587" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
       <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
       <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.2497332" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
       <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.34754798" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
-      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32942432" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" />
       <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
       <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.39978677" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
     </layout>
     <option name="MAXIMUM_HISTORY_ROWS" value="1000" />
     <option name="FORCE_NON_EMPTY_COMMENT" value="false" />
     <option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="false" />
-    <option name="LAST_COMMIT_MESSAGE" value="Fully ported Example 16.1. Also moved the 'dds' classes to their original packaging for better credit to author." />
+    <option name="LAST_COMMIT_MESSAGE" value="Forgot to add files." />
     <option name="MAKE_NEW_CHANGELIST_ACTIVE" value="false" />
     <option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
     <option name="CHECK_FILES_UP_TO_DATE_BEFORE_COMMIT" value="false" />
     <option name="UPDATE_GROUP_BY_CHANGELIST" value="false" />
     <option name="SHOW_FILE_HISTORY_AS_TREE" value="false" />
     <option name="FILE_HISTORY_SPLITTER_PROPORTION" value="0.6" />
-    <MESSAGE value="Example 12.1 completely ported and fully working." />
     <MESSAGE value="Setup Example 12.2." />
     <MESSAGE value="Workspace.xml being weird." />
     <MESSAGE value="Silly typo." />
     <MESSAGE value="Forgot to remove the call to setFPS(0) in Example 15.1." />
     <MESSAGE value="Fully ported Example 16.1." />
     <MESSAGE value="Fully ported Example 16.1. Also moved the 'dds' classes to their original packaging for better credit to author." />
+    <MESSAGE value="Forgot to add files." />
   </component>
   <component name="XDebuggerManager">
     <breakpoint-manager>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/ra4king/opengl/arcsynthesis/gl33/chapter15/Example15_1.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="225" column="8" selection-start="7412" selection-end="7634" vertical-scroll-proportion="0.44407895" />
+        <state line="225" column="8" selection-start="7412" selection-end="7634" vertical-scroll-proportion="0.44407895">
+          <folding>
+            <element signature="imports" expanded="false" />
+          </folding>
+        </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/ra4king/opengl/arcsynthesis/gl33/chapter16/example1/example16.1.TextureGamma.frag">

src/com/ra4king/opengl/arcsynthesis/gl33/chapter16/example1/Example16_1.java

 import org.lwjgl.input.Keyboard;
 
 import com.ra4king.opengl.GLProgram;
+import com.ra4king.opengl.util.PNGDecoder;
+import com.ra4king.opengl.util.PNGDecoder.Format;
 import com.ra4king.opengl.util.ShaderProgram;
-import com.ra4king.opengl.util.img.PNGDecoder;
-import com.ra4king.opengl.util.img.PNGDecoder.Format;
 import com.ra4king.opengl.util.math.Matrix4;
 
 /**

src/com/ra4king/opengl/util/PNGDecoder.java

+/*
+ * Copyright (c) 2008-2010, Matthias Mann
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Matthias Mann nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.ra4king.opengl.util;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.zip.CRC32;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+/**
+ * A PNGDecoder. The slick PNG decoder is based on this class :)
+ * 
+ * @author Matthias Mann
+ */
+public class PNGDecoder {
+	
+	public enum Format {
+		ALPHA(1, true),
+		LUMINANCE(1, false),
+		LUMINANCE_ALPHA(2, true),
+		RGB(3, false),
+		RGBA(4, true),
+		BGRA(4, true),
+		ABGR(4, true);
+		
+		final int numComponents;
+		final boolean hasAlpha;
+		
+		private Format(int numComponents, boolean hasAlpha) {
+			this.numComponents = numComponents;
+			this.hasAlpha = hasAlpha;
+		}
+		
+		public int getNumComponents() {
+			return numComponents;
+		}
+		
+		public boolean isHasAlpha() {
+			return hasAlpha;
+		}
+	}
+	
+	private static final byte[] SIGNATURE = { (byte)137, 80, 78, 71, 13, 10, 26, 10 };
+	
+	private static final int IHDR = 0x49484452;
+	private static final int PLTE = 0x504C5445;
+	private static final int tRNS = 0x74524E53;
+	private static final int IDAT = 0x49444154;
+	
+	private static final byte COLOR_GREYSCALE = 0;
+	private static final byte COLOR_TRUECOLOR = 2;
+	private static final byte COLOR_INDEXED = 3;
+	private static final byte COLOR_GREYALPHA = 4;
+	private static final byte COLOR_TRUEALPHA = 6;
+	
+	private final InputStream input;
+	private final CRC32 crc;
+	private final byte[] buffer;
+	
+	private int chunkLength;
+	private int chunkType;
+	private int chunkRemaining;
+	
+	private int width;
+	private int height;
+	private int bitdepth;
+	private int colorType;
+	private int bytesPerPixel;
+	private byte[] palette;
+	private byte[] paletteA;
+	private byte[] transPixel;
+	
+	public PNGDecoder(InputStream input) throws IOException {
+		this.input = input;
+		this.crc = new CRC32();
+		this.buffer = new byte[4096];
+		
+		readFully(buffer, 0, SIGNATURE.length);
+		if(!checkSignature(buffer)) {
+			throw new IOException("Not a valid PNG file");
+		}
+		
+		openChunk(IHDR);
+		readIHDR();
+		closeChunk();
+		
+		searchIDAT: for(;;) {
+			openChunk();
+			switch(chunkType) {
+				case IDAT:
+					break searchIDAT;
+				case PLTE:
+					readPLTE();
+					break;
+				case tRNS:
+					readtRNS();
+					break;
+			}
+			closeChunk();
+		}
+		
+		if(colorType == COLOR_INDEXED && palette == null) {
+			throw new IOException("Missing PLTE chunk");
+		}
+	}
+	
+	public int getHeight() {
+		return height;
+	}
+	
+	public int getWidth() {
+		return width;
+	}
+	
+	/**
+	 * Checks if the image has a real alpha channel.
+	 * This method does not check for the presence of a tRNS chunk.
+	 * 
+	 * @return true if the image has an alpha channel
+	 * @see #hasAlpha()
+	 */
+	public boolean hasAlphaChannel() {
+		return colorType == COLOR_TRUEALPHA || colorType == COLOR_GREYALPHA;
+	}
+	
+	/**
+	 * Checks if the image has transparency information either from
+	 * an alpha channel or from a tRNS chunk.
+	 * 
+	 * @return true if the image has transparency
+	 * @see #hasAlphaChannel()
+	 * @see #overwriteTRNS(byte, byte, byte)
+	 */
+	public boolean hasAlpha() {
+		return hasAlphaChannel() ||
+				paletteA != null || transPixel != null;
+	}
+	
+	public boolean isRGB() {
+		return colorType == COLOR_TRUEALPHA ||
+				colorType == COLOR_TRUECOLOR ||
+				colorType == COLOR_INDEXED;
+	}
+	
+	/**
+	 * Overwrites the tRNS chunk entry to make a selected color transparent.
+	 * <p>
+	 * This can only be invoked when the image has no alpha channel.
+	 * </p>
+	 * <p>
+	 * Calling this method causes {@link #hasAlpha()} to return true.
+	 * </p>
+	 * 
+	 * @param r
+	 *            the red component of the color to make transparent
+	 * @param g
+	 *            the green component of the color to make transparent
+	 * @param b
+	 *            the blue component of the color to make transparent
+	 * @throws UnsupportedOperationException
+	 *             if the tRNS chunk data can't be set
+	 * @see #hasAlphaChannel()
+	 */
+	public void overwriteTRNS(byte r, byte g, byte b) {
+		if(hasAlphaChannel()) {
+			throw new UnsupportedOperationException("image has an alpha channel");
+		}
+		byte[] pal = this.palette;
+		if(pal == null) {
+			transPixel = new byte[] { 0, r, 0, g, 0, b };
+		} else {
+			paletteA = new byte[pal.length / 3];
+			for(int i = 0, j = 0; i < pal.length; i += 3, j++) {
+				if(pal[i] != r || pal[i + 1] != g || pal[i + 2] != b) {
+					paletteA[j] = (byte)0xFF;
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Computes the implemented format conversion for the desired format.
+	 * 
+	 * @param fmt
+	 *            the desired format
+	 * @return format which best matches the desired format
+	 * @throws UnsupportedOperationException
+	 *             if this PNG file can't be decoded
+	 */
+	public Format decideTextureFormat(Format fmt) {
+		switch(colorType) {
+			case COLOR_TRUECOLOR:
+				switch(fmt) {
+					case ABGR:
+					case RGBA:
+					case BGRA:
+					case RGB:
+						return fmt;
+					default:
+						return Format.RGB;
+				}
+			case COLOR_TRUEALPHA:
+				switch(fmt) {
+					case ABGR:
+					case RGBA:
+					case BGRA:
+					case RGB:
+						return fmt;
+					default:
+						return Format.RGBA;
+				}
+			case COLOR_GREYSCALE:
+				switch(fmt) {
+					case LUMINANCE:
+					case ALPHA:
+						return fmt;
+					default:
+						return Format.LUMINANCE;
+				}
+			case COLOR_GREYALPHA:
+				return Format.LUMINANCE_ALPHA;
+			case COLOR_INDEXED:
+				switch(fmt) {
+					case ABGR:
+					case RGBA:
+					case BGRA:
+						return fmt;
+					default:
+						return Format.RGBA;
+				}
+			default:
+				throw new UnsupportedOperationException("Not yet implemented");
+		}
+	}
+	
+	/**
+	 * Decodes the image into the specified buffer. The first line is placed at
+	 * the current position. After decode the buffer position is at the end of
+	 * the last line.
+	 * 
+	 * @param buffer
+	 *            the buffer
+	 * @param stride
+	 *            the stride in bytes from start of a line to start of the next line, can be negative.
+	 * @param fmt
+	 *            the target format into which the image should be decoded.
+	 * @throws IOException
+	 *             if a read or data error occurred
+	 * @throws IllegalArgumentException
+	 *             if the start position of a line falls outside the buffer
+	 * @throws UnsupportedOperationException
+	 *             if the image can't be decoded into the desired format
+	 */
+	public void decode(ByteBuffer buffer, int stride, Format fmt) throws IOException {
+		final int offset = buffer.position();
+		final int lineSize = ((width * bitdepth + 7) / 8) * bytesPerPixel;
+		byte[] curLine = new byte[lineSize + 1];
+		byte[] prevLine = new byte[lineSize + 1];
+		byte[] palLine = (bitdepth < 8) ? new byte[width + 1] : null;
+		
+		final Inflater inflater = new Inflater();
+		try {
+			for(int y = 0; y < height; y++) {
+				readChunkUnzip(inflater, curLine, 0, curLine.length);
+				unfilter(curLine, prevLine);
+				
+				buffer.position(offset + y * stride);
+				
+				switch(colorType) {
+					case COLOR_TRUECOLOR:
+						switch(fmt) {
+							case ABGR:
+								copyRGBtoABGR(buffer, curLine);
+								break;
+							case RGBA:
+								copyRGBtoRGBA(buffer, curLine);
+								break;
+							case BGRA:
+								copyRGBtoBGRA(buffer, curLine);
+								break;
+							case RGB:
+								copy(buffer, curLine);
+								break;
+							default:
+								throw new UnsupportedOperationException("Unsupported format for this image");
+						}
+						break;
+					case COLOR_TRUEALPHA:
+						switch(fmt) {
+							case ABGR:
+								copyRGBAtoABGR(buffer, curLine);
+								break;
+							case RGBA:
+								copy(buffer, curLine);
+								break;
+							case BGRA:
+								copyRGBAtoBGRA(buffer, curLine);
+								break;
+							case RGB:
+								copyRGBAtoRGB(buffer, curLine);
+								break;
+							default:
+								throw new UnsupportedOperationException("Unsupported format for this image");
+						}
+						break;
+					case COLOR_GREYSCALE:
+						switch(fmt) {
+							case LUMINANCE:
+							case ALPHA:
+								copy(buffer, curLine);
+								break;
+							default:
+								throw new UnsupportedOperationException("Unsupported format for this image");
+						}
+						break;
+					case COLOR_GREYALPHA:
+						switch(fmt) {
+							case LUMINANCE_ALPHA:
+								copy(buffer, curLine);
+								break;
+							default:
+								throw new UnsupportedOperationException("Unsupported format for this image");
+						}
+						break;
+					case COLOR_INDEXED:
+						switch(bitdepth) {
+							case 8:
+								palLine = curLine;
+								break;
+							case 4:
+								expand4(curLine, palLine);
+								break;
+							case 2:
+								expand2(curLine, palLine);
+								break;
+							case 1:
+								expand1(curLine, palLine);
+								break;
+							default:
+								throw new UnsupportedOperationException("Unsupported bitdepth for this image");
+						}
+						switch(fmt) {
+							case ABGR:
+								copyPALtoABGR(buffer, palLine);
+								break;
+							case RGBA:
+								copyPALtoRGBA(buffer, palLine);
+								break;
+							case BGRA:
+								copyPALtoBGRA(buffer, palLine);
+								break;
+							default:
+								throw new UnsupportedOperationException("Unsupported format for this image");
+						}
+						break;
+					default:
+						throw new UnsupportedOperationException("Not yet implemented");
+				}
+				
+				byte[] tmp = curLine;
+				curLine = prevLine;
+				prevLine = tmp;
+			}
+		} finally {
+			inflater.end();
+		}
+	}
+	
+	/**
+	 * Decodes the image into the specified buffer. The last line is placed at
+	 * the current position. After decode the buffer position is at the end of
+	 * the first line.
+	 * 
+	 * @param buffer
+	 *            the buffer
+	 * @param stride
+	 *            the stride in bytes from start of a line to start of the next line, must be positive.
+	 * @param fmt
+	 *            the target format into which the image should be decoded.
+	 * @throws IOException
+	 *             if a read or data error occurred
+	 * @throws IllegalArgumentException
+	 *             if the start position of a line falls outside the buffer
+	 * @throws UnsupportedOperationException
+	 *             if the image can't be decoded into the desired format
+	 */
+	public void decodeFlipped(ByteBuffer buffer, int stride, Format fmt) throws IOException {
+		if(stride <= 0) {
+			throw new IllegalArgumentException("stride");
+		}
+		int pos = buffer.position();
+		int posDelta = (height - 1) * stride;
+		buffer.position(pos + posDelta);
+		decode(buffer, -stride, fmt);
+		buffer.position(buffer.position() + posDelta);
+	}
+	
+	private void copy(ByteBuffer buffer, byte[] curLine) {
+		buffer.put(curLine, 1, curLine.length - 1);
+	}
+	
+	private void copyRGBtoABGR(ByteBuffer buffer, byte[] curLine) {
+		if(transPixel != null) {
+			byte tr = transPixel[1];
+			byte tg = transPixel[3];
+			byte tb = transPixel[5];
+			for(int i = 1, n = curLine.length; i < n; i += 3) {
+				byte r = curLine[i];
+				byte g = curLine[i + 1];
+				byte b = curLine[i + 2];
+				byte a = (byte)0xFF;
+				if(r == tr && g == tg && b == tb) {
+					a = 0;
+				}
+				buffer.put(a).put(b).put(g).put(r);
+			}
+		} else {
+			for(int i = 1, n = curLine.length; i < n; i += 3) {
+				buffer.put((byte)0xFF).put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]);
+			}
+		}
+	}
+	
+	private void copyRGBtoRGBA(ByteBuffer buffer, byte[] curLine) {
+		if(transPixel != null) {
+			byte tr = transPixel[1];
+			byte tg = transPixel[3];
+			byte tb = transPixel[5];
+			for(int i = 1, n = curLine.length; i < n; i += 3) {
+				byte r = curLine[i];
+				byte g = curLine[i + 1];
+				byte b = curLine[i + 2];
+				byte a = (byte)0xFF;
+				if(r == tr && g == tg && b == tb) {
+					a = 0;
+				}
+				buffer.put(r).put(g).put(b).put(a);
+			}
+		} else {
+			for(int i = 1, n = curLine.length; i < n; i += 3) {
+				buffer.put(curLine[i]).put(curLine[i + 1]).put(curLine[i + 2]).put((byte)0xFF);
+			}
+		}
+	}
+	
+	private void copyRGBtoBGRA(ByteBuffer buffer, byte[] curLine) {
+		if(transPixel != null) {
+			byte tr = transPixel[1];
+			byte tg = transPixel[3];
+			byte tb = transPixel[5];
+			for(int i = 1, n = curLine.length; i < n; i += 3) {
+				byte r = curLine[i];
+				byte g = curLine[i + 1];
+				byte b = curLine[i + 2];
+				byte a = (byte)0xFF;
+				if(r == tr && g == tg && b == tb) {
+					a = 0;
+				}
+				buffer.put(b).put(g).put(r).put(a);
+			}
+		} else {
+			for(int i = 1, n = curLine.length; i < n; i += 3) {
+				buffer.put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]).put((byte)0xFF);
+			}
+		}
+	}
+	
+	private void copyRGBAtoABGR(ByteBuffer buffer, byte[] curLine) {
+		for(int i = 1, n = curLine.length; i < n; i += 4) {
+			buffer.put(curLine[i + 3]).put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]);
+		}
+	}
+	
+	private void copyRGBAtoBGRA(ByteBuffer buffer, byte[] curLine) {
+		for(int i = 1, n = curLine.length; i < n; i += 4) {
+			buffer.put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]).put(curLine[i + 3]);
+		}
+	}
+	
+	private void copyRGBAtoRGB(ByteBuffer buffer, byte[] curLine) {
+		for(int i = 1, n = curLine.length; i < n; i += 4) {
+			buffer.put(curLine[i]).put(curLine[i + 1]).put(curLine[i + 2]);
+		}
+	}
+	
+	private void copyPALtoABGR(ByteBuffer buffer, byte[] curLine) {
+		if(paletteA != null) {
+			for(int i = 1, n = curLine.length; i < n; i += 1) {
+				int idx = curLine[i] & 255;
+				byte r = palette[idx * 3 + 0];
+				byte g = palette[idx * 3 + 1];
+				byte b = palette[idx * 3 + 2];
+				byte a = paletteA[idx];
+				buffer.put(a).put(b).put(g).put(r);
+			}
+		} else {
+			for(int i = 1, n = curLine.length; i < n; i += 1) {
+				int idx = curLine[i] & 255;
+				byte r = palette[idx * 3 + 0];
+				byte g = palette[idx * 3 + 1];
+				byte b = palette[idx * 3 + 2];
+				byte a = (byte)0xFF;
+				buffer.put(a).put(b).put(g).put(r);
+			}
+		}
+	}
+	
+	private void copyPALtoRGBA(ByteBuffer buffer, byte[] curLine) {
+		if(paletteA != null) {
+			for(int i = 1, n = curLine.length; i < n; i += 1) {
+				int idx = curLine[i] & 255;
+				byte r = palette[idx * 3 + 0];
+				byte g = palette[idx * 3 + 1];
+				byte b = palette[idx * 3 + 2];
+				byte a = paletteA[idx];
+				buffer.put(r).put(g).put(b).put(a);
+			}
+		} else {
+			for(int i = 1, n = curLine.length; i < n; i += 1) {
+				int idx = curLine[i] & 255;
+				byte r = palette[idx * 3 + 0];
+				byte g = palette[idx * 3 + 1];
+				byte b = palette[idx * 3 + 2];
+				byte a = (byte)0xFF;
+				buffer.put(r).put(g).put(b).put(a);
+			}
+		}
+	}
+	
+	private void copyPALtoBGRA(ByteBuffer buffer, byte[] curLine) {
+		if(paletteA != null) {
+			for(int i = 1, n = curLine.length; i < n; i += 1) {
+				int idx = curLine[i] & 255;
+				byte r = palette[idx * 3 + 0];
+				byte g = palette[idx * 3 + 1];
+				byte b = palette[idx * 3 + 2];
+				byte a = paletteA[idx];
+				buffer.put(b).put(g).put(r).put(a);
+			}
+		} else {
+			for(int i = 1, n = curLine.length; i < n; i += 1) {
+				int idx = curLine[i] & 255;
+				byte r = palette[idx * 3 + 0];
+				byte g = palette[idx * 3 + 1];
+				byte b = palette[idx * 3 + 2];
+				byte a = (byte)0xFF;
+				buffer.put(b).put(g).put(r).put(a);
+			}
+		}
+	}
+	
+	private void expand4(byte[] src, byte[] dst) {
+		for(int i = 1, n = dst.length; i < n; i += 2) {
+			int val = src[1 + (i >> 1)] & 255;
+			switch(n - i) {
+				default:
+					dst[i + 1] = (byte)(val & 15);
+				case 1:
+					dst[i] = (byte)(val >> 4);
+			}
+		}
+	}
+	
+	private void expand2(byte[] src, byte[] dst) {
+		for(int i = 1, n = dst.length; i < n; i += 4) {
+			int val = src[1 + (i >> 2)] & 255;
+			switch(n - i) {
+				default:
+					dst[i + 3] = (byte)((val) & 3);
+				case 3:
+					dst[i + 2] = (byte)((val >> 2) & 3);
+				case 2:
+					dst[i + 1] = (byte)((val >> 4) & 3);
+				case 1:
+					dst[i] = (byte)((val >> 6));
+			}
+		}
+	}
+	
+	private void expand1(byte[] src, byte[] dst) {
+		for(int i = 1, n = dst.length; i < n; i += 8) {
+			int val = src[1 + (i >> 3)] & 255;
+			switch(n - i) {
+				default:
+					dst[i + 7] = (byte)((val) & 1);
+				case 7:
+					dst[i + 6] = (byte)((val >> 1) & 1);
+				case 6:
+					dst[i + 5] = (byte)((val >> 2) & 1);
+				case 5:
+					dst[i + 4] = (byte)((val >> 3) & 1);
+				case 4:
+					dst[i + 3] = (byte)((val >> 4) & 1);
+				case 3:
+					dst[i + 2] = (byte)((val >> 5) & 1);
+				case 2:
+					dst[i + 1] = (byte)((val >> 6) & 1);
+				case 1:
+					dst[i] = (byte)((val >> 7));
+			}
+		}
+	}
+	
+	private void unfilter(byte[] curLine, byte[] prevLine) throws IOException {
+		switch(curLine[0]) {
+			case 0: // none
+				break;
+			case 1:
+				unfilterSub(curLine);
+				break;
+			case 2:
+				unfilterUp(curLine, prevLine);
+				break;
+			case 3:
+				unfilterAverage(curLine, prevLine);
+				break;
+			case 4:
+				unfilterPaeth(curLine, prevLine);
+				break;
+			default:
+				throw new IOException("invalide filter type in scanline: " + curLine[0]);
+		}
+	}
+	
+	private void unfilterSub(byte[] curLine) {
+		final int bpp = this.bytesPerPixel;
+		for(int i = bpp + 1, n = curLine.length; i < n; ++i) {
+			curLine[i] += curLine[i - bpp];
+		}
+	}
+	
+	private void unfilterUp(byte[] curLine, byte[] prevLine) {
+		for(int i = 1, n = curLine.length; i < n; ++i) {
+			curLine[i] += prevLine[i];
+		}
+	}
+	
+	private void unfilterAverage(byte[] curLine, byte[] prevLine) {
+		final int bpp = this.bytesPerPixel;
+		
+		int i;
+		for(i = 1; i <= bpp; ++i) {
+			curLine[i] += (byte)((prevLine[i] & 0xFF) >>> 1);
+		}
+		for(int n = curLine.length; i < n; ++i) {
+			curLine[i] += (byte)(((prevLine[i] & 0xFF) + (curLine[i - bpp] & 0xFF)) >>> 1);
+		}
+	}
+	
+	private void unfilterPaeth(byte[] curLine, byte[] prevLine) {
+		final int bpp = this.bytesPerPixel;
+		
+		int i;
+		for(i = 1; i <= bpp; ++i) {
+			curLine[i] += prevLine[i];
+		}
+		for(int n = curLine.length; i < n; ++i) {
+			int a = curLine[i - bpp] & 255;
+			int b = prevLine[i] & 255;
+			int c = prevLine[i - bpp] & 255;
+			int p = a + b - c;
+			int pa = p - a;
+			if(pa < 0)
+				pa = -pa;
+			int pb = p - b;
+			if(pb < 0)
+				pb = -pb;
+			int pc = p - c;
+			if(pc < 0)
+				pc = -pc;
+			if(pa <= pb && pa <= pc)
+				c = a;
+			else if(pb <= pc)
+				c = b;
+			curLine[i] += (byte)c;
+		}
+	}
+	
+	private void readIHDR() throws IOException {
+		checkChunkLength(13);
+		readChunk(buffer, 0, 13);
+		width = readInt(buffer, 0);
+		height = readInt(buffer, 4);
+		bitdepth = buffer[8] & 255;
+		colorType = buffer[9] & 255;
+		
+		switch(colorType) {
+			case COLOR_GREYSCALE:
+				if(bitdepth != 8) {
+					throw new IOException("Unsupported bit depth: " + bitdepth);
+				}
+				bytesPerPixel = 1;
+				break;
+			case COLOR_GREYALPHA:
+				if(bitdepth != 8) {
+					throw new IOException("Unsupported bit depth: " + bitdepth);
+				}
+				bytesPerPixel = 2;
+				break;
+			case COLOR_TRUECOLOR:
+				if(bitdepth != 8) {
+					throw new IOException("Unsupported bit depth: " + bitdepth);
+				}
+				bytesPerPixel = 3;
+				break;
+			case COLOR_TRUEALPHA:
+				if(bitdepth != 8) {
+					throw new IOException("Unsupported bit depth: " + bitdepth);
+				}
+				bytesPerPixel = 4;
+				break;
+			case COLOR_INDEXED:
+				switch(bitdepth) {
+					case 8:
+					case 4:
+					case 2:
+					case 1:
+						bytesPerPixel = 1;
+						break;
+					default:
+						throw new IOException("Unsupported bit depth: " + bitdepth);
+				}
+				break;
+			default:
+				throw new IOException("unsupported color format: " + colorType);
+		}
+		
+		if(buffer[10] != 0) {
+			throw new IOException("unsupported compression method");
+		}
+		if(buffer[11] != 0) {
+			throw new IOException("unsupported filtering method");
+		}
+		if(buffer[12] != 0) {
+			throw new IOException("unsupported interlace method");
+		}
+	}
+	
+	private void readPLTE() throws IOException {
+		int paletteEntries = chunkLength / 3;
+		if(paletteEntries < 1 || paletteEntries > 256 || (chunkLength % 3) != 0) {
+			throw new IOException("PLTE chunk has wrong length");
+		}
+		palette = new byte[paletteEntries * 3];
+		readChunk(palette, 0, palette.length);
+	}
+	
+	private void readtRNS() throws IOException {
+		switch(colorType) {
+			case COLOR_GREYSCALE:
+				checkChunkLength(2);
+				transPixel = new byte[2];
+				readChunk(transPixel, 0, 2);
+				break;
+			case COLOR_TRUECOLOR:
+				checkChunkLength(6);
+				transPixel = new byte[6];
+				readChunk(transPixel, 0, 6);
+				break;
+			case COLOR_INDEXED:
+				if(palette == null) {
+					throw new IOException("tRNS chunk without PLTE chunk");
+				}
+				paletteA = new byte[palette.length / 3];
+				Arrays.fill(paletteA, (byte)0xFF);
+				readChunk(paletteA, 0, paletteA.length);
+				break;
+			default:
+				// just ignore it
+		}
+	}
+	
+	private void closeChunk() throws IOException {
+		if(chunkRemaining > 0) {
+			// just skip the rest and the CRC
+			skip(chunkRemaining + 4);
+		} else {
+			readFully(buffer, 0, 4);
+			int expectedCrc = readInt(buffer, 0);
+			int computedCrc = (int)crc.getValue();
+			if(computedCrc != expectedCrc) {
+				throw new IOException("Invalid CRC");
+			}
+		}
+		chunkRemaining = 0;
+		chunkLength = 0;
+		chunkType = 0;
+	}
+	
+	private void openChunk() throws IOException {
+		readFully(buffer, 0, 8);
+		chunkLength = readInt(buffer, 0);
+		chunkType = readInt(buffer, 4);
+		chunkRemaining = chunkLength;
+		crc.reset();
+		crc.update(buffer, 4, 4); // only chunkType
+	}
+	
+	private void openChunk(int expected) throws IOException {
+		openChunk();
+		if(chunkType != expected) {
+			throw new IOException("Expected chunk: " + Integer.toHexString(expected));
+		}
+	}
+	
+	private void checkChunkLength(int expected) throws IOException {
+		if(chunkLength != expected) {
+			throw new IOException("Chunk has wrong size");
+		}
+	}
+	
+	private int readChunk(byte[] buffer, int offset, int length) throws IOException {
+		if(length > chunkRemaining) {
+			length = chunkRemaining;
+		}
+		readFully(buffer, offset, length);
+		crc.update(buffer, offset, length);
+		chunkRemaining -= length;
+		return length;
+	}
+	
+	private void refillInflater(Inflater inflater) throws IOException {
+		while(chunkRemaining == 0) {
+			closeChunk();
+			openChunk(IDAT);
+		}
+		int read = readChunk(buffer, 0, buffer.length);
+		inflater.setInput(buffer, 0, read);
+	}
+	
+	private void readChunkUnzip(Inflater inflater, byte[] buffer, int offset, int length) throws IOException {
+		assert (buffer != this.buffer);
+		try {
+			do {
+				int read = inflater.inflate(buffer, offset, length);
+				if(read <= 0) {
+					if(inflater.finished()) {
+						throw new EOFException();
+					}
+					if(inflater.needsInput()) {
+						refillInflater(inflater);
+					} else {
+						throw new IOException("Can't inflate " + length + " bytes");
+					}
+				} else {
+					offset += read;
+					length -= read;
+				}
+			} while(length > 0);
+		} catch(DataFormatException ex) {
+			throw (IOException)(new IOException("inflate error").initCause(ex));
+		}
+	}
+	
+	private void readFully(byte[] buffer, int offset, int length) throws IOException {
+		do {
+			int read = input.read(buffer, offset, length);
+			if(read < 0) {
+				throw new EOFException();
+			}
+			offset += read;
+			length -= read;
+		} while(length > 0);
+	}
+	
+	private int readInt(byte[] buffer, int offset) {
+		return ((buffer[offset]) << 24) |
+				((buffer[offset + 1] & 255) << 16) |
+				((buffer[offset + 2] & 255) << 8) |
+				((buffer[offset + 3] & 255));
+	}
+	
+	private void skip(long amount) throws IOException {
+		while(amount > 0) {
+			long skipped = input.skip(amount);
+			if(skipped < 0) {
+				throw new EOFException();
+			}
+			amount -= skipped;
+		}
+	}
+	
+	private static boolean checkSignature(byte[] buffer) {
+		for(int i = 0; i < SIGNATURE.length; i++) {
+			if(buffer[i] != SIGNATURE[i]) {
+				return false;
+			}
+		}
+		return true;
+	}
+}

src/com/ra4king/opengl/util/img/PNGDecoder.java

-/*
- * Copyright (c) 2008-2010, Matthias Mann
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *     * Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of Matthias Mann nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.ra4king.opengl.util.img;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.zip.CRC32;
-import java.util.zip.DataFormatException;
-import java.util.zip.Inflater;
-
-/**
- * A PNGDecoder. The slick PNG decoder is based on this class :)
- * 
- * @author Matthias Mann
- */
-public class PNGDecoder {
-	
-	public enum Format {
-		ALPHA(1, true),
-		LUMINANCE(1, false),
-		LUMINANCE_ALPHA(2, true),
-		RGB(3, false),
-		RGBA(4, true),
-		BGRA(4, true),
-		ABGR(4, true);
-		
-		final int numComponents;
-		final boolean hasAlpha;
-		
-		private Format(int numComponents, boolean hasAlpha) {
-			this.numComponents = numComponents;
-			this.hasAlpha = hasAlpha;
-		}
-		
-		public int getNumComponents() {
-			return numComponents;
-		}
-		
-		public boolean isHasAlpha() {
-			return hasAlpha;
-		}
-	}
-	
-	private static final byte[] SIGNATURE = { (byte)137, 80, 78, 71, 13, 10, 26, 10 };
-	
-	private static final int IHDR = 0x49484452;
-	private static final int PLTE = 0x504C5445;
-	private static final int tRNS = 0x74524E53;
-	private static final int IDAT = 0x49444154;
-	
-	private static final byte COLOR_GREYSCALE = 0;
-	private static final byte COLOR_TRUECOLOR = 2;
-	private static final byte COLOR_INDEXED = 3;
-	private static final byte COLOR_GREYALPHA = 4;
-	private static final byte COLOR_TRUEALPHA = 6;
-	
-	private final InputStream input;
-	private final CRC32 crc;
-	private final byte[] buffer;
-	
-	private int chunkLength;
-	private int chunkType;
-	private int chunkRemaining;
-	
-	private int width;
-	private int height;
-	private int bitdepth;
-	private int colorType;
-	private int bytesPerPixel;
-	private byte[] palette;
-	private byte[] paletteA;
-	private byte[] transPixel;
-	
-	public PNGDecoder(InputStream input) throws IOException {
-		this.input = input;
-		this.crc = new CRC32();
-		this.buffer = new byte[4096];
-		
-		readFully(buffer, 0, SIGNATURE.length);
-		if(!checkSignature(buffer)) {
-			throw new IOException("Not a valid PNG file");
-		}
-		
-		openChunk(IHDR);
-		readIHDR();
-		closeChunk();
-		
-		searchIDAT: for(;;) {
-			openChunk();
-			switch(chunkType) {
-				case IDAT:
-					break searchIDAT;
-				case PLTE:
-					readPLTE();
-					break;
-				case tRNS:
-					readtRNS();
-					break;
-			}
-			closeChunk();
-		}
-		
-		if(colorType == COLOR_INDEXED && palette == null) {
-			throw new IOException("Missing PLTE chunk");
-		}
-	}
-	
-	public int getHeight() {
-		return height;
-	}
-	
-	public int getWidth() {
-		return width;
-	}
-	
-	/**
-	 * Checks if the image has a real alpha channel.
-	 * This method does not check for the presence of a tRNS chunk.
-	 * 
-	 * @return true if the image has an alpha channel
-	 * @see #hasAlpha()
-	 */
-	public boolean hasAlphaChannel() {
-		return colorType == COLOR_TRUEALPHA || colorType == COLOR_GREYALPHA;
-	}
-	
-	/**
-	 * Checks if the image has transparency information either from
-	 * an alpha channel or from a tRNS chunk.
-	 * 
-	 * @return true if the image has transparency
-	 * @see #hasAlphaChannel()
-	 * @see #overwriteTRNS(byte, byte, byte)
-	 */
-	public boolean hasAlpha() {
-		return hasAlphaChannel() ||
-				paletteA != null || transPixel != null;
-	}
-	
-	public boolean isRGB() {
-		return colorType == COLOR_TRUEALPHA ||
-				colorType == COLOR_TRUECOLOR ||
-				colorType == COLOR_INDEXED;
-	}
-	
-	/**
-	 * Overwrites the tRNS chunk entry to make a selected color transparent.
-	 * <p>
-	 * This can only be invoked when the image has no alpha channel.
-	 * </p>
-	 * <p>
-	 * Calling this method causes {@link #hasAlpha()} to return true.
-	 * </p>
-	 * 
-	 * @param r
-	 *            the red component of the color to make transparent
-	 * @param g
-	 *            the green component of the color to make transparent
-	 * @param b
-	 *            the blue component of the color to make transparent
-	 * @throws UnsupportedOperationException
-	 *             if the tRNS chunk data can't be set
-	 * @see #hasAlphaChannel()
-	 */
-	public void overwriteTRNS(byte r, byte g, byte b) {
-		if(hasAlphaChannel()) {
-			throw new UnsupportedOperationException("image has an alpha channel");
-		}
-		byte[] pal = this.palette;
-		if(pal == null) {
-			transPixel = new byte[] { 0, r, 0, g, 0, b };
-		} else {
-			paletteA = new byte[pal.length / 3];
-			for(int i = 0, j = 0; i < pal.length; i += 3, j++) {
-				if(pal[i] != r || pal[i + 1] != g || pal[i + 2] != b) {
-					paletteA[j] = (byte)0xFF;
-				}
-			}
-		}
-	}
-	
-	/**
-	 * Computes the implemented format conversion for the desired format.
-	 * 
-	 * @param fmt
-	 *            the desired format
-	 * @return format which best matches the desired format
-	 * @throws UnsupportedOperationException
-	 *             if this PNG file can't be decoded
-	 */
-	public Format decideTextureFormat(Format fmt) {
-		switch(colorType) {
-			case COLOR_TRUECOLOR:
-				switch(fmt) {
-					case ABGR:
-					case RGBA:
-					case BGRA:
-					case RGB:
-						return fmt;
-					default:
-						return Format.RGB;
-				}
-			case COLOR_TRUEALPHA:
-				switch(fmt) {
-					case ABGR:
-					case RGBA:
-					case BGRA:
-					case RGB:
-						return fmt;
-					default:
-						return Format.RGBA;
-				}
-			case COLOR_GREYSCALE:
-				switch(fmt) {
-					case LUMINANCE:
-					case ALPHA:
-						return fmt;
-					default:
-						return Format.LUMINANCE;
-				}
-			case COLOR_GREYALPHA:
-				return Format.LUMINANCE_ALPHA;
-			case COLOR_INDEXED:
-				switch(fmt) {
-					case ABGR:
-					case RGBA:
-					case BGRA:
-						return fmt;
-					default:
-						return Format.RGBA;
-				}
-			default:
-				throw new UnsupportedOperationException("Not yet implemented");
-		}
-	}
-	
-	/**
-	 * Decodes the image into the specified buffer. The first line is placed at
-	 * the current position. After decode the buffer position is at the end of
-	 * the last line.
-	 * 
-	 * @param buffer
-	 *            the buffer
-	 * @param stride
-	 *            the stride in bytes from start of a line to start of the next line, can be negative.
-	 * @param fmt
-	 *            the target format into which the image should be decoded.
-	 * @throws IOException
-	 *             if a read or data error occurred
-	 * @throws IllegalArgumentException
-	 *             if the start position of a line falls outside the buffer
-	 * @throws UnsupportedOperationException
-	 *             if the image can't be decoded into the desired format
-	 */
-	public void decode(ByteBuffer buffer, int stride, Format fmt) throws IOException {
-		final int offset = buffer.position();
-		final int lineSize = ((width * bitdepth + 7) / 8) * bytesPerPixel;
-		byte[] curLine = new byte[lineSize + 1];
-		byte[] prevLine = new byte[lineSize + 1];
-		byte[] palLine = (bitdepth < 8) ? new byte[width + 1] : null;
-		
-		final Inflater inflater = new Inflater();
-		try {
-			for(int y = 0; y < height; y++) {
-				readChunkUnzip(inflater, curLine, 0, curLine.length);
-				unfilter(curLine, prevLine);
-				
-				buffer.position(offset + y * stride);
-				
-				switch(colorType) {
-					case COLOR_TRUECOLOR:
-						switch(fmt) {
-							case ABGR:
-								copyRGBtoABGR(buffer, curLine);
-								break;
-							case RGBA:
-								copyRGBtoRGBA(buffer, curLine);
-								break;
-							case BGRA:
-								copyRGBtoBGRA(buffer, curLine);
-								break;
-							case RGB:
-								copy(buffer, curLine);
-								break;
-							default:
-								throw new UnsupportedOperationException("Unsupported format for this image");
-						}
-						break;
-					case COLOR_TRUEALPHA:
-						switch(fmt) {
-							case ABGR:
-								copyRGBAtoABGR(buffer, curLine);
-								break;
-							case RGBA:
-								copy(buffer, curLine);
-								break;
-							case BGRA:
-								copyRGBAtoBGRA(buffer, curLine);
-								break;
-							case RGB:
-								copyRGBAtoRGB(buffer, curLine);
-								break;
-							default:
-								throw new UnsupportedOperationException("Unsupported format for this image");
-						}
-						break;
-					case COLOR_GREYSCALE:
-						switch(fmt) {
-							case LUMINANCE:
-							case ALPHA:
-								copy(buffer, curLine);
-								break;
-							default:
-								throw new UnsupportedOperationException("Unsupported format for this image");
-						}
-						break;
-					case COLOR_GREYALPHA:
-						switch(fmt) {
-							case LUMINANCE_ALPHA:
-								copy(buffer, curLine);
-								break;
-							default:
-								throw new UnsupportedOperationException("Unsupported format for this image");
-						}
-						break;
-					case COLOR_INDEXED:
-						switch(bitdepth) {
-							case 8:
-								palLine = curLine;
-								break;
-							case 4:
-								expand4(curLine, palLine);
-								break;
-							case 2:
-								expand2(curLine, palLine);
-								break;
-							case 1:
-								expand1(curLine, palLine);
-								break;
-							default:
-								throw new UnsupportedOperationException("Unsupported bitdepth for this image");
-						}
-						switch(fmt) {
-							case ABGR:
-								copyPALtoABGR(buffer, palLine);
-								break;
-							case RGBA:
-								copyPALtoRGBA(buffer, palLine);
-								break;
-							case BGRA:
-								copyPALtoBGRA(buffer, palLine);
-								break;
-							default:
-								throw new UnsupportedOperationException("Unsupported format for this image");
-						}
-						break;
-					default:
-						throw new UnsupportedOperationException("Not yet implemented");
-				}
-				
-				byte[] tmp = curLine;
-				curLine = prevLine;
-				prevLine = tmp;
-			}
-		} finally {
-			inflater.end();
-		}
-	}
-	
-	/**
-	 * Decodes the image into the specified buffer. The last line is placed at
-	 * the current position. After decode the buffer position is at the end of
-	 * the first line.
-	 * 
-	 * @param buffer
-	 *            the buffer
-	 * @param stride
-	 *            the stride in bytes from start of a line to start of the next line, must be positive.
-	 * @param fmt
-	 *            the target format into which the image should be decoded.
-	 * @throws IOException
-	 *             if a read or data error occurred
-	 * @throws IllegalArgumentException
-	 *             if the start position of a line falls outside the buffer
-	 * @throws UnsupportedOperationException
-	 *             if the image can't be decoded into the desired format
-	 */
-	public void decodeFlipped(ByteBuffer buffer, int stride, Format fmt) throws IOException {
-		if(stride <= 0) {
-			throw new IllegalArgumentException("stride");
-		}
-		int pos = buffer.position();
-		int posDelta = (height - 1) * stride;
-		buffer.position(pos + posDelta);
-		decode(buffer, -stride, fmt);
-		buffer.position(buffer.position() + posDelta);
-	}
-	
-	private void copy(ByteBuffer buffer, byte[] curLine) {
-		buffer.put(curLine, 1, curLine.length - 1);
-	}
-	
-	private void copyRGBtoABGR(ByteBuffer buffer, byte[] curLine) {
-		if(transPixel != null) {
-			byte tr = transPixel[1];
-			byte tg = transPixel[3];
-			byte tb = transPixel[5];
-			for(int i = 1, n = curLine.length; i < n; i += 3) {
-				byte r = curLine[i];
-				byte g = curLine[i + 1];
-				byte b = curLine[i + 2];
-				byte a = (byte)0xFF;
-				if(r == tr && g == tg && b == tb) {
-					a = 0;
-				}
-				buffer.put(a).put(b).put(g).put(r);
-			}
-		} else {
-			for(int i = 1, n = curLine.length; i < n; i += 3) {
-				buffer.put((byte)0xFF).put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]);
-			}
-		}
-	}
-	
-	private void copyRGBtoRGBA(ByteBuffer buffer, byte[] curLine) {
-		if(transPixel != null) {
-			byte tr = transPixel[1];
-			byte tg = transPixel[3];
-			byte tb = transPixel[5];
-			for(int i = 1, n = curLine.length; i < n; i += 3) {
-				byte r = curLine[i];
-				byte g = curLine[i + 1];
-				byte b = curLine[i + 2];
-				byte a = (byte)0xFF;
-				if(r == tr && g == tg && b == tb) {
-					a = 0;
-				}
-				buffer.put(r).put(g).put(b).put(a);
-			}
-		} else {
-			for(int i = 1, n = curLine.length; i < n; i += 3) {
-				buffer.put(curLine[i]).put(curLine[i + 1]).put(curLine[i + 2]).put((byte)0xFF);
-			}
-		}
-	}
-	
-	private void copyRGBtoBGRA(ByteBuffer buffer, byte[] curLine) {
-		if(transPixel != null) {
-			byte tr = transPixel[1];
-			byte tg = transPixel[3];
-			byte tb = transPixel[5];
-			for(int i = 1, n = curLine.length; i < n; i += 3) {
-				byte r = curLine[i];
-				byte g = curLine[i + 1];
-				byte b = curLine[i + 2];
-				byte a = (byte)0xFF;
-				if(r == tr && g == tg && b == tb) {
-					a = 0;
-				}
-				buffer.put(b).put(g).put(r).put(a);
-			}
-		} else {
-			for(int i = 1, n = curLine.length; i < n; i += 3) {
-				buffer.put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]).put((byte)0xFF);
-			}
-		}
-	}
-	
-	private void copyRGBAtoABGR(ByteBuffer buffer, byte[] curLine) {
-		for(int i = 1, n = curLine.length; i < n; i += 4) {
-			buffer.put(curLine[i + 3]).put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]);
-		}
-	}
-	
-	private void copyRGBAtoBGRA(ByteBuffer buffer, byte[] curLine) {
-		for(int i = 1, n = curLine.length; i < n; i += 4) {
-			buffer.put(curLine[i + 2]).put(curLine[i + 1]).put(curLine[i]).put(curLine[i + 3]);
-		}
-	}
-	
-	private void copyRGBAtoRGB(ByteBuffer buffer, byte[] curLine) {
-		for(int i = 1, n = curLine.length; i < n; i += 4) {
-			buffer.put(curLine[i]).put(curLine[i + 1]).put(curLine[i + 2]);
-		}
-	}
-	
-	private void copyPALtoABGR(ByteBuffer buffer, byte[] curLine) {
-		if(paletteA != null) {
-			for(int i = 1, n = curLine.length; i < n; i += 1) {
-				int idx = curLine[i] & 255;
-				byte r = palette[idx * 3 + 0];
-				byte g = palette[idx * 3 + 1];
-				byte b = palette[idx * 3 + 2];
-				byte a = paletteA[idx];
-				buffer.put(a).put(b).put(g).put(r);
-			}
-		} else {
-			for(int i = 1, n = curLine.length; i < n; i += 1) {
-				int idx = curLine[i] & 255;
-				byte r = palette[idx * 3 + 0];
-				byte g = palette[idx * 3 + 1];
-				byte b = palette[idx * 3 + 2];
-				byte a = (byte)0xFF;
-				buffer.put(a).put(b).put(g).put(r);
-			}
-		}
-	}
-	
-	private void copyPALtoRGBA(ByteBuffer buffer, byte[] curLine) {
-		if(paletteA != null) {
-			for(int i = 1, n = curLine.length; i < n; i += 1) {
-				int idx = curLine[i] & 255;
-				byte r = palette[idx * 3 + 0];
-				byte g = palette[idx * 3 + 1];
-				byte b = palette[idx * 3 + 2];
-				byte a = paletteA[idx];
-				buffer.put(r).put(g).put(b).put(a);
-			}
-		} else {
-			for(int i = 1, n = curLine.length; i < n; i += 1) {
-				int idx = curLine[i] & 255;
-				byte r = palette[idx * 3 + 0];
-				byte g = palette[idx * 3 + 1];
-				byte b = palette[idx * 3 + 2];
-				byte a = (byte)0xFF;
-				buffer.put(r).put(g).put(b).put(a);
-			}
-		}
-	}
-	
-	private void copyPALtoBGRA(ByteBuffer buffer, byte[] curLine) {
-		if(paletteA != null) {
-			for(int i = 1, n = curLine.length; i < n; i += 1) {
-				int idx = curLine[i] & 255;
-				byte r = palette[idx * 3 + 0];
-				byte g = palette[idx * 3 + 1];
-				byte b = palette[idx * 3 + 2];
-				byte a = paletteA[idx];
-				buffer.put(b).put(g).put(r).put(a);
-			}
-		} else {
-			for(int i = 1, n = curLine.length; i < n; i += 1) {
-				int idx = curLine[i] & 255;
-				byte r = palette[idx * 3 + 0];
-				byte g = palette[idx * 3 + 1];
-				byte b = palette[idx * 3 + 2];
-				byte a = (byte)0xFF;
-				buffer.put(b).put(g).put(r).put(a);
-			}
-		}
-	}
-	
-	private void expand4(byte[] src, byte[] dst) {
-		for(int i = 1, n = dst.length; i < n; i += 2) {
-			int val = src[1 + (i >> 1)] & 255;
-			switch(n - i) {
-				default:
-					dst[i + 1] = (byte)(val & 15);
-				case 1:
-					dst[i] = (byte)(val >> 4);
-			}
-		}
-	}
-	
-	private void expand2(byte[] src, byte[] dst) {
-		for(int i = 1, n = dst.length; i < n; i += 4) {
-			int val = src[1 + (i >> 2)] & 255;
-			switch(n - i) {
-				default:
-					dst[i + 3] = (byte)((val) & 3);
-				case 3:
-					dst[i + 2] = (byte)((val >> 2) & 3);
-				case 2:
-					dst[i + 1] = (byte)((val >> 4) & 3);
-				case 1:
-					dst[i] = (byte)((val >> 6));
-			}
-		}
-	}
-	
-	private void expand1(byte[] src, byte[] dst) {
-		for(int i = 1, n = dst.length; i < n; i += 8) {
-			int val = src[1 + (i >> 3)] & 255;
-			switch(n - i) {
-				default:
-					dst[i + 7] = (byte)((val) & 1);
-				case 7:
-					dst[i + 6] = (byte)((val >> 1) & 1);
-				case 6:
-					dst[i + 5] = (byte)((val >> 2) & 1);
-				case 5:
-					dst[i + 4] = (byte)((val >> 3) & 1);
-				case 4:
-					dst[i + 3] = (byte)((val >> 4) & 1);
-				case 3:
-					dst[i + 2] = (byte)((val >> 5) & 1);
-				case 2:
-					dst[i + 1] = (byte)((val >> 6) & 1);
-				case 1:
-					dst[i] = (byte)((val >> 7));
-			}
-		}
-	}
-	
-	private void unfilter(byte[] curLine, byte[] prevLine) throws IOException {
-		switch(curLine[0]) {
-			case 0: // none
-				break;
-			case 1:
-				unfilterSub(curLine);
-				break;
-			case 2:
-				unfilterUp(curLine, prevLine);
-				break;
-			case 3:
-				unfilterAverage(curLine, prevLine);
-				break;
-			case 4:
-				unfilterPaeth(curLine, prevLine);
-				break;
-			default:
-				throw new IOException("invalide filter type in scanline: " + curLine[0]);
-		}
-	}
-	
-	private void unfilterSub(byte[] curLine) {
-		final int bpp = this.bytesPerPixel;
-		for(int i = bpp + 1, n = curLine.length; i < n; ++i) {
-			curLine[i] += curLine[i - bpp];
-		}
-	}
-	
-	private void unfilterUp(byte[] curLine, byte[] prevLine) {
-		for(int i = 1, n = curLine.length; i < n; ++i) {
-			curLine[i] += prevLine[i];
-		}
-	}
-	
-	private void unfilterAverage(byte[] curLine, byte[] prevLine) {
-		final int bpp = this.bytesPerPixel;
-		
-		int i;
-		for(i = 1; i <= bpp; ++i) {
-			curLine[i] += (byte)((prevLine[i] & 0xFF) >>> 1);
-		}
-		for(int n = curLine.length; i < n; ++i) {
-			curLine[i] += (byte)(((prevLine[i] & 0xFF) + (curLine[i - bpp] & 0xFF)) >>> 1);
-		}
-	}
-	
-	private void unfilterPaeth(byte[] curLine, byte[] prevLine) {
-		final int bpp = this.bytesPerPixel;
-		
-		int i;
-		for(i = 1; i <= bpp; ++i) {
-			curLine[i] += prevLine[i];
-		}
-		for(int n = curLine.length; i < n; ++i) {
-			int a = curLine[i - bpp] & 255;
-			int b = prevLine[i] & 255;
-			int c = prevLine[i - bpp] & 255;
-			int p = a + b - c;
-			int pa = p - a;
-			if(pa < 0)
-				pa = -pa;
-			int pb = p - b;
-			if(pb < 0)
-				pb = -pb;
-			int pc = p - c;
-			if(pc < 0)
-				pc = -pc;
-			if(pa <= pb && pa <= pc)
-				c = a;
-			else if(pb <= pc)
-				c = b;
-			curLine[i] += (byte)c;
-		}
-	}
-	
-	private void readIHDR() throws IOException {
-		checkChunkLength(13);
-		readChunk(buffer, 0, 13);
-		width = readInt(buffer, 0);
-		height = readInt(buffer, 4);
-		bitdepth = buffer[8] & 255;
-		colorType = buffer[9] & 255;
-		
-		switch(colorType) {
-			case COLOR_GREYSCALE:
-				if(bitdepth != 8) {
-					throw new IOException("Unsupported bit depth: " + bitdepth);
-				}
-				bytesPerPixel = 1;
-				break;
-			case COLOR_GREYALPHA:
-				if(bitdepth != 8) {
-					throw new IOException("Unsupported bit depth: " + bitdepth);
-				}
-				bytesPerPixel = 2;
-				break;
-			case COLOR_TRUECOLOR:
-				if(bitdepth != 8) {
-					throw new IOException("Unsupported bit depth: " + bitdepth);
-				}
-				bytesPerPixel = 3;
-				break;
-			case COLOR_TRUEALPHA:
-				if(bitdepth != 8) {
-					throw new IOException("Unsupported bit depth: " + bitdepth);
-				}
-				bytesPerPixel = 4;
-				break;
-			case COLOR_INDEXED:
-				switch(bitdepth) {
-					case 8:
-					case 4:
-					case 2:
-					case 1:
-						bytesPerPixel = 1;
-						break;
-					default:
-						throw new IOException("Unsupported bit depth: " + bitdepth);
-				}
-				break;
-			default:
-				throw new IOException("unsupported color format: " + colorType);
-		}
-		
-		if(buffer[10] != 0) {
-			throw new IOException("unsupported compression method");
-		}
-		if(buffer[11] != 0) {
-			throw new IOException("unsupported filtering method");
-		}
-		if(buffer[12] != 0) {
-			throw new IOException("unsupported interlace method");
-		}
-	}
-	
-	private void readPLTE() throws IOException {
-		int paletteEntries = chunkLength / 3;
-		if(paletteEntries < 1 || paletteEntries > 256 || (chunkLength % 3) != 0) {
-			throw new IOException("PLTE chunk has wrong length");
-		}
-		palette = new byte[paletteEntries * 3];
-		readChunk(palette, 0, palette.length);
-	}
-	
-	private void readtRNS() throws IOException {
-		switch(colorType) {
-			case COLOR_GREYSCALE:
-				checkChunkLength(2);
-				transPixel = new byte[2];
-				readChunk(transPixel, 0, 2);
-				break;
-			case COLOR_TRUECOLOR:
-				checkChunkLength(6);
-				transPixel = new byte[6];
-				readChunk(transPixel, 0, 6);
-				break;
-			case COLOR_INDEXED:
-				if(palette == null) {
-					throw new IOException("tRNS chunk without PLTE chunk");
-				}
-				paletteA = new byte[palette.length / 3];
-				Arrays.fill(paletteA, (byte)0xFF);
-				readChunk(paletteA, 0, paletteA.length);
-				break;
-			default:
-				// just ignore it
-		}
-	}
-	
-	private void closeChunk() throws IOException {
-		if(chunkRemaining > 0) {
-			// just skip the rest and the CRC
-			skip(chunkRemaining + 4);
-		} else {
-			readFully(buffer, 0, 4);
-			int expectedCrc = readInt(buffer, 0);
-			int computedCrc = (int)crc.getValue();
-			if(computedCrc != expectedCrc) {
-				throw new IOException("Invalid CRC");
-			}
-		}
-		chunkRemaining = 0;
-		chunkLength = 0;
-		chunkType = 0;
-	}
-	
-	private void openChunk() throws IOException {
-		readFully(buffer, 0, 8);
-		chunkLength = readInt(buffer, 0);
-		chunkType = readInt(buffer, 4);
-		chunkRemaining = chunkLength;
-		crc.reset();
-		crc.update(buffer, 4, 4); // only chunkType
-	}
-	
-	private void openChunk(int expected) throws IOException {
-		openChunk();
-		if(chunkType != expected) {
-			throw new IOException("Expected chunk: " + Integer.toHexString(expected));
-		}
-	}
-	
-	private void checkChunkLength(int expected) throws IOException {
-		if(chunkLength != expected) {
-			throw new IOException("Chunk has wrong size");
-		}
-	}
-	
-	private int readChunk(byte[] buffer, int offset, int length) throws IOException {
-		if(length > chunkRemaining) {
-			length = chunkRemaining;
-		}
-		readFully(buffer, offset, length);
-		crc.update(buffer, offset, length);
-		chunkRemaining -= length;
-		return length;
-	}
-	
-	private void refillInflater(Inflater inflater) throws IOException {
-		while(chunkRemaining == 0) {
-			closeChunk();
-			openChunk(IDAT);
-		}
-		int read = readChunk(buffer, 0, buffer.length);
-		inflater.setInput(buffer, 0, read);
-	}
-	
-	private void readChunkUnzip(Inflater inflater, byte[] buffer, int offset, int length) throws IOException {
-		assert (buffer != this.buffer);
-		try {
-			do {
-				int read = inflater.inflate(buffer, offset, length);
-				if(read <= 0) {
-					if(inflater.finished()) {
-						throw new EOFException();
-					}
-					if(inflater.needsInput()) {
-						refillInflater(inflater);
-					} else {
-						throw new IOException("Can't inflate " + length + " bytes");
-					}
-				} else {
-					offset += read;
-					length -= read;
-				}
-			} while(length > 0);
-		} catch(DataFormatException ex) {
-			throw (IOException)(new IOException("inflate error").initCause(ex));
-		}
-	}
-	
-	private void readFully(byte[] buffer, int offset, int length) throws IOException {
-		do {
-			int read = input.read(buffer, offset, length);
-			if(read < 0) {
-				throw new EOFException();
-			}
-			offset += read;
-			length -= read;
-		} while(length > 0);
-	}
-	
-	private int readInt(byte[] buffer, int offset) {
-		return ((buffer[offset]) << 24) |
-				((buffer[offset + 1] & 255) << 16) |
-				((buffer[offset + 2] & 255) << 8) |
-				((buffer[offset + 3] & 255));
-	}
-	
-	private void skip(long amount) throws IOException {
-		while(amount > 0) {
-			long skipped = input.skip(amount);
-			if(skipped < 0) {
-				throw new EOFException();
-			}
-			amount -= skipped;
-		}
-	}
-	
-	private static boolean checkSignature(byte[] buffer) {
-		for(int i = 0; i < SIGNATURE.length; i++) {
-			if(buffer[i] != SIGNATURE[i]) {
-				return false;
-			}
-		}
-		return true;
-	}
-}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.