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