You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2010/09/10 18:33:42 UTC

svn commit: r995859 [15/30] - in /commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan: ./ color/ common/ common/byteSources/ common/mylzw/ formats/bmp/ formats/bmp/pixelparsers/ formats/bmp/writers/ formats/gif/ formats/ico/ formats/jpeg/ f...

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngImageParser.java Fri Sep 10 16:33:35 2010
@@ -65,873 +65,873 @@ import org.apache.sanselan.util.ParamMap
 public class PngImageParser extends ImageParser implements PngConstants
 {
 
-	public PngImageParser()
-	{
-		// setDebug(true);
-	}
-
-	public String getName()
-	{
-		return "Png-Custom";
-	}
-
-	public String getDefaultExtension()
-	{
-		return DEFAULT_EXTENSION;
-	}
-
-	private static final String DEFAULT_EXTENSION = ".png";
-
-	private static final String ACCEPTED_EXTENSIONS[] = { DEFAULT_EXTENSION, };
-
-	protected String[] getAcceptedExtensions()
-	{
-		return ACCEPTED_EXTENSIONS;
-	}
-
-	protected ImageFormat[] getAcceptedTypes()
-	{
-		return new ImageFormat[] { ImageFormat.IMAGE_FORMAT_PNG, //
-		};
-	}
-
-	// private final static int tRNS = CharsToQuad('t', 'R', 'N', 's');
-	
-	public static final String getChunkTypeName(int chunkType) {
-		StringBuffer result = new StringBuffer();
-		result.append((char) (0xff & (chunkType >> 24)));
-		result.append((char) (0xff & (chunkType >> 16)));
-		result.append((char) (0xff & (chunkType >> 8)));
-		result.append((char) (0xff & (chunkType >> 0)));
-		return result.toString();
-	}
-	
-	/**
-	 * @return List of String-formatted chunk types, ie. "tRNs".
-	 */
-	public List getChuckTypes(InputStream is) throws ImageReadException, IOException {
-		List chunks = readChunks(is, null, false);
-		List chunkTypes = new ArrayList();
-		for (int i=0; i<chunks.size(); i++) {
-			PNGChunk chunk = (PNGChunk) chunks.get(i);
-			chunkTypes.add(getChunkTypeName(chunk.chunkType));
-		}
-		return chunkTypes;
-	}
-	
-	public boolean hasChuckType(ByteSource byteSource, int chunkType) throws ImageReadException, IOException
-	{
-		InputStream is = null;
-
-		try
-		{
-			is = byteSource.getInputStream();
-
-			ArrayList chunks = null;
-
-			readSignature(is);
-			chunks = readChunks(is, new int[] { chunkType, }, true);
-			return chunks.size() > 0;
-		} finally
-		{
-			try
-			{
-				if (is != null) {
-				    is.close();
-				}
-			} catch (Exception e)
-			{
-				Debug.debug(e);
-			}
-		}
-	}
-	
-	
-	private boolean keepChunk(int ChunkType, int chunkTypes[])
-	{
-		// System.out.println("keepChunk: ");
-		if (chunkTypes == null)
-			return true;
-
-		for (int i = 0; i < chunkTypes.length; i++)
-		{
-			if (chunkTypes[i] == ChunkType)
-				return true;
-		}
-		return false;
-	}
-
-	private ArrayList readChunks(InputStream is, int chunkTypes[],
-			boolean returnAfterFirst) throws ImageReadException, IOException
-	{
-		ArrayList result = new ArrayList();
-
-		while (true)
-		{
-			if (debug)
-				System.out.println("");
-
-			int length = read4Bytes("Length", is, "Not a Valid PNG File");
-			int chunkType = read4Bytes("ChunkType", is, "Not a Valid PNG File");
-			
-			if (debug)
-			{
-				printCharQuad("ChunkType", chunkType);
-				debugNumber("Length", length, 4);
-			}
-			boolean keep = keepChunk(chunkType, chunkTypes);
-
-			byte bytes[] = null;
-			if (keep)
-			{
-				bytes = readByteArray("Chunk Data", length, is,
-						"Not a Valid PNG File: Couldn't read Chunk Data.");
-			} else
-				skipBytes(is, length, "Not a Valid PNG File");
-
-			if (debug)
-				if (bytes != null)
-					debugNumber("bytes", bytes.length, 4);
-
-			int CRC = read4Bytes("CRC", is, "Not a Valid PNG File");
-			
-			if (keep)
-			{
-				if (chunkType == iCCP)
-					result.add(new PNGChunkiCCP(length, chunkType, CRC, bytes));
-				else if (chunkType == tEXt)
-					result.add(new PNGChunktEXt(length, chunkType, CRC, bytes));
-				else if (chunkType == zTXt)
-					result.add(new PNGChunkzTXt(length, chunkType, CRC, bytes));
-				else if (chunkType == IHDR)
-					result.add(new PNGChunkIHDR(length, chunkType, CRC, bytes));
-				else if (chunkType == PLTE)
-					result.add(new PNGChunkPLTE(length, chunkType, CRC, bytes));
-				else if (chunkType == pHYs)
-					result.add(new PNGChunkpHYs(length, chunkType, CRC, bytes));
-				else if (chunkType == IDAT)
-					result.add(new PNGChunkIDAT(length, chunkType, CRC, bytes));
-				else if (chunkType == gAMA)
-					result.add(new PNGChunkgAMA(length, chunkType, CRC, bytes));
-				else if (chunkType == iTXt)
-					result.add(new PNGChunkiTXt(length, chunkType, CRC, bytes));
-				else
-					result.add(new PNGChunk(length, chunkType, CRC, bytes));
-
-				if (returnAfterFirst)
-					return result;
-			}
-
-			if (chunkType == IEND)
-				break;
-
-		}
-
-		return result;
-
-	}
-
-	public void readSignature(InputStream is) throws ImageReadException,
-			IOException
-	{
-		readAndVerifyBytes(is, PNG_Signature,
-				"Not a Valid PNG Segment: Incorrect Signature");
-
-	}
-
-	private ArrayList readChunks(ByteSource byteSource, int chunkTypes[],
-			boolean returnAfterFirst) throws ImageReadException, IOException
-	{
-		InputStream is = null;
-
-		try
-		{
-			is = byteSource.getInputStream();
-
-			ArrayList chunks = null;
-
-			readSignature(is);
-			chunks = readChunks(is, chunkTypes, returnAfterFirst);
-			return chunks;
-		} finally
-		{
-			try
-			{
-			    if (is != null) {
-			        is.close();
-			    }
-			} catch (Exception e)
-			{
-				Debug.debug(e);
-			}
-		}
-	}
-
-	public byte[] getICCProfileBytes(ByteSource byteSource, Map params)
-			throws ImageReadException, IOException
-	{
-		ArrayList chunks = readChunks(byteSource, new int[] { iCCP, }, true);
-
-		if ((chunks == null) || (chunks.size() < 1))
-		{
-			// throw new ImageReadException("Png: No chunks");
-			return null;
-		}
-
-		if (chunks.size() > 1)
-			throw new ImageReadException(
-					"PNG contains more than one ICC Profile ");
-
-		PNGChunkiCCP pngChunkiCCP = (PNGChunkiCCP) chunks.get(0);
-		byte bytes[] = pngChunkiCCP.UncompressedProfile;
-
-		return (bytes);
-	}
-
-	public Dimension getImageSize(ByteSource byteSource, Map params)
-			throws ImageReadException, IOException
-	{
-		ArrayList chunks = readChunks(byteSource, new int[] { IHDR, }, true);
-
-		if ((chunks == null) || (chunks.size() < 1))
-			throw new ImageReadException("Png: No chunks");
-
-		if (chunks.size() > 1)
-			throw new ImageReadException("PNG contains more than one Header");
-
-		PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) chunks.get(0);
-
-		return new Dimension(pngChunkIHDR.width, pngChunkIHDR.height);
-	}
-
-	public byte[] embedICCProfile(byte image[], byte profile[])
-	{
-		return null;
-	}
-
-	public boolean embedICCProfile(File src, File dst, byte profile[])
-	{
-		return false;
-	}
-
-	public IImageMetadata getMetadata(ByteSource byteSource, Map params)
-			throws ImageReadException, IOException
-	{
-		ArrayList chunks = readChunks(byteSource, new int[] { tEXt, zTXt, },
-				true);
-
-		if ((chunks == null) || (chunks.size() < 1))
-			return null;
-
-		ImageMetadata result = new ImageMetadata();
-
-		for (int i = 0; i < chunks.size(); i++)
-		{
-			PNGTextChunk chunk = (PNGTextChunk) chunks.get(i);
-
-			result.add(chunk.getKeyword(), chunk.getText());
-		}
-
-		return result;
-	}
-
-	private boolean isGrayscale(int colorType) throws ImageReadException
-	{
-		// Color type is a single-byte integer that describes the interpretation
-		// of the
-		// image data. Color type codes represent sums of the following values:
-		// 1 (palette used), 2 (color used), and 4 (alpha channel used).
-		// Valid values are 0, 2, 3, 4, and 6.
-		//
-		// Bit depth restrictions for each color type are imposed to simplify
-		// implementations
-		// and to prohibit combinations that do not compress well. Decoders must
-		// support all
-		// valid combinations of bit depth and color type. The allowed
-		// combinations are:
-		//
-		// Color Allowed Interpretation
-		// Type Bit Depths
-		//
-		// 0 1,2,4,8,16 Each pixel is a grayscale sample.
-		//
-		// 2 8,16 Each pixel is an R,G,B triple.
-		//
-		// 3 1,2,4,8 Each pixel is a palette index;
-		// a PLTE chunk must appear.
-		//
-		// 4 8,16 Each pixel is a grayscale sample,
-		// followed by an alpha sample.
-		//
-		// 6 8,16 Each pixel is an R,G,B triple,
-		// followed by an alpha sample.
-		switch (colorType)
-		{
-		case COLOR_TYPE_GREYSCALE:
-			return true;
-		case COLOR_TYPE_TRUE_COLOR:
-			return false;
-		case COLOR_TYPE_INDEXED_COLOR:
-			return false;
-		case COLOR_TYPE_GREYSCALE_WITH_ALPHA:
-			return true;
-		case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA:
-			return false;
-		}
-
-		// return -1;
-		throw new ImageReadException("PNG: unknown color type: " + colorType);
-	}
-
-	private int samplesPerPixel(int colorType) throws ImageReadException
-	{
-		// Color type is a single-byte integer that describes the interpretation
-		// of the
-		// image data. Color type codes represent sums of the following values:
-		// 1 (palette used), 2 (color used), and 4 (alpha channel used).
-		// Valid values are 0, 2, 3, 4, and 6.
-		//
-		// Bit depth restrictions for each color type are imposed to simplify
-		// implementations
-		// and to prohibit combinations that do not compress well. Decoders must
-		// support all
-		// valid combinations of bit depth and color type. The allowed
-		// combinations are:
-		//
-		// Color Allowed Interpretation
-		// Type Bit Depths
-		//
-		// 0 1,2,4,8,16 Each pixel is a grayscale sample.
-		//
-		// 2 8,16 Each pixel is an R,G,B triple.
-		//
-		// 3 1,2,4,8 Each pixel is a palette index;
-		// a PLTE chunk must appear.
-		//
-		// 4 8,16 Each pixel is a grayscale sample,
-		// followed by an alpha sample.
-		//
-		// 6 8,16 Each pixel is an R,G,B triple,
-		// followed by an alpha sample.
-		switch (colorType)
-		{
-		case COLOR_TYPE_GREYSCALE:
-			return 1;
-		case COLOR_TYPE_TRUE_COLOR:
-			return 3;
-		case COLOR_TYPE_INDEXED_COLOR:
-			return 1; // is this accurate ? how may bits per index?
-		case COLOR_TYPE_GREYSCALE_WITH_ALPHA:
-			return 2;
-		case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA:
-			return 4;
-		}
-
-		// return -1;
-		throw new ImageReadException("PNG: unknown color type: " + colorType);
-	}
-
-	private ArrayList filterChunks(ArrayList v, int type)
-	{
-		ArrayList result = new ArrayList();
-
-		for (int i = 0; i < v.size(); i++)
-		{
-			PNGChunk chunk = (PNGChunk) v.get(i);
-			if (chunk.chunkType == type)
-				result.add(chunk);
-		}
-
-		return result;
-	}
-
-	private boolean hasAlphaChannel(int ColorType) throws ImageReadException
-	{
-		switch (ColorType)
-		{
-		case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
-			// sample.
-		case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
-		case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette index;
-			return false;
-		case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a grayscale
-			// sample,
-			// followed by an alpha sample.
-		case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an R,G,B
-			// triple,
-			// followed by an alpha sample.
-			return true;
-		default:
-			throw new ImageReadException("PNG: unknown color type: "
-					+ ColorType);
-		}
-	}
-
-	private String getColorTypeDescription(int ColorType)
-	{
-		switch (ColorType)
-		{
-		case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
-			// sample.
-			return "grayscale";
-		case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
-			return "rgb";
-		case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette index;
-			return "indexed rgb";
-		case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a grayscale
-			// sample,
-			// followed by an alpha sample.
-			return "grayscale w/ alpha";
-		case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an R,G,B
-			// triple,
-			// followed by an alpha sample.
-			return "RGB w/ alpha";
-		default:
-			return "Unknown Color Type";
-		}
-	}
-
-	// TODO: I have been too casual about making inner classes subclass of
-	// BinaryFileParser
-	// I may not have always preserved byte order correctly.
-
-	private TransparencyFilter getTransparencyFilter(int ColorType,
-			PNGChunk pngChunktRNS) throws ImageReadException, IOException
-	{
-		// this.printCharQuad("pngChunktRNS.ChunkType", pngChunktRNS.ChunkType);
-		// this.debugNumber("pngChunktRNS.Length", pngChunktRNS.Length);
-
-		switch (ColorType)
-		{
-		case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
-			// sample.
-			return new TransparencyFilterGrayscale(pngChunktRNS.bytes);
-		case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
-			return new TransparencyFilterTrueColor(pngChunktRNS.bytes);
-		case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette index;
-			return new TransparencyFilterIndexedColor(pngChunktRNS.bytes);
-		case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a grayscale
-			// sample,
-		case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an R,G,B
-			// triple,
-		default:
-			throw new ImageReadException(
-					"Simple Transparency not compatible with ColorType: "
-							+ ColorType);
-		}
-	}
-
-	public ImageInfo getImageInfo(ByteSource byteSource, Map params)
-			throws ImageReadException, IOException
-	{
-		ArrayList chunks = readChunks(byteSource, new int[] { IHDR, pHYs, tEXt,
-				zTXt, tRNS, PLTE, iTXt, }, false);
-
-		// if(chunks!=null)
-		// System.out.println("chunks: " + chunks.size());
-
-		if ((chunks == null) || (chunks.size() < 1))
-			throw new ImageReadException("PNG: no chunks");
-
-		ArrayList IHDRs = filterChunks(chunks, IHDR);
-		if (IHDRs.size() != 1)
-			throw new ImageReadException("PNG contains more than one Header");
-
-		PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) IHDRs.get(0);
-		PNGChunk pngChunktRNS = null;
-
-		boolean isTransparent = false;
-
-		ArrayList tRNSs = filterChunks(chunks, tRNS);
-		if (tRNSs.size() > 0)
-		{
-			isTransparent = true;
-			pngChunktRNS = (PNGChunk) IHDRs.get(0);
-		} else
-			hasAlphaChannel(pngChunkIHDR.colorType);
-
-		PNGChunkpHYs pngChunkpHYs = null;
-
-		ArrayList pHYss = filterChunks(chunks, pHYs);
-		if (pHYss.size() > 1)
-			throw new ImageReadException("PNG contains more than one pHYs: "
-					+ pHYss.size());
-		else if (pHYss.size() == 1)
-			pngChunkpHYs = (PNGChunkpHYs) pHYss.get(0);
-
-		ArrayList tEXts = filterChunks(chunks, tEXt);
-		ArrayList zTXts = filterChunks(chunks, zTXt);
-		ArrayList iTXts = filterChunks(chunks, iTXt);
-
-		{
-			ArrayList comments = new ArrayList();
-			List textChunks = new ArrayList();
-
-			for (int i = 0; i < tEXts.size(); i++)
-			{
-				PNGChunktEXt pngChunktEXt = (PNGChunktEXt) tEXts.get(i);
-				comments.add(pngChunktEXt.keyword + ": " + pngChunktEXt.text);
-				textChunks.add(pngChunktEXt.getContents());
-			}
-			for (int i = 0; i < zTXts.size(); i++)
-			{
-				PNGChunkzTXt pngChunkzTXt = (PNGChunkzTXt) zTXts.get(i);
-				comments.add(pngChunkzTXt.keyword + ": " + pngChunkzTXt.text);
-				textChunks.add(pngChunkzTXt.getContents());
-			}
-			for (int i = 0; i < iTXts.size(); i++)
-			{
-				PNGChunkiTXt pngChunkiTXt = (PNGChunkiTXt) iTXts.get(i);
-				comments.add(pngChunkiTXt.keyword + ": " + pngChunkiTXt.text);
-				textChunks.add(pngChunkiTXt.getContents());
-			}
-
-			int BitsPerPixel = pngChunkIHDR.bitDepth
-					* samplesPerPixel(pngChunkIHDR.colorType);
-			ImageFormat Format = ImageFormat.IMAGE_FORMAT_PNG;
-			String FormatName = "PNG Portable Network Graphics";
-			int Height = pngChunkIHDR.height;
-			String MimeType = "image/png";
-			int NumberOfImages = 1;
-			int Width = pngChunkIHDR.width;
-			boolean isProgressive = (pngChunkIHDR.interlaceMethod != 0);
-
-			int PhysicalHeightDpi = -1;
-			float PhysicalHeightInch = -1;
-			int PhysicalWidthDpi = -1;
-			float PhysicalWidthInch = -1;
-
-			// if (pngChunkpHYs != null)
-			// {
-			// System.out.println("\t" + "pngChunkpHYs.UnitSpecifier: " +
-			// pngChunkpHYs.UnitSpecifier );
-			// System.out.println("\t" + "pngChunkpHYs.PixelsPerUnitYAxis: " +
-			// pngChunkpHYs.PixelsPerUnitYAxis );
-			// System.out.println("\t" + "pngChunkpHYs.PixelsPerUnitXAxis: " +
-			// pngChunkpHYs.PixelsPerUnitXAxis );
-			// }
-			if ((pngChunkpHYs != null) && (pngChunkpHYs.UnitSpecifier == 1)) // meters
-			{
-				double meters_per_inch = 0.0254;
-
-				PhysicalWidthDpi = (int) Math
-						.round(pngChunkpHYs.PixelsPerUnitXAxis
-								* meters_per_inch);
-				PhysicalWidthInch = (float) ((double) Width
-						* (double) pngChunkpHYs.PixelsPerUnitXAxis * meters_per_inch);
-				PhysicalHeightDpi = (int) Math
-						.round(pngChunkpHYs.PixelsPerUnitYAxis
-								* meters_per_inch);
-				PhysicalHeightInch = (float) ((double) Height
-						* (double) pngChunkpHYs.PixelsPerUnitYAxis * meters_per_inch);
-			}
-
-			String FormatDetails = "Png";
-
-			boolean usesPalette = false;
-
-			ArrayList PLTEs = filterChunks(chunks, PLTE);
-			if (PLTEs.size() > 1)
-				usesPalette = true;
-
-			int ColorType;
-			switch (pngChunkIHDR.colorType)
-			{
-			case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
-				// sample.
-			case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a
-				// grayscale sample,
-				// followed by an alpha sample.
-				ColorType = ImageInfo.COLOR_TYPE_GRAYSCALE;
-				break;
-			case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
-			case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette
-				// index;
-			case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an
-				// R,G,B triple,
-				// followed by an alpha sample.
-				ColorType = ImageInfo.COLOR_TYPE_RGB;
-				break;
-			default:
-				throw new ImageReadException("Png: Unknown ColorType: "
-						+ pngChunkIHDR.colorType);
-			}
-
-			String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_PNG_FILTER;
-
-			ImageInfo result = new PngImageInfo(FormatDetails, BitsPerPixel,
-					comments, Format, FormatName, Height, MimeType,
-					NumberOfImages, PhysicalHeightDpi, PhysicalHeightInch,
-					PhysicalWidthDpi, PhysicalWidthInch, Width, isProgressive,
-					isTransparent, usesPalette, ColorType,
-					compressionAlgorithm, textChunks);
-
-			return result;
-		}
-	}
-
-	public BufferedImage getBufferedImage(ByteSource byteSource, Map params)
-			throws ImageReadException, IOException
-	{
-		boolean verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
-				false);
-
-		if (params.containsKey(PARAM_KEY_VERBOSE))
-			params.remove(PARAM_KEY_VERBOSE);
-
-		// if (params.size() > 0) {
-		// Object firstKey = params.keySet().iterator().next();
-		// throw new ImageWriteException("Unknown parameter: " + firstKey);
-		// }
-
-		ArrayList chunks = readChunks(byteSource, new int[] { IHDR, PLTE, IDAT,
-				tRNS, iCCP, gAMA, sRGB, }, false);
-
-		if ((chunks == null) || (chunks.size() < 1))
-			throw new ImageReadException("PNG: no chunks");
-
-		ArrayList IHDRs = filterChunks(chunks, IHDR);
-		if (IHDRs.size() != 1)
-			throw new ImageReadException("PNG contains more than one Header");
-
-		PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) IHDRs.get(0);
-
-		ArrayList PLTEs = filterChunks(chunks, PLTE);
-		if (PLTEs.size() > 1)
-			throw new ImageReadException("PNG contains more than one Palette");
-
-		PNGChunkPLTE pngChunkPLTE = null;
-		if (PLTEs.size() == 1)
-			pngChunkPLTE = (PNGChunkPLTE) PLTEs.get(0);
-
-		// -----
-
-		ArrayList IDATs = filterChunks(chunks, IDAT);
-		if (IDATs.size() < 1)
-			throw new ImageReadException("PNG missing image data");
-
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		for (int i = 0; i < IDATs.size(); i++)
-		{
-			PNGChunkIDAT pngChunkIDAT = (PNGChunkIDAT) IDATs.get(i);
-			byte bytes[] = pngChunkIDAT.bytes;
-			// System.out.println(i + ": bytes: " + bytes.length);
-			baos.write(bytes);
-		}
-
-		byte compressed[] = baos.toByteArray();
-
-		baos = null;
-
-		TransparencyFilter transparencyFilter = null;
-
-		ArrayList tRNSs = filterChunks(chunks, tRNS);
-		if (tRNSs.size() > 0)
-		{
-			PNGChunk pngChunktRNS = (PNGChunk) tRNSs.get(0);
-			transparencyFilter = getTransparencyFilter(pngChunkIHDR.colorType,
-					pngChunktRNS);
-		}
-
-		ICC_Profile icc_profile = null;
-		GammaCorrection gammaCorrection = null;
-		{
-			ArrayList sRGBs = filterChunks(chunks, sRGB);
-			ArrayList gAMAs = filterChunks(chunks, gAMA);
-			ArrayList iCCPs = filterChunks(chunks, iCCP);
-			if (sRGBs.size() > 1)
-				throw new ImageReadException("PNG: unexpected sRGB chunk");
-			if (gAMAs.size() > 1)
-				throw new ImageReadException("PNG: unexpected gAMA chunk");
-			if (iCCPs.size() > 1)
-				throw new ImageReadException("PNG: unexpected iCCP chunk");
-
-			if (sRGBs.size() == 1)
-			{
-				// no color management neccesary.
-				if (debug)
-					System.out.println("sRGB, no color management neccesary.");
-			} else if (iCCPs.size() == 1)
-			{
-				if (debug)
-					System.out.println("iCCP.");
-
-				PNGChunkiCCP pngChunkiCCP = (PNGChunkiCCP) iCCPs.get(0);
-				byte bytes[] = pngChunkiCCP.UncompressedProfile;
-
-				icc_profile = ICC_Profile.getInstance(bytes);
-			} else if (gAMAs.size() == 1)
-			{
-				PNGChunkgAMA pngChunkgAMA = (PNGChunkgAMA) gAMAs.get(0);
-				double gamma = pngChunkgAMA.getGamma();
-
-				// charles: what is the correct target value here?
-				// double targetGamma = 2.2;
-				double targetGamma = 1.0;
-				double diff = Math.abs(targetGamma - gamma);
-				if (diff >= 0.5)
-					gammaCorrection = new GammaCorrection(gamma, targetGamma);
-
-				if (gammaCorrection != null)
-					if (pngChunkPLTE != null)
-						pngChunkPLTE.correct(gammaCorrection);
-
-			}
-		}
-
-		{
-			int width = pngChunkIHDR.width;
-			int height = pngChunkIHDR.height;
-			int colorType = pngChunkIHDR.colorType;
-			int bitDepth = pngChunkIHDR.bitDepth;
-
-			int bitsPerSample = bitDepth;
-
-			if (pngChunkIHDR.filterMethod != 0)
-				throw new ImageReadException("PNG: unknown FilterMethod: "
-						+ pngChunkIHDR.filterMethod);
-
-			int samplesPerPixel = samplesPerPixel(pngChunkIHDR.colorType);
-			boolean isGrayscale = isGrayscale(pngChunkIHDR.colorType);
-
-			int bitsPerPixel = bitsPerSample * samplesPerPixel;
-
-			boolean hasAlpha = colorType == COLOR_TYPE_GREYSCALE_WITH_ALPHA
-					|| colorType == COLOR_TYPE_TRUE_COLOR_WITH_ALPHA;
-
-			BufferedImage result;
-			if (isGrayscale)
-				result = getBufferedImageFactory(params)
-						.getGrayscaleBufferedImage(width, height, hasAlpha);
-			else
-				result = getBufferedImageFactory(params).getColorBufferedImage(
-						width, height, hasAlpha);
-
-			ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
-			InflaterInputStream iis = new InflaterInputStream(bais);
-
-			ScanExpediter scanExpediter;
-
-			if (pngChunkIHDR.interlaceMethod == 0)
-				scanExpediter = new ScanExpediterSimple(width, height, iis,
-						result, colorType, bitDepth, bitsPerPixel,
-						pngChunkPLTE, gammaCorrection, transparencyFilter);
-			else if (pngChunkIHDR.interlaceMethod == 1)
-				scanExpediter = new ScanExpediterInterlaced(width, height, iis,
-						result, colorType, bitDepth, bitsPerPixel,
-						pngChunkPLTE, gammaCorrection, transparencyFilter);
-			else
-				throw new ImageReadException("Unknown InterlaceMethod: "
-						+ pngChunkIHDR.interlaceMethod);
-
-			scanExpediter.drive();
-
-			if (icc_profile != null)
-			{
-				Boolean is_srgb = new IccProfileParser().issRGB(icc_profile);
-				if (is_srgb == null || !is_srgb.booleanValue())
-				{
-					ICC_ColorSpace cs = new ICC_ColorSpace(icc_profile);
-
-					ColorModel srgbCM = ColorModel.getRGBdefault();
-					ColorSpace cs_sRGB = srgbCM.getColorSpace();
-
-					result = new ColorTools().convertBetweenColorSpaces(result,
-							cs, cs_sRGB);
-				}
-			}
-
-			return result;
-
-		}
-
-	}
-
-	public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
-			throws ImageReadException, IOException
-	{
-		ImageInfo imageInfo = getImageInfo(byteSource);
-		if (imageInfo == null)
-			return false;
-
-		imageInfo.toString(pw, "");
-
-		{
-			ArrayList chunks = readChunks(byteSource, null, false);
-			{
-				ArrayList IHDRs = filterChunks(chunks, IHDR);
-				if (IHDRs.size() != 1)
-				{
-					if (debug)
-						System.out.println("PNG contains more than one Header");
-					return false;
-				}
-				PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) IHDRs.get(0);
-				pw.println("Color: "
-						+ getColorTypeDescription(pngChunkIHDR.colorType));
-			}
-
-			pw.println("chunks: " + chunks.size());
-
-			if ((chunks.size() < 1))
-				return false;
-
-			for (int i = 0; i < chunks.size(); i++)
-			{
-				PNGChunk chunk = (PNGChunk) chunks.get(i);
-				printCharQuad(pw, "\t" + i + ": ", chunk.chunkType);
-			}
-		}
-
-		pw.println("");
-
-		pw.flush();
-
-		return true;
-	}
-
-	public void writeImage(BufferedImage src, OutputStream os, Map params)
-			throws ImageWriteException, IOException
-	{
-		new PngWriter(params).writeImage(src, os, params);
-	}
-
-	/**
-	 * Extracts embedded XML metadata as XML string.
-	 * <p>
-	 * 
-	 * @param byteSource
-	 *            File containing image data.
-	 * @param params
-	 *            Map of optional parameters, defined in SanselanConstants.
-	 * @return Xmp Xml as String, if present. Otherwise, returns null.
-	 */
-	public String getXmpXml(ByteSource byteSource, Map params)
-			throws ImageReadException, IOException
-	{
-
-		List chunks = readChunks(byteSource, new int[] { iTXt, }, false);
-
-		if ((chunks == null) || (chunks.size() < 1))
-			return null;
-
-		List xmpChunks = new ArrayList();
-		for (int i = 0; i < chunks.size(); i++)
-		{
-			PNGChunkiTXt chunk = (PNGChunkiTXt) chunks.get(i);
-			if (!chunk.getKeyword().equals(XMP_KEYWORD))
-				continue;
-			xmpChunks.add(chunk);
-		}
-
-		if (xmpChunks.size() < 1)
-			return null;
-		if (xmpChunks.size() > 1)
-			throw new ImageReadException(
-					"PNG contains more than one XMP chunk.");
-
-		PNGChunkiTXt chunk = (PNGChunkiTXt) xmpChunks.get(0);
-		return chunk.getText();
-	}
+    public PngImageParser()
+    {
+        // setDebug(true);
+    }
+
+    public String getName()
+    {
+        return "Png-Custom";
+    }
+
+    public String getDefaultExtension()
+    {
+        return DEFAULT_EXTENSION;
+    }
+
+    private static final String DEFAULT_EXTENSION = ".png";
+
+    private static final String ACCEPTED_EXTENSIONS[] = { DEFAULT_EXTENSION, };
+
+    protected String[] getAcceptedExtensions()
+    {
+        return ACCEPTED_EXTENSIONS;
+    }
+
+    protected ImageFormat[] getAcceptedTypes()
+    {
+        return new ImageFormat[] { ImageFormat.IMAGE_FORMAT_PNG, //
+        };
+    }
+
+    // private final static int tRNS = CharsToQuad('t', 'R', 'N', 's');
+
+    public static final String getChunkTypeName(int chunkType) {
+        StringBuffer result = new StringBuffer();
+        result.append((char) (0xff & (chunkType >> 24)));
+        result.append((char) (0xff & (chunkType >> 16)));
+        result.append((char) (0xff & (chunkType >> 8)));
+        result.append((char) (0xff & (chunkType >> 0)));
+        return result.toString();
+    }
+
+    /**
+     * @return List of String-formatted chunk types, ie. "tRNs".
+     */
+    public List getChuckTypes(InputStream is) throws ImageReadException, IOException {
+        List chunks = readChunks(is, null, false);
+        List chunkTypes = new ArrayList();
+        for (int i=0; i<chunks.size(); i++) {
+            PNGChunk chunk = (PNGChunk) chunks.get(i);
+            chunkTypes.add(getChunkTypeName(chunk.chunkType));
+        }
+        return chunkTypes;
+    }
+
+    public boolean hasChuckType(ByteSource byteSource, int chunkType) throws ImageReadException, IOException
+    {
+        InputStream is = null;
+
+        try
+        {
+            is = byteSource.getInputStream();
+
+            ArrayList chunks = null;
+
+            readSignature(is);
+            chunks = readChunks(is, new int[] { chunkType, }, true);
+            return chunks.size() > 0;
+        } finally
+        {
+            try
+            {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (Exception e)
+            {
+                Debug.debug(e);
+            }
+        }
+    }
+
+
+    private boolean keepChunk(int ChunkType, int chunkTypes[])
+    {
+        // System.out.println("keepChunk: ");
+        if (chunkTypes == null)
+            return true;
+
+        for (int i = 0; i < chunkTypes.length; i++)
+        {
+            if (chunkTypes[i] == ChunkType)
+                return true;
+        }
+        return false;
+    }
+
+    private ArrayList readChunks(InputStream is, int chunkTypes[],
+            boolean returnAfterFirst) throws ImageReadException, IOException
+    {
+        ArrayList result = new ArrayList();
+
+        while (true)
+        {
+            if (debug)
+                System.out.println("");
+
+            int length = read4Bytes("Length", is, "Not a Valid PNG File");
+            int chunkType = read4Bytes("ChunkType", is, "Not a Valid PNG File");
+
+            if (debug)
+            {
+                printCharQuad("ChunkType", chunkType);
+                debugNumber("Length", length, 4);
+            }
+            boolean keep = keepChunk(chunkType, chunkTypes);
+
+            byte bytes[] = null;
+            if (keep)
+            {
+                bytes = readByteArray("Chunk Data", length, is,
+                        "Not a Valid PNG File: Couldn't read Chunk Data.");
+            } else
+                skipBytes(is, length, "Not a Valid PNG File");
+
+            if (debug)
+                if (bytes != null)
+                    debugNumber("bytes", bytes.length, 4);
+
+            int CRC = read4Bytes("CRC", is, "Not a Valid PNG File");
+
+            if (keep)
+            {
+                if (chunkType == iCCP)
+                    result.add(new PNGChunkiCCP(length, chunkType, CRC, bytes));
+                else if (chunkType == tEXt)
+                    result.add(new PNGChunktEXt(length, chunkType, CRC, bytes));
+                else if (chunkType == zTXt)
+                    result.add(new PNGChunkzTXt(length, chunkType, CRC, bytes));
+                else if (chunkType == IHDR)
+                    result.add(new PNGChunkIHDR(length, chunkType, CRC, bytes));
+                else if (chunkType == PLTE)
+                    result.add(new PNGChunkPLTE(length, chunkType, CRC, bytes));
+                else if (chunkType == pHYs)
+                    result.add(new PNGChunkpHYs(length, chunkType, CRC, bytes));
+                else if (chunkType == IDAT)
+                    result.add(new PNGChunkIDAT(length, chunkType, CRC, bytes));
+                else if (chunkType == gAMA)
+                    result.add(new PNGChunkgAMA(length, chunkType, CRC, bytes));
+                else if (chunkType == iTXt)
+                    result.add(new PNGChunkiTXt(length, chunkType, CRC, bytes));
+                else
+                    result.add(new PNGChunk(length, chunkType, CRC, bytes));
+
+                if (returnAfterFirst)
+                    return result;
+            }
+
+            if (chunkType == IEND)
+                break;
+
+        }
+
+        return result;
+
+    }
+
+    public void readSignature(InputStream is) throws ImageReadException,
+            IOException
+    {
+        readAndVerifyBytes(is, PNG_Signature,
+                "Not a Valid PNG Segment: Incorrect Signature");
+
+    }
+
+    private ArrayList readChunks(ByteSource byteSource, int chunkTypes[],
+            boolean returnAfterFirst) throws ImageReadException, IOException
+    {
+        InputStream is = null;
+
+        try
+        {
+            is = byteSource.getInputStream();
+
+            ArrayList chunks = null;
+
+            readSignature(is);
+            chunks = readChunks(is, chunkTypes, returnAfterFirst);
+            return chunks;
+        } finally
+        {
+            try
+            {
+                if (is != null) {
+                    is.close();
+                }
+            } catch (Exception e)
+            {
+                Debug.debug(e);
+            }
+        }
+    }
+
+    public byte[] getICCProfileBytes(ByteSource byteSource, Map params)
+            throws ImageReadException, IOException
+    {
+        ArrayList chunks = readChunks(byteSource, new int[] { iCCP, }, true);
+
+        if ((chunks == null) || (chunks.size() < 1))
+        {
+            // throw new ImageReadException("Png: No chunks");
+            return null;
+        }
+
+        if (chunks.size() > 1)
+            throw new ImageReadException(
+                    "PNG contains more than one ICC Profile ");
+
+        PNGChunkiCCP pngChunkiCCP = (PNGChunkiCCP) chunks.get(0);
+        byte bytes[] = pngChunkiCCP.UncompressedProfile;
+
+        return (bytes);
+    }
+
+    public Dimension getImageSize(ByteSource byteSource, Map params)
+            throws ImageReadException, IOException
+    {
+        ArrayList chunks = readChunks(byteSource, new int[] { IHDR, }, true);
+
+        if ((chunks == null) || (chunks.size() < 1))
+            throw new ImageReadException("Png: No chunks");
+
+        if (chunks.size() > 1)
+            throw new ImageReadException("PNG contains more than one Header");
+
+        PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) chunks.get(0);
+
+        return new Dimension(pngChunkIHDR.width, pngChunkIHDR.height);
+    }
+
+    public byte[] embedICCProfile(byte image[], byte profile[])
+    {
+        return null;
+    }
+
+    public boolean embedICCProfile(File src, File dst, byte profile[])
+    {
+        return false;
+    }
+
+    public IImageMetadata getMetadata(ByteSource byteSource, Map params)
+            throws ImageReadException, IOException
+    {
+        ArrayList chunks = readChunks(byteSource, new int[] { tEXt, zTXt, },
+                true);
+
+        if ((chunks == null) || (chunks.size() < 1))
+            return null;
+
+        ImageMetadata result = new ImageMetadata();
+
+        for (int i = 0; i < chunks.size(); i++)
+        {
+            PNGTextChunk chunk = (PNGTextChunk) chunks.get(i);
+
+            result.add(chunk.getKeyword(), chunk.getText());
+        }
+
+        return result;
+    }
+
+    private boolean isGrayscale(int colorType) throws ImageReadException
+    {
+        // Color type is a single-byte integer that describes the interpretation
+        // of the
+        // image data. Color type codes represent sums of the following values:
+        // 1 (palette used), 2 (color used), and 4 (alpha channel used).
+        // Valid values are 0, 2, 3, 4, and 6.
+        //
+        // Bit depth restrictions for each color type are imposed to simplify
+        // implementations
+        // and to prohibit combinations that do not compress well. Decoders must
+        // support all
+        // valid combinations of bit depth and color type. The allowed
+        // combinations are:
+        //
+        // Color Allowed Interpretation
+        // Type Bit Depths
+        //
+        // 0 1,2,4,8,16 Each pixel is a grayscale sample.
+        //
+        // 2 8,16 Each pixel is an R,G,B triple.
+        //
+        // 3 1,2,4,8 Each pixel is a palette index;
+        // a PLTE chunk must appear.
+        //
+        // 4 8,16 Each pixel is a grayscale sample,
+        // followed by an alpha sample.
+        //
+        // 6 8,16 Each pixel is an R,G,B triple,
+        // followed by an alpha sample.
+        switch (colorType)
+        {
+        case COLOR_TYPE_GREYSCALE:
+            return true;
+        case COLOR_TYPE_TRUE_COLOR:
+            return false;
+        case COLOR_TYPE_INDEXED_COLOR:
+            return false;
+        case COLOR_TYPE_GREYSCALE_WITH_ALPHA:
+            return true;
+        case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA:
+            return false;
+        }
+
+        // return -1;
+        throw new ImageReadException("PNG: unknown color type: " + colorType);
+    }
+
+    private int samplesPerPixel(int colorType) throws ImageReadException
+    {
+        // Color type is a single-byte integer that describes the interpretation
+        // of the
+        // image data. Color type codes represent sums of the following values:
+        // 1 (palette used), 2 (color used), and 4 (alpha channel used).
+        // Valid values are 0, 2, 3, 4, and 6.
+        //
+        // Bit depth restrictions for each color type are imposed to simplify
+        // implementations
+        // and to prohibit combinations that do not compress well. Decoders must
+        // support all
+        // valid combinations of bit depth and color type. The allowed
+        // combinations are:
+        //
+        // Color Allowed Interpretation
+        // Type Bit Depths
+        //
+        // 0 1,2,4,8,16 Each pixel is a grayscale sample.
+        //
+        // 2 8,16 Each pixel is an R,G,B triple.
+        //
+        // 3 1,2,4,8 Each pixel is a palette index;
+        // a PLTE chunk must appear.
+        //
+        // 4 8,16 Each pixel is a grayscale sample,
+        // followed by an alpha sample.
+        //
+        // 6 8,16 Each pixel is an R,G,B triple,
+        // followed by an alpha sample.
+        switch (colorType)
+        {
+        case COLOR_TYPE_GREYSCALE:
+            return 1;
+        case COLOR_TYPE_TRUE_COLOR:
+            return 3;
+        case COLOR_TYPE_INDEXED_COLOR:
+            return 1; // is this accurate ? how may bits per index?
+        case COLOR_TYPE_GREYSCALE_WITH_ALPHA:
+            return 2;
+        case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA:
+            return 4;
+        }
+
+        // return -1;
+        throw new ImageReadException("PNG: unknown color type: " + colorType);
+    }
+
+    private ArrayList filterChunks(ArrayList v, int type)
+    {
+        ArrayList result = new ArrayList();
+
+        for (int i = 0; i < v.size(); i++)
+        {
+            PNGChunk chunk = (PNGChunk) v.get(i);
+            if (chunk.chunkType == type)
+                result.add(chunk);
+        }
+
+        return result;
+    }
+
+    private boolean hasAlphaChannel(int ColorType) throws ImageReadException
+    {
+        switch (ColorType)
+        {
+        case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
+            // sample.
+        case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
+        case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette index;
+            return false;
+        case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a grayscale
+            // sample,
+            // followed by an alpha sample.
+        case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an R,G,B
+            // triple,
+            // followed by an alpha sample.
+            return true;
+        default:
+            throw new ImageReadException("PNG: unknown color type: "
+                    + ColorType);
+        }
+    }
+
+    private String getColorTypeDescription(int ColorType)
+    {
+        switch (ColorType)
+        {
+        case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
+            // sample.
+            return "grayscale";
+        case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
+            return "rgb";
+        case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette index;
+            return "indexed rgb";
+        case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a grayscale
+            // sample,
+            // followed by an alpha sample.
+            return "grayscale w/ alpha";
+        case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an R,G,B
+            // triple,
+            // followed by an alpha sample.
+            return "RGB w/ alpha";
+        default:
+            return "Unknown Color Type";
+        }
+    }
+
+    // TODO: I have been too casual about making inner classes subclass of
+    // BinaryFileParser
+    // I may not have always preserved byte order correctly.
+
+    private TransparencyFilter getTransparencyFilter(int ColorType,
+            PNGChunk pngChunktRNS) throws ImageReadException, IOException
+    {
+        // this.printCharQuad("pngChunktRNS.ChunkType", pngChunktRNS.ChunkType);
+        // this.debugNumber("pngChunktRNS.Length", pngChunktRNS.Length);
+
+        switch (ColorType)
+        {
+        case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
+            // sample.
+            return new TransparencyFilterGrayscale(pngChunktRNS.bytes);
+        case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
+            return new TransparencyFilterTrueColor(pngChunktRNS.bytes);
+        case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette index;
+            return new TransparencyFilterIndexedColor(pngChunktRNS.bytes);
+        case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a grayscale
+            // sample,
+        case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an R,G,B
+            // triple,
+        default:
+            throw new ImageReadException(
+                    "Simple Transparency not compatible with ColorType: "
+                            + ColorType);
+        }
+    }
+
+    public ImageInfo getImageInfo(ByteSource byteSource, Map params)
+            throws ImageReadException, IOException
+    {
+        ArrayList chunks = readChunks(byteSource, new int[] { IHDR, pHYs, tEXt,
+                zTXt, tRNS, PLTE, iTXt, }, false);
+
+        // if(chunks!=null)
+        // System.out.println("chunks: " + chunks.size());
+
+        if ((chunks == null) || (chunks.size() < 1))
+            throw new ImageReadException("PNG: no chunks");
+
+        ArrayList IHDRs = filterChunks(chunks, IHDR);
+        if (IHDRs.size() != 1)
+            throw new ImageReadException("PNG contains more than one Header");
+
+        PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) IHDRs.get(0);
+        PNGChunk pngChunktRNS = null;
+
+        boolean isTransparent = false;
+
+        ArrayList tRNSs = filterChunks(chunks, tRNS);
+        if (tRNSs.size() > 0)
+        {
+            isTransparent = true;
+            pngChunktRNS = (PNGChunk) IHDRs.get(0);
+        } else
+            hasAlphaChannel(pngChunkIHDR.colorType);
+
+        PNGChunkpHYs pngChunkpHYs = null;
+
+        ArrayList pHYss = filterChunks(chunks, pHYs);
+        if (pHYss.size() > 1)
+            throw new ImageReadException("PNG contains more than one pHYs: "
+                    + pHYss.size());
+        else if (pHYss.size() == 1)
+            pngChunkpHYs = (PNGChunkpHYs) pHYss.get(0);
+
+        ArrayList tEXts = filterChunks(chunks, tEXt);
+        ArrayList zTXts = filterChunks(chunks, zTXt);
+        ArrayList iTXts = filterChunks(chunks, iTXt);
+
+        {
+            ArrayList comments = new ArrayList();
+            List textChunks = new ArrayList();
+
+            for (int i = 0; i < tEXts.size(); i++)
+            {
+                PNGChunktEXt pngChunktEXt = (PNGChunktEXt) tEXts.get(i);
+                comments.add(pngChunktEXt.keyword + ": " + pngChunktEXt.text);
+                textChunks.add(pngChunktEXt.getContents());
+            }
+            for (int i = 0; i < zTXts.size(); i++)
+            {
+                PNGChunkzTXt pngChunkzTXt = (PNGChunkzTXt) zTXts.get(i);
+                comments.add(pngChunkzTXt.keyword + ": " + pngChunkzTXt.text);
+                textChunks.add(pngChunkzTXt.getContents());
+            }
+            for (int i = 0; i < iTXts.size(); i++)
+            {
+                PNGChunkiTXt pngChunkiTXt = (PNGChunkiTXt) iTXts.get(i);
+                comments.add(pngChunkiTXt.keyword + ": " + pngChunkiTXt.text);
+                textChunks.add(pngChunkiTXt.getContents());
+            }
+
+            int BitsPerPixel = pngChunkIHDR.bitDepth
+                    * samplesPerPixel(pngChunkIHDR.colorType);
+            ImageFormat Format = ImageFormat.IMAGE_FORMAT_PNG;
+            String FormatName = "PNG Portable Network Graphics";
+            int Height = pngChunkIHDR.height;
+            String MimeType = "image/png";
+            int NumberOfImages = 1;
+            int Width = pngChunkIHDR.width;
+            boolean isProgressive = (pngChunkIHDR.interlaceMethod != 0);
+
+            int PhysicalHeightDpi = -1;
+            float PhysicalHeightInch = -1;
+            int PhysicalWidthDpi = -1;
+            float PhysicalWidthInch = -1;
+
+            // if (pngChunkpHYs != null)
+            // {
+            // System.out.println("\t" + "pngChunkpHYs.UnitSpecifier: " +
+            // pngChunkpHYs.UnitSpecifier );
+            // System.out.println("\t" + "pngChunkpHYs.PixelsPerUnitYAxis: " +
+            // pngChunkpHYs.PixelsPerUnitYAxis );
+            // System.out.println("\t" + "pngChunkpHYs.PixelsPerUnitXAxis: " +
+            // pngChunkpHYs.PixelsPerUnitXAxis );
+            // }
+            if ((pngChunkpHYs != null) && (pngChunkpHYs.UnitSpecifier == 1)) // meters
+            {
+                double meters_per_inch = 0.0254;
+
+                PhysicalWidthDpi = (int) Math
+                        .round(pngChunkpHYs.PixelsPerUnitXAxis
+                                * meters_per_inch);
+                PhysicalWidthInch = (float) ((double) Width
+                        * (double) pngChunkpHYs.PixelsPerUnitXAxis * meters_per_inch);
+                PhysicalHeightDpi = (int) Math
+                        .round(pngChunkpHYs.PixelsPerUnitYAxis
+                                * meters_per_inch);
+                PhysicalHeightInch = (float) ((double) Height
+                        * (double) pngChunkpHYs.PixelsPerUnitYAxis * meters_per_inch);
+            }
+
+            String FormatDetails = "Png";
+
+            boolean usesPalette = false;
+
+            ArrayList PLTEs = filterChunks(chunks, PLTE);
+            if (PLTEs.size() > 1)
+                usesPalette = true;
+
+            int ColorType;
+            switch (pngChunkIHDR.colorType)
+            {
+            case COLOR_TYPE_GREYSCALE: // 1,2,4,8,16 Each pixel is a grayscale
+                // sample.
+            case COLOR_TYPE_GREYSCALE_WITH_ALPHA: // 8,16 Each pixel is a
+                // grayscale sample,
+                // followed by an alpha sample.
+                ColorType = ImageInfo.COLOR_TYPE_GRAYSCALE;
+                break;
+            case COLOR_TYPE_TRUE_COLOR: // 8,16 Each pixel is an R,G,B triple.
+            case COLOR_TYPE_INDEXED_COLOR: // 1,2,4,8 Each pixel is a palette
+                // index;
+            case COLOR_TYPE_TRUE_COLOR_WITH_ALPHA: // 8,16 Each pixel is an
+                // R,G,B triple,
+                // followed by an alpha sample.
+                ColorType = ImageInfo.COLOR_TYPE_RGB;
+                break;
+            default:
+                throw new ImageReadException("Png: Unknown ColorType: "
+                        + pngChunkIHDR.colorType);
+            }
+
+            String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_PNG_FILTER;
+
+            ImageInfo result = new PngImageInfo(FormatDetails, BitsPerPixel,
+                    comments, Format, FormatName, Height, MimeType,
+                    NumberOfImages, PhysicalHeightDpi, PhysicalHeightInch,
+                    PhysicalWidthDpi, PhysicalWidthInch, Width, isProgressive,
+                    isTransparent, usesPalette, ColorType,
+                    compressionAlgorithm, textChunks);
+
+            return result;
+        }
+    }
+
+    public BufferedImage getBufferedImage(ByteSource byteSource, Map params)
+            throws ImageReadException, IOException
+    {
+        boolean verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
+                false);
+
+        if (params.containsKey(PARAM_KEY_VERBOSE))
+            params.remove(PARAM_KEY_VERBOSE);
+
+        // if (params.size() > 0) {
+        // Object firstKey = params.keySet().iterator().next();
+        // throw new ImageWriteException("Unknown parameter: " + firstKey);
+        // }
+
+        ArrayList chunks = readChunks(byteSource, new int[] { IHDR, PLTE, IDAT,
+                tRNS, iCCP, gAMA, sRGB, }, false);
+
+        if ((chunks == null) || (chunks.size() < 1))
+            throw new ImageReadException("PNG: no chunks");
+
+        ArrayList IHDRs = filterChunks(chunks, IHDR);
+        if (IHDRs.size() != 1)
+            throw new ImageReadException("PNG contains more than one Header");
+
+        PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) IHDRs.get(0);
+
+        ArrayList PLTEs = filterChunks(chunks, PLTE);
+        if (PLTEs.size() > 1)
+            throw new ImageReadException("PNG contains more than one Palette");
+
+        PNGChunkPLTE pngChunkPLTE = null;
+        if (PLTEs.size() == 1)
+            pngChunkPLTE = (PNGChunkPLTE) PLTEs.get(0);
+
+        // -----
+
+        ArrayList IDATs = filterChunks(chunks, IDAT);
+        if (IDATs.size() < 1)
+            throw new ImageReadException("PNG missing image data");
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        for (int i = 0; i < IDATs.size(); i++)
+        {
+            PNGChunkIDAT pngChunkIDAT = (PNGChunkIDAT) IDATs.get(i);
+            byte bytes[] = pngChunkIDAT.bytes;
+            // System.out.println(i + ": bytes: " + bytes.length);
+            baos.write(bytes);
+        }
+
+        byte compressed[] = baos.toByteArray();
+
+        baos = null;
+
+        TransparencyFilter transparencyFilter = null;
+
+        ArrayList tRNSs = filterChunks(chunks, tRNS);
+        if (tRNSs.size() > 0)
+        {
+            PNGChunk pngChunktRNS = (PNGChunk) tRNSs.get(0);
+            transparencyFilter = getTransparencyFilter(pngChunkIHDR.colorType,
+                    pngChunktRNS);
+        }
+
+        ICC_Profile icc_profile = null;
+        GammaCorrection gammaCorrection = null;
+        {
+            ArrayList sRGBs = filterChunks(chunks, sRGB);
+            ArrayList gAMAs = filterChunks(chunks, gAMA);
+            ArrayList iCCPs = filterChunks(chunks, iCCP);
+            if (sRGBs.size() > 1)
+                throw new ImageReadException("PNG: unexpected sRGB chunk");
+            if (gAMAs.size() > 1)
+                throw new ImageReadException("PNG: unexpected gAMA chunk");
+            if (iCCPs.size() > 1)
+                throw new ImageReadException("PNG: unexpected iCCP chunk");
+
+            if (sRGBs.size() == 1)
+            {
+                // no color management neccesary.
+                if (debug)
+                    System.out.println("sRGB, no color management neccesary.");
+            } else if (iCCPs.size() == 1)
+            {
+                if (debug)
+                    System.out.println("iCCP.");
+
+                PNGChunkiCCP pngChunkiCCP = (PNGChunkiCCP) iCCPs.get(0);
+                byte bytes[] = pngChunkiCCP.UncompressedProfile;
+
+                icc_profile = ICC_Profile.getInstance(bytes);
+            } else if (gAMAs.size() == 1)
+            {
+                PNGChunkgAMA pngChunkgAMA = (PNGChunkgAMA) gAMAs.get(0);
+                double gamma = pngChunkgAMA.getGamma();
+
+                // charles: what is the correct target value here?
+                // double targetGamma = 2.2;
+                double targetGamma = 1.0;
+                double diff = Math.abs(targetGamma - gamma);
+                if (diff >= 0.5)
+                    gammaCorrection = new GammaCorrection(gamma, targetGamma);
+
+                if (gammaCorrection != null)
+                    if (pngChunkPLTE != null)
+                        pngChunkPLTE.correct(gammaCorrection);
+
+            }
+        }
+
+        {
+            int width = pngChunkIHDR.width;
+            int height = pngChunkIHDR.height;
+            int colorType = pngChunkIHDR.colorType;
+            int bitDepth = pngChunkIHDR.bitDepth;
+
+            int bitsPerSample = bitDepth;
+
+            if (pngChunkIHDR.filterMethod != 0)
+                throw new ImageReadException("PNG: unknown FilterMethod: "
+                        + pngChunkIHDR.filterMethod);
+
+            int samplesPerPixel = samplesPerPixel(pngChunkIHDR.colorType);
+            boolean isGrayscale = isGrayscale(pngChunkIHDR.colorType);
+
+            int bitsPerPixel = bitsPerSample * samplesPerPixel;
+
+            boolean hasAlpha = colorType == COLOR_TYPE_GREYSCALE_WITH_ALPHA
+                    || colorType == COLOR_TYPE_TRUE_COLOR_WITH_ALPHA;
+
+            BufferedImage result;
+            if (isGrayscale)
+                result = getBufferedImageFactory(params)
+                        .getGrayscaleBufferedImage(width, height, hasAlpha);
+            else
+                result = getBufferedImageFactory(params).getColorBufferedImage(
+                        width, height, hasAlpha);
+
+            ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
+            InflaterInputStream iis = new InflaterInputStream(bais);
+
+            ScanExpediter scanExpediter;
+
+            if (pngChunkIHDR.interlaceMethod == 0)
+                scanExpediter = new ScanExpediterSimple(width, height, iis,
+                        result, colorType, bitDepth, bitsPerPixel,
+                        pngChunkPLTE, gammaCorrection, transparencyFilter);
+            else if (pngChunkIHDR.interlaceMethod == 1)
+                scanExpediter = new ScanExpediterInterlaced(width, height, iis,
+                        result, colorType, bitDepth, bitsPerPixel,
+                        pngChunkPLTE, gammaCorrection, transparencyFilter);
+            else
+                throw new ImageReadException("Unknown InterlaceMethod: "
+                        + pngChunkIHDR.interlaceMethod);
+
+            scanExpediter.drive();
+
+            if (icc_profile != null)
+            {
+                Boolean is_srgb = new IccProfileParser().issRGB(icc_profile);
+                if (is_srgb == null || !is_srgb.booleanValue())
+                {
+                    ICC_ColorSpace cs = new ICC_ColorSpace(icc_profile);
+
+                    ColorModel srgbCM = ColorModel.getRGBdefault();
+                    ColorSpace cs_sRGB = srgbCM.getColorSpace();
+
+                    result = new ColorTools().convertBetweenColorSpaces(result,
+                            cs, cs_sRGB);
+                }
+            }
+
+            return result;
+
+        }
+
+    }
+
+    public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
+            throws ImageReadException, IOException
+    {
+        ImageInfo imageInfo = getImageInfo(byteSource);
+        if (imageInfo == null)
+            return false;
+
+        imageInfo.toString(pw, "");
+
+        {
+            ArrayList chunks = readChunks(byteSource, null, false);
+            {
+                ArrayList IHDRs = filterChunks(chunks, IHDR);
+                if (IHDRs.size() != 1)
+                {
+                    if (debug)
+                        System.out.println("PNG contains more than one Header");
+                    return false;
+                }
+                PNGChunkIHDR pngChunkIHDR = (PNGChunkIHDR) IHDRs.get(0);
+                pw.println("Color: "
+                        + getColorTypeDescription(pngChunkIHDR.colorType));
+            }
+
+            pw.println("chunks: " + chunks.size());
+
+            if ((chunks.size() < 1))
+                return false;
+
+            for (int i = 0; i < chunks.size(); i++)
+            {
+                PNGChunk chunk = (PNGChunk) chunks.get(i);
+                printCharQuad(pw, "\t" + i + ": ", chunk.chunkType);
+            }
+        }
+
+        pw.println("");
+
+        pw.flush();
+
+        return true;
+    }
+
+    public void writeImage(BufferedImage src, OutputStream os, Map params)
+            throws ImageWriteException, IOException
+    {
+        new PngWriter(params).writeImage(src, os, params);
+    }
+
+    /**
+     * Extracts embedded XML metadata as XML string.
+     * <p>
+     *
+     * @param byteSource
+     *            File containing image data.
+     * @param params
+     *            Map of optional parameters, defined in SanselanConstants.
+     * @return Xmp Xml as String, if present. Otherwise, returns null.
+     */
+    public String getXmpXml(ByteSource byteSource, Map params)
+            throws ImageReadException, IOException
+    {
+
+        List chunks = readChunks(byteSource, new int[] { iTXt, }, false);
+
+        if ((chunks == null) || (chunks.size() < 1))
+            return null;
+
+        List xmpChunks = new ArrayList();
+        for (int i = 0; i < chunks.size(); i++)
+        {
+            PNGChunkiTXt chunk = (PNGChunkiTXt) chunks.get(i);
+            if (!chunk.getKeyword().equals(XMP_KEYWORD))
+                continue;
+            xmpChunks.add(chunk);
+        }
+
+        if (xmpChunks.size() < 1)
+            return null;
+        if (xmpChunks.size() > 1)
+            throw new ImageReadException(
+                    "PNG contains more than one XMP chunk.");
+
+        PNGChunkiTXt chunk = (PNGChunkiTXt) xmpChunks.get(0);
+        return chunk.getText();
+    }
 
 }

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngText.java Fri Sep 10 16:33:35 2010
@@ -18,54 +18,54 @@ package org.apache.sanselan.formats.png;
 
 public abstract class PngText
 {
-	public PngText(String keyword, String text)
-	{
-		this.keyword = keyword;
-		this.text = text;
-	}
-
-	public final String keyword, text;
-
-	public static class tEXt extends PngText
-	{
-		public tEXt(String keyword, String text)
-		{
-			super(keyword, text);
-		}
-	}
-
-	public static class zTXt extends PngText
-	{
-		public zTXt(String keyword, String text)
-		{
-			super(keyword, text);
-		}
-	}
-
-	public static class iTXt extends PngText
-	{
-
-		/*
-		 * The language tag defined in [RFC-3066] indicates the human language
-		 * used by the translated keyword and the text. Unlike the keyword, the
-		 * language tag is case-insensitive. It is an ISO 646.IRV:1991 [ISO 646]
-		 * string consisting of hyphen-separated words of 1-8 alphanumeric
-		 * characters each (for example cn, en-uk, no-bok, x-klingon,
-		 * x-KlInGoN). If the first word is two or three letters long, it is an
-		 * ISO language code [ISO-639]. If the language tag is empty, the
-		 * language is unspecified.
-		 */
-		public final String languageTag;
-
-		public final String translatedKeyword;
-
-		public iTXt(String keyword, String text, String languageTag,
-				String translatedKeyword)
-		{
-			super(keyword, text);
-			this.languageTag = languageTag;
-			this.translatedKeyword = translatedKeyword;
-		}
-	}
+    public PngText(String keyword, String text)
+    {
+        this.keyword = keyword;
+        this.text = text;
+    }
+
+    public final String keyword, text;
+
+    public static class tEXt extends PngText
+    {
+        public tEXt(String keyword, String text)
+        {
+            super(keyword, text);
+        }
+    }
+
+    public static class zTXt extends PngText
+    {
+        public zTXt(String keyword, String text)
+        {
+            super(keyword, text);
+        }
+    }
+
+    public static class iTXt extends PngText
+    {
+
+        /*
+         * The language tag defined in [RFC-3066] indicates the human language
+         * used by the translated keyword and the text. Unlike the keyword, the
+         * language tag is case-insensitive. It is an ISO 646.IRV:1991 [ISO 646]
+         * string consisting of hyphen-separated words of 1-8 alphanumeric
+         * characters each (for example cn, en-uk, no-bok, x-klingon,
+         * x-KlInGoN). If the first word is two or three letters long, it is an
+         * ISO language code [ISO-639]. If the language tag is empty, the
+         * language is unspecified.
+         */
+        public final String languageTag;
+
+        public final String translatedKeyword;
+
+        public iTXt(String keyword, String text, String languageTag,
+                String translatedKeyword)
+        {
+            super(keyword, text);
+            this.languageTag = languageTag;
+            this.translatedKeyword = translatedKeyword;
+        }
+    }
 
 }