You are viewing a plain text version of this content. The canonical link for it is here.
Posted to sanselan-commits@incubator.apache.org by cm...@apache.org on 2007/11/17 21:58:40 UTC

svn commit: r596008 [5/15] - in /incubator/sanselan/trunk/src: main/java/org/apache/sanselan/ main/java/org/apache/sanselan/color/ main/java/org/apache/sanselan/common/ main/java/org/apache/sanselan/common/byteSources/ main/java/org/apache/sanselan/com...

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GenericGIFBlock.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GenericGIFBlock.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GenericGIFBlock.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GenericGIFBlock.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.gif;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+class GenericGIFBlock extends GIFBlock
+{
+	public final Vector subblocks;
+
+	public GenericGIFBlock(int blockCode, Vector subblocks)
+	{
+		super(blockCode);
+
+		this.subblocks = subblocks;
+
+	}
+
+	public byte[] appendSubBlocks() throws IOException
+	{
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+		for (int i = 0; i < subblocks.size(); i++)
+		{
+			byte subblock[] = (byte[]) subblocks.get(i);
+			out.write(subblock);
+		}
+
+		return out.toByteArray();
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GenericGIFBlock.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GifImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GifImageParser.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GifImageParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GifImageParser.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,1056 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.gif;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Vector;
+
+import org.cmc.sanselan.FormatCompliance;
+import org.cmc.sanselan.ImageFormat;
+import org.cmc.sanselan.ImageInfo;
+import org.cmc.sanselan.ImageParser;
+import org.cmc.sanselan.ImageReadException;
+import org.cmc.sanselan.ImageWriteException;
+import org.cmc.sanselan.common.BinaryOutputStream;
+import org.cmc.sanselan.common.IImageMetadata;
+import org.cmc.sanselan.common.byteSources.ByteSource;
+import org.cmc.sanselan.common.mylzw.MyLZWCompressor;
+import org.cmc.sanselan.common.mylzw.MyLZWDecompressor;
+import org.cmc.sanselan.palette.Palette;
+import org.cmc.sanselan.palette.PaletteFactory;
+import org.cmc.sanselan.util.Debug;
+
+public class GifImageParser extends ImageParser
+{
+
+	public GifImageParser()
+	{
+		super.setByteOrder(BYTE_ORDER_LSB);
+	}
+
+	public String getName()
+	{
+		return "Gif-Custom";
+	}
+
+	public String getDefaultExtension()
+	{
+		return DEFAULT_EXTENSION;
+	}
+
+	private static final String DEFAULT_EXTENSION = ".gif";
+
+	private static final String ACCEPTED_EXTENSIONS[] = {
+		DEFAULT_EXTENSION,
+	};
+
+	protected String[] getAcceptedExtensions()
+	{
+		return ACCEPTED_EXTENSIONS;
+	}
+
+	protected ImageFormat[] getAcceptedTypes()
+	{
+		return new ImageFormat[]{
+			ImageFormat.IMAGE_FORMAT_GIF, //
+		};
+	}
+
+	private static final byte GIF_HEADER_SIGNATURE[] = {
+			71, 73, 70
+	};
+
+	private GIFHeaderInfo readHeader(InputStream is,
+			FormatCompliance formatCompliance) throws ImageReadException,
+			IOException
+	{
+		byte identifier1 = readByte("identifier1", is, "Not a Valid GIF File");
+		byte identifier2 = readByte("identifier2", is, "Not a Valid GIF File");
+		byte identifier3 = readByte("identifier3", is, "Not a Valid GIF File");
+
+		byte version1 = readByte("version1", is, "Not a Valid GIF File");
+		byte version2 = readByte("version2", is, "Not a Valid GIF File");
+		byte version3 = readByte("version3", is, "Not a Valid GIF File");
+
+		if (formatCompliance != null)
+		{
+			formatCompliance.compare_bytes("Signature", GIF_HEADER_SIGNATURE,
+					new byte[]{
+							identifier1, identifier2, identifier3,
+					});
+			formatCompliance.compare("version", 56, version1);
+			formatCompliance.compare("version", new int[]{
+					55, 57,
+			}, version2);
+			formatCompliance.compare("version", 97, version3);
+		}
+
+		if (debug)
+			printCharQuad("identifier: ", ((identifier1 << 16)
+					| (identifier2 << 8) | (identifier3 << 0)));
+		if (debug)
+			printCharQuad("version: ",
+					((version1 << 16) | (version2 << 8) | (version3 << 0)));
+
+		int logicalScreenWidth = read2Bytes("Logical Screen Width", is,
+				"Not a Valid GIF File");
+		int logicalScreenHeight = read2Bytes("Logical Screen Height", is,
+				"Not a Valid GIF File");
+
+		if (formatCompliance != null)
+		{
+			formatCompliance.checkBounds("Width", 1, Integer.MAX_VALUE,
+					logicalScreenWidth);
+			formatCompliance.checkBounds("Height", 1, Integer.MAX_VALUE,
+					logicalScreenHeight);
+		}
+
+		byte packedFields = readByte("Packed Fields", is,
+				"Not a Valid GIF File");
+		byte backgroundColorIndex = readByte("Background Color Index", is,
+				"Not a Valid GIF File");
+		byte pixelAspectRatio = readByte("Pixel Aspect Ratio", is,
+				"Not a Valid GIF File");
+
+		if (debug)
+			printByteBits("PackedFields bits", packedFields);
+
+		boolean globalColorTableFlag = ((packedFields & 128) > 0);
+		if (debug)
+			System.out.println("GlobalColorTableFlag: " + globalColorTableFlag);
+		byte colorResolution = (byte) ((packedFields >> 4) & 7);
+		if (debug)
+			System.out.println("ColorResolution: " + colorResolution);
+		boolean sortFlag = ((packedFields & 8) > 0);
+		if (debug)
+			System.out.println("SortFlag: " + sortFlag);
+		byte sizeofGlobalColorTable = (byte) (packedFields & 7);
+		if (debug)
+			System.out.println("SizeofGlobalColorTable: "
+					+ sizeofGlobalColorTable);
+
+		if (formatCompliance != null)
+		{
+			if (globalColorTableFlag && backgroundColorIndex != -1)
+				formatCompliance.checkBounds("Background Color Index", 0,
+						convertColorTableSize(sizeofGlobalColorTable),
+						backgroundColorIndex);
+		}
+
+		return new GIFHeaderInfo(identifier1, identifier2, identifier3,
+				version1, version2, version3, logicalScreenWidth,
+				logicalScreenHeight, packedFields, backgroundColorIndex,
+				pixelAspectRatio, globalColorTableFlag, colorResolution,
+				sortFlag, sizeofGlobalColorTable);
+	}
+
+	private GraphicControlExtension readGraphicControlExtension(int code,
+			InputStream is) throws ImageReadException, IOException
+	{
+		readByte("block_size", is, "GIF: corrupt GraphicControlExt");
+		int packed = readByte("packed fields", is,
+				"GIF: corrupt GraphicControlExt");
+
+		int dispose = (packed & 0x1c) >> 2; // disposal method
+		boolean transparency = (packed & 1) != 0;
+
+		int delay = read2Bytes("delay in milliseconds", is,
+				"GIF: corrupt GraphicControlExt");
+		int transparentColorIndex = 0xff & readByte("transparent color index",
+				is, "GIF: corrupt GraphicControlExt");
+		readByte("block terminator", is, "GIF: corrupt GraphicControlExt");
+
+		return new GraphicControlExtension(code, packed, dispose, transparency,
+				delay, transparentColorIndex);
+	}
+
+	private byte[] readSubBlock(InputStream is) throws ImageReadException,
+			IOException
+	{
+		int block_size = 0xff & readByte("block_size", is, "GIF: corrupt block");
+
+		byte bytes[] = readByteArray("block", block_size, is,
+				"GIF: corrupt block");
+
+		return bytes;
+	}
+
+	protected GenericGIFBlock readGenericGIFBlock(InputStream is, int code)
+			throws ImageReadException, IOException
+	{
+		return readGenericGIFBlock(is, code, null);
+	}
+
+	protected GenericGIFBlock readGenericGIFBlock(InputStream is, int code,
+			byte first[]) throws ImageReadException, IOException
+	{
+		byte bytes[] = null;
+		Vector subblocks = new Vector();
+
+		if (first != null)
+			subblocks.add(first);
+
+		while (true)
+		{
+			bytes = readSubBlock(is);
+			if (bytes.length < 1)
+				break;
+			subblocks.add(bytes);
+		}
+
+		return new GenericGIFBlock(code, subblocks);
+	}
+
+	private final static int IMAGE_SEPARATOR = 0x2C;
+	private final static int GRAPHIC_CONTROL_EXTENSION = (0x2100 | 0xf9);
+	private final static int COMMENT_EXTENSION = 0xfe;
+	private final static int PLAIN_TEXT_EXTENSION = 0x01;
+	private final static int TERMINATOR_BYTE = 0x3b;
+
+	private Vector readBlocks(GIFHeaderInfo ghi, InputStream is,
+			boolean stop_before_image_data, FormatCompliance formatCompliance)
+			throws ImageReadException, IOException
+	{
+		Vector result = new Vector();
+
+		while (true)
+		{
+			int code = is.read();
+			//			this.debugNumber("code: ", code);
+
+			switch (code)
+			{
+				case -1 :
+					throw new ImageReadException("GIF: unexpected end of data");
+
+				case IMAGE_SEPARATOR :
+					ImageDescriptor id = readImageDescriptor(ghi, code, is,
+							stop_before_image_data, formatCompliance);
+					result.add(id);
+
+					break;
+
+				case 0x21 : // extension
+				{
+					int extension_code = is.read();
+					//					this.debugNumber("extension_code: ", extension_code);
+					int complete_code = ((0xff & code) << 8)
+							| (0xff & extension_code);
+
+					switch (extension_code)
+					{
+						case 0xf9 :
+							GraphicControlExtension gce = readGraphicControlExtension(
+									complete_code, is);
+							result.add(gce);
+							break;
+
+						case COMMENT_EXTENSION : {
+							GenericGIFBlock block = readGenericGIFBlock(is,
+									complete_code);
+							result.add(block);
+							break;
+						}
+
+						case PLAIN_TEXT_EXTENSION : {
+							GenericGIFBlock block = readGenericGIFBlock(is,
+									complete_code);
+							result.add(block);
+							break;
+						}
+
+						case 0xff : // 255 (hex 0xFF) Application Extension Label
+						{
+							byte label[] = readSubBlock(is);
+
+							if (formatCompliance != null)
+								formatCompliance.addComment(
+										"Unknown Application Extension ("
+												+ new String(label) + ")",
+										complete_code);
+
+							// if (label == new String("ICCRGBG1")) 
+							{
+								// GIF's can have embedded ICC Profiles - who knew? 
+							}
+
+							if ((label != null) && (label.length > 0))
+							{
+								GenericGIFBlock block = readGenericGIFBlock(is,
+										complete_code, label);
+								byte bytes[] = block.appendSubBlocks();
+
+								result.add(block);
+							}
+							break;
+						}
+
+						default : {
+
+							if (formatCompliance != null)
+								formatCompliance.addComment("Unknown block",
+										complete_code);
+
+							GenericGIFBlock block = readGenericGIFBlock(is,
+									complete_code);
+							result.add(block);
+							break;
+						}
+					}
+				}
+					break;
+
+				case TERMINATOR_BYTE :
+					return result;
+
+				case 0x00 : // bad byte, but keep going and see what happens
+					break;
+
+				default :
+					throw new ImageReadException("GIF: unknown code: " + code);
+			}
+		}
+	}
+
+	private ImageDescriptor readImageDescriptor(GIFHeaderInfo ghi,
+			int blockCode, InputStream is, boolean stop_before_image_data,
+			FormatCompliance formatCompliance) throws ImageReadException,
+			IOException
+	{
+		int ImageLeftPosition = read2Bytes("Image Left Position", is,
+				"Not a Valid GIF File");
+		int ImageTopPosition = read2Bytes("Image Top Position", is,
+				"Not a Valid GIF File");
+		int imageWidth = read2Bytes("Image Width", is, "Not a Valid GIF File");
+		int imageHeight = read2Bytes("Image Height", is, "Not a Valid GIF File");
+		byte PackedFields = readByte("Packed Fields", is,
+				"Not a Valid GIF File");
+
+		if (formatCompliance != null)
+		{
+			formatCompliance.checkBounds("Width", 1, ghi.logicalScreenWidth,
+					imageWidth);
+			formatCompliance.checkBounds("Height", 1, ghi.logicalScreenHeight,
+					imageHeight);
+			formatCompliance.checkBounds("Left Position", 0,
+					ghi.logicalScreenWidth - imageWidth, ImageLeftPosition);
+			formatCompliance.checkBounds("Top Position", 0,
+					ghi.logicalScreenHeight - imageHeight, ImageTopPosition);
+		}
+
+		if (debug)
+			printByteBits("PackedFields bits", PackedFields);
+
+		boolean LocalColorTableFlag = (((PackedFields >> 7) & 1) > 0);
+		if (debug)
+			System.out.println("LocalColorTableFlag: " + LocalColorTableFlag);
+		boolean InterlaceFlag = (((PackedFields >> 6) & 1) > 0);
+		if (debug)
+			System.out.println("Interlace Flag: " + InterlaceFlag);
+		boolean SortFlag = (((PackedFields >> 5) & 1) > 0);
+		if (debug)
+			System.out.println("Sort  Flag: " + SortFlag);
+
+		byte SizeofLocalColorTable = (byte) (PackedFields & 7);
+		if (debug)
+			System.out.println("SizeofLocalColorTable: "
+					+ SizeofLocalColorTable);
+
+		byte LocalColorTable[] = null;
+		if (LocalColorTableFlag)
+			LocalColorTable = readColorTable(is, SizeofLocalColorTable,
+					formatCompliance);
+
+		byte imageData[] = null;
+		if (!stop_before_image_data)
+		{
+			int LZWMinimumCodeSize = is.read();
+
+			GenericGIFBlock block = readGenericGIFBlock(is, -1);
+			byte bytes[] = block.appendSubBlocks();
+			InputStream bais = new ByteArrayInputStream(bytes);
+
+			int size = imageWidth * imageHeight;
+			MyLZWDecompressor myLzwDecompressor = new MyLZWDecompressor(
+					LZWMinimumCodeSize, BYTE_ORDER_LSB);
+			imageData = myLzwDecompressor.decompress(bais, size);
+		}
+		else
+		{
+			int LZWMinimumCodeSize = is.read();
+			if (debug)
+				System.out.println("LZWMinimumCodeSize: " + LZWMinimumCodeSize);
+
+			readGenericGIFBlock(is, -1);
+		}
+
+		ImageDescriptor result = new ImageDescriptor(blockCode,
+				ImageLeftPosition, ImageTopPosition, imageWidth, imageHeight,
+				PackedFields, LocalColorTableFlag, InterlaceFlag, SortFlag,
+				SizeofLocalColorTable, LocalColorTable, imageData);
+
+		return result;
+	}
+
+	private int simple_pow(int base, int power)
+	{
+		int result = 1;
+
+		for (int i = 0; i < power; i++)
+			result *= base;
+
+		return result;
+	}
+
+	private int convertColorTableSize(int ct_size)
+	{
+		return 3 * simple_pow(2, ct_size + 1);
+	}
+
+	private byte[] readColorTable(InputStream is, int ct_size,
+			FormatCompliance formatCompliance) throws ImageReadException,
+			IOException
+	{
+		int actual_size = convertColorTableSize(ct_size);
+
+		byte bytes[] = readByteArray("block", actual_size, is,
+				"GIF: corrupt Color Table");
+
+		return bytes;
+	}
+
+	private GIFHeaderInfo readHeader(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		InputStream is = null;
+		try
+		{
+			is = byteSource.getInputStream();
+
+			return readHeader(is, getDefaultFormatCompliance());
+		}
+		finally
+		{
+			try
+			{
+				is.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+
+		}
+	}
+
+	private GIFBlock findBlock(Vector v, int code)
+	{
+		for (int i = 0; i < v.size(); i++)
+		{
+			GIFBlock fGIFBlock = (GIFBlock) v.get(i);
+			if (fGIFBlock.blockCode == code)
+				return fGIFBlock;
+		}
+		return null;
+	}
+
+	private ImageContents readFile(ByteSource byteSource,
+			boolean stop_before_image_data) throws ImageReadException,
+			IOException
+	{
+		return readFile(byteSource, stop_before_image_data,
+				getDefaultFormatCompliance());
+	}
+
+	private ImageContents readFile(ByteSource byteSource,
+			boolean stop_before_image_data, FormatCompliance formatCompliance)
+			throws ImageReadException, IOException
+	{
+		InputStream is = null;
+		try
+		{
+			is = byteSource.getInputStream();
+
+			GIFHeaderInfo ghi = readHeader(is, formatCompliance);
+
+			byte globalColorTable[] = null;
+			if (ghi.globalColorTableFlag)
+				globalColorTable = readColorTable(is,
+						ghi.sizeOfGlobalColorTable, formatCompliance);
+
+			Vector blocks = readBlocks(ghi, is, stop_before_image_data,
+					formatCompliance);
+
+			ImageContents result = new ImageContents(ghi, globalColorTable,
+					blocks);
+
+			return result;
+		}
+		finally
+		{
+			try
+			{
+				//					bis.close();
+				is.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+
+		}
+	}
+
+	public byte[] getICCProfileBytes(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		return null;
+	}
+
+	public Dimension getImageSize(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		GIFHeaderInfo bhi = readHeader(byteSource);
+
+		if (bhi == null)
+			throw new ImageReadException("GIF: Couldn't read Header");
+
+		return new Dimension(bhi.logicalScreenWidth, bhi.logicalScreenHeight);
+
+	}
+
+	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
+	{
+		return null;
+	}
+
+	private Vector getComments(Vector v) throws ImageReadException, IOException
+	{
+		Vector result = new Vector();
+		int code = 0x21fe;
+
+		for (int i = 0; i < v.size(); i++)
+		{
+			GIFBlock block = (GIFBlock) v.get(i);
+			if (block.blockCode == code)
+			{
+				byte bytes[] = ((GenericGIFBlock) block).appendSubBlocks();
+				result.add(new String(bytes));
+			}
+		}
+
+		return result;
+	}
+
+	public ImageInfo getImageInfo(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		ImageContents blocks = readFile(byteSource, false);
+
+		if (blocks == null)
+			throw new ImageReadException("GIF: Couldn't read blocks");
+
+		GIFHeaderInfo bhi = blocks.gifHeaderInfo;
+		if (bhi == null)
+			throw new ImageReadException("GIF: Couldn't read Header");
+
+		ImageDescriptor id = (ImageDescriptor) findBlock(blocks.blocks,
+				IMAGE_SEPARATOR);
+		if (id == null)
+			throw new ImageReadException("GIF: Couldn't read ImageDescriptor");
+
+		GraphicControlExtension gce = (GraphicControlExtension) findBlock(
+				blocks.blocks, GRAPHIC_CONTROL_EXTENSION);
+
+		int Height = bhi.logicalScreenHeight;
+		int Width = bhi.logicalScreenWidth;
+
+		Vector Comments;
+
+		Comments = getComments(blocks.blocks);
+
+		int BitsPerPixel = (bhi.colorResolution + 1) * 3;
+		ImageFormat Format = ImageFormat.IMAGE_FORMAT_GIF;
+		String FormatName = "GIF Graphics Interchange Format";
+		String MimeType = "image/gif";
+		// we ought to count images, but don't yet.
+		int NumberOfImages = -1;
+
+		boolean isProgressive = id.interlaceFlag;
+
+		int PhysicalWidthDpi = 72;
+		float PhysicalWidthInch = (float) ((double) Width / (double) PhysicalWidthDpi);
+		int PhysicalHeightDpi = 72;
+		float PhysicalHeightInch = (float) ((double) Height / (double) PhysicalHeightDpi);
+
+		String FormatDetails = "Gif " + ((char) blocks.gifHeaderInfo.version1)
+				+ ((char) blocks.gifHeaderInfo.version2)
+				+ ((char) blocks.gifHeaderInfo.version3);
+
+		boolean isTransparent = false;
+		if (gce != null)
+		{
+			if (gce.transparency)
+				isTransparent = true;
+		}
+
+		boolean usesPalette = true;
+		int colorType = ImageInfo.COLOR_TYPE_RGB;
+		String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_LZW;
+
+		ImageInfo result = new ImageInfo(FormatDetails, BitsPerPixel, Comments,
+				Format, FormatName, Height, MimeType, NumberOfImages,
+				PhysicalHeightDpi, PhysicalHeightInch, PhysicalWidthDpi,
+				PhysicalWidthInch, Width, isProgressive, isTransparent,
+				usesPalette, colorType, compressionAlgorithm);
+
+		return result;
+	}
+
+	public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		pw.println("gif.dumpImageFile");
+
+		{
+			ImageInfo fImageData = getImageInfo(byteSource);
+			if (fImageData == null)
+				return false;
+
+			fImageData.toString(pw, "");
+		}
+		{
+			ImageContents blocks = readFile(byteSource, false);
+
+			if (blocks == null)
+				return false;
+
+			pw.println("gif.blocks: " + blocks.blocks.size());
+			for (int i = 0; i < blocks.blocks.size(); i++)
+			{
+				GIFBlock fGIFBlock = (GIFBlock) blocks.blocks.get(i);
+				this.debugNumber(pw, "\t" + i + " ("
+						+ fGIFBlock.getClass().getName() + ")",
+						fGIFBlock.blockCode, 4);
+			}
+
+		}
+
+		pw.println("");
+
+		return true;
+	}
+
+	private int[] getColorTable(byte bytes[]) throws ImageReadException,
+			IOException
+	{
+		if ((bytes.length % 3) != 0)
+			throw new ImageReadException("Bad Color Table Length: "
+					+ bytes.length);
+		int length = bytes.length / 3;
+
+		int result[] = new int[length];
+
+		for (int i = 0; i < length; i++)
+		{
+			int red = 0xff & bytes[(i * 3) + 0];
+			int green = 0xff & bytes[(i * 3) + 1];
+			int blue = 0xff & bytes[(i * 3) + 2];
+
+			int alpha = 0xff;
+
+			int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+			result[i] = rgb;
+		}
+
+		return result;
+	}
+
+	public FormatCompliance getFormatCompliance(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		FormatCompliance result = new FormatCompliance(byteSource
+				.getDescription());
+
+		readFile(byteSource, false, result);
+
+		return result;
+	}
+
+	public BufferedImage getBufferedImage(ByteSource byteSource, Map params)
+			throws ImageReadException, IOException
+	{
+		ImageContents imageContents = readFile(byteSource, false);
+
+		if (imageContents == null)
+			throw new ImageReadException("GIF: Couldn't read blocks");
+
+		GIFHeaderInfo ghi = imageContents.gifHeaderInfo;
+		if (ghi == null)
+			throw new ImageReadException("GIF: Couldn't read Header");
+
+		ImageDescriptor id = (ImageDescriptor) findBlock(imageContents.blocks,
+				IMAGE_SEPARATOR);
+		if (id == null)
+			throw new ImageReadException("GIF: Couldn't read Image Descriptor");
+		GraphicControlExtension gce = (GraphicControlExtension) findBlock(
+				imageContents.blocks, GRAPHIC_CONTROL_EXTENSION);
+
+		int width = ghi.logicalScreenWidth;
+		int height = ghi.logicalScreenHeight;
+
+		BufferedImage result = getBufferedImageFactory(params)
+				.getColorBufferedImage(width, height);
+
+		{
+			int colortable[];
+			if (id.localColorTable != null)
+				colortable = getColorTable(id.localColorTable);
+			else if (imageContents.globalColorTable != null)
+				colortable = getColorTable(imageContents.globalColorTable);
+			else
+				throw new ImageReadException("Gif: No Color Table");
+
+			int transparentIndex = -1;
+			if (gce != null)
+			{
+				if (gce.transparency)
+					transparentIndex = gce.transparentColorIndex;
+			}
+
+			//			Debug.debug("charles TransparentIndex", TransparentIndex);
+
+			int counter = 0;
+			//			ByteArrayInputStream bais = new ByteArrayInputStream(id.ImageData);
+			//			for (int y = 0; y < height; y++)
+
+			int rows_in_pass_1 = (height + 7) / 8;
+			int rows_in_pass_2 = (height + 3) / 8;
+			int rows_in_pass_3 = (height + 1) / 4;
+			int rows_in_pass_4 = (height) / 2;
+
+			DataBuffer db = result.getRaster().getDataBuffer();
+
+			for (int row = 0; row < height; row++)
+			{
+
+				int y;
+				if (id.interlaceFlag)
+				{
+					int the_row = row;
+					if (the_row < rows_in_pass_1)
+						y = the_row * 8;
+					else
+					{
+						the_row -= rows_in_pass_1;
+						if (the_row < (rows_in_pass_2))
+							y = 4 + (the_row * 8);
+						else
+						{
+							the_row -= rows_in_pass_2;
+							if (the_row < (rows_in_pass_3))
+								y = 2 + (the_row * 4);
+							else
+							{
+								the_row -= rows_in_pass_3;
+								if (the_row < (rows_in_pass_4))
+									y = 1 + (the_row * 2);
+								else
+									throw new ImageReadException(
+											"Gif: Strange Row");
+							}
+						}
+					}
+					//					System.out.println("row(" + row + "): " + y);
+				}
+				else
+					y = row;
+
+				for (int x = 0; x < width; x++)
+				{
+
+					int index = 0xff & id.imageData[counter++];
+					int rgb = colortable[index];
+
+					if (transparentIndex == index)
+						rgb = 0x00;
+
+					db.setElem(y * width + x, rgb);
+				}
+
+			}
+		}
+
+		return result;
+
+	}
+
+	private void writeAsSubBlocks(OutputStream os, byte bytes[])
+			throws IOException
+	{
+		int index = 0;
+
+		while (index < bytes.length)
+		{
+			int block_size = Math.min(bytes.length - index, 255);
+			os.write(block_size);
+			os.write(bytes, index, block_size);
+			index += block_size;
+		}
+		os.write(0); // last block 
+	}
+
+	private static final int LOCAL_COLOR_TABLE_FLAG_MASK = 1 << 7;
+	private static final int INTERLACE_FLAG_MASK = 1 << 6;
+	private static final int SORT_FLAG_MASK = 1 << 5;
+
+	public void writeImage(BufferedImage src, OutputStream os, Map params)
+			throws ImageWriteException, IOException
+	{
+		// make copy of params; we'll clear keys as we consume them.
+		params = new Hashtable(params);
+
+		// clear format key.
+		if (params.containsKey(PARAM_KEY_FORMAT))
+			params.remove(PARAM_KEY_FORMAT);
+
+		if (params.size() > 0)
+		{
+			Object firstKey = params.keySet().iterator().next();
+			throw new ImageWriteException("Unknown parameter: " + firstKey);
+		}
+
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		boolean hasAlpha = new PaletteFactory().hasTransparency(src);
+
+		int max_colors = hasAlpha ? 255 : 256;
+
+		Palette palette2 = new PaletteFactory().makePaletteSimple(src,
+				max_colors);
+		//		int palette[] = new PaletteFactory().makePaletteSimple(src, 256);
+		//		Map palette_map = paletteToMap(palette);
+
+		if (palette2 == null)
+		{
+			palette2 = new PaletteFactory().makePaletteQuantized(src,
+					max_colors);
+			System.out.println("quantizing");
+		}
+		else
+			System.out.println("exact palette");
+
+		if (palette2 == null)
+			throw new ImageWriteException(
+					"Gif: can't write images with more than 256 colors");
+		int palette_size = palette2.length() + (hasAlpha ? 1 : 0);
+
+		BinaryOutputStream bos = new BinaryOutputStream(os, BYTE_ORDER_LSB);
+
+		{
+			// write Header
+			os.write(0x47); // G magic numbers
+			os.write(0x49); // I 
+			os.write(0x46); // F
+
+			os.write(0x38); // 8 version magic numbers
+			os.write(0x39); // 9 
+			os.write(0x61); // a
+
+			// Logical Screen Descriptor.
+
+			bos.write2Bytes(width);
+			bos.write2Bytes(height);
+
+			int colorTableScaleLessOne = (palette_size > 128)
+					? 7
+					: (palette_size > 64) ? 6 : (palette_size > 32)
+							? 5
+							: (palette_size > 16) ? 4 : (palette_size > 8)
+									? 3
+									: (palette_size > 4)
+											? 2
+											: (palette_size > 2) ? 1 : 0;
+
+			int colorTableSizeInFormat = 1 << (colorTableScaleLessOne + 1);
+			int actual_size = 3 * simple_pow(2, colorTableScaleLessOne + 1);
+			{
+				byte colorResolution = (byte) colorTableScaleLessOne; // TODO: 
+
+				boolean globalColorTableFlag = false;
+				boolean sortFlag = false;
+				int globalColorTableFlagMask = 1 << 7;
+				int sortFlagMask = 8;
+				int sizeOfGlobalColorTable = 0;
+
+				int packedFields = ((globalColorTableFlag
+						? globalColorTableFlagMask
+						: 0)
+						| (sortFlag ? sortFlagMask : 0)
+						| ((7 & colorResolution) << 4) | (7 & sizeOfGlobalColorTable));
+				bos.write(packedFields); // one byte
+			}
+			{
+				byte BackgroundColorIndex = 0;
+				bos.write(BackgroundColorIndex);
+			}
+			{
+				byte PixelAspectRatio = 0;
+				bos.write(PixelAspectRatio);
+			}
+
+			{ // write Global Color Table.
+
+			}
+
+			if (hasAlpha)
+			{ // write GraphicControlExtension
+				bos.write((byte) 0x21);
+				bos.write((byte) 0xf9);
+				//				bos.write(0xff & (kGraphicControlExtension >> 8));
+				//				bos.write(0xff & (kGraphicControlExtension >> 0));
+
+				bos.write((byte) 4); // block size;
+				int fPackedFields = hasAlpha ? 1 : 0; // transparency flag
+				bos.write((byte) fPackedFields);
+				bos.write((byte) 0); //  Delay Time
+				bos.write((byte) 0); //  Delay Time
+				bos.write((byte) (hasAlpha ? palette2.length() : 0)); //   Transparent Color Index
+				bos.write((byte) 0); // terminator
+			}
+
+			{ //  Image Descriptor.
+				bos.write(IMAGE_SEPARATOR);
+				bos.write2Bytes(0); // Image Left Position  
+				bos.write2Bytes(0); //  Image Top Position  
+				bos.write2Bytes(width); // Image Width    
+				bos.write2Bytes(height); //  Image Height     
+
+				{
+					boolean LocalColorTableFlag = true;
+					//					boolean LocalColorTableFlag = false;
+					boolean InterlaceFlag = false;
+					boolean SortFlag = false;
+					int SizeOfLocalColorTable = colorTableScaleLessOne;
+
+					//					int SizeOfLocalColorTable = 0;
+
+					int PackedFields = ((LocalColorTableFlag
+							? LOCAL_COLOR_TABLE_FLAG_MASK
+							: 0)
+							| (InterlaceFlag ? INTERLACE_FLAG_MASK : 0)
+							| (SortFlag ? SORT_FLAG_MASK : 0) | (7 & SizeOfLocalColorTable));
+					bos.write(PackedFields); // one byte
+				}
+			}
+
+			{ // write Local Color Table.
+				for (int i = 0; i < colorTableSizeInFormat; i++)
+				{
+					if (i < palette2.length())
+					{
+						int rgb = palette2.getEntry(i);
+
+						int red = 0xff & (rgb >> 16);
+						int green = 0xff & (rgb >> 8);
+						int blue = 0xff & (rgb >> 0);
+
+						bos.write(red);
+						bos.write(green);
+						bos.write(blue);
+					}
+					else
+					{
+						bos.write(0);
+						bos.write(0);
+						bos.write(0);
+					}
+				}
+			}
+
+			{ // get Image Data.
+				int image_data_total = 0;
+
+				int LZWMinimumCodeSize = colorTableScaleLessOne + 1; // TODO: make better choice here.
+				bos.write(LZWMinimumCodeSize);
+
+				MyLZWCompressor compressor = new MyLZWCompressor(
+						LZWMinimumCodeSize, BYTE_ORDER_LSB, false); // GIF Mode);
+
+				byte imagedata[] = new byte[width * height];
+				for (int y = 0; y < height; y++)
+				{
+					for (int x = 0; x < width; x++)
+					{
+						int argb = src.getRGB(x, y);
+						int rgb = 0xffffff & argb;
+						int index;
+
+						if (hasAlpha)
+						{
+							int alpha = 0xff & (argb >> 24);
+							final int alphaThreshold = 255;
+							if (alpha < alphaThreshold)
+								index = palette2.length(); // is transparent
+							else
+								index = palette2.getPaletteIndex(rgb);
+						}
+						else
+						{
+							index = palette2.getPaletteIndex(rgb);
+						}
+
+						imagedata[y * width + x] = (byte) index;
+					}
+				}
+
+				byte compressed[] = compressor.compress(imagedata);
+				writeAsSubBlocks(bos, compressed);
+				image_data_total += compressed.length;
+			}
+
+			palette2.dump();
+
+			bos.write(TERMINATOR_BYTE);
+		}
+
+		bos.close();
+		os.close();
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GifImageParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GraphicControlExtension.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GraphicControlExtension.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GraphicControlExtension.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GraphicControlExtension.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.gif;
+
+class GraphicControlExtension extends GIFBlock
+{
+
+	public final int packed;
+	public final int dispose;
+	public final boolean transparency;
+	public final int delay;
+	public final int transparentColorIndex;
+
+	public GraphicControlExtension(int blockCode, int packed, int dispose,
+			boolean transparency, int delay, int transparentColorIndex)
+	{
+		super(blockCode);
+
+		this.packed = packed;
+		this.dispose = dispose;
+		this.transparency = transparency;
+		this.delay = delay;
+		this.transparentColorIndex = transparentColorIndex;
+
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/GraphicControlExtension.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageContents.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageContents.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageContents.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageContents.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.gif;
+
+import java.util.Vector;
+
+class ImageContents
+{
+	public final GIFHeaderInfo gifHeaderInfo;
+
+	public final Vector blocks;
+	public final byte globalColorTable[];
+
+	public ImageContents(GIFHeaderInfo gifHeaderInfo, byte globalColorTable[],
+			Vector blocks)
+	{
+		this.gifHeaderInfo = gifHeaderInfo;
+		this.globalColorTable = globalColorTable;
+		this.blocks = blocks;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageContents.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageDescriptor.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageDescriptor.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageDescriptor.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageDescriptor.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.gif;
+
+public class ImageDescriptor extends GIFBlock
+{
+
+	public final int imageLeftPosition;
+	public final int imageTopPosition;
+	public final int imageWidth;
+	public final int imageHeight;
+	public final byte packedFields;
+	public final boolean localColorTableFlag;
+	public final boolean interlaceFlag;
+	public final boolean sortFlag;
+	public final byte sizeOfLocalColorTable;
+
+	public final byte localColorTable[];
+	public final byte imageData[];
+
+	public ImageDescriptor(int blockCode, int ImageLeftPosition,
+			int ImageTopPosition, int ImageWidth, int ImageHeight,
+			byte PackedFields, boolean LocalColorTableFlag,
+			boolean InterlaceFlag, boolean SortFlag,
+			byte SizeofLocalColorTable, byte LocalColorTable[],
+			byte ImageData[])
+	{
+		super(blockCode);
+
+		this.imageLeftPosition = ImageLeftPosition;
+		this.imageTopPosition = ImageTopPosition;
+		this.imageWidth = ImageWidth;
+		this.imageHeight = ImageHeight;
+		this.packedFields = PackedFields;
+		this.localColorTableFlag = LocalColorTableFlag;
+		this.interlaceFlag = InterlaceFlag;
+		this.sortFlag = SortFlag;
+		this.sizeOfLocalColorTable = SizeofLocalColorTable;
+
+		this.localColorTable = LocalColorTable;
+		this.imageData = ImageData;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/gif/ImageDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/ico/IcoImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/ico/IcoImageParser.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/ico/IcoImageParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/ico/IcoImageParser.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,544 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.ico;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Vector;
+
+import org.cmc.sanselan.ImageFormat;
+import org.cmc.sanselan.ImageInfo;
+import org.cmc.sanselan.ImageParser;
+import org.cmc.sanselan.ImageReadException;
+import org.cmc.sanselan.ImageWriteException;
+import org.cmc.sanselan.common.IImageMetadata;
+import org.cmc.sanselan.common.byteSources.ByteSource;
+import org.cmc.sanselan.util.Debug;
+
+public class IcoImageParser extends ImageParser
+{
+
+	public IcoImageParser()
+	{
+		super.setByteOrder(BYTE_ORDER_LSB);
+		//		setDebug(true);
+	}
+
+	public String getName()
+	{
+		return "ico-Custom";
+	}
+
+	public String getDefaultExtension()
+	{
+		return DEFAULT_EXTENSION;
+	}
+
+	private static final String DEFAULT_EXTENSION = ".ico";
+
+	private static final String ACCEPTED_EXTENSIONS[] = {
+			".ico", ".cur",
+	};
+
+	protected String[] getAcceptedExtensions()
+	{
+		return ACCEPTED_EXTENSIONS;
+	}
+
+	protected ImageFormat[] getAcceptedTypes()
+	{
+		return new ImageFormat[]{
+			ImageFormat.IMAGE_FORMAT_ICO, //
+		};
+	}
+
+	public boolean embedICCProfile(File src, File dst, byte profile[])
+	{
+		return false;
+	}
+
+	public IImageMetadata getMetadata(ByteSource byteSource, Map params)
+			throws ImageReadException, IOException
+	{
+		return null;
+	}
+
+	public ImageInfo getImageInfo(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		return null;
+	}
+
+	public Dimension getImageSize(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		return null;
+	}
+
+	public byte[] getICCProfileBytes(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		return null;
+	}
+
+	private static class FileHeader
+	{
+		public final int reserved; // Reserved (2 bytes), always 0
+		public final int iconType; // IconType (2 bytes), if the image is an icon it?s 1, for cursors the value is 2.
+		public final int iconCount; //IconCount (2 bytes), number of icons in this file.
+
+		public FileHeader(final int reserved, final int iconType,
+				final int iconCount)
+		{
+			this.reserved = reserved;
+			this.iconType = iconType;
+			this.iconCount = iconCount;
+		}
+
+		public void dump()
+		{
+			System.out.println("FileHeader");
+			System.out.println("Reserved: " + reserved);
+			System.out.println("IconType: " + iconType);
+			System.out.println("IconCount: " + iconCount);
+			System.out.println("");
+		}
+	}
+
+	private FileHeader readFileHeader(InputStream is)
+			throws ImageReadException, IOException
+	{
+		int Reserved = read2Bytes("Reserved", is, "Not a Valid ICO File");
+		int IconType = read2Bytes("IconType", is, "Not a Valid ICO File");
+		int IconCount = read2Bytes("IconCount", is, "Not a Valid ICO File");
+
+		return new FileHeader(Reserved, IconType, IconCount);
+
+	}
+
+	private static class IconInfo
+	{
+		public final byte Width;
+		public final byte Height;
+		public final byte ColorCount;
+		public final byte Reserved;
+		public final int Planes;
+		public final int BitCount;
+		public final int ImageSize;
+		public final int ImageOffset;
+
+		public IconInfo(final byte width, final byte height,
+				final byte colorCount, final byte reserved, final int planes,
+				final int bitCount, final int imageSize, final int imageOffset)
+		{
+			Width = width;
+			Height = height;
+			ColorCount = colorCount;
+			Reserved = reserved;
+			Planes = planes;
+			BitCount = bitCount;
+			ImageSize = imageSize;
+			ImageOffset = imageOffset;
+		}
+
+		public void dump()
+		{
+			System.out.println("IconInfo");
+
+			System.out.println("Width: " + Width);
+			System.out.println("Height: " + Height);
+			System.out.println("ColorCount: " + ColorCount);
+			System.out.println("Reserved: " + Reserved);
+			System.out.println("Planes: " + Planes);
+			System.out.println("BitCount: " + BitCount);
+			System.out.println("ImageSize: " + ImageSize);
+			System.out.println("ImageOffset: " + ImageOffset);
+			System.out.println("");
+		}
+	}
+
+	private IconInfo readIconInfo(InputStream is) throws ImageReadException,
+			IOException
+	{
+		byte Width = readByte("Width", is, "Not a Valid ICO File"); // Width (1 byte), Width of Icon (1 to 255)
+		byte Height = readByte("Height", is, "Not a Valid ICO File"); // Height (1 byte), Height of Icon (1 to 255)
+		byte ColorCount = readByte("ColorCount", is, "Not a Valid ICO File"); // ColorCount (1 byte), Number of colors, either 0 for 24 bit or higher, 2 for monochrome or 16 for 16 color images.
+		byte Reserved = readByte("Reserved", is, "Not a Valid ICO File"); // Reserved (1 byte), Not used (always 0)
+		int Planes = read2Bytes("Planes", is, "Not a Valid ICO File"); // Planes (2 bytes), always 1
+		int BitCount = read2Bytes("BitCount", is, "Not a Valid ICO File"); // BitCount (2 bytes), number of bits per pixel (1 for monochrome, 4 for 16 colors, 8 for 256 colors, 24 for true colors, 32 for true colors + alpha channel)
+		int ImageSize = read4Bytes("ImageSize", is, "Not a Valid ICO File"); // ImageSize (4 bytes), Length of resource in bytes
+		int ImageOffset = read4Bytes("ImageOffset", is, "Not a Valid ICO File"); // ImageOffset (4 bytes), start of the image in the file.
+
+		return new IconInfo(Width, Height, ColorCount, Reserved, Planes,
+				BitCount, ImageSize, ImageOffset);
+	}
+
+	private static class BitmapHeader
+	{
+		public final int Size;
+		public final int Width;
+		public final int Height;
+		public final int Planes;
+		public final int BitCount;
+		public final int Compression;
+		public final int SizeImage;
+		public final int XPelsPerMeter;
+		public final int YPelsPerMeter;
+		public final int ColorsUsed;
+		public final int ColorsImportant;
+
+		public BitmapHeader(final int size, final int width, final int height,
+				final int planes, final int bitCount, final int compression,
+				final int sizeImage, final int pelsPerMeter,
+				final int pelsPerMeter2, final int colorsUsed,
+				final int colorsImportant)
+		{
+			Size = size;
+			Width = width;
+			Height = height;
+			Planes = planes;
+			BitCount = bitCount;
+			Compression = compression;
+			SizeImage = sizeImage;
+			XPelsPerMeter = pelsPerMeter;
+			YPelsPerMeter = pelsPerMeter2;
+			ColorsUsed = colorsUsed;
+			ColorsImportant = colorsImportant;
+		}
+
+		public void dump()
+		{
+			System.out.println("BitmapHeader");
+
+			System.out.println("Size: " + Size);
+			System.out.println("Width: " + Width);
+			System.out.println("Height: " + Height);
+			System.out.println("Planes: " + Planes);
+			System.out.println("BitCount: " + BitCount);
+			System.out.println("Compression: " + Compression);
+			System.out.println("SizeImage: " + SizeImage);
+			System.out.println("XPelsPerMeter: " + XPelsPerMeter);
+			System.out.println("YPelsPerMeter: " + YPelsPerMeter);
+			System.out.println("ColorsUsed: " + ColorsUsed);
+			System.out.println("ColorsImportant: " + ColorsImportant);
+
+			System.out.println("");
+		}
+	}
+
+	private static class IconData
+	{
+		public final IconInfo iconInfo;
+		public final BitmapHeader header;
+		public final byte palette[];
+		public final byte color_map[];
+		public final int scanline_size;
+		public final byte transparency_map[];
+		public final int t_scanline_size;
+
+		public IconData(final IconInfo iconInfo, final BitmapHeader header,
+				final byte[] palette, final byte[] color_map,
+				final int scanline_size, final byte[] transparency_map,
+				final int t_scanline_size)
+		{
+			super();
+			this.iconInfo = iconInfo;
+			this.header = header;
+			this.palette = palette;
+			this.color_map = color_map;
+			this.scanline_size = scanline_size;
+			this.transparency_map = transparency_map;
+			this.t_scanline_size = t_scanline_size;
+		}
+
+		public void dump()
+		{
+			System.out.println("IconData");
+
+			iconInfo.dump();
+			header.dump();
+
+			System.out.println("scanline_size: " + scanline_size);
+			System.out.println("t_scanline_size: " + t_scanline_size);
+			System.out.println("palette: "
+					+ ((palette == null) ? "null" : "" + palette.length));
+			System.out.println("color_map: "
+					+ ((color_map == null) ? "null" : "" + color_map.length));
+			System.out.println("transparency_map: "
+					+ ((transparency_map == null) ? "null" : ""
+							+ transparency_map.length));
+
+			System.out.println("");
+		}
+	}
+
+	private IconData readIconData(InputStream is, IconInfo fIconInfo)
+			throws ImageReadException, IOException
+	{
+		int Size = read4Bytes("Size", is, "Not a Valid ICO File"); // Size (4 bytes), size of this structure (always 40)
+		int Width = read4Bytes("Width", is, "Not a Valid ICO File"); // Width (4 bytes), width of the image (same as iconinfo.width)
+		int Height = read4Bytes("Height", is, "Not a Valid ICO File"); // Height (4 bytes), scanlines in the color map + transparent map (iconinfo.height * 2)
+		int Planes = read2Bytes("Planes", is, "Not a Valid ICO File"); // Planes (2 bytes), always 1
+		int BitCount = read2Bytes("BitCount", is, "Not a Valid ICO File"); // BitCount (2 bytes), 1,4,8,24,32 (see iconinfo for details)
+		int Compression = read4Bytes("Compression", is, "Not a Valid ICO File"); // Compression (4 bytes), we don?t use this (0)
+		int SizeImage = read4Bytes("SizeImage", is, "Not a Valid ICO File"); // SizeImage (4 bytes), we don?t use this (0)
+		int XPelsPerMeter = read4Bytes("XPelsPerMeter", is,
+				"Not a Valid ICO File"); // XPelsPerMeter (4 bytes), we don?t use this (0)
+		int YPelsPerMeter = read4Bytes("YPelsPerMeter", is,
+				"Not a Valid ICO File"); // YPelsPerMeter (4 bytes), we don?t use this (0)
+		int ColorsUsed = read4Bytes("ColorsUsed", is, "Not a Valid ICO File"); // ColorsUsed (4 bytes), we don?t use this (0)
+		int ColorsImportant = read4Bytes("ColorsImportant", is,
+				"Not a Valid ICO File"); // ColorsImportant (4 bytes), we don?t use this (0)
+
+		BitmapHeader header = new BitmapHeader(Size, Width, Height, Planes,
+				BitCount, Compression, SizeImage, XPelsPerMeter, YPelsPerMeter,
+				ColorsUsed, ColorsImportant);
+
+		//		System.out.println("XXXXXXXXXXXXXXXXXXXX");
+		//		fIconInfo.dump();
+		//		header.dump();
+		//		System.out.println("XXXXXXXXXXXXXXXXXXXX");
+
+		int palette_size = 0;
+		byte palette[] = null;
+
+		if ((fIconInfo.BitCount == 1) || (fIconInfo.BitCount == 4)
+				|| (fIconInfo.BitCount == 8))
+		{
+			palette_size = 4 * (1 << fIconInfo.BitCount);
+			palette = this.readByteArray("palette", palette_size, is,
+					"Not a Valid ICO File");
+		}
+
+		byte color_map[] = null;
+		int scanline_size = (fIconInfo.BitCount * fIconInfo.Width + 7) / 8;
+		if ((scanline_size % 4) != 0)
+			scanline_size += 4 - (scanline_size % 4); // pad scanline to 4 byte size.
+
+		int color_map_size_bytes = scanline_size * fIconInfo.Height;
+		{
+			color_map = this.readByteArray("color_map", color_map_size_bytes,
+					is, "Not a Valid ICO File");
+		}
+
+		byte transparency_map[] = null;
+		int t_scanline_size = (fIconInfo.Width + 7) / 8;
+		if ((t_scanline_size % 4) != 0)
+			t_scanline_size += 4 - (t_scanline_size % 4); // pad scanline to 4 byte size.
+
+		int tcolor_map_size_bytes = t_scanline_size * fIconInfo.Height;
+		{
+			transparency_map = this.readByteArray("transparency_map",
+					tcolor_map_size_bytes, is, "Not a Valid ICO File");
+		}
+
+		return new IconData(fIconInfo, header, palette, color_map,
+				scanline_size, transparency_map, t_scanline_size);
+	}
+
+	private static class ImageContents
+	{
+		public final FileHeader fileHeader;
+		public final IconData iconDatas[];
+
+		public ImageContents(final FileHeader fileHeader,
+				final IconData[] iconDatas)
+		{
+			super();
+			this.fileHeader = fileHeader;
+			this.iconDatas = iconDatas;
+		}
+	}
+
+	private ImageContents readImage(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		InputStream is = null;
+		try
+		{
+			is = byteSource.getInputStream();
+			FileHeader fileHeader = readFileHeader(is);
+
+			//			fileHeader.dump();
+
+			IconInfo fIconInfos[] = new IconInfo[fileHeader.iconCount];
+			for (int i = 0; i < fileHeader.iconCount; i++)
+			{
+				fIconInfos[i] = readIconInfo(is);
+				//				fIconInfos[i].dump();
+			}
+
+			IconData fIconDatas[] = new IconData[fileHeader.iconCount];
+			for (int i = 0; i < fileHeader.iconCount; i++)
+			{
+				fIconDatas[i] = readIconData(is, fIconInfos[i]);
+				//				fIconDatas[i].dump();
+			}
+
+			return new ImageContents(fileHeader, fIconDatas);
+		}
+		finally
+		{
+			try
+			{
+				is.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+
+		}
+	}
+
+	public final BufferedImage getBufferedImage(ByteSource byteSource,
+			Map params) throws ImageReadException, IOException
+	{
+		throw new ImageReadException(
+				"Use getAllBufferedImages() instead for .ico images.");
+	}
+
+
+	private BufferedImage readBufferedImage(IconData fIconData)
+			throws ImageReadException
+	{
+		IconInfo fIconInfo = fIconData.iconInfo;
+
+		int width = fIconInfo.Width;
+		int height = fIconInfo.Height;
+		int data[] = new int[width * height];
+
+		for (int y = 0; y < height; y++)
+		{
+			for (int x = 0; x < width; x++)
+			{
+				int rgb;
+
+				int alpha_byte = 0xff & fIconData.transparency_map[fIconData.t_scanline_size
+						* y + (x / 8)];
+				int alpha = 0x01 & (alpha_byte >> (7 - (x % 8)));
+				alpha = (alpha == 0) ? 0xff : 0x00;
+
+				if ((fIconInfo.BitCount == 1) || (fIconInfo.BitCount == 4)
+						|| (fIconInfo.BitCount == 8))
+				{
+					int bit_index = fIconData.scanline_size * y * 8 + x
+							* fIconInfo.BitCount;
+					int b = 0xff & fIconData.color_map[(bit_index >> 3)];
+					int mask = (1 << fIconInfo.BitCount) - 1;
+					int shift = 8 - (bit_index % 8) - fIconInfo.BitCount;
+					int color_index = mask & (b >> shift);
+
+					int red = 0xff & fIconData.palette[4 * color_index + 2];
+					int green = 0xff & fIconData.palette[4 * color_index + 1];
+					int blue = 0xff & fIconData.palette[4 * color_index + 0];
+					rgb = ((0xff & red) << 16) | ((0xff & green) << 8)
+							| ((0xff & blue) << 0);
+				}
+				else if ((fIconInfo.BitCount == 24)
+						|| (fIconInfo.BitCount == 32))
+				{
+					int byte_count = fIconInfo.BitCount >> 3;
+					int index = fIconData.scanline_size * y + x * byte_count;
+					int red = 0xff & fIconData.color_map[index + 2];
+					int green = 0xff & fIconData.color_map[index + 1];
+					int blue = 0xff & fIconData.color_map[index + 0];
+
+					rgb = ((0xff & red) << 16) | ((0xff & green) << 8)
+							| ((0xff & blue) << 0);
+				}
+				else
+					throw new ImageReadException("Unknown BitCount: "
+							+ fIconInfo.BitCount);
+
+				int argb = ((alpha & 0xff) << 24) | (rgb & 0xffffff);
+
+				//				argb = 0xff000000 | argb;
+
+				data[(height - y - 1) * width + x] = argb;
+			}
+		}
+
+		ColorModel cModel = ColorModel.getRGBdefault();
+		DataBufferInt intBuf = new DataBufferInt(data, (width * height));
+		SampleModel sModel = cModel.createCompatibleSampleModel(width, height);
+
+		// create our raster
+		WritableRaster raster = Raster.createWritableRaster(sModel, intBuf,
+				null);
+
+		// now create and return our buffered image
+		BufferedImage result = new BufferedImage(cModel, raster, false, null);
+
+		return result;
+	}
+	
+
+	public Vector getAllBufferedImages(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		Vector result = new Vector();
+		ImageContents contents = readImage(byteSource);
+
+		FileHeader fileHeader = contents.fileHeader;
+		for (int i = 0; i < fileHeader.iconCount; i++)
+		{
+			IconData iconData = contents.iconDatas[i];
+
+			BufferedImage image = readBufferedImage(iconData);
+
+			result.add(image);
+		}
+
+		return result;
+	}
+
+//	public boolean extractImages(ByteSource byteSource, File dst_dir,
+//			String dst_root, ImageParser encoder) throws ImageReadException,
+//			IOException, ImageWriteException
+//	{
+//		ImageContents contents = readImage(byteSource);
+//
+//		FileHeader fileHeader = contents.fileHeader;
+//		for (int i = 0; i < fileHeader.iconCount; i++)
+//		{
+//			IconData iconData = contents.iconDatas[i];
+//
+//			BufferedImage image = readBufferedImage(iconData);
+//
+//			int size = Math.max(iconData.iconInfo.Width,
+//					iconData.iconInfo.Height);
+//			File file = new File(dst_dir, dst_root + "_" + size + "_"
+//					+ iconData.iconInfo.BitCount
+//					+ encoder.getDefaultExtension());
+//			encoder.writeImage(image, new FileOutputStream(file), null);
+//		}
+//
+//		return true;
+//	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/ico/IcoImageParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcElement.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcElement.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcElement.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcElement.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.jpeg;
+
+public class IptcElement
+{
+	public final IptcType iptcType;
+	public final String value;
+
+	public IptcElement(IptcType fIptcType, String value)
+	{
+		this.iptcType = fIptcType;
+		this.value = value;
+	}
+
+	public String getValue()
+	{
+		return value;
+	}
+
+	public String getIptcTypeName()
+	{
+		return iptcType.name;
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcElement.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcType.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcType.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcType.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcType.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.jpeg;
+
+public class IptcType implements JpegConstants
+{
+	public final int type;
+	public final String name;
+
+	public IptcType(int type, String name)
+	{
+		this.type = type;
+		this.name = name;
+	}
+
+	public static final IptcType getIptcType(int type)
+	{
+		for (int i = 0; i < IPTC_TYPES.length; i++)
+		{
+			IptcType fIptcType = IPTC_TYPES[i];
+			if (fIptcType.type == type)
+				return fIptcType;
+		}
+		return IPTC_TYPE_Unknown;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/IptcType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegConstants.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegConstants.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegConstants.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.jpeg;
+
+public interface JpegConstants
+{
+
+	public static final byte ExifIdentifierCode[] = {
+			0xff & 'E', 0xff & 'x', 0xff & 'i', 0xff & 'f',
+	};
+
+	public static final byte SOI[] = new byte[]{
+			(byte) 0xff, (byte) 0xd8
+	};
+	public static final byte EOI[] = new byte[]{
+			(byte) 0xff, (byte) 0xd9
+	};
+	public static final int SOS_Marker = (0xff00) | (0xda);
+
+	public static final int JPEG_APP0 = 0xE0;
+	//	public static final  int JPEG_APP1 = JPEG_APP0 + 1;
+	//	public static final  int JPEG_APP1_Marker = (0xff00) | JPEG_APP1;
+	public static final int JPEG_APP0_Marker = (0xff00) | (JPEG_APP0);
+	public static final int JPEG_APP1_Marker = (0xff00) | (JPEG_APP0 + 1);
+	//	public static final  int JPEG_APP2 = ;
+	public static final int JPEG_APP2_Marker = (0xff00) | (JPEG_APP0 + 2);
+	public static final int JPEG_APP13_Marker = (0xff00) | (JPEG_APP0 + 13);
+	public static final int JPEG_APP14_Marker = (0xff00) | (JPEG_APP0 + 14);
+	public static final int JPEG_APP15_Marker = (0xff00) | (JPEG_APP0 + 15);
+
+	public static final int JFIFMarker = 0xFFE0;
+	public static final int SOF0Marker = 0xFFc0;
+	public static final int SOF1Marker = 0xFFc0 + 0x1;
+	public static final int SOF2Marker = 0xFFc0 + 0x2;
+	public static final int SOF3Marker = 0xFFc0 + 0x3;
+	public static final int SOF4Marker = 0xFFc0 + 0x4;
+	public static final int SOF5Marker = 0xFFc0 + 0x5;
+	public static final int SOF6Marker = 0xFFc0 + 0x6;
+	public static final int SOF7Marker = 0xFFc0 + 0x7;
+	public static final int SOF8Marker = 0xFFc0 + 0x8;
+	public static final int SOF9Marker = 0xFFc0 + 0x9;
+	public static final int SOF10Marker = 0xFFc0 + 0xa;
+	public static final int SOF11Marker = 0xFFc0 + 0xb;
+	public static final int SOF12Marker = 0xFFc0 + 0xc;
+	public static final int SOF13Marker = 0xFFc0 + 0xd;
+	public static final int SOF14Marker = 0xFFc0 + 0xe;
+	public static final int SOF15Marker = 0xFFc0 + 0xf;
+
+	public static final byte icc_profile_label[] = {
+			0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45,
+			0x0
+	};
+
+	//	public static final byte PhotoshopIdentificationString[] = "Photoshop 3.0"
+	//		.getBytes();
+	public static final byte PhotoshopIdentificationString[] = {
+			0xff & 'P', 0xff & 'h', 0xff & 'o', 0xff & 't', 0xff & 'o',
+			0xff & 's', 0xff & 'h', 0xff & 'o', 0xff & 'p', 0xff & ' ',
+			0xff & '3', 0xff & '.', 0xff & '0', 0,
+	};
+	public static final byte CONST_8BIM[] = {
+			0xff & '8', 0xff & 'B', 0xff & 'I', 0xff & 'M',
+	};
+
+	public static final byte IPTCPrefix[] = {
+			0x1C, 0x02,
+	};
+
+	public static final IptcType IPTC_TYPE_RecordVersion = new IptcType(0,
+			"RecordVersion");
+	public static final IptcType IPTC_TYPE_ObjectTypeReference = new IptcType(
+			3, "ObjectTypeReference");
+	public static final IptcType IPTC_TYPE_ObjectAttributeReference = new IptcType(
+			4, "ObjectAttributeReference");
+	public static final IptcType IPTC_TYPE_ObjectName = new IptcType(5,
+			"ObjectName");
+	public static final IptcType IPTC_TYPE_EditStatus = new IptcType(7,
+			"EditStatus");
+	public static final IptcType IPTC_TYPE_EditorialUpdate = new IptcType(8,
+			"EditorialUpdate");
+	public static final IptcType IPTC_TYPE_Urgency = new IptcType(10, "Urgency");
+	public static final IptcType IPTC_TYPE_SubjectReference = new IptcType(12,
+			"SubjectReference");
+	public static final IptcType IPTC_TYPE_Category = new IptcType(15,
+			"Category");
+	public static final IptcType IPTC_TYPE_SupplementalCategory = new IptcType(
+			20, "SupplementalCategory");
+	public static final IptcType IPTC_TYPE_FixtureIdentifier = new IptcType(22,
+			"FixtureIdentifier");
+	public static final IptcType IPTC_TYPE_Keywords = new IptcType(25,
+			"Keywords");
+	public static final IptcType IPTC_TYPE_ContentLocationCode = new IptcType(
+			26, "ContentLocationCode");
+	public static final IptcType IPTC_TYPE_ContentLocationName = new IptcType(
+			27, "ContentLocationName");
+	public static final IptcType IPTC_TYPE_ReleaseDate = new IptcType(30,
+			"ReleaseDate");
+	public static final IptcType IPTC_TYPE_ReleaseTime = new IptcType(35,
+			"ReleaseTime");
+	public static final IptcType IPTC_TYPE_ExpirationDate = new IptcType(37,
+			"ExpirationDate");
+	public static final IptcType IPTC_TYPE_ExpirationTime = new IptcType(38,
+			"ExpirationTime");
+	public static final IptcType IPTC_TYPE_SpecialInstructions = new IptcType(
+			40, "SpecialInstructions");
+	public static final IptcType IPTC_TYPE_ActionAdvised = new IptcType(42,
+			"ActionAdvised");
+	public static final IptcType IPTC_TYPE_ReferenceService = new IptcType(45,
+			"ReferenceService");
+	public static final IptcType IPTC_TYPE_ReferenceDate = new IptcType(47,
+			"ReferenceDate");
+	public static final IptcType IPTC_TYPE_ReferenceNumber = new IptcType(50,
+			"ReferenceNumber");
+	public static final IptcType IPTC_TYPE_DateCreated = new IptcType(55,
+			"DateCreated");
+	public static final IptcType IPTC_TYPE_TimeCreated = new IptcType(60,
+			"TimeCreated");
+	public static final IptcType IPTC_TYPE_DigitalCreationDate = new IptcType(
+			62, "DigitalCreationDate");
+	public static final IptcType IPTC_TYPE_DigitalCreationTime = new IptcType(
+			63, "DigitalCreationTime");
+	public static final IptcType IPTC_TYPE_OriginatingProgram = new IptcType(
+			65, "OriginatingProgram");
+	public static final IptcType IPTC_TYPE_ProgramVersion = new IptcType(70,
+			"ProgramVersion");
+	public static final IptcType IPTC_TYPE_ObjectCycle = new IptcType(75,
+			"ObjectCycle");
+	public static final IptcType IPTC_TYPE_Byline = new IptcType(80, "By-line");
+	public static final IptcType IPTC_TYPE_BylineTitle = new IptcType(85,
+			"By-lineTitle");
+	public static final IptcType IPTC_TYPE_City = new IptcType(90, "City");
+	public static final IptcType IPTC_TYPE_Sublocation = new IptcType(92,
+			"Sublocation");
+	public static final IptcType IPTC_TYPE_Province_State = new IptcType(95,
+			"Province/State");
+	public static final IptcType IPTC_TYPE_Country_PrimaryLocationCode = new IptcType(
+			100, "Country/PrimaryLocationCode");
+	public static final IptcType IPTC_TYPE_Country_PrimaryLocationName = new IptcType(
+			101, "Country/PrimaryLocationName");
+	public static final IptcType IPTC_TYPE_OriginalTransmission_Reference = new IptcType(
+			103, "OriginalTransmission,Reference");
+	public static final IptcType IPTC_TYPE_Headline = new IptcType(105,
+			"Headline");
+	public static final IptcType IPTC_TYPE_Credit = new IptcType(110, "Credit");
+	public static final IptcType IPTC_TYPE_Source = new IptcType(115, "Source");
+	public static final IptcType IPTC_TYPE_CopyrightNotice = new IptcType(116,
+			"CopyrightNotice");
+	public static final IptcType IPTC_TYPE_Contact = new IptcType(118,
+			"Contact");
+	public static final IptcType IPTC_TYPE_Caption_Abstract = new IptcType(120,
+			"Caption/Abstract");
+	public static final IptcType IPTC_TYPE_Writer_Editor = new IptcType(122,
+			"Writer/Editor");
+	public static final IptcType IPTC_TYPE_RasterizedCaption = new IptcType(
+			125, "RasterizedCaption");
+	public static final IptcType IPTC_TYPE_ImageType = new IptcType(130,
+			"ImageType");
+	public static final IptcType IPTC_TYPE_ImageOrientation = new IptcType(131,
+			"ImageOrientation");
+	public static final IptcType IPTC_TYPE_LanguageIdentifier = new IptcType(
+			135, "LanguageIdentifier");
+	public static final IptcType IPTC_TYPE_AudioType = new IptcType(150,
+			"AudioType");
+	public static final IptcType IPTC_TYPE_AudioSamplingRate = new IptcType(
+			151, "AudioSamplingRate");
+	public static final IptcType IPTC_TYPE_AudioSamplingResolution = new IptcType(
+			152, "AudioSamplingResolution");
+	public static final IptcType IPTC_TYPE_AudioDuration = new IptcType(153,
+			"AudioDuration");
+	public static final IptcType IPTC_TYPE_AudioOutcue = new IptcType(154,
+			"AudioOutcue");
+	public static final IptcType IPTC_TYPE_ObjectDataPreview_FileFormat = new IptcType(
+			200, "ObjectDataPreview,FileFormat");
+	public static final IptcType IPTC_TYPE_ObjectDataPreview_FileFormatVersion = new IptcType(
+			201, "ObjectDataPreview,FileFormatVersion");
+	public static final IptcType IPTC_TYPE_ObjectDataPreviewData = new IptcType(
+			202, "ObjectDataPreviewData");
+	//--
+	public static final IptcType IPTC_TYPE_Unknown = new IptcType(-1, "Unknown");
+
+	public static final IptcType IPTC_TYPES[] = {
+			IPTC_TYPE_RecordVersion, IPTC_TYPE_ObjectTypeReference,
+			IPTC_TYPE_ObjectAttributeReference, IPTC_TYPE_ObjectName,
+			IPTC_TYPE_EditStatus, IPTC_TYPE_EditorialUpdate, IPTC_TYPE_Urgency,
+			IPTC_TYPE_SubjectReference, IPTC_TYPE_Category,
+			IPTC_TYPE_SupplementalCategory, IPTC_TYPE_FixtureIdentifier,
+			IPTC_TYPE_Keywords, IPTC_TYPE_ContentLocationCode,
+			IPTC_TYPE_ContentLocationName, IPTC_TYPE_ReleaseDate,
+			IPTC_TYPE_ReleaseTime, IPTC_TYPE_ExpirationDate,
+			IPTC_TYPE_ExpirationTime, IPTC_TYPE_SpecialInstructions,
+			IPTC_TYPE_ActionAdvised, IPTC_TYPE_ReferenceService,
+			IPTC_TYPE_ReferenceDate, IPTC_TYPE_ReferenceNumber,
+			IPTC_TYPE_DateCreated, IPTC_TYPE_TimeCreated,
+			IPTC_TYPE_DigitalCreationDate, IPTC_TYPE_DigitalCreationTime,
+			IPTC_TYPE_OriginatingProgram, IPTC_TYPE_ProgramVersion,
+			IPTC_TYPE_ObjectCycle, IPTC_TYPE_Byline, IPTC_TYPE_BylineTitle,
+			IPTC_TYPE_City, IPTC_TYPE_Sublocation, IPTC_TYPE_Province_State,
+			IPTC_TYPE_Country_PrimaryLocationCode,
+			IPTC_TYPE_Country_PrimaryLocationName,
+			IPTC_TYPE_OriginalTransmission_Reference, IPTC_TYPE_Headline,
+			IPTC_TYPE_Credit, IPTC_TYPE_Source, IPTC_TYPE_CopyrightNotice,
+			IPTC_TYPE_Contact, IPTC_TYPE_Caption_Abstract,
+			IPTC_TYPE_Writer_Editor, IPTC_TYPE_RasterizedCaption,
+			IPTC_TYPE_ImageType, IPTC_TYPE_ImageOrientation,
+			IPTC_TYPE_LanguageIdentifier, IPTC_TYPE_AudioType,
+			IPTC_TYPE_AudioSamplingRate, IPTC_TYPE_AudioSamplingResolution,
+			IPTC_TYPE_AudioDuration, IPTC_TYPE_AudioOutcue,
+			IPTC_TYPE_ObjectDataPreview_FileFormat,
+			IPTC_TYPE_ObjectDataPreview_FileFormatVersion,
+			IPTC_TYPE_ObjectDataPreviewData,
+	};
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegImageMetadata.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegImageMetadata.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegImageMetadata.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegImageMetadata.java Sat Nov 17 13:58:22 2007
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cmc.sanselan.formats.jpeg;
+
+import java.awt.image.BufferedImage;
+import java.util.Vector;
+
+import org.cmc.sanselan.common.IImageMetadata;
+import org.cmc.sanselan.common.ImageMetadata;
+import org.cmc.sanselan.formats.tiff.RawTiffImageData;
+import org.cmc.sanselan.formats.tiff.TagInfo;
+import org.cmc.sanselan.formats.tiff.TiffField;
+import org.cmc.sanselan.formats.tiff.TiffImageMetadata;
+
+public class JpegImageMetadata implements IImageMetadata
+{
+	public static class Photoshop extends ImageMetadata
+	{
+	}
+
+	private final Photoshop photoshop;
+	private final TiffImageMetadata exif;
+
+	public JpegImageMetadata(final Photoshop photoshop,
+			final TiffImageMetadata exif)
+	{
+		this.photoshop = photoshop;
+		this.exif = exif;
+	}
+
+	public TiffImageMetadata getExif()
+	{
+		return exif;
+	}
+
+	public Photoshop getPhotoshop()
+	{
+		return photoshop;
+	}
+
+	public TiffField findEXIFValue(TagInfo tagInfo)
+	{
+		Vector items = getItems();
+		for (int i = 0; i < items.size(); i++)
+		{
+			Object o = items.get(i);
+			if (!(o instanceof TiffImageMetadata.Item))
+				continue;
+
+			TiffImageMetadata.Item item = (TiffImageMetadata.Item) o;
+			TiffField field = item.getTiffField();
+			if (field.tag == tagInfo.tag)
+				return field;
+		}
+
+		return null;
+	}
+
+	public BufferedImage getEXIFThumbnail()
+	{
+		Vector dirs = exif.getDirectories();
+		for (int i = 0; i < dirs.size(); i++)
+		{
+			TiffImageMetadata.Directory dir = (TiffImageMetadata.Directory) dirs
+					.get(i);
+			//			Debug.debug("dir", dir);
+			BufferedImage image = dir.getThumbnail();
+			if (null != image)
+				return image;
+		}
+
+		return null;
+	}
+
+	public RawTiffImageData getRawImageData()
+	{
+		Vector dirs = exif.getDirectories();
+		for (int i = 0; i < dirs.size(); i++)
+		{
+			TiffImageMetadata.Directory dir = (TiffImageMetadata.Directory) dirs
+					.get(i);
+			//			Debug.debug("dir", dir);
+			RawTiffImageData rawImageData = dir.getRawTiffImageData();
+			if (null != rawImageData)
+				return rawImageData;
+		}
+
+		return null;
+	}
+
+	public Vector getItems()
+	{
+		Vector result = new Vector();
+
+		if (null != exif)
+			result.addAll(exif.getItems());
+
+		if (null != photoshop)
+			result.addAll(photoshop.getItems());
+
+		return result;
+	}
+
+	private static final String newline = System.getProperty("line.separator");
+
+	public String toString()
+	{
+		return toString(null);
+	}
+
+	public String toString(String prefix)
+	{
+		if (prefix == null)
+			prefix = "";
+
+		StringBuffer result = new StringBuffer();
+
+		result.append(prefix);
+		if (null == exif)
+			result.append("No Exif metadata.");
+		else
+		{
+			result.append("Exif metadata:");
+			result.append(newline);
+			result.append(exif.toString("\t"));
+		}
+
+		//		if (null != exif && null != photoshop)
+		result.append(newline);
+
+		result.append(prefix);
+		if (null == photoshop)
+			result.append("No Photoshop (IPTC) metadata.");
+		else
+		{
+			result.append("Photoshop (IPTC) metadata:");
+			result.append(newline);
+			result.append(photoshop.toString("\t"));
+		}
+
+		return result.toString();
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/formats/jpeg/JpegImageMetadata.java
------------------------------------------------------------------------------
    svn:eol-style = native