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/29 02:27:15 UTC

svn commit: r599250 [14/15] - in /incubator/sanselan/trunk/src/main/java/org: apache/sanselan/ apache/sanselan/color/ apache/sanselan/common/ apache/sanselan/common/byteSources/ apache/sanselan/common/mylzw/ apache/sanselan/formats/bmp/ apache/sanselan...

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccConstants.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccConstants.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccConstants.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,452 @@
+/*
+ * 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.apache.sanselan.icc;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.BinaryConstants;
+import org.apache.sanselan.common.BinaryInputStream;
+
+public interface IccConstants
+{
+	public final static int IEC = (((0xff & 'I') << 24) | ((0xff & 'E') << 16)
+			| ((0xff & 'C') << 8) | ((0xff & ' ') << 0));
+	public final static int sRGB = (((0xff & 's') << 24) | ((0xff & 'R') << 16)
+			| ((0xff & 'G') << 8) | ((0xff & 'B') << 0));
+
+	public static final IccTagDataType descType = new IccTagDataType(
+			"descType", 0x64657363)
+	{
+		public void dump(String prefix, byte bytes[])
+				throws ImageReadException, IOException
+		{
+			BinaryInputStream bis = new BinaryInputStream(
+					new ByteArrayInputStream(bytes),
+					BinaryConstants.BYTE_ORDER_NETWORK);
+			bis.read4Bytes("type_signature", "ICC: corrupt tag data");
+
+			//			bis.setDebug(true);
+			bis.read4Bytes("ignore", "ICC: corrupt tag data");
+			int string_length = bis.read4Bytes("string_length",
+					"ICC: corrupt tag data");
+
+			//			bis.readByteArray("ignore", bytes.length -12, "none");
+			String s = new String(bytes, 12, string_length - 1);
+			System.out.println(prefix + "s: '" + s + "'");
+		}
+
+	};
+
+	public static final IccTagDataType dataType = new IccTagDataType(
+			"dataType", 0x64617461)
+	{
+		public void dump(String prefix, byte bytes[])
+				throws ImageReadException, IOException
+		{
+			BinaryInputStream bis = new BinaryInputStream(
+					new ByteArrayInputStream(bytes),
+					BinaryConstants.BYTE_ORDER_NETWORK);
+			bis.read4Bytes("type_signature", "ICC: corrupt tag data");
+		}
+
+	};
+
+	public static final IccTagDataType multiLocalizedUnicodeType = new IccTagDataType(
+			"multiLocalizedUnicodeType", (0x6D6C7563))
+	{
+		public void dump(String prefix, byte bytes[])
+				throws ImageReadException, IOException
+		{
+			BinaryInputStream bis = new BinaryInputStream(
+					new ByteArrayInputStream(bytes),
+					BinaryConstants.BYTE_ORDER_NETWORK);
+			bis.read4Bytes("type_signature", "ICC: corrupt tag data");
+		}
+
+	};
+
+	public static final IccTagDataType signatureType = new IccTagDataType(
+			"signatureType", ((0x73696720)))
+	{
+		public void dump(String prefix, byte bytes[])
+				throws ImageReadException, IOException
+		{
+			BinaryInputStream bis = new BinaryInputStream(
+					new ByteArrayInputStream(bytes),
+					BinaryConstants.BYTE_ORDER_NETWORK);
+			bis.read4Bytes("type_signature", "ICC: corrupt tag data");
+			bis.read4Bytes("ignore", "ICC: corrupt tag data");
+			int thesignature = bis.read4Bytes("thesignature ",
+					"ICC: corrupt tag data");
+			System.out.println(prefix
+					+ "thesignature: "
+					+ Integer.toHexString(thesignature)
+					+ " ("
+					+ new String(new byte[]{
+							(byte) (0xff & (thesignature >> 24)),
+							(byte) (0xff & (thesignature >> 16)),
+							(byte) (0xff & (thesignature >> 8)),
+							(byte) (0xff & (thesignature >> 0)),
+					}) + ")");
+		}
+
+	};
+
+	public static final IccTagDataType textType = new IccTagDataType(
+			"textType", 0x74657874)
+	{
+		public void dump(String prefix, byte bytes[])
+				throws ImageReadException, IOException
+		{
+			BinaryInputStream bis = new BinaryInputStream(
+					new ByteArrayInputStream(bytes),
+					BinaryConstants.BYTE_ORDER_NETWORK);
+			bis.read4Bytes("type_signature", "ICC: corrupt tag data");
+			bis.read4Bytes("ignore", "ICC: corrupt tag data");
+			String s = new String(bytes, 8, bytes.length - 8);
+			System.out.println(prefix + "s: '" + s + "'");
+		}
+
+	};
+
+	public static final IccTagDataType IccTagDataTypes[] = {
+			descType, dataType, multiLocalizedUnicodeType, signatureType,
+			textType,
+	};
+	//	public static final IccTagDataType dataType = new IccTagDataType("dataType",
+	//			0x64617461
+	//	);
+
+	public static final IccTagType AToB0Tag = new IccTagType("AToB0Tag",
+			"lut8Type or lut16Type or lutAtoBType", 0x41324230
+	//			"This tag defines a color transform from Device to PCS using lookup table tag element structures. The processing mechanisms are described in lut8Type or lut16Type or lutAtoBType.");
+	);
+
+	//	public static final IccTagType AToB0Tag = new IccTagType(
+	//	"AToB0Tag",
+	//	"lut8Type or lut16Type or lutAtoBType",
+	//	"‘A2B0’ (41324230h)",
+	//	"This tag defines a color transform from Device to PCS using lookup table tag element structures. The processing",
+	//	"mechanisms are described in lut8Type or lut16Type or lutAtoBType.",
+	//	);
+
+	public static final IccTagType AToB1Tag = new IccTagType("AToB1Tag",
+			"lut8Type or lut16Type or lutAtoBType", 0x41324231
+	//	"This tag defines a color transform from Device to PCS using lookup table tag element structures. The processing",
+	//	"mechanisms are described in lut8Type or lut16Type or lutAtoBType.",
+	);
+
+	public static final IccTagType AToB2Tag = new IccTagType("AToB2Tag",
+			"lut8Type or lut16Type or lutAtoBType", 0x41324232
+	//	"This tag defines a color transform from Device to PCS using lookup table tag element structures. The processing",
+	//	"mechanisms are described in lut8Type or lut16Type or lutAtoBType.",
+	);
+
+	public static final IccTagType blueMatrixColumnTag = new IccTagType(
+			"blueMatrixColumnTag", "XYZType", 0x6258595A
+	//	"The third column in the matrix used in TRC/matrix transforms.",
+	);
+
+	public static final IccTagType blueTRCTag = new IccTagType("blueTRCTag",
+			"curveType or parametricCurveType", 0x62545243
+	//	"Blue channel tone reproduction curve. The first element represents no colorant (white) or phosphors",
+	//	"(black) and the last element represents 100 percent colorant (blue) or 100 percent phosphor (blue).",
+	);
+
+	public static final IccTagType BToA0Tag = new IccTagType("BToA0Tag",
+			"lut8Type or lut16Type or lutBtoAType", 0x42324130
+	//	"This tag defines a color transform from PCS to Device using the lookup table tag element structures. The",
+	//	"processing mechanisms are described in lut8Type or lut16Type or lutBtoAType.",
+	);
+
+	public static final IccTagType BToA1Tag = new IccTagType("BToA1Tag",
+			"lut8Type or lut16Type or lutBtoAType", 0x42324131
+	//	"This tag defines a color transform from PCS to Device using the lookup table tag element structures. The",
+	//	"processing mechanisms are described in lut8Type or lut16Type or lutBtoAType.",
+	);
+
+	public static final IccTagType BToA2Tag = new IccTagType("BToA2Tag",
+			"lut8Type or lut16Type or lutBtoAType", 0x42324132
+	//	"This tag defines a color transform from PCS to Device using the lookup table tag element structures. The",
+	//	"processing mechanisms are described in lut8Type or lut16Type or lutBtoAType.",
+	);
+
+	public static final IccTagType calibrationDateTimeTag = new IccTagType(
+			"calibrationDateTimeTag", "dateTimeType", 0x63616C74
+	//	"Profile calibration date and time. Initially, this tag matches the contents of the profile header’s creation",
+	//	"date/time field. This allows applications and utilities to verify if this profile matches a vendor’s profile and",
+	//	"how recently calibration has been performed.",
+	);
+
+	public static final IccTagType charTargetTag = new IccTagType(
+			"charTargetTag", "textType", 0x74617267
+	//	"This tag contains the name of the registered characterization data set, or it contains the measurement data",
+	//	"for a characterization target. This tag is provided so that distributed utilities can identify the underlying",
+	//	"characterization data, create transforms \"on the fly\" or check the current performance against the original",
+	//	"device performance.",
+	//	"The first seven characters of the text shall identify the nature of the characterization data.",
+	//	"If the first seven characters are \"ICCHDAT\", then the remainder of the text shall be a single space followed",
+	//	"by the Reference Name of a characterization data set in the ICC Characterization Data Registry and terminated",
+	//	"with a NULL byte (00h). The Reference Name in the text must match exactly (including case) the",
+	//	"Reference Name in the registry.",
+	//	"If the first seven characters match one of the identifiers defined in an ANSI or ISO standard, then the tag",
+	//	"embeds the exact data file format defined in that standard. Each of these file formats contains an identifying",
+	//	"character string as the first seven characters of the format, allowing an external parser to determine",
+	//	"which data file format is being used. This provides the facilities to include a wide range of targets using a",
+	//	"variety of measurement specifications in a standard manner.",
+	//	"NOTE: It is highly recommended that the profileDescriptionTag also include an identification of the characterization",
+	//	"data that was used in the creation of the profile (e.g. \"Based on CGATS TR 001\").",
+	);
+
+	public static final IccTagType chromaticAdaptationTag = new IccTagType(
+			"chromaticAdaptationTag", "s15Fixed16ArrayType", 0x63686164
+	//	"This tag converts an XYZ color, measured at a device's specific illumination conditions, to an XYZ color in",
+	//	"the PCS illumination conditions after complete adaptation.",
+	//	"The tag reflects a survey of the currently used methods of conversion, all of which can be formulated as a",
+	//	"matrix transformation (see Annex E). Such a 3 by 3 chromatic adaptation matrix is organized as a 9-element",
+	//	"array of signed 15.16 numbers (s15Fixed16ArrayType tag). Similarly as in the other occurrences of a",
+	//	"3 by 3 matrix in the ICC tags, the dimension corresponding to the matrix rows varies least rapidly while the",
+	//	"one corresponding to the matrix columns varies most rapidly.",
+	//	"(19)",
+	//	"(20)",
+	//	"array a0 a1 a2 a3 a4 a5 a6 a7 a8 =",
+	//	"Xpcs",
+	//	"Ypcs",
+	//	"Zpcs",
+	//	"a0 a1 a2",
+	//	"a3 a4 a5",
+	//	"a6 a7 a8",
+	//	"Xsrc",
+	//	"Ysrc",
+	//	"Zsrc",
+	//	"=",
+	//	"Where XYZsrc represents the measured value in the actual device viewing condition and XYZpcs represents",
+	//	"the chromatically adapted value in the PCS.",
+	//	"The chromatic adaptation matrix is a combination of three separate conversions:",
+	//	"1) Conversion of source CIE XYZ tristimulus values to cone response tristimulus values.",
+	//	"2) Adjustment of the cone response values for an observer’s chromatic adaptation.",
+	//	"3) Conversion of the adjusted cone response tristimulus back to CIE XYZ values.",
+	);
+
+	public static final IccTagType chromaticityTag = new IccTagType(
+			"chromaticityTag", "chromaticityType", 0x6368726D
+	//	"The data and type of phosphor/colorant chromaticity set.",
+	);
+
+	public static final IccTagType colorantOrderTag = new IccTagType(
+			"colorantOrderTag", "colorantOrderType", 0x636C726F
+	//	"This tag specifies the laydown order of colorants.",
+	);
+
+	public static final IccTagType colorantTableTag = new IccTagType(
+			"colorantTableTag", "colorantTableType", 0x636C7274
+	//	"This tag identifies the colorants used in the profile by a unique name and an XYZ or L*a*b* value.",
+	//	"This is a required tag for profiles where the color space defined in the header is xCLR, where x is one of",
+	//	"the allowed numbers from 2 through Fh, per Table 13. See Section 6.3.3.2, Section 6.3.4.1.",
+	);
+
+	public static final IccTagType copyrightTag = new IccTagType(
+			"copyrightTag", "multiLocalizedUnicodeType", 0x63707274
+	//	"This tag contains the text copyright information for the profile.",
+	);
+
+	public static final IccTagType deviceMfgDescTag = new IccTagType(
+			"deviceMfgDescTag", "multiLocalizedUnicodeType", 0x646D6E64
+	//	"Structure containing invariant and localizable versions of the device manufacturer for display. The content",
+	//	"of this structure is described in 6.5.12.",
+	);
+
+	public static final IccTagType deviceModelDescTag = new IccTagType(
+			"deviceModelDescTag", "multiLocalizedUnicodeType", 0x646D6464
+	//	"Structure containing invariant and localizable versions of the device model for display. The content of this",
+	//	"structure is described in 6.5.12.",
+	);
+
+	public static final IccTagType gamutTag = new IccTagType("gamutTag",
+			"lut8Type or lut16Type or lutBtoAType", 0x67616D74
+	//	"Out of gamut tag. The processing mechanisms are described in lut8Type or lut16Type or lutBtoAType.",
+	//	"This tag takes PCS values as its input and produces a single channel of output. If the output value is 0, the",
+	//	"PCS color is in-gamut. If the output is non-zero, the PCS color is out-of-gamut, with the output value “n+1”",
+	//	"being at least as far out of gamut as the output value “n”.",
+	);
+
+	public static final IccTagType grayTRCTag = new IccTagType("grayTRCTag",
+			"curveType or parametricCurveType", 0x6B545243
+	//	"Gray tone reproduction curve. The tone reproduction curve provides the necessary information to convert",
+	//	"between a single device channel and the CIEXYZ encoding of the profile connection space. The first element",
+	//	"represents black and the last element represents white.",
+	);
+
+	public static final IccTagType greenMatrixColumnTag = new IccTagType(
+			"greenMatrixColumnTag", "XYZType", 0x6758595A
+	//	"The second column in the matrix used in TRC/matrix transforms.",
+	);
+
+	public static final IccTagType greenTRCTag = new IccTagType(
+	//	"6.4.21 ",
+			"greenTRCTag", "curveType or parametricCurveType", 0x67545243
+	//	"Green channel tone reproduction curve. The first element represents no colorant (white) or phosphors",
+	//	"(black) and the last element represents 100 percent colorant (green) or 100 percent phosphor (green).",
+	);
+
+	public static final IccTagType luminanceTag = new IccTagType(
+	//	"6.4.22 ",
+			"luminanceTag", "XYZType", 0x6C756D69
+	//	"Absolute luminance of emissive devices in candelas per square meter as described by the Y channel. The",
+	//	"X and Z channels are ignored in all cases.",
+	);
+
+	public static final IccTagType measurementTag = new IccTagType(
+	//	"6.4.23 ",
+			"measurementTag", "measurementType", 0x6D656173
+	//	"Alternative measurement specification such as a D65 illuminant instead of the default D50.",
+	);
+
+	public static final IccTagType mediaBlackPointTag = new IccTagType(
+	//	"6.4.24 ",
+			"mediaBlackPointTag", "XYZType", 0x626B7074
+	//	"This tag specifies the media black point and contains the CIE 1931 XYZ colorimetry of the black point of",
+	//	"the actual medium.",
+	//	"NOTE Previous revisions of this specification contained an error indicating that this tag is used to calculate",
+	//	"ICC-absolute colorimetry. This is not the case.",
+	);
+
+	public static final IccTagType mediaWhitePointTag = new IccTagType(
+	//	"6.4.25 ",
+			"mediaWhitePointTag", "XYZType", 0x77747074
+	//	"This tag, which is used for generating ICC-absolute colorimetric intent, specifies the XYZ tristimulus values",
+	//	"of the media white point. If the media is measured under an illumination source which has a chromaticity",
+	//	"other than D50, the measured values must be adjusted to D50 using the chromaticAdaptationTag matrix",
+	//	"before recording in the tag. For reflecting and transmitting media, the tag values are specified relative to",
+	//	"the perfect diffuser (which is normalized to a Y value of 1,0) for illuminant D50. For displays, the values",
+	//	"specified must be those of D50 (i.e. 0,9642, 1,0 0,8249) normalized such that Y = 1,0.",
+	//	"See Annex A for a more complete description of the use of the media white point.",
+	);
+
+	public static final IccTagType namedColor2Tag = new IccTagType(
+	//	"6.4.26 ",
+			"namedColor2Tag", "namedColor2Type", 0x6E636C32
+	//	"Named color information providing a PCS and optional device representation for a list of named colors.",
+	);
+
+	public static final IccTagType outputResponseTag = new IccTagType(
+	//	"6.4.27 ",
+			"outputResponseTag", "responseCurveSet16Type", 0x72657370
+	//	"Structure containing a description of the device response for which the profile is intended. The content of",
+	//	"this structure is described in 6.5.16.",
+	//	"NOTE The user’s attention is called to the possibility that the use of this tag for device calibration may",
+	//	"require use of an invention covered by patent rights. By publication of this specification, no position is",
+	//	"taken with respect to the validity of this claim or of any patent rights in connection therewith. The patent",
+	//	"holder has, however, filed a statement of willingness to grant a license under these rights on reasonable",
+	//	"and nondiscriminatory terms and conditions to applicants desiring to obtain such a license. Details may be",
+	//	"obtained from the publisher.",
+	);
+
+	public static final IccTagType preview0Tag = new IccTagType(
+	//	"6.4.28 ",
+			"preview0Tag", "lut8Type or lut16Type or lutBtoAType", 0x70726530
+	//	"Preview transformation from PCS to device space and back to the PCS. The processing mechanisms are",
+	//	"described in lut8Type or lut16Type or lutBtoAType.",
+	//	"This tag contains the combination of tag B2A0 and tag A2B1.",
+	);
+
+	public static final IccTagType preview1Tag = new IccTagType(
+	//	"6.4.29 ",
+			"preview1Tag", "lut8Type or lut16Type or lutBtoAType", 0x70726531
+	//	"Preview transformation from the PCS to device space and back to the PCS. The processing mechanisms",
+	//	"are described in lut8Type or lut16Type or lutBtoAType.",
+	//	"This tag contains the combination of tag B2A1 and tag A2B1.",
+	);
+
+	public static final IccTagType preview2Tag = new IccTagType(
+	//	"6.4.30 ",
+			"preview2Tag", "lut8Type or lut16Type or lutBtoAType", 0x70726532
+	//	"Preview transformation from PCS to device space and back to the PCS. The processing mechanisms are",
+	//	"described in lut8Type or lut16Type or lutBtoAType.",
+	//	"This tag contains the combination of tag B2A2 and tag A2B1.",
+	);
+
+	public static final IccTagType profileDescriptionTag = new IccTagType(
+	//	"6.4.31 ",
+			"profileDescriptionTag", "multiLocalizedUnicodeType", 0x64657363
+	//	"Structure containing invariant and localizable versions of the profile description for display. The content of",
+	//	"this structure is described in 6.5.12. This invariant description has no fixed relationship to the actual profile",
+	//	"disk file name.",
+	);
+
+	public static final IccTagType profileSequenceDescTag = new IccTagType(
+	//	"6.4.32 ",
+			"profileSequenceDescTag", "profileSequenceDescType", 0x70736571
+	//	"Structure containing a description of the profile sequence from source to destination, typically used with",
+	//	"the DeviceLink profile. The content of this structure is described in 6.5.15.",
+	);
+
+	public static final IccTagType redMatrixColumnTag = new IccTagType(
+	//	"6.4.33 ",
+			"redMatrixColumnTag", "XYZType", 0x7258595A
+	//	"The first column in the matrix used in TRC/matrix transforms.",
+	);
+
+	public static final IccTagType redTRCTag = new IccTagType(
+	//	"6.4.34 ",
+			"redTRCTag", "curveType or parametricCurveType", 0x72545243
+	//	"Red channel tone reproduction curve. The first element represents no colorant (white) or phosphors",
+	//	"(black) and the last element represents 100 percent colorant (red) or 100 percent phosphor (red).",
+	);
+
+	public static final IccTagType technologyTag = new IccTagType(
+	//	"6.4.35 ",
+			"technologyTag", "signatureType", 0x74656368
+	//	"Device technology information such as CRT, Dye Sublimation, etc. The encoding is such that:",
+	);
+
+	public static final IccTagType viewingCondDescTag = new IccTagType(
+	//	"6.4.36 ",
+			"viewingCondDescTag", "multiLocalizedUnicodeType", 0x76756564
+	//	"Structure containing invariant and localizable versions of the viewing conditions. The content of this structure",
+	//	"is described in 6.5.12.",
+
+	);
+
+	public static final IccTagType viewingConditionsTag = new IccTagType(
+	//	"6.4.37 ",
+			"viewingConditionsTag", "viewingConditionsType", 0x76696577
+	//	"Viewing conditions parameters. The content of this structure is described in 6.5.25.",
+	);
+
+	//	public static final IccTagType  = new IccTagType(
+	//			//	"6.4.37 ",
+	//					"viewingConditionsTag", "viewingConditionsType", 0x76696577
+	//			//	"Viewing conditions parameters. The content of this structure is described in 6.5.25.",
+	//			);
+
+	public static final IccTagType TagTypes[] = {
+			AToB0Tag, AToB1Tag, AToB2Tag, blueMatrixColumnTag, blueTRCTag,
+			BToA0Tag, BToA1Tag, BToA2Tag, calibrationDateTimeTag,
+			charTargetTag, chromaticAdaptationTag, chromaticityTag,
+			colorantOrderTag, colorantTableTag, copyrightTag, deviceMfgDescTag,
+			deviceModelDescTag, gamutTag, grayTRCTag, greenMatrixColumnTag,
+			greenTRCTag, luminanceTag, measurementTag, mediaBlackPointTag,
+			mediaWhitePointTag, namedColor2Tag, outputResponseTag, preview0Tag,
+			preview1Tag, preview2Tag, profileDescriptionTag,
+			profileSequenceDescTag, redMatrixColumnTag, redTRCTag,
+			technologyTag, viewingCondDescTag, viewingConditionsTag,
+	};
+
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileInfo.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileInfo.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileInfo.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileInfo.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,154 @@
+/*
+ * 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.apache.sanselan.icc;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.sanselan.ImageReadException;
+
+public class IccProfileInfo implements IccConstants
+{
+
+	public final byte data[];
+	public final int ProfileSize;
+	public final int CMMTypeSignature;
+	public final int ProfileVersion;
+	public final int ProfileDeviceClassSignature;
+	public final int ColorSpace;
+	public final int ProfileConnectionSpace;
+	public final int ProfileFileSignature;
+	public final int PrimaryPlatformSignature;
+	public final int VariousFlags;
+	public final int DeviceManufacturer;
+	public final int DeviceModel;
+	public final int RenderingIntent;
+	public final int ProfileCreatorSignature;
+	public final byte ProfileID[];
+	public final IccTag tags[];
+
+	public IccProfileInfo(byte data[], int ProfileSize, int CMMTypeSignature,
+			int ProfileVersion, int ProfileDeviceClassSignature,
+			int ColorSpace, int ProfileConnectionSpace,
+			int ProfileFileSignature, int PrimaryPlatformSignature,
+			int VariousFlags, int DeviceManufacturer, int DeviceModel,
+			int RenderingIntent, int ProfileCreatorSignature, byte ProfileID[],
+			IccTag tags[])
+	{
+		this.data = data;
+
+		this.ProfileSize = ProfileSize;
+		this.CMMTypeSignature = CMMTypeSignature;
+		this.ProfileVersion = ProfileVersion;
+		this.ProfileDeviceClassSignature = ProfileDeviceClassSignature;
+		this.ColorSpace = ColorSpace;
+		this.ProfileConnectionSpace = ProfileConnectionSpace;
+		this.ProfileFileSignature = ProfileFileSignature;
+		this.PrimaryPlatformSignature = PrimaryPlatformSignature;
+		this.VariousFlags = VariousFlags;
+		this.DeviceManufacturer = DeviceManufacturer;
+		this.DeviceModel = DeviceModel;
+		this.RenderingIntent = RenderingIntent;
+		this.ProfileCreatorSignature = ProfileCreatorSignature;
+		this.ProfileID = ProfileID;
+
+		this.tags = tags;
+	}
+
+	public boolean issRGB()
+	{
+		boolean result = ((DeviceManufacturer == IEC) && (DeviceModel == sRGB));
+		return result;
+	}
+
+	private void printCharQuad(PrintWriter pw, String msg, int i)
+	{
+		pw.println(msg + ": '" + (char) (0xff & (i >> 24))
+				+ (char) (0xff & (i >> 16)) + (char) (0xff & (i >> 8))
+				+ (char) (0xff & (i >> 0)) + "'");
+	}
+
+	public void dump(String prefix) throws IOException
+	{
+		System.out.print(toString());
+	}
+
+	public String toString()
+	{
+		try
+		{
+			return toString("");
+		}
+		catch (Exception e)
+		{
+			return "IccProfileInfo: Error";
+		}
+	}
+
+	public String toString(String prefix) throws ImageReadException,
+			IOException
+	{
+		StringWriter sw = new StringWriter();
+		PrintWriter pw = new PrintWriter(sw);
+
+		//		StringBuffer result = new StringBuffer();
+		pw.println(prefix + ": " + "data length: " + data.length);
+
+		printCharQuad(pw, prefix + ": " + "ProfileDeviceClassSignature",
+				ProfileDeviceClassSignature);
+
+		printCharQuad(pw, prefix + ": " + "CMMTypeSignature", CMMTypeSignature);
+
+		printCharQuad(pw, prefix + ": " + "ProfileDeviceClassSignature",
+				ProfileDeviceClassSignature);
+		printCharQuad(pw, prefix + ": " + "ColorSpace", ColorSpace);
+		printCharQuad(pw, prefix + ": " + "ProfileConnectionSpace",
+				ProfileConnectionSpace);
+
+		printCharQuad(pw, prefix + ": " + "ProfileFileSignature",
+				ProfileFileSignature);
+
+		printCharQuad(pw, prefix + ": " + "PrimaryPlatformSignature",
+				PrimaryPlatformSignature);
+
+		printCharQuad(pw, prefix + ": " + "ProfileFileSignature",
+				ProfileFileSignature);
+
+		printCharQuad(pw, prefix + ": " + "DeviceManufacturer",
+				DeviceManufacturer);
+
+		printCharQuad(pw, prefix + ": " + "DeviceModel", DeviceModel);
+
+		printCharQuad(pw, prefix + ": " + "RenderingIntent", RenderingIntent);
+
+		printCharQuad(pw, prefix + ": " + "ProfileCreatorSignature",
+				ProfileCreatorSignature);
+
+		for (int i = 0; i < tags.length; i++)
+		{
+			IccTag tag = tags[i];
+			tag.dump(pw, "\t" + i + ": ");
+		}
+
+		pw.println(prefix + ": " + "issRGB: " + issRGB());
+		pw.flush();
+
+		return sw.getBuffer().toString();
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileParser.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileParser.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,382 @@
+/*
+ * 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.apache.sanselan.icc;
+
+import java.awt.color.ICC_Profile;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.common.BinaryFileParser;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.common.byteSources.ByteSourceArray;
+import org.apache.sanselan.common.byteSources.ByteSourceFile;
+import org.apache.sanselan.util.CachingInputStream;
+import org.apache.sanselan.util.Debug;
+
+public class IccProfileParser extends BinaryFileParser implements IccConstants
+{
+	public IccProfileParser()
+	{
+		this.setByteOrder(BYTE_ORDER_NETWORK);
+	}
+
+	public IccProfileInfo getICCProfileInfo(ICC_Profile icc_profile)
+	{
+		if (icc_profile == null)
+			return null;
+
+		return getICCProfileInfo(new ByteSourceArray(icc_profile.getData()));
+	}
+
+	public IccProfileInfo getICCProfileInfo(byte bytes[])
+	{
+		if (bytes == null)
+			return null;
+
+		return getICCProfileInfo(new ByteSourceArray(bytes));
+	}
+
+	public IccProfileInfo getICCProfileInfo(File file)
+	{
+		if (file == null)
+			return null;
+
+		return getICCProfileInfo(new ByteSourceFile(file));
+	}
+
+	public IccProfileInfo getICCProfileInfo(ByteSource byteSource)
+	{
+
+		InputStream is = null;
+
+		try
+		{
+
+			IccProfileInfo result;
+			{
+				is = byteSource.getInputStream();
+
+				result = readICCProfileInfo(is);
+			}
+
+			if (result == null)
+				return null;
+
+			is.close();
+			is = null;
+
+			for (int i = 0; i < result.tags.length; i++)
+			{
+				IccTag tag = result.tags[i];
+				byte bytes[] = byteSource.getBlock(tag.offset, tag.length);
+				//				Debug.debug("bytes: " + bytes.length);
+				tag.setData(bytes);
+				//				tag.dump("\t" + i + ": ");
+			}
+			//			result.fillInTagData(byteSource);
+
+			return result;
+		}
+		catch (Exception e)
+		{
+			//			Debug.debug("Error: " + file.getAbsolutePath());
+			Debug.debug(e);
+		}
+		finally
+		{
+			try
+			{
+				if (is != null)
+					is.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+
+		}
+
+		if (debug)
+			Debug.debug();
+
+		return null;
+	}
+
+	private IccProfileInfo readICCProfileInfo(InputStream is)
+	{
+		CachingInputStream cis = new CachingInputStream(is);
+		is = cis;
+
+		if (debug)
+			Debug.debug();
+
+		//				setDebug(true);
+
+		//		if (debug)
+		//			Debug.debug("length: " + length);
+
+		try
+		{
+			int ProfileSize = read4Bytes("ProfileSize", is,
+					"Not a Valid ICC Profile");
+
+			//			if (length != ProfileSize)
+			//			{
+			//				//				Debug.debug("Unexpected Length data expected: " + Integer.toHexString((int) length)
+			//				//						+ ", encoded: " + Integer.toHexString(ProfileSize));
+			//				//				Debug.debug("Unexpected Length data: " + length
+			//				//						+ ", length: " + ProfileSize);
+			//				//				throw new Error("asd");
+			//				return null;
+			//			}
+
+			int CMMTypeSignature = read4Bytes("Signature", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("CMMTypeSignature", CMMTypeSignature);
+
+			int ProfileVersion = read4Bytes("ProfileVersion", is,
+					"Not a Valid ICC Profile");
+
+			int ProfileDeviceClassSignature = read4Bytes(
+					"ProfileDeviceClassSignature", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("ProfileDeviceClassSignature",
+						ProfileDeviceClassSignature);
+
+			int ColorSpace = read4Bytes("ColorSpace", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("ColorSpace", ColorSpace);
+
+			int ProfileConnectionSpace = read4Bytes("ProfileConnectionSpace",
+					is, "Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("ProfileConnectionSpace", ProfileConnectionSpace);
+
+			skipBytes(is, 12, "Not a Valid ICC Profile");
+
+			int ProfileFileSignature = read4Bytes("ProfileFileSignature", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("ProfileFileSignature", ProfileFileSignature);
+
+			int PrimaryPlatformSignature = read4Bytes(
+					"PrimaryPlatformSignature", is, "Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("PrimaryPlatformSignature",
+						PrimaryPlatformSignature);
+
+			int VariousFlags = read4Bytes("ProfileFileSignature", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("ProfileFileSignature", ProfileFileSignature);
+
+			int DeviceManufacturer = read4Bytes("ProfileFileSignature", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("DeviceManufacturer", DeviceManufacturer);
+
+			int DeviceModel = read4Bytes("DeviceModel", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("DeviceModel", DeviceModel);
+
+			skipBytes(is, 8, "Not a Valid ICC Profile");
+
+			int RenderingIntent = read4Bytes("RenderingIntent", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("RenderingIntent", RenderingIntent);
+
+			skipBytes(is, 12, "Not a Valid ICC Profile");
+
+			int ProfileCreatorSignature = read4Bytes("ProfileCreatorSignature",
+					is, "Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("ProfileCreatorSignature",
+						ProfileCreatorSignature);
+
+			byte ProfileID[] = null;
+			skipBytes(is, 16, "Not a Valid ICC Profile");
+			//			readByteArray("ProfileID", 16, is,
+			//					"Not a Valid ICC Profile");
+			//			if (debug)
+			//				System.out
+			//						.println("ProfileID: '" + new String(ProfileID) + "'");
+
+			skipBytes(is, 28, "Not a Valid ICC Profile");
+
+			//			this.setDebug(true);
+
+			int TagCount = read4Bytes("TagCount", is, "Not a Valid ICC Profile");
+
+			//			Vector tags = new Vector();
+			IccTag tags[] = new IccTag[TagCount];
+
+			for (int i = 0; i < TagCount; i++)
+			{
+				int TagSignature = read4Bytes("TagSignature[" + i + "]", is,
+						"Not a Valid ICC Profile");
+				//				Debug.debug("TagSignature t "
+				//						+ Integer.toHexString(TagSignature));
+
+				//				this.printCharQuad("TagSignature", TagSignature);
+				int OffsetToData = read4Bytes("OffsetToData[" + i + "]", is,
+						"Not a Valid ICC Profile");
+				int ElementSize = read4Bytes("ElementSize[" + i + "]", is,
+						"Not a Valid ICC Profile");
+
+				IccTagType fIccTagType = getIccTagType(TagSignature);
+				//				if (fIccTagType == null)
+				//					throw new Error("oops.");
+
+				//				System.out
+				//						.println("\t["
+				//								+ i
+				//								+ "]: "
+				//								+ ((fIccTagType == null)
+				//										? "unknown"
+				//										: fIccTagType.name));
+				//				Debug.debug();
+
+				IccTag tag = new IccTag(TagSignature, OffsetToData,
+						ElementSize, fIccTagType);
+				//				tag.dump("\t" + i + ": ");
+				tags[i] = tag;
+				//				tags .add(tag);
+			}
+
+			{
+				// read stream to end, filling cache.
+				while (is.read() >= 0)
+					;
+			}
+
+			byte data[] = cis.getCache();
+
+			if (data.length < ProfileSize)
+				throw new IOException("Couldn't read ICC Profile.");
+
+			IccProfileInfo result = new IccProfileInfo(data, ProfileSize,
+					CMMTypeSignature, ProfileVersion,
+					ProfileDeviceClassSignature, ColorSpace,
+					ProfileConnectionSpace, ProfileFileSignature,
+					PrimaryPlatformSignature, VariousFlags, DeviceManufacturer,
+					DeviceModel, RenderingIntent, ProfileCreatorSignature,
+					ProfileID, tags);
+
+			if (debug)
+				Debug.debug("issRGB: " + result.issRGB());
+
+			return result;
+		}
+		catch (Exception e)
+		{
+			Debug.debug(e);
+		}
+
+		return null;
+	}
+
+	private IccTagType getIccTagType(int quad)
+	{
+		for (int i = 0; i < TagTypes.length; i++)
+			if (TagTypes[i].signature == quad)
+				return TagTypes[i];
+
+		return null;
+	}
+
+	public Boolean issRGB(ICC_Profile icc_profile)
+	{
+		if (icc_profile == null)
+			return null;
+
+		return issRGB(new ByteSourceArray(icc_profile.getData()));
+	}
+
+	public Boolean issRGB(byte bytes[])
+	{
+		if (bytes == null)
+			return null;
+
+		return issRGB(new ByteSourceArray(bytes));
+	}
+
+	public Boolean issRGB(File file)
+	{
+		if (file == null)
+			return null;
+
+		return issRGB(new ByteSourceFile(file));
+	}
+
+	public Boolean issRGB(ByteSource byteSource)
+	{
+		try
+		{
+			if (debug)
+				Debug.debug();
+
+			//			setDebug(true);
+
+			//			long length = byteSource.getLength();
+			//
+			//			if (debug)
+			//				Debug.debug("length: " + length);
+
+			InputStream is = byteSource.getInputStream();
+
+			int ProfileSize = read4Bytes("ProfileSize", is,
+					"Not a Valid ICC Profile");
+
+			//			if (length != ProfileSize)
+			//				return null;
+
+			this.skipBytes(is, 4 * 5);
+
+			skipBytes(is, 12, "Not a Valid ICC Profile");
+
+			this.skipBytes(is, 4 * 3);
+
+			int DeviceManufacturer = read4Bytes("ProfileFileSignature", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("DeviceManufacturer", DeviceManufacturer);
+
+			int DeviceModel = read4Bytes("DeviceModel", is,
+					"Not a Valid ICC Profile");
+			if (debug)
+				printCharQuad("DeviceModel", DeviceModel);
+
+			boolean result = ((DeviceManufacturer == IEC) && (DeviceModel == sRGB));
+
+			return new Boolean(result);
+		}
+		catch (Exception e)
+		{
+			Debug.debug(e);
+		}
+
+		return null;
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccProfileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTag.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTag.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTag.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTag.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,126 @@
+/*
+ * 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.apache.sanselan.icc;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.BinaryConstants;
+import org.apache.sanselan.common.BinaryInputStream;
+
+public class IccTag implements BinaryConstants, IccConstants
+{
+	public final int signature;
+	public final int offset, length;
+	public final IccTagType fIccTagType;
+
+	//		public final byte data[];
+
+	public IccTag(int signature, int offset, int length, IccTagType fIccTagType)
+	{
+		this.signature = signature;
+		this.offset = offset;
+		this.length = length;
+		this.fIccTagType = fIccTagType;
+	}
+
+	public byte data[] = null;
+	private IccTagDataType itdt = null;
+	private int data_type_signature;
+
+	public void setData(byte bytes[]) throws ImageReadException, IOException
+	{
+		data = bytes;
+
+		BinaryInputStream bis = new BinaryInputStream(new ByteArrayInputStream(
+				bytes), BYTE_ORDER_NETWORK);
+		data_type_signature = bis.read4Bytes("data type signature",
+				"ICC: corrupt tag data");
+
+		itdt = getIccTagDataType(data_type_signature);
+		//		if (itdt != null)
+		//		{
+		//			System.out.println("\t\t\t" + "itdt: " + itdt.name);
+		//		}
+
+	}
+
+	private IccTagDataType getIccTagDataType(int quad)
+	{
+		for (int i = 0; i < IccTagDataTypes.length; i++)
+			if (IccTagDataTypes[i].signature == quad)
+				return IccTagDataTypes[i];
+
+		return null;
+	}
+
+	public void dump(String prefix) throws ImageReadException, IOException
+	{
+		PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
+
+		dump(pw, prefix);
+	}
+
+	public void dump(PrintWriter pw, String prefix) throws ImageReadException,
+			IOException
+	{
+		pw.println(prefix
+				+ "tag signature: "
+				+ Integer.toHexString(signature)
+				+ " ("
+				+ new String(new byte[]{
+						(byte) (0xff & (signature >> 24)),
+						(byte) (0xff & (signature >> 16)),
+						(byte) (0xff & (signature >> 8)),
+						(byte) (0xff & (signature >> 0)),
+				}) + ")");
+
+		if (data == null)
+			pw.println(prefix + "data: " + data);
+		else
+		{
+			pw.println(prefix + "data: " + data.length);
+
+			pw.println(prefix
+					+ "data type signature: "
+					+ Integer.toHexString(data_type_signature)
+					+ " ("
+					+ new String(new byte[]{
+							(byte) (0xff & (data_type_signature >> 24)),
+							(byte) (0xff & (data_type_signature >> 16)),
+							(byte) (0xff & (data_type_signature >> 8)),
+							(byte) (0xff & (data_type_signature >> 0)),
+					}) + ")");
+
+			if (itdt == null)
+				pw.println(prefix + "IccTagType : " + "unknown");
+			else
+			{
+				pw.println(prefix + "IccTagType : " + itdt.name);
+				itdt.dump(prefix, data);
+			}
+
+		}
+
+		pw.println("");
+		pw.flush();
+
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTag.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagDataType.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagDataType.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagDataType.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagDataType.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,36 @@
+/*
+ * 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.apache.sanselan.icc;
+
+import java.io.IOException;
+
+import org.apache.sanselan.ImageReadException;
+
+public abstract class IccTagDataType
+{
+	public final String name;
+	public final int signature;
+
+	public IccTagDataType(String name, int signature)
+	{
+		this.name = name;
+		this.signature = signature;
+	}
+
+	public abstract void dump(String prefix, byte bytes[])
+			throws ImageReadException, IOException;
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagDataType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagType.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagType.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagType.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagType.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,31 @@
+/*
+ * 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.apache.sanselan.icc;
+
+public class IccTagType
+{
+	public final String name;
+	public final String type_description;
+	public final int signature;
+
+	public IccTagType(String name, String type_description, int signature)
+	{
+		this.name = name;
+		this.type_description = type_description;
+		this.signature = signature;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/icc/IccTagType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/ColorSpaceSubset.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/ColorSpaceSubset.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/ColorSpaceSubset.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/ColorSpaceSubset.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,178 @@
+/*
+ * 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.apache.sanselan.palette;
+
+class ColorSpaceSubset implements Comparable
+{
+	public final int mins[], maxs[];
+	public final int precision;
+	public final int precision_mask;
+	public final int total;
+	public int rgb; // median
+
+	public ColorSpaceSubset(int total, int precision)
+	{
+		this.total = total;
+		this.precision = precision;
+		precision_mask = (1 << precision) - 1;
+
+		mins = new int[PaletteFactory.components];
+		maxs = new int[PaletteFactory.components];
+		for (int i = 0; i < PaletteFactory.components; i++)
+		{
+			mins[i] = 0;
+			//			maxs[i] = 255;
+			maxs[i] = precision_mask;
+		}
+
+		rgb = -1;
+	}
+
+	public ColorSpaceSubset(int total, int precision, int mins[], int maxs[],
+			int table[])
+	{
+		this.total = total;
+		this.precision = precision;
+		this.mins = mins;
+		this.maxs = maxs;
+		precision_mask = (1 << precision) - 1;
+
+		rgb = -1;
+	}
+
+	public static long compares = 0;
+
+	public final boolean contains(int red, int green, int blue)
+	{
+		compares++;
+
+		red >>= (8 - precision);
+		if (mins[0] > red)
+			return false;
+		if (maxs[0] < red)
+			return false;
+
+		green >>= (8 - precision);
+		if (mins[1] > green)
+			return false;
+		if (maxs[1] < green)
+			return false;
+
+		blue >>= (8 - precision);
+		if (mins[2] > blue)
+			return false;
+		if (maxs[2] < blue)
+			return false;
+
+		return true;
+	}
+
+	public void dump(String prefix)
+	{
+		int rdiff = maxs[0] - mins[0] + 1;
+		int gdiff = maxs[1] - mins[1] + 1;
+		int bdiff = maxs[2] - mins[2] + 1;
+		int color_area = rdiff * gdiff * bdiff;
+
+		System.out.println(prefix + ": [" + Integer.toHexString(rgb)
+				+ "] total : " + total
+		//						+ " ("
+				//						+ (100.0 * (double) total / (double) total_area)
+				//						+ " %)"
+				);
+		System.out.println("\t" + "rgb: " + Integer.toHexString(rgb) + ", "
+				+ "red: " + Integer.toHexString(mins[0] << (8 - precision))
+				+ ", " + Integer.toHexString(maxs[0] << (8 - precision)) + ", "
+				+ "green: " + Integer.toHexString(mins[1] << (8 - precision))
+				+ ", " + Integer.toHexString(maxs[1] << (8 - precision)) + ", "
+				+ "blue: " + Integer.toHexString(mins[2] << (8 - precision))
+				+ ", " + Integer.toHexString(maxs[2] << (8 - precision)));
+		System.out.println("\t" + "red: " + mins[0] + ", " + maxs[0] + ", "
+				+ "green: " + mins[1] + ", " + maxs[1] + ", " + "blue: "
+				+ mins[2] + ", " + maxs[2]);
+		System.out
+				.println("\t" + "rdiff: " + rdiff + ", " + "gdiff: " + gdiff
+						+ ", " + "bdiff: " + bdiff + ", " + "color_area: "
+						+ color_area);
+	}
+
+	public void dumpJustRGB(String prefix)
+	{
+		System.out.println("\t" + "rgb: " + Integer.toHexString(rgb) + ", "
+				+ "red: " + Integer.toHexString(mins[0] << (8 - precision))
+				+ ", " + Integer.toHexString(maxs[0] << (8 - precision)) + ", "
+				+ "green: " + Integer.toHexString(mins[1] << (8 - precision))
+				+ ", " + Integer.toHexString(maxs[1] << (8 - precision)) + ", "
+				+ "blue: " + Integer.toHexString(mins[2] << (8 - precision))
+				+ ", " + Integer.toHexString(maxs[2] << (8 - precision)));
+	}
+
+	public int getArea()
+	{
+		int rdiff = maxs[0] - mins[0] + 1;
+		int gdiff = maxs[1] - mins[1] + 1;
+		int bdiff = maxs[2] - mins[2] + 1;
+		int color_area = rdiff * gdiff * bdiff;
+
+		return color_area;
+
+	}
+
+	public void setAverageRGB(int table[])
+	{
+
+		{
+			long redsum = 0, greensum = 0, bluesum = 0;
+
+			for (int red = mins[0]; red <= maxs[0]; red++)
+				for (int green = mins[1]; green <= maxs[1]; green++)
+					for (int blue = mins[2]; blue <= maxs[2]; blue++)
+					//					for (int red = 0; red <= precision_mask; red++)
+					//						for (int green = 0; green <= precision_mask; green++)
+					//							for (int blue = 0; blue <= precision_mask; blue++)
+					{
+						int index = (blue << (2 * precision)) // note: order reversed
+								| (green << (1 * precision))
+								| (red << (0 * precision));
+						int count = table[index];
+						redsum += count * (red << (8 - precision));
+						greensum += count * (green << (8 - precision));
+						bluesum += count * (blue << (8 - precision));
+
+					}
+
+			redsum /= total;
+			greensum /= total;
+			bluesum /= total;
+			rgb = (int) (((redsum & 0xff) << 16) | ((greensum & 0xff) << 8) | ((bluesum & 0xff) << 0));
+		}
+	}
+
+	public int compareTo(Object o)
+	{
+		ColorSpaceSubset other = (ColorSpaceSubset) o;
+		return rgb - other.rgb;
+	}
+
+	public int index;
+
+	public final void setIndex(int i)
+	{
+		index = i;
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/ColorSpaceSubset.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/MedianCutQuantizer.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/MedianCutQuantizer.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/MedianCutQuantizer.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/MedianCutQuantizer.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,525 @@
+/*
+ * 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.apache.sanselan.palette;
+
+import java.awt.image.BufferedImage;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.util.Debug;
+
+public class MedianCutQuantizer
+{
+	private final boolean ignoreAlpha;
+
+	public MedianCutQuantizer(boolean ignore_alpha)
+	{
+		this.ignoreAlpha = ignore_alpha;
+	}
+
+	private static class ColorCount
+	{
+		public final int argb;
+		public int count = 0;
+		public final int alpha, red, green, blue;
+
+		public ColorCount(int argb)
+		{
+			this.argb = argb;
+
+			alpha = 0xff & (argb >> 24);
+			red = 0xff & (argb >> 16);
+			green = 0xff & (argb >> 8);
+			blue = 0xff & (argb >> 0);
+
+			//			super.hashCode();
+		}
+
+		public int hashCode()
+		{
+			return argb;
+		}
+
+		public boolean equals(Object o)
+		{
+			ColorCount other = (ColorCount) o;
+			return other.argb == this.argb;
+		}
+
+	}
+
+	private class ColorGroup
+	{
+		//		public final ColorGroup parent;
+		public ColorGroupCut cut = null;
+		//		public final Vector children = new Vector();
+		public int palette_index = -1;
+
+		public final Vector color_counts;
+		public int min_red = Integer.MAX_VALUE;
+		public int max_red = Integer.MIN_VALUE;
+		public int min_green = Integer.MAX_VALUE;
+		public int max_green = Integer.MIN_VALUE;
+		public int min_blue = Integer.MAX_VALUE;
+		public int max_blue = Integer.MIN_VALUE;
+		public int min_alpha = Integer.MAX_VALUE;
+		public int max_alpha = Integer.MIN_VALUE;
+
+		public final int alpha_diff;
+		public final int red_diff;
+		public final int green_diff;
+		public final int blue_diff;
+
+		public final int max_diff;
+		public final int diff_total;
+
+		public ColorGroup(final Vector color_counts) throws ImageWriteException
+		{
+			this.color_counts = color_counts;
+
+			if (color_counts.size() < 1)
+				throw new ImageWriteException("empty color_group");
+
+			for (int i = 0; i < color_counts.size(); i++)
+			{
+				ColorCount color = (ColorCount) color_counts.get(i);
+
+				min_alpha = Math.min(min_alpha, color.alpha);
+				max_alpha = Math.max(max_alpha, color.alpha);
+				min_red = Math.min(min_red, color.red);
+				max_red = Math.max(max_red, color.red);
+				min_green = Math.min(min_green, color.green);
+				max_green = Math.max(max_green, color.green);
+				min_blue = Math.min(min_blue, color.blue);
+				max_blue = Math.max(max_blue, color.blue);
+			}
+
+			alpha_diff = max_alpha - min_alpha;
+			red_diff = max_red - min_red;
+			green_diff = max_green - min_green;
+			blue_diff = max_blue - min_blue;
+			max_diff = Math.max(ignoreAlpha ? red_diff : Math.max(alpha_diff,
+					red_diff), Math.max(green_diff, blue_diff));
+			diff_total = (ignoreAlpha ? 0 : alpha_diff) + red_diff
+					+ green_diff + blue_diff;
+
+		}
+
+		public boolean contains(int argb)
+		{
+			int alpha = 0xff & (argb >> 24);
+			int red = 0xff & (argb >> 16);
+			int green = 0xff & (argb >> 8);
+			int blue = 0xff & (argb >> 0);
+
+			if (!ignoreAlpha && (alpha < min_alpha || alpha > max_alpha))
+				return false;
+			if (red < min_red || red > max_red)
+				return false;
+			if (green < min_green || green > max_green)
+				return false;
+			if (blue < min_blue || blue > max_blue)
+				return false;
+			return true;
+		}
+
+		public int getMedianValue()
+		{
+			long count_total = 0;
+			long alpha_total = 0, red_total = 0, green_total = 0, blue_total = 0;
+
+			for (int i = 0; i < color_counts.size(); i++)
+			{
+				ColorCount color = (ColorCount) color_counts.get(i);
+
+				count_total += color.count;
+				alpha_total += color.count * color.alpha;
+				red_total += color.count * color.red;
+				green_total += color.count * color.green;
+				blue_total += color.count * color.blue;
+			}
+
+			int alpha = ignoreAlpha ? 0xff : (int) Math
+					.round((double) alpha_total / count_total);
+			int red = (int) Math.round((double) red_total / count_total);
+			int green = (int) Math.round((double) green_total / count_total);
+			int blue = (int) Math.round((double) blue_total / count_total);
+
+			return (alpha << 24) | (red << 16) | (green << 8) | blue;
+		}
+
+		public String toString()
+		{
+			return "{ColorGroup. min_red: " + Integer.toHexString(min_red)
+					+ ", max_red: " + Integer.toHexString(max_red)
+					+ ", min_green: " + Integer.toHexString(min_green)
+					+ ", max_green: " + Integer.toHexString(max_green)
+					+ ", min_blue: " + Integer.toHexString(min_blue)
+					+ ", max_blue: " + Integer.toHexString(max_blue)
+					+ ", min_alpha: " + Integer.toHexString(min_alpha)
+					+ ", max_alpha: " + Integer.toHexString(max_alpha)
+					+ ", max_diff: " + Integer.toHexString(max_diff)
+					+ ", diff_total: " + diff_total + "}";
+		}
+
+	}
+
+	public Map groupColors1(BufferedImage image, int max, int mask)
+			throws ImageWriteException
+	{
+		Map color_map = new Hashtable();
+
+		int width = image.getWidth();
+		int height = image.getHeight();
+
+		int row[] = new int[width];
+		for (int y = 0; y < height; y++)
+		{
+			image.getRGB(0, y, width, 1, row, 0, width);
+			for (int x = 0; x < width; x++)
+			{
+				int argb = row[x];
+
+				if (ignoreAlpha)
+					argb &= 0xffffff;
+				argb &= mask;
+
+				ColorCount color = (ColorCount) color_map
+						.get(new Integer(argb));
+				if (color == null)
+				{
+					color = new ColorCount(argb);
+					color_map.put(new Integer(argb), color);
+					if (color_map.keySet().size() > max)
+						return null;
+				}
+				color.count++;
+			}
+		}
+
+		return color_map;
+	}
+
+	public Map groupColors(BufferedImage image, int max_colors)
+			throws ImageWriteException
+	{
+		int max = Integer.MAX_VALUE;
+
+		for (int i = 0; i < 8; i++)
+		{
+			int mask = 0xff & (0xff << i);
+			mask = mask | (mask << 8) | (mask << 16) | (mask << 24);
+
+			Debug.debug("mask(" + i + ")", mask + " ("
+					+ Integer.toHexString(mask) + ")");
+
+			Map result = groupColors1(image, max, mask);
+			if (result != null)
+				return result;
+		}
+		throw new Error("");
+	}
+
+	public Palette process(BufferedImage image, int max_colors, boolean verbose)
+			throws ImageWriteException
+	{
+		Map color_map = groupColors(image, max_colors);
+
+		int discrete_colors = color_map.keySet().size();
+		if (discrete_colors <= max_colors)
+		{
+			if (verbose)
+				Debug.debug("lossless palette: " + discrete_colors);
+
+			int palette[] = new int[discrete_colors];
+			Vector color_counts = new Vector(color_map.values());
+
+			for (int i = 0; i < color_counts.size(); i++)
+			{
+				ColorCount color_count = (ColorCount) color_counts.get(i);
+				palette[i] = color_count.argb;
+				if (ignoreAlpha)
+					palette[i] |= 0xff000000;
+			}
+
+			return new SimplePalette(palette);
+		}
+
+		if (verbose)
+			Debug.debug("discrete colors: " + discrete_colors);
+
+		Vector color_groups = new Vector();
+		ColorGroup root = new ColorGroup(new Vector(color_map.values()));
+		{
+			color_groups.add(root);
+
+			final Comparator comparator = new Comparator()
+			{
+				public int compare(Object o1, Object o2)
+				{
+					ColorGroup cg1 = (ColorGroup) o1;
+					ColorGroup cg2 = (ColorGroup) o2;
+
+					if (cg1.max_diff == cg2.max_diff)
+						return cg2.diff_total - cg1.diff_total;
+					return cg2.max_diff - cg1.max_diff;
+				}
+			};
+
+			while (color_groups.size() < max_colors)
+			{
+				Collections.sort(color_groups, comparator);
+
+				ColorGroup color_group = (ColorGroup) color_groups.get(0);
+
+				if (color_group.max_diff == 0)
+					break;
+				if (!ignoreAlpha
+						&& color_group.alpha_diff > color_group.red_diff
+						&& color_group.alpha_diff > color_group.green_diff
+						&& color_group.alpha_diff > color_group.blue_diff)
+				{
+					doCut(color_group, ALPHA, color_groups);
+				}
+				else if (color_group.red_diff > color_group.green_diff
+						&& color_group.red_diff > color_group.blue_diff)
+				{
+					doCut(color_group, RED, color_groups);
+				}
+				else if (color_group.green_diff > color_group.blue_diff)
+				{
+					doCut(color_group, GREEN, color_groups);
+				}
+				else
+				{
+					doCut(color_group, BLUE, color_groups);
+				}
+			}
+		}
+
+		{
+			int palette_size = color_groups.size();
+			if (verbose)
+				Debug.debug("palette size: " + palette_size);
+
+			int palette[] = new int[palette_size];
+
+			for (int i = 0; i < color_groups.size(); i++)
+			{
+				ColorGroup color_group = (ColorGroup) color_groups.get(i);
+
+				palette[i] = color_group.getMedianValue();
+
+				color_group.palette_index = i;
+
+				if (color_group.color_counts.size() < 1)
+					throw new ImageWriteException("empty color_group: "
+							+ color_group);
+
+				//				if(color_group.)
+				//				Debug.debug("color_group", color_group);
+				//				Debug.debug("palette[" + i + "]", palette[i] + " ("
+				//						+ Integer.toHexString(palette[i]) + ")");
+			}
+
+			if (palette_size > discrete_colors)
+				throw new ImageWriteException("palette_size>discrete_colors");
+
+			return new MedianCutPalette(root, palette);
+		}
+	}
+
+	private static final int ALPHA = 0;
+	private static final int RED = 1;
+	private static final int GREEN = 2;
+	private static final int BLUE = 3;
+
+	private void doCut(ColorGroup color_group, final int mode,
+			final Vector color_groups) throws ImageWriteException
+	{
+		int count_total = 0;
+		for (int i = 0; i < color_group.color_counts.size(); i++)
+		{
+			ColorCount color_count = (ColorCount) color_group.color_counts
+					.get(i);
+			count_total += color_count.count;
+		}
+
+		Comparator comparator = new Comparator()
+		{
+			public int compare(Object o1, Object o2)
+			{
+				ColorCount c1 = (ColorCount) o1;
+				ColorCount c2 = (ColorCount) o2;
+
+				switch (mode)
+				{
+					case ALPHA :
+						return c1.alpha - c2.alpha;
+					case RED :
+						return c1.red - c2.red;
+					case GREEN :
+						return c1.green - c2.green;
+					case BLUE :
+						return c1.blue - c2.blue;
+					default :
+						return 0;
+				}
+			}
+		};
+
+		Collections.sort(color_group.color_counts, comparator);
+		int count_half = (int) Math.round((double) count_total / 2);
+		int old_count = 0, new_count = 0;
+		int median_index;
+		for (median_index = 0; median_index < color_group.color_counts.size(); median_index++)
+		{
+			ColorCount color_count = (ColorCount) color_group.color_counts
+					.get(median_index);
+
+			new_count += color_count.count;
+
+			if (new_count < count_half)
+			{
+				old_count = new_count;
+				continue;
+			}
+			break;
+		}
+
+		if (median_index == color_group.color_counts.size() - 1)
+			median_index--;
+		else if (median_index > 0)
+		{
+			int new_diff = Math.abs(new_count - count_half);
+			int old_diff = Math.abs(count_half - old_count);
+			if (old_diff < new_diff)
+				median_index--;
+		}
+
+		color_groups.remove(color_group);
+		{
+			Vector color_counts1 = new Vector(color_group.color_counts.subList(
+					0, median_index + 1));
+			Vector color_counts2 = new Vector(color_group.color_counts.subList(
+					median_index + 1, color_group.color_counts.size()));
+
+			ColorGroup less, more;
+			{
+				less = new ColorGroup(new Vector(color_counts1));
+				color_groups.add(less);
+			}
+			{
+				more = new ColorGroup(new Vector(color_counts2));
+				color_groups.add(more);
+			}
+
+			ColorCount median_value = (ColorCount) color_group.color_counts
+					.get(median_index);
+			int limit;
+			switch (mode)
+			{
+				case ALPHA :
+					limit = median_value.alpha;
+					break;
+				case RED :
+					limit = median_value.red;
+					break;
+				case GREEN :
+					limit = median_value.green;
+					break;
+				case BLUE :
+					limit = median_value.blue;
+					break;
+				default :
+					throw new Error("Bad mode.");
+			}
+			color_group.cut = new ColorGroupCut(less, more, mode, limit);
+
+		}
+	}
+	private class ColorGroupCut
+	{
+		public final ColorGroup less, more;
+		public final int mode, limit;
+
+		public ColorGroupCut(ColorGroup less, ColorGroup more, int mode,
+				int limit)
+		{
+			this.less = less;
+			this.more = more;
+			this.mode = mode;
+			this.limit = limit;
+		}
+
+		public ColorGroup getColorGroup(int argb)
+		{
+			int value;
+			switch (mode)
+			{
+				case ALPHA :
+					value = 0xff & (argb >> 24);
+					break;
+				case RED :
+					value = 0xff & (argb >> 16);
+					break;
+				case GREEN :
+					value = 0xff & (argb >> 8);
+					break;
+				case BLUE :
+					value = 0xff & (argb >> 0);
+					break;
+				default :
+					throw new Error("bad mode.");
+			}
+			if (value <= limit)
+				return less;
+			return more;
+		}
+
+	}
+
+	public class MedianCutPalette extends SimplePalette
+	{
+		private final ColorGroup root;
+
+		public MedianCutPalette(ColorGroup root, int palette[])
+		{
+			super(palette);
+			this.root = root;
+		}
+
+		public int getPaletteIndex(int rgb)
+		{
+			ColorGroup cg = root;
+
+			while (cg.cut != null)
+			{
+				ColorGroup next = cg.cut.getColorGroup(rgb);
+
+				cg = next;
+			}
+
+			return cg.palette_index;
+		}
+	}
+
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/MedianCutQuantizer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/Palette.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/Palette.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/Palette.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/Palette.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,34 @@
+/*
+ * 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.apache.sanselan.palette;
+
+import org.apache.sanselan.ImageWriteException;
+
+public abstract class Palette
+{
+
+	public abstract int getPaletteIndex(int rgb) throws ImageWriteException;
+
+	public abstract int getEntry(int index);
+
+	public abstract int length();
+
+	public void dump()
+	{
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/Palette.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/PaletteFactory.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/PaletteFactory.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/PaletteFactory.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/PaletteFactory.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,580 @@
+/*
+ * 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.apache.sanselan.palette;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Vector;
+
+public class PaletteFactory
+{
+	private static final boolean debug = false;
+
+	public void makePaletteFancy(BufferedImage src)
+	{
+		//		 map what rgb values have been used
+
+		byte rgbmap[] = new byte[256 * 256 * 32];
+		for (int i = 0; i < rgbmap.length; i++)
+			rgbmap[i] = 0;
+
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+			{
+				int argb = src.getRGB(x, y);
+				int rggbb = 0x1fffff & argb;
+				int highred = 0x7 & (argb >> 21);
+				int mask = 1 << highred;
+				rgbmap[rggbb] |= mask;
+			}
+
+		int count = 0;
+		for (int i = 0; i < rgbmap.length; i++)
+		{
+			int eight = 0xff & rgbmap[i];
+			if ((i < 3) || ((i - rgbmap.length) > -3))
+			{
+			}
+			for (int j = 0; j < 8; j++)
+			{
+				int mask = 1 << (7 - j);
+				int bit = eight & mask;
+				if (bit > 0)
+					count++;
+
+			}
+		}
+
+		if (debug)
+			System.out.println("Used colors: " + count);
+
+		int colormap[] = new int[count];
+		int mapsize = 0;
+		for (int i = 0; i < rgbmap.length; i++)
+		{
+			int eight = 0xff & rgbmap[i];
+
+			for (int j = 0; j < 8; j++)
+			{
+				int mask = 1 << (7 - j);
+				int bit = eight & mask;
+
+				if (bit > 0)
+				{
+					int rgb = i | ((7 - j) << 21);
+
+					if (mapsize < colormap.length)
+						colormap[mapsize] = rgb;
+					mapsize++;
+				}
+			}
+		}
+
+		if (debug)
+			System.out.println("mapsize: " + mapsize);
+
+//		for (int i = 0; i < colormap.length; i++)
+//		{
+//			int rgb = colormap[i];
+//		}
+
+	}
+
+	private int pixelToQuantizationTableIndex(int argb, int precision)
+	{
+		int result = 0;
+		int precision_mask = (1 << precision) - 1;
+
+		for (int i = 0; i < components; i++)
+		{
+			int sample = argb & 0xff;
+			argb >>= 8;
+
+			sample >>= (8 - precision);
+			result = (result << precision) | (sample & precision_mask);
+		}
+
+		return result;
+	}
+
+	private int getFrequencyTotal(int table[], int mins[], int maxs[],
+			int precision)
+	{
+		int sum = 0;
+
+		for (int blue = mins[2]; blue <= maxs[2]; blue++)
+		{
+			int b = (blue << (2 * precision));
+			for (int green = mins[1]; green <= maxs[1]; green++)
+			{
+				int g = (green << (1 * precision));
+
+				for (int red = mins[0]; red <= maxs[0]; red++)
+				{
+					int index = b | g | red;
+
+					sum += table[index];
+				}
+			}
+		}
+
+		return sum;
+	}
+
+	private DivisionCandidate finishDivision(int table[],
+			ColorSpaceSubset subset, int component, int precision, int sum,
+			int slice)
+	{
+		if (debug)
+			subset.dump("trying (" + component + "): ");
+
+		int total = subset.total;
+
+		if ((slice < subset.mins[component])
+				|| (slice >= subset.maxs[component]))
+		{
+			return null;
+		}
+
+		if ((sum < 1) || (sum >= total))
+		{
+			return null;
+		}
+
+		int remainder = total - sum;
+		if ((remainder < 1) || (remainder >= total))
+		{
+			return null;
+		}
+
+		//		Vector result = new Vector();
+
+		int slice_mins[] = new int[subset.mins.length];
+		System.arraycopy(subset.mins, 0, slice_mins, 0, subset.mins.length);
+		int slice_maxs[] = new int[subset.maxs.length];
+		System.arraycopy(subset.maxs, 0, slice_maxs, 0, subset.maxs.length);
+
+		slice_maxs[component] = slice;
+		slice_mins[component] = slice + 1;
+
+		if (debug)
+		{
+			System.out.println("total: " + total);
+			System.out.println("first total: " + sum);
+			System.out.println("second total: " + (total - sum));
+			//			System.out.println("start: " + start);
+			//			System.out.println("end: " + end);
+			System.out.println("slice: " + slice);
+
+		}
+
+		ColorSpaceSubset first = new ColorSpaceSubset(sum, precision,
+				subset.mins, slice_maxs, table);
+		ColorSpaceSubset second = new ColorSpaceSubset(total - sum, precision,
+				slice_mins, subset.maxs, table);
+
+		return new DivisionCandidate(subset, first, second);
+
+	}
+
+	private Vector divideSubset2(int table[], ColorSpaceSubset subset,
+			int component, int precision)
+	{
+		if (debug)
+			subset.dump("trying (" + component + "): ");
+
+		int total = subset.total;
+
+		int slice_mins[] = new int[subset.mins.length];
+		System.arraycopy(subset.mins, 0, slice_mins, 0, subset.mins.length);
+		int slice_maxs[] = new int[subset.maxs.length];
+		System.arraycopy(subset.maxs, 0, slice_maxs, 0, subset.maxs.length);
+
+		int sum1 = 0, sum2;
+		int slice1, slice2;
+		int last = 0;
+
+		{
+			for (slice1 = subset.mins[component]; slice1 != subset.maxs[component] + 1; slice1++)
+			{
+
+				slice_mins[component] = slice1;
+				slice_maxs[component] = slice1;
+
+				last = getFrequencyTotal(table, slice_mins, slice_maxs,
+						precision);
+
+				sum1 += last;
+
+				if (sum1 >= (total / 2))
+					break;
+			}
+
+			sum2 = sum1 - last;
+			slice2 = slice1 - 1;
+
+		}
+
+		DivisionCandidate dc1 = finishDivision(table, subset, component,
+				precision, sum1, slice1);
+		DivisionCandidate dc2 = finishDivision(table, subset, component,
+				precision, sum2, slice2);
+
+		Vector result = new Vector();
+
+		if (dc1 != null)
+			result.add(dc1);
+		if (dc2 != null)
+			result.add(dc2);
+
+		return result;
+	}
+
+	private DivisionCandidate divideSubset2(int table[],
+			ColorSpaceSubset subset, int precision)
+	{
+		Vector dcs = new Vector();
+
+		dcs.addAll(divideSubset2(table, subset, 0, precision));
+		dcs.addAll(divideSubset2(table, subset, 1, precision));
+		dcs.addAll(divideSubset2(table, subset, 2, precision));
+
+		DivisionCandidate best_v = null;
+		//		int best_split 
+		double best_score = Double.MAX_VALUE;
+
+		for (int i = 0; i < dcs.size(); i++)
+		{
+			DivisionCandidate dc = (DivisionCandidate) dcs.get(i);
+
+			ColorSpaceSubset first = dc.dst_a;
+			ColorSpaceSubset second = dc.dst_b;
+			int area1 = first.total;
+			int area2 = second.total;
+
+			int diff = Math.abs(area1 - area2);
+			double split = ((double) diff) / ((double) Math.max(area1, area2));
+
+			double score = split;
+
+			if (best_v == null)
+			{
+				best_v = dc;
+				best_score = score;
+			}
+			else if (score < best_score)
+			{
+				best_v = dc;
+				best_score = score;
+			}
+
+		}
+
+		return best_v;
+	}
+
+	public static final int components = 3; // in bits
+
+	private static class DivisionCandidate
+	{
+		private final ColorSpaceSubset src, dst_a, dst_b;
+
+		public DivisionCandidate(ColorSpaceSubset src, ColorSpaceSubset dst_a,
+				ColorSpaceSubset dst_b)
+		{
+			this.src = src;
+			this.dst_a = dst_a;
+			this.dst_b = dst_b;
+		}
+	}
+
+	private Vector divide(Vector v, int desired_count, int table[],
+			int precision)
+	{
+		Vector ignore = new Vector();
+
+		int count = 0;
+		while (true)
+		{
+			count++;
+
+			if (debug)
+				System.out.println("cycle(" + count + "): " + v.size()
+						+ " done");
+
+			int max_area = -1;
+			ColorSpaceSubset max_subset = null;
+
+			for (int i = 0; i < v.size(); i++)
+			{
+				ColorSpaceSubset subset = (ColorSpaceSubset) v.get(i);
+				if (ignore.contains(subset))
+					continue;
+				int area = subset.total;
+
+				if (max_subset == null)
+				{
+					max_subset = subset;
+					max_area = area;
+				}
+				else if (area > max_area)
+				{
+					max_subset = subset;
+					max_area = area;
+				}
+			}
+
+			if (max_subset == null)
+			{
+				return v;
+			}
+			if (debug)
+				System.out.println("\t" + "area: " + max_area);
+
+			{
+
+				DivisionCandidate dc = divideSubset2(table, max_subset,
+						precision);
+				if (dc != null)
+				{
+					v.remove(max_subset);
+					v.add(dc.dst_a);
+					v.add(dc.dst_b);
+				}
+				else
+					ignore.add(max_subset);
+			}
+
+			if (v.size() == desired_count)
+				return v;
+		}
+
+		//		return result;
+	}
+
+	public Palette makePaletteQuantized(BufferedImage src, int max)
+	{
+		int precision = 6; // in bits
+
+		int table_scale = precision * components;
+		int table_size = 1 << table_scale;
+		int table[] = new int[table_size];
+
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		Vector subsets = new Vector();
+		ColorSpaceSubset all = new ColorSpaceSubset(width * height, precision);
+		subsets.add(all);
+
+		int pre_total = getFrequencyTotal(table, all.mins, all.maxs, precision);
+		if (debug)
+			System.out.println("pre total: " + pre_total);
+
+		{ // step 1: count frequency of colors
+
+			for (int y = 0; y < height; y++)
+				for (int x = 0; x < width; x++)
+				{
+					int argb = src.getRGB(x, y);
+
+					int index = pixelToQuantizationTableIndex(argb, precision);
+
+					table[index]++;
+				}
+		}
+
+		int all_total = getFrequencyTotal(table, all.mins, all.maxs, precision);
+		if (debug)
+		{
+			System.out.println("all total: " + all_total);
+
+			System.out.println("width * height: " + (width * height));
+		}
+
+		subsets = divide(subsets, 256, table, precision);
+
+		if (debug)
+		{
+			System.out.println("subsets: " + subsets.size());
+			System.out.println("width*height: " + width * height);
+		}
+
+		for (int i = 0; i < subsets.size(); i++)
+		{
+			ColorSpaceSubset subset = (ColorSpaceSubset) subsets.get(i);
+
+			subset.setAverageRGB(table);
+
+			if (debug)
+				subset.dump(i + ": ");
+		}
+
+		Collections.sort(subsets);
+
+		return new QuantizedPalette(subsets, precision);
+	}
+
+	public SimplePalette makePaletteSimple(BufferedImage src, int max)
+	// This is not efficient for large values of max, say, max > 256;
+	{
+		Map map = new Hashtable();
+		int rgbs[] = new int[max];
+		int rgb_count = 0;
+
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+			{
+				int argb = src.getRGB(x, y);
+				int rgb = 0xffffff & argb;
+
+				String key = "" + rgb;
+				if (null == map.get(key))
+				{
+					if (rgb_count == max)
+						return null;
+
+					rgbs[rgb_count] = rgb;
+					map.put(key, key);
+					rgb_count++;
+				}
+			}
+
+		int result[] = new int[rgb_count];
+		System.arraycopy(rgbs, 0, result, 0, rgb_count);
+
+		//		return result;
+		return new SimplePalette(result);
+	}
+
+	public boolean isGrayscale(BufferedImage src)
+	{
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		if (ColorSpace.TYPE_GRAY == src.getColorModel().getColorSpace()
+				.getType())
+			return true;
+
+		for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+			{
+				int argb = src.getRGB(x, y);
+
+				int red = 0xff & (argb >> 16);
+				int green = 0xff & (argb >> 8);
+				int blue = 0xff & (argb >> 0);
+
+				if (red != green || red != blue)
+					return false;
+			}
+
+		return true;
+	}
+
+	public boolean hasTransparency(BufferedImage src)
+	{
+		return hasTransparency(src, 255);
+	}
+
+	public boolean hasTransparency(BufferedImage src, int threshold)
+	{
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		if (!src.getColorModel().hasAlpha())
+			return false;
+
+		for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+			{
+				int argb = src.getRGB(x, y);
+				int alpha = 0xff & (argb >> 24);
+				if (alpha < threshold)
+					return true;
+			}
+
+		return false;
+	}
+
+	public int countTrasparentColors(int rgbs[])
+	{
+		int first = -1;
+
+		for (int i = 0; i < rgbs.length; i++)
+		{
+			int rgb = rgbs[i];
+			int alpha = 0xff & (rgb >> 24);
+			if (alpha < 0xff)
+			{
+				if (first < 0)
+				{
+					first = rgb;
+				}
+				else if (rgb != first)
+					return 2; // more than one transparent color;
+			}
+		}
+
+		if (first < 0)
+			return 0;
+		return 1;
+	}
+
+	public int countTransparentColors(BufferedImage src)
+	{
+		ColorModel cm = src.getColorModel();
+		if (!cm.hasAlpha())
+			return 0;
+
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		int first = -1;
+
+		for (int y = 0; y < height; y++)
+			for (int x = 0; x < width; x++)
+			{
+				int rgb = src.getRGB(x, y);
+				int alpha = 0xff & (rgb >> 24);
+				if (alpha < 0xff)
+				{
+					if (first < 0)
+					{
+						first = rgb;
+					}
+					else if (rgb != first)
+						return 2; // more than one transparent color;
+				}
+			}
+
+		if (first < 0)
+			return 0;
+		return 1;
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/PaletteFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/QuantizedPalette.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/QuantizedPalette.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/QuantizedPalette.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/QuantizedPalette.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,86 @@
+/*
+ * 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.apache.sanselan.palette;
+
+import java.util.Vector;
+
+import org.apache.sanselan.ImageWriteException;
+
+public class QuantizedPalette extends Palette
+{
+	private final int precision;
+	private final Vector subsets;
+	private final ColorSpaceSubset straight[];
+
+	public QuantizedPalette(Vector subsets, int precision)
+	{
+		this.subsets = subsets;
+		this.precision = precision;
+
+		{
+			straight = new ColorSpaceSubset[1 << (precision * 3)];
+
+			for (int i = 0; i < subsets.size(); i++)
+			{
+				ColorSpaceSubset subset = (ColorSpaceSubset) subsets.get(i);
+				subset.setIndex(i);
+
+				for (int u = subset.mins[0]; u <= subset.maxs[0]; u++)
+					for (int j = subset.mins[1]; j <= subset.maxs[1]; j++)
+						for (int k = subset.mins[2]; k <= subset.maxs[2]; k++)
+						{
+							int index = (u << (precision * 2))
+									| (j << (precision * 1))
+									| (k << (precision * 0));
+							straight[index] = subset;
+						}
+			}
+		}
+
+	}
+
+	public int getPaletteIndex(int rgb) throws ImageWriteException
+	{
+		int precisionMask = (1 << precision) - 1;
+
+		int index = ((rgb >> (24 - 3 * precision)) & (precisionMask << (precision << 1)))
+				| ((rgb >> (16 - 2 * precision)) & (precisionMask << precision))
+				| ((rgb >> (8 - precision)) & (precisionMask));
+
+		return straight[index].index;
+	}
+
+	public void dump()
+	{
+		//		System.out.println("ColorSpaceSubset.compares: "
+		//				+ ColorSpaceSubset.compares);
+		//		System.out.println("converted: " + converted);
+		//		System.out.println("avg. distance: " + (distance / converted));
+	}
+
+	public int getEntry(int index)
+	{
+		ColorSpaceSubset subset = (ColorSpaceSubset) subsets.get(index);
+		return subset.rgb;
+	}
+
+	public int length()
+	{
+		return subsets.size();
+
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/QuantizedPalette.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/SimplePalette.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/SimplePalette.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/SimplePalette.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/palette/SimplePalette.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,72 @@
+/*
+ * 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.apache.sanselan.palette;
+
+import org.apache.sanselan.util.Debug;
+
+public class SimplePalette extends Palette
+{
+	private final int palette[];
+
+	public SimplePalette(int palette[])
+	{
+		this.palette = palette;
+	}
+
+	public int getPaletteIndex(int rgb)
+	{
+		return getPaletteIndex(palette, rgb);
+	}
+
+	public int getEntry(int index)
+	{
+		return palette[index];
+		//			return getPaletteIndex(palette, rgb);
+	}
+
+	private int getPaletteIndex(int palette[], int argb)
+	{
+
+		//		Debug.debug("getPaletteIndex argb", argb + " ("
+		//				+ Integer.toHexString(argb) + ")");
+
+		for (int i = 0; i < palette.length; i++)
+		{
+			//			Debug.debug("\t" + "palette[" + i + "]", palette[i] + " ("
+			//					+ Integer.toHexString(palette[i]) + ")");
+
+			if (palette[i] == argb)
+				return i;
+		}
+
+		return -1;
+	}
+
+	public void dump()
+	{
+		for (int i = 0; i < palette.length; i++)
+		{
+			Debug.debug("\t" + "palette[" + i + "]", palette[i] + " (0x"
+					+ Integer.toHexString(palette[i]) + ")");
+		}
+	}
+
+	public int length()
+	{
+		return palette.length;
+	}
+}
\ No newline at end of file