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 [14/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/co...
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccConstants.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccConstants.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccConstants.java Sat Nov 17 13:58:22 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.cmc.sanselan.icc;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.cmc.sanselan.ImageReadException;
+import org.cmc.sanselan.common.BinaryConstants;
+import org.cmc.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 headers creation",
+ // "date/time field. This allows applications and utilities to verify if this profile matches a vendors 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 observers 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 users 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/cmc/sanselan/icc/IccConstants.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileInfo.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileInfo.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileInfo.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileInfo.java Sat Nov 17 13:58:22 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.cmc.sanselan.icc;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.cmc.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/cmc/sanselan/icc/IccProfileInfo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileParser.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccProfileParser.java Sat Nov 17 13:58:22 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.cmc.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.cmc.sanselan.common.BinaryFileParser;
+import org.cmc.sanselan.common.byteSources.ByteSource;
+import org.cmc.sanselan.common.byteSources.ByteSourceArray;
+import org.cmc.sanselan.common.byteSources.ByteSourceFile;
+import org.cmc.sanselan.util.CachingInputStream;
+import org.cmc.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/cmc/sanselan/icc/IccProfileParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTag.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTag.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTag.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTag.java Sat Nov 17 13:58:22 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.cmc.sanselan.icc;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import org.cmc.sanselan.ImageReadException;
+import org.cmc.sanselan.common.BinaryConstants;
+import org.cmc.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/cmc/sanselan/icc/IccTag.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagDataType.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagDataType.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagDataType.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagDataType.java Sat Nov 17 13:58:22 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.cmc.sanselan.icc;
+
+import java.io.IOException;
+
+import org.cmc.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/cmc/sanselan/icc/IccTagDataType.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagType.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagType.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagType.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/icc/IccTagType.java Sat Nov 17 13:58:22 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.cmc.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/cmc/sanselan/icc/IccTagType.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/ColorSpaceSubset.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/ColorSpaceSubset.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/ColorSpaceSubset.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/ColorSpaceSubset.java Sat Nov 17 13:58:22 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.cmc.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/cmc/sanselan/palette/ColorSpaceSubset.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/MedianCutQuantizer.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/MedianCutQuantizer.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/MedianCutQuantizer.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/MedianCutQuantizer.java Sat Nov 17 13:58:22 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.cmc.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.cmc.sanselan.ImageWriteException;
+import org.cmc.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/cmc/sanselan/palette/MedianCutQuantizer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/Palette.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/Palette.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/Palette.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/Palette.java Sat Nov 17 13:58:22 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.cmc.sanselan.palette;
+
+import org.cmc.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/cmc/sanselan/palette/Palette.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/PaletteFactory.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/PaletteFactory.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/PaletteFactory.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/PaletteFactory.java Sat Nov 17 13:58:22 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.cmc.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/cmc/sanselan/palette/PaletteFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/QuantizedPalette.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/QuantizedPalette.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/QuantizedPalette.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/QuantizedPalette.java Sat Nov 17 13:58:22 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.cmc.sanselan.palette;
+
+import java.util.Vector;
+
+import org.cmc.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/cmc/sanselan/palette/QuantizedPalette.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/SimplePalette.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/SimplePalette.java?rev=596008&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/SimplePalette.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/SimplePalette.java Sat Nov 17 13:58:22 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.cmc.sanselan.palette;
+
+import org.cmc.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
Propchange: incubator/sanselan/trunk/src/main/java/org/cmc/sanselan/palette/SimplePalette.java
------------------------------------------------------------------------------
svn:eol-style = native