Index: java/awt/color/ICC_ColorSpace.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/awt/color/ICC_ColorSpace.java,v retrieving revision 1.6 diff -u -r1.6 ICC_ColorSpace.java --- java/awt/color/ICC_ColorSpace.java 13 Feb 2003 19:32:37 -0000 1.6 +++ java/awt/color/ICC_ColorSpace.java 26 Oct 2004 12:57:11 -0000 @@ -1,46 +1,80 @@ /* ICC_ColorSpace.java -- the canonical color space implementation Copyright (C) 2000, 2002 Free Software Foundation -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -02111-1307 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ + This file is part of GNU Classpath. + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ package java.awt.color; +import gnu.java.awt.color.CieXyzConverter; +import gnu.java.awt.color.ClutProfileConverter; +import gnu.java.awt.color.ColorSpaceConverter; +import gnu.java.awt.color.GrayProfileConverter; +import gnu.java.awt.color.GrayScaleConverter; +import gnu.java.awt.color.LinearRGBConverter; +import gnu.java.awt.color.PyccConverter; +import gnu.java.awt.color.RgbProfileConverter; +import gnu.java.awt.color.SrgbConverter; +import java.io.IOException; +import java.io.ObjectInputStream; + + /** - * NEEDS DOCUMENTATION + * ICC_ColorSpace - an implementation of ColorSpace + * + * While an ICC_Profile class abstracts the data in an ICC profile file + * an ICC_ColorSpace performs the color space conversions defined by + * an ICC_Profile instance. + * + * Typically, an ICC_Profile will either be created using getInstance, + * either from the built-in colorspaces, or from an ICC profile file. + * Then a ICC_Colorspace will be used to perform transforms from the + * device colorspace to and from the profile color space. * + * The PCS used by ColorSpace is CIE XYZ relative a D50 white point. + * (Profiles using a CIE Lab PCS will have their input and output converted + * to D50 CIE XYZ accordingly. + * + * Note that a valid profile may not contain transforms in both directions, + * in which case the output may be undefined. + * All built-in colorspaces have bidirectional transforms, but developers + * using an ICC profile file may want to check the profile class using + * the ICC_Profile.getProfileClass() method. Input class profiles are + * guaranteed to have transforms to the PCS, output class profiles are + * guaranteed to have transforms from the PCS to device space. + * + * @author Sven de Marothy * @author Rolf W. Rasmussen
* @since 1.2 */ @@ -82,6 +116,13 @@ private boolean needScaleInit; /** + * Tells us if the PCS is CIE LAB (must be CIEXYZ otherwise) + */ + private transient int type; + private transient int nComponents; + private transient ColorSpaceConverter converter; + + /** * Constructs a new ICC_ColorSpace from an ICC_Profile object. * * @exception IllegalArgumentException If profile is inappropriate for @@ -89,10 +130,18 @@ */ public ICC_ColorSpace(ICC_Profile profile) { - super(CS_sRGB, profile.getNumComponents()); + super(profile.getColorSpaceType(), profile.getNumComponents()); + + converter = getConverter(profile); thisProfile = profile; + nComponents = profile.getNumComponents(); + type = profile.getColorSpaceType(); + makeArrays(); } + /** + * Return the profile + */ public ICC_Profile getProfile() { return thisProfile; @@ -107,11 +156,7 @@ */ public float[] toRGB(float[] colorvalue) { - if (colorvalue.length < numComponents) - throw new IllegalArgumentException (); - - // FIXME: Always assumes sRGB: - return colorvalue; + return converter.toRGB(colorvalue); } /** @@ -123,11 +168,7 @@ */ public float[] fromRGB(float[] rgbvalue) { - if (rgbvalue.length < 3) - throw new IllegalArgumentException (); - - // FIXME: Always assumes sRGB: - return rgbvalue; + return converter.fromRGB(rgbvalue); } /** @@ -139,8 +180,7 @@ */ public float[] toCIEXYZ(float[] colorvalue) { - // FIXME: Not implemented - throw new UnsupportedOperationException(); + return converter.toCIEXYZ(colorvalue); } /** @@ -152,8 +192,12 @@ */ public float[] fromCIEXYZ(float[] colorvalue) { - // FIXME: Not implemented - throw new UnsupportedOperationException(); + return converter.fromCIEXYZ(colorvalue); + } + + public boolean isCS_sRGB() + { + return converter instanceof SrgbConverter; } /** @@ -167,9 +211,11 @@ */ public float getMinValue(int idx) { - if (type == TYPE_Lab && (idx == 1 || idx == 2)) - return -128; - if (idx < 0 || idx >= numComponents) + // FIXME: Not 100% certain of this. + if (type == ColorSpace.TYPE_Lab && (idx == 1 || idx == 2)) + return -128f; + + if (idx < 0 || idx >= nComponents) throw new IllegalArgumentException(); return 0; } @@ -185,17 +231,83 @@ */ public float getMaxValue(int idx) { - if (type == TYPE_XYZ && idx >= 0 && idx <= 2) + if (type == ColorSpace.TYPE_XYZ && idx >= 0 && idx <= 2) return 1 + 32767 / 32768f; - else if (type == TYPE_Lab) + else if (type == ColorSpace.TYPE_Lab) { - if (idx == 0) - return 100; - if (idx == 1 || idx == 2) - return 127; + if (idx == 0) + return 100; + if (idx == 1 || idx == 2) + return 127; } - if (idx < 0 || idx >= numComponents) + if (idx < 0 || idx >= nComponents) throw new IllegalArgumentException(); return 1; } + + /** + * Returns a colorspace converter suitable for a given profile + */ + private ColorSpaceConverter getConverter(ICC_Profile profile) + { + ColorSpaceConverter converter; + switch (profile.isPredefined()) + { + case CS_sRGB: + converter = new SrgbConverter(); + break; + case CS_CIEXYZ: + converter = new CieXyzConverter(); + break; + case CS_GRAY: + converter = new GrayScaleConverter(); + break; + case CS_LINEAR_RGB: + converter = new LinearRGBConverter(); + break; + case CS_PYCC: + converter = new PyccConverter(); + break; + default: + if (profile instanceof ICC_ProfileRGB) + converter = new RgbProfileConverter((ICC_ProfileRGB) profile); + else if (profile instanceof ICC_ProfileGray) + converter = new GrayProfileConverter((ICC_ProfileGray) profile); + else + converter = new ClutProfileConverter(profile); + break; + } + return converter; + } + + /** + * Serialization compatibility requires these variable to be set, + * although we don't use them. Perhaps we should? + */ + private void makeArrays() + { + minVal = new float[nComponents]; + maxVal = new float[nComponents]; + + invDiffMinMax = diffMinMax = null; + for (int i = 0; i < nComponents; i++) + { + minVal[i] = getMinValue(i); + maxVal[i] = getMaxValue(i); + } + needScaleInit = true; + } + + /** + * Deserializes the object + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + // set up objects + converter = getConverter(thisProfile); + nComponents = thisProfile.getNumComponents(); + type = thisProfile.getColorSpaceType(); + } } // class ICC_ColorSpace Index: java/awt/color/ICC_Profile.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/awt/color/ICC_Profile.java,v retrieving revision 1.6 diff -u -r1.6 ICC_Profile.java --- java/awt/color/ICC_Profile.java 27 Sep 2004 15:11:46 -0000 1.6 +++ java/awt/color/ICC_Profile.java 26 Oct 2004 12:57:11 -0000 @@ -1,43 +1,44 @@ /* ICC_Profile.java -- color space profiling Copyright (C) 2000, 2002 Free Software Foundation -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -02111-1307 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ + This file is part of GNU Classpath. + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ package java.awt.color; +import gnu.java.awt.color.ProfileHeader; +import gnu.java.awt.color.TagEntry; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -47,9 +48,36 @@ import java.io.ObjectStreamException; import java.io.OutputStream; import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.Hashtable; + /** - * STUBBED + * ICC Profile - represents an ICC Color profile. + * The ICC profile format is a standard file format which maps the transform + * from a device color space to a standard Profile Color Space (PCS), which + * can either be CIE L*a*b or CIE XYZ. + * (With the exception of device link profiles which map from one device space + * to another) + * + * ICC profiles calibrated to specific input/output devices are used when color + * fidelity is of importance. + * + * An instance of ICC_Profile can be created using the getInstance() methods, + * either using one of the predefined color spaces enumerated in ColorSpace, + * or from an ICC profile file, or from an input stream. + * + * An ICC_ColorSpace object can then be created to transform color values + * through the profile. + * + * The ICC_Profile class implements the version 2 format specified by + * International Color Consortium Specification ICC.1:1998-09, + * and it's addendum ICC.1A:1999-04, April 1999 + * (available at www.color.org) + * + * @author Sven de Marothy * @author Rolf W. Rasmussen * @since 1.2 */ @@ -60,6 +88,9 @@ */ private static final long serialVersionUID = -3938515861990936766L; + /** + * ICC Profile classes + */ public static final int CLASS_INPUT = 0; public static final int CLASS_DISPLAY = 1; public static final int CLASS_OUTPUT = 2; @@ -68,92 +99,112 @@ public static final int CLASS_ABSTRACT = 5; public static final int CLASS_NAMEDCOLOR = 6; - public static final int icSigXYZData = 1482250784; - public static final int icSigLabData = 1281450528; - public static final int icSigLuvData = 1282766368; - public static final int icSigYCbCrData = 1497588338; - public static final int icSigYxyData = 1501067552; - public static final int icSigRgbData = 1380401696; - public static final int icSigGrayData = 1196573017; - public static final int icSigHsvData = 1213421088; - public static final int icSigHlsData = 1212961568; - public static final int icSigCmykData = 1129142603; - public static final int icSigCmyData = 1129142560; - public static final int icSigSpace2CLR = 843271250; - public static final int icSigSpace3CLR = 860048466; - public static final int icSigSpace4CLR = 876825682; - public static final int icSigSpace5CLR = 893602898; - public static final int icSigSpace6CLR = 910380114; - public static final int icSigSpace7CLR = 927157330; - public static final int icSigSpace8CLR = 943934546; - public static final int icSigSpace9CLR = 960711762; - public static final int icSigSpaceACLR = 1094929490; - public static final int icSigSpaceBCLR = 1111706706; - public static final int icSigSpaceCCLR = 1128483922; - public static final int icSigSpaceDCLR = 1145261138; - public static final int icSigSpaceECLR = 1162038354; - public static final int icSigSpaceFCLR = 1178815570; - - public static final int icSigInputClass = 1935896178; - public static final int icSigDisplayClass = 1835955314; - public static final int icSigOutputClass = 1886549106; - public static final int icSigLinkClass = 1818848875; - public static final int icSigAbstractClass = 1633842036; - public static final int icSigColorSpaceClass = 1936744803; - public static final int icSigNamedColorClass = 1852662636; + /** + * ICC Profile class signatures + */ + public static final int icSigInputClass = 0x73636e72; // 'scnr' + public static final int icSigDisplayClass = 0x6d6e7472; // 'mntr' + public static final int icSigOutputClass = 0x70727472; // 'prtr' + public static final int icSigLinkClass = 0x6c696e6b; // 'link' + public static final int icSigColorSpaceClass = 0x73706163; // 'spac' + public static final int icSigAbstractClass = 0x61627374; // 'abst' + public static final int icSigNamedColorClass = 0x6e6d636c; // 'nmcl' + + /** + * Color space signatures + */ + public static final int icSigXYZData = 0x58595A20; // 'XYZ ' + public static final int icSigLabData = 0x4C616220; // 'Lab ' + public static final int icSigLuvData = 0x4C757620; // 'Luv ' + public static final int icSigYCbCrData = 0x59436272; // 'YCbr' + public static final int icSigYxyData = 0x59787920; // 'Yxy ' + public static final int icSigRgbData = 0x52474220; // 'RGB ' + public static final int icSigGrayData = 0x47524159; // 'GRAY' + public static final int icSigHsvData = 0x48535620; // 'HSV ' + public static final int icSigHlsData = 0x484C5320; // 'HLS ' + public static final int icSigCmykData = 0x434D594B; // 'CMYK' + public static final int icSigCmyData = 0x434D5920; // 'CMY ' + public static final int icSigSpace2CLR = 0x32434C52; // '2CLR' + public static final int icSigSpace3CLR = 0x33434C52; // '3CLR' + public static final int icSigSpace4CLR = 0x34434C52; // '4CLR' + public static final int icSigSpace5CLR = 0x35434C52; // '5CLR' + public static final int icSigSpace6CLR = 0x36434C52; // '6CLR' + public static final int icSigSpace7CLR = 0x37434C52; // '7CLR' + public static final int icSigSpace8CLR = 0x38434C52; // '8CLR' + public static final int icSigSpace9CLR = 0x39434C52; // '9CLR' + public static final int icSigSpaceACLR = 0x41434C52; // 'ACLR' + public static final int icSigSpaceBCLR = 0x42434C52; // 'BCLR' + public static final int icSigSpaceCCLR = 0x43434C52; // 'CCLR' + public static final int icSigSpaceDCLR = 0x44434C52; // 'DCLR' + public static final int icSigSpaceECLR = 0x45434C52; // 'ECLR' + public static final int icSigSpaceFCLR = 0x46434C52; // 'FCLR' + /** + * Rendering intents + */ public static final int icPerceptual = 0; public static final int icRelativeColorimetric = 1; public static final int icSaturation = 2; public static final int icAbsoluteColorimetric = 3; - public static final int icSigHead = 1751474532; - public static final int icSigAToB0Tag = 1093812784; - public static final int icSigAToB1Tag = 1093812785; - public static final int icSigAToB2Tag = 1093812786; - public static final int icSigBlueColorantTag = 1649957210; - public static final int icSigBlueTRCTag = 1649693251; - public static final int icSigBToA0Tag = 1110589744; - public static final int icSigBToA1Tag = 1110589745; - public static final int icSigBToA2Tag = 1110589746; - public static final int icSigCalibrationDateTimeTag = 1667329140; - public static final int icSigCharTargetTag = 1952543335; - public static final int icSigCopyrightTag = 1668313716; - public static final int icSigCrdInfoTag = 1668441193; - public static final int icSigDeviceMfgDescTag = 1684893284; - public static final int icSigDeviceModelDescTag = 1684890724; - public static final int icSigDeviceSettingsTag = 1684371059; - public static final int icSigGamutTag = 1734438260; - public static final int icSigGrayTRCTag = 1800688195; - public static final int icSigGreenColorantTag = 1733843290; - public static final int icSigGreenTRCTag = 1733579331; - public static final int icSigLuminanceTag = 1819635049; - public static final int icSigMeasurementTag = 1835360627; - public static final int icSigMediaBlackPointTag = 1651208308; - public static final int icSigMediaWhitePointTag = 2004119668; - public static final int icSigNamedColor2Tag = 1852009522; - public static final int icSigOutputResponseTag = 1919251312; - public static final int icSigPreview0Tag = 1886545200; - public static final int icSigPreview1Tag = 1886545201; - public static final int icSigPreview2Tag = 1886545202; - public static final int icSigProfileDescriptionTag = 1684370275; - public static final int icSigProfileSequenceDescTag = 1886610801; - public static final int icSigPs2CRD0Tag = 1886610480; - public static final int icSigPs2CRD1Tag = 1886610481; - public static final int icSigPs2CRD2Tag = 1886610482; - public static final int icSigPs2CRD3Tag = 1886610483; - public static final int icSigPs2CSATag = 1886597747; - public static final int icSigPs2RenderingIntentTag = 1886597737; - public static final int icSigRedColorantTag = 1918392666; - public static final int icSigRedTRCTag = 1918128707; - public static final int icSigScreeningDescTag = 1935897188; - public static final int icSigScreeningTag = 1935897198; - public static final int icSigTechnologyTag = 1952801640; - public static final int icSigUcrBgTag = 1650877472; - public static final int icSigViewingCondDescTag = 1987405156; - public static final int icSigViewingConditionsTag = 1986618743; - public static final int icSigChromaticityTag = 1667789421; + /** + * Tag signatures + */ + public static final int icSigAToB0Tag = 0x41324230; // 'A2B0' + public static final int icSigAToB1Tag = 0x41324231; // 'A2B1' + public static final int icSigAToB2Tag = 0x41324232; // 'A2B2' + public static final int icSigBlueColorantTag = 0x6258595A; // 'bXYZ' + public static final int icSigBlueTRCTag = 0x62545243; // 'bTRC' + public static final int icSigBToA0Tag = 0x42324130; // 'B2A0' + public static final int icSigBToA1Tag = 0x42324131; // 'B2A1' + public static final int icSigBToA2Tag = 0x42324132; // 'B2A2' + public static final int icSigCalibrationDateTimeTag = 0x63616C74; // 'calt' + public static final int icSigCharTargetTag = 0x74617267; // 'targ' + public static final int icSigCopyrightTag = 0x63707274; // 'cprt' + public static final int icSigCrdInfoTag = 0x63726469; // 'crdi' + public static final int icSigDeviceMfgDescTag = 0x646D6E64; // 'dmnd' + public static final int icSigDeviceModelDescTag = 0x646D6464; // 'dmdd' + public static final int icSigDeviceSettingsTag = 0x64657673; // 'devs' + public static final int icSigGamutTag = 0x67616D74; // 'gamt' + public static final int icSigGrayTRCTag = 0x6b545243; // 'kTRC' + public static final int icSigGreenColorantTag = 0x6758595A; // 'gXYZ' + public static final int icSigGreenTRCTag = 0x67545243; // 'gTRC' + public static final int icSigLuminanceTag = 0x6C756d69; // 'lumi' + public static final int icSigMeasurementTag = 0x6D656173; // 'meas' + public static final int icSigMediaBlackPointTag = 0x626B7074; // 'bkpt' + public static final int icSigMediaWhitePointTag = 0x77747074; // 'wtpt' + public static final int icSigNamedColorTag = 0x6E636f6C; // ''ncol' + public static final int icSigNamedColor2Tag = 0x6E636C32; // 'ncl2' + public static final int icSigOutputResponseTag = 0x72657370; // 'resp' + public static final int icSigPreview0Tag = 0x70726530; // 'pre0' + public static final int icSigPreview1Tag = 0x70726531; // 'pre1' + public static final int icSigPreview2Tag = 0x70726532; // 'pre2' + public static final int icSigProfileDescriptionTag = 0x64657363; // 'desc' + public static final int icSigProfileSequenceDescTag = 0x70736571; // 'pseq' + public static final int icSigPs2CRD0Tag = 0x70736430; // 'psd0' + public static final int icSigPs2CRD1Tag = 0x70736431; // 'psd1' + public static final int icSigPs2CRD2Tag = 0x70736432; // 'psd2' + public static final int icSigPs2CRD3Tag = 0x70736433; // 'psd3' + public static final int icSigPs2CSATag = 0x70733273; // 'ps2s' + public static final int icSigPs2RenderingIntentTag = 0x70733269; // 'ps2i' + public static final int icSigRedColorantTag = 0x7258595A; // 'rXYZ' + public static final int icSigRedTRCTag = 0x72545243; // 'rTRC' + public static final int icSigScreeningDescTag = 0x73637264; // 'scrd' + public static final int icSigScreeningTag = 0x7363726E; // 'scrn' + public static final int icSigTechnologyTag = 0x74656368; // 'tech' + public static final int icSigUcrBgTag = 0x62666420; // 'bfd ' + public static final int icSigViewingCondDescTag = 0x76756564; // 'vued' + public static final int icSigViewingConditionsTag = 0x76696577; // 'view' + public static final int icSigChromaticityTag = 0x6368726D; // 'chrm' + + /** + * Non-ICC tag 'head' for use in retrieving the header with getData() + */ + public static final int icSigHead = 0x68656164; + /** + * Header offsets + */ public static final int icHdrSize = 0; public static final int icHdrCmmId = 4; public static final int icHdrVersion = 8; @@ -171,129 +222,1026 @@ public static final int icHdrIlluminant = 68; public static final int icHdrCreator = 80; + /** + * + */ public static final int icTagType = 0; public static final int icTagReserved = 4; public static final int icCurveCount = 8; public static final int icCurveData = 12; - public static final int icXYZNumberX = 8; /** + * offset of the Tag table + */ + private static final int tagTableOffset = 128; + + /** * @serial */ - final int iccProfileSerializedDataVersion = 1; + private final int iccProfileSerializedDataVersion = 1; + + /** + * Constants related to generating profiles for + * built-in colorspace profiles + */ + /** + * Copyright notice to stick into built-in-profile files. + */ + private static final String copyrightNotice = "Generated by GNU Classpath."; + + /** + * Resolution of the TRC to use for predefined profiles. + * 1024 should suffice. + */ + private static final int TRC_POINTS = 1024; + + /** + * CIE 1931 D50 white point (in Lab coordinates) + */ + private static final float[] D50 = { 0.96422f, 1.00f, 0.82521f }; - transient int profileID; + /** + * Color space profile ID + * Set to the predefined profile class (e.g. CS_sRGB) if a predefined + * color space is used, set to -1 otherwise. + * (or if the profile has been modified) + */ + private transient int profileID; + /** + * The profile header data + */ + private transient ProfileHeader header; + + /** + * A hashtable containing the profile tags as TagEntry objects + */ + private transient Hashtable tagTable; + + /** + * Contructor for predefined colorspaces + */ ICC_Profile(int profileID) { - this.profileID = profileID; + header = null; + tagTable = null; + createProfile(profileID); + } + + /** + * Constructs an ICC_Profile from a header and a table of loaded tags. + */ + ICC_Profile(ProfileHeader h, Hashtable tags) throws IllegalArgumentException + { + header = h; + tagTable = tags; + profileID = -1; // Not a predefined color space } + /** + * Constructs an ICC_Profile from a byte array of data. + */ + ICC_Profile(byte[] data) throws IllegalArgumentException + { + // get header and verify it + header = new ProfileHeader(data); + header.verifyHeader(data.length); + tagTable = createTagTable(data); + profileID = -1; // Not a predefined color space + } + + /** + * Free up the used memory. + */ protected void finalize() { - // XXX What resources should we free? + header = null; + tagTable = null; } + /** + * Returns an ICC_Profile instance from a byte array of profile data. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * + * @param data - the profile data + * @return An ICC_Profile object + */ public static ICC_Profile getInstance(byte[] data) { - throw new Error("not implemented"); + ProfileHeader header = new ProfileHeader(data); + + // verify it as a correct ICC header, including size + header.verifyHeader(data.length); + + Hashtable tags = createTagTable(data); + + if (isRGBProfile(header, tags)) + return new ICC_ProfileRGB(data); + if (isGrayProfile(header, tags)) + return new ICC_ProfileGray(data); + + return new ICC_Profile(header, tags); } + /** + * Returns an predefined ICC_Profile instance. + * + * This will construct an ICC_Profile instance from one of the predefined + * color spaces in the ColorSpace class. (e.g. CS_sRGB, CS_GRAY, etc) + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @return An ICC_Profile object + */ public static ICC_Profile getInstance(int cspace) { + if (cspace == ColorSpace.CS_sRGB || cspace == ColorSpace.CS_LINEAR_RGB) + return new ICC_ProfileRGB(cspace); + if (cspace == ColorSpace.CS_GRAY) + return new ICC_ProfileGray(cspace); return new ICC_Profile(cspace); } - public static ICC_Profile getInstance(String filename) throws IOException + /** + * Returns an ICC_Profile instance from an ICC Profile file. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * @throws IOException if the file could not be read. + * + * @param filename - the file name of the profile file. + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(String filename) + throws IOException { return getInstance(new FileInputStream(filename)); } - public static ICC_Profile getInstance(InputStream in) throws IOException + /** + * Returns an ICC_Profile instance from an InputStream. + * + * This method can be used for reading ICC profiles embedded in files + * which support this. (JPEG and SVG for instance). + * + * The stream is treated in the following way: The profile header + * (128 bytes) is read first, and the header is validated. If the profile + * header is valid, it will then attempt to read the rest of the profile + * from the stream. The stream is not closed after reading. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * @throws IOException if the stream could not be read. + * + * @param in - the input stream to read the profile from. + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(InputStream in) + throws IOException { - throw new Error("not implemented"); + // read the header + byte[] headerData = new byte[ProfileHeader.HEADERSIZE]; + if (in.read(headerData) != ProfileHeader.HEADERSIZE) + throw new IllegalArgumentException("Invalid profile header"); + + ProfileHeader header = new ProfileHeader(headerData); + + // verify it as a correct ICC header, but do not verify the + // size as we are reading from a stream. + header.verifyHeader(-1); + + // get the size + byte[] data = new byte[header.getSize()]; + System.arraycopy(headerData, 0, data, 0, ProfileHeader.HEADERSIZE); + + // read the rest + if (in.read(data, ProfileHeader.HEADERSIZE, + header.getSize() - ProfileHeader.HEADERSIZE) != header.getSize() + - ProfileHeader.HEADERSIZE) + throw new IOException("Incorrect profile size"); + + return getInstance(data); } + /** + * Returns the major version number + */ public int getMajorVersion() { - throw new Error("not implemented"); + return header.getMajorVersion(); } + /** + * Returns the minor version number. + * + * Only the least-significant byte contains data, in BCD form: + * the least-significant nibble is the BCD bug fix revision, + * the most-significant nibble is the BCD minor revision number. + * + * (E.g. For a v2.1.0 profile this will return0x10
)
+ */
public int getMinorVersion()
{
- throw new Error("not implemented");
+ return header.getMinorVersion();
}
+ /**
+ * Returns the device class of this profile,
+ *
+ * (E.g. CLASS_INPUT for a scanner profile,
+ * CLASS_OUTPUT for a printer)
+ */
public int getProfileClass()
{
- throw new Error("not implemented");
+ return header.getProfileClass();
}
+ /**
+ * Returns the color space of this profile, in terms
+ * of the color space constants defined in ColorSpace.
+ * (For example, it may be a ColorSpace.TYPE_RGB)
+ */
public int getColorSpaceType()
{
- throw new Error("not implemented");
+ return header.getColorSpace();
}
+ /**
+ * Returns the color space of this profile's Profile Connection Space (OCS)
+ *
+ * In terms of the color space constants defined in ColorSpace.
+ * This may be TYPE_XYZ or TYPE_Lab
+ */
public int getPCSType()
{
- throw new Error("not implemented");
+ return header.getProfileColorSpace();
}
+ /**
+ * Writes the profile data to an ICC profile file.
+ * @param filename - The name of the file to write
+ * @throws IOException if the write failed.
+ */
public void write(String filename) throws IOException
{
- write(new FileOutputStream(filename));
+ FileOutputStream out = new FileOutputStream(filename);
+ write(out);
+ out.flush();
+ out.close();
}
+ /**
+ * Writes the profile data in ICC profile file-format to a stream.
+ * This is useful for embedding ICC profiles in file formats which
+ * support this (such as JPEG and SVG).
+ *
+ * The stream is not closed after writing.
+ * @param out - The outputstream to which the profile data should be written
+ * @throws IOException if the write failed.
+ */
public void write(OutputStream out) throws IOException
{
- throw new Error("not implemented");
+ out.write(getData());
}
+ /**
+ * Returns the data corresponding to this ICC_Profile as a byte array.
+ *
+ * @return The data in a byte array,
+ * where the first element corresponds to first byte of the profile file.
+ */
public byte[] getData()
{
- throw new Error("not implemented");
+ int size = getSize();
+ byte[] data = new byte[size];
+
+ // Header
+ System.arraycopy(header.getData(size), 0, data, 0, ProfileHeader.HEADERSIZE);
+ // # of tags
+ byte[] tt = getTagTable();
+ System.arraycopy(tt, 0, data, ProfileHeader.HEADERSIZE, tt.length);
+
+ Enumeration e = tagTable.elements();
+ while (e.hasMoreElements())
+ {
+ TagEntry tag = (TagEntry) e.nextElement();
+ System.arraycopy(tag.getData(), 0,
+ data, tag.getOffset(), tag.getSize());
+ }
+ return data;
}
+ /**
+ * Returns the ICC profile tag data
+ * The non ICC-tag icSigHead is also permitted to request the header data.
+ *
+ * @param tagSignature The ICC signature of the requested tag
+ * @return A byte array containing the tag data
+ */
public byte[] getData(int tagSignature)
{
- throw new Error("not implemented");
+ if (tagSignature == icSigHead)
+ return header.getData(getSize());
+
+ TagEntry t = (TagEntry) tagTable.get(TagEntry.tagHashKey(tagSignature));
+ if (t == null)
+ return null;
+ return t.getData();
}
+ /**
+ * Sets the ICC profile tag data.
+ *
+ * Note that an ICC profile can only contain one tag of each type, if
+ * a tag already exists with the given signature, it is replaced.
+ *
+ * @param tagSignature - The signature of the tag to set
+ * @param data - A byte array containing the tag data
+ */
public void setData(int tagSignature, byte[] data)
{
- throw new Error("not implemented");
+ profileID = -1; // Not a predefined color space if modified.
+
+ if (tagSignature == icSigHead)
+ header = new ProfileHeader(data);
+ else
+ {
+ TagEntry t = new TagEntry(tagSignature, data);
+ tagTable.put(t.hashKey(), t);
+ }
}
+ /**
+ * Get the number of components in the profile's device color space.
+ */
public int getNumComponents()
{
- switch (profileID)
+ int[] lookup =
+ {
+ ColorSpace.TYPE_RGB, 3, ColorSpace.TYPE_CMY, 3,
+ ColorSpace.TYPE_CMYK, 4, ColorSpace.TYPE_GRAY, 1,
+ ColorSpace.TYPE_YCbCr, 3, ColorSpace.TYPE_XYZ, 3,
+ ColorSpace.TYPE_Lab, 3, ColorSpace.TYPE_HSV, 3,
+ ColorSpace.TYPE_2CLR, 2, ColorSpace.TYPE_Luv, 3,
+ ColorSpace.TYPE_Yxy, 3, ColorSpace.TYPE_HLS, 3,
+ ColorSpace.TYPE_3CLR, 3, ColorSpace.TYPE_4CLR, 4,
+ ColorSpace.TYPE_5CLR, 5, ColorSpace.TYPE_6CLR, 6,
+ ColorSpace.TYPE_7CLR, 7, ColorSpace.TYPE_8CLR, 8,
+ ColorSpace.TYPE_9CLR, 9, ColorSpace.TYPE_ACLR, 10,
+ ColorSpace.TYPE_BCLR, 11, ColorSpace.TYPE_CCLR, 12,
+ ColorSpace.TYPE_DCLR, 13, ColorSpace.TYPE_ECLR, 14,
+ ColorSpace.TYPE_FCLR, 15
+ };
+ for (int i = 0; i < lookup.length; i += 2)
+ if (header.getColorSpace() == lookup[i])
+ return lookup[i + 1];
+ return 3; // should never happen.
+ }
+
+ /**
+ * After deserializing we must determine if the class we want
+ * is really one of the more specialized ICC_ProfileRGB or
+ * ICC_ProfileGray classes.
+ */
+ protected Object readResolve() throws ObjectStreamException
+ {
+ if (isRGBProfile(header, tagTable))
+ return new ICC_ProfileRGB(getData());
+ if (isGrayProfile(header, tagTable))
+ return new ICC_ProfileGray(getData());
+ return this;
+ }
+
+ /**
+ * Deserializes an instance
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ String predef = (String) s.readObject();
+ byte[] data = (byte[]) s.readObject();
+
+ if (data != null)
+ {
+ header = new ProfileHeader(data);
+ tagTable = createTagTable(data);
+ profileID = -1; // Not a predefined color space
+ }
+
+ if (predef != null)
+ {
+ predef = predef.intern();
+ if (predef.equals("CS_sRGB"))
+ createProfile(ColorSpace.CS_sRGB);
+ if (predef.equals("CS_LINEAR_RGB"))
+ createProfile(ColorSpace.CS_LINEAR_RGB);
+ if (predef.equals("CS_CIEXYZ"))
+ createProfile(ColorSpace.CS_CIEXYZ);
+ if (predef.equals("CS_GRAY"))
+ createProfile(ColorSpace.CS_GRAY);
+ if (predef.equals("CS_PYCC"))
+ createProfile(ColorSpace.CS_PYCC);
+ }
+ }
+
+ /**
+ * Serializes an instance
+ * The format is a String and a byte array,
+ * The string is non-null if the instance is one of the built-in profiles.
+ * Otherwise the byte array is non-null and represents the profile data.
+ */
+ private void writeObject(ObjectOutputStream s) throws IOException
+ {
+ s.defaultWriteObject();
+ if (profileID == ColorSpace.CS_sRGB)
+ s.writeObject("CS_sRGB");
+ else if (profileID == ColorSpace.CS_LINEAR_RGB)
+ s.writeObject("CS_LINEAR_RGB");
+ else if (profileID == ColorSpace.CS_CIEXYZ)
+ s.writeObject("CS_CIEXYZ");
+ else if (profileID == ColorSpace.CS_GRAY)
+ s.writeObject("CS_GRAY");
+ else if (profileID == ColorSpace.CS_PYCC)
+ s.writeObject("CS_PYCC");
+ else
+ {
+ s.writeObject(null); // null string
+ s.writeObject(getData()); // data
+ return;
+ }
+ s.writeObject(null); // null data
+ }
+
+ /**
+ * Sorts a ICC profile byte array into TagEntry objects stored in
+ * a hash table.
+ */
+ private static Hashtable createTagTable(byte[] data)
+ throws IllegalArgumentException
+ {
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ int nTags = buf.getInt(tagTableOffset);
+
+ Hashtable tagTable = new Hashtable();
+ for (int i = 0; i < nTags; i++)
+ {
+ TagEntry te = new TagEntry(buf.getInt(tagTableOffset
+ + i * TagEntry.entrySize + 4),
+ buf.getInt(tagTableOffset
+ + i * TagEntry.entrySize + 8),
+ buf.getInt(tagTableOffset
+ + i * TagEntry.entrySize + 12),
+ data);
+
+ // System.out.println("Tag:"+te);
+ if (tagTable.put(te.hashKey(), te) != null)
+ throw new IllegalArgumentException("Duplicate tag in profile:" + te);
+ }
+ return tagTable;
+ }
+
+ /**
+ * Returns the total size of the padded, stored data
+ * Note: Tags must be stored on 4-byte aligned offsets.
+ */
+ private int getSize()
+ {
+ int totalSize = ProfileHeader.HEADERSIZE; // size of header
+
+ int tagTableSize = 4 + tagTable.size() * TagEntry.entrySize; // size of tag table
+ if ((tagTableSize & 0x0003) != 0)
+ tagTableSize += 4 - (tagTableSize & 0x0003); // pad
+ totalSize += tagTableSize;
+
+ Enumeration e = tagTable.elements();
+ while (e.hasMoreElements())
+ { // tag data
+ int tagSize = ((TagEntry) e.nextElement()).getSize();
+ if ((tagSize & 0x0003) != 0)
+ tagSize += 4 - (tagSize & 0x0003); // pad
+ totalSize += tagSize;
+ }
+ return totalSize;
+ }
+
+ /**
+ * Generates the tag index table
+ */
+ private byte[] getTagTable()
+ {
+ int tagTableSize = 4 + tagTable.size() * TagEntry.entrySize;
+ if ((tagTableSize & 0x0003) != 0)
+ tagTableSize += 4 - (tagTableSize & 0x0003); // pad
+
+ int offset = 4;
+ int tagOffset = ProfileHeader.HEADERSIZE + tagTableSize;
+ ByteBuffer buf = ByteBuffer.allocate(tagTableSize);
+ buf.putInt(tagTable.size()); // number of tags
+
+ Enumeration e = tagTable.elements();
+ while (e.hasMoreElements())
+ {
+ TagEntry tag = (TagEntry) e.nextElement();
+ buf.putInt(offset, tag.getSignature());
+ buf.putInt(offset + 4, tagOffset);
+ buf.putInt(offset + 8, tag.getSize());
+ tag.setOffset(tagOffset);
+ int tagSize = tag.getSize();
+ if ((tagSize & 0x0003) != 0)
+ tagSize += 4 - (tagSize & 0x0003); // pad
+ tagOffset += tagSize;
+ offset += 12;
+ }
+ return buf.array();
+ }
+
+ /**
+ * Returns if the criteria for an ICC_ProfileRGB are met.
+ * This means:
+ * Color space is TYPE_RGB
+ * (r,g,b)ColorantTags included
+ * (r,g,b)TRCTags included
+ * mediaWhitePointTag included
+ */
+ private static boolean isRGBProfile(ProfileHeader header, Hashtable tags)
+ {
+ if (header.getColorSpace() != ColorSpace.TYPE_RGB)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigRedColorantTag)) == null)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigGreenColorantTag)) == null)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigBlueColorantTag)) == null)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigRedTRCTag)) == null)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigGreenTRCTag)) == null)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigBlueTRCTag)) == null)
+ return false;
+ return (tags.get(TagEntry.tagHashKey(icSigMediaWhitePointTag)) != null);
+ }
+
+ /**
+ * Returns if the criteria for an ICC_ProfileGray are met.
+ * This means:
+ * Colorspace is TYPE_GRAY
+ * grayTRCTag included
+ * mediaWhitePointTag included
+ */
+ private static boolean isGrayProfile(ProfileHeader header, Hashtable tags)
+ {
+ if (header.getColorSpace() != ColorSpace.TYPE_GRAY)
+ return false;
+ if (tags.get(TagEntry.tagHashKey(icSigGrayTRCTag)) == null)
+ return false;
+ return (tags.get(TagEntry.tagHashKey(icSigMediaWhitePointTag)) != null);
+ }
+
+ /**
+ * Returns curve data for a 'curv'-type tag
+ * If it's a gamma curve, a singly entry will be returned with the
+ * gamma value (including 1.0 for linear response)
+ * Otherwise the TRC table is returned.
+ *
+ * (Package private - used by ICC_ProfileXYZ and ICC_ProfileGray)
+ */
+ short[] getCurve(int signature)
+ {
+ byte[] data = getData(signature);
+ short[] curve;
+
+ // can't find tag?
+ if (data == null)
+ return null;
+
+ // not an curve type tag?
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ if (buf.getInt(0) != 0x63757276) // 'curv' type
+ return null;
+ int count = buf.getInt(8);
+ if (count == 0)
+ {
+ curve = new short[1];
+ curve[0] = 0x0100; // 1.00 in u8fixed8
+ return curve;
+ }
+ if (count == 1)
+ {
+ curve = new short[1];
+ curve[0] = buf.getShort(12); // other u8fixed8 gamma
+ return curve;
+ }
+ curve = new short[count];
+ for (int i = 0; i < count; i++)
+ curve[i] = buf.getShort(12 + i * 2);
+ return curve;
+ }
+
+ /**
+ * Returns XYZ tristimulus values for an 'XYZ ' type tag
+ * @return the XYZ values, or null if the tag was not an 'XYZ ' type tag.
+ *
+ * (Package private - used by ICC_ProfileXYZ and ICC_ProfileGray)
+ */
+ float[] getXYZData(int signature)
+ {
+ byte[] data = getData(signature);
+
+ // can't find tag?
+ if (data == null)
+ return null;
+
+ // not an XYZData type tag?
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ if (buf.getInt(0) != icSigXYZData) // 'XYZ ' type
+ return null;
+
+ float[] point = new float[3];
+
+ // get the X,Y,Z tristimulus values
+ point[0] = ((float) buf.getInt(8)) / 65536f;
+ point[1] = ((float) buf.getInt(12)) / 65536f;
+ point[2] = ((float) buf.getInt(16)) / 65536f;
+ return point;
+ }
+
+ /**
+ * Returns the profile ID if it's a predefined profile
+ * Or -1 for a profile loaded from an ICC profile
+ *
+ * (Package private - used by ICC_ColorSpace)
+ */
+ int isPredefined()
+ {
+ return profileID;
+ }
+
+ /**
+ * Creates a tag of XYZ-value type.
+ */
+ private byte[] makeXYZData(float[] values)
+ {
+ ByteBuffer buf = ByteBuffer.allocate(20);
+ buf.putInt(0, icSigXYZData); // 'XYZ '
+ buf.putInt(4, 0);
+ buf.putInt(8, (int) (values[0] * 65536.0));
+ buf.putInt(12, (int) (values[1] * 65536.0));
+ buf.putInt(16, (int) (values[2] * 65536.0));
+ return buf.array();
+ }
+
+ /**
+ * Creates a tag of text type
+ */
+ private byte[] makeTextTag(String text)
+ {
+ int length = text.length();
+ ByteBuffer buf = ByteBuffer.allocate(8 + length + 1);
+ byte[] data;
+ try
+ {
+ data = text.getBytes("US-ASCII");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ data = new byte[length]; // shouldn't happen
+ }
+
+ buf.putInt(0, (int) 0x74657874); // 'text'
+ buf.putInt(4, 0);
+ for (int i = 0; i < length; i++)
+ buf.put(8 + i, data[i]);
+ buf.put(8 + length, (byte) 0); // null-terminate
+ return buf.array();
+ }
+
+ /**
+ * Creates a tag of textDescriptionType
+ */
+ private byte[] makeDescTag(String text)
+ {
+ int length = text.length();
+ ByteBuffer buf = ByteBuffer.allocate(90 + length + 1);
+ buf.putInt(0, (int) 0x64657363); // 'desc'
+ buf.putInt(4, 0); // reserved
+ buf.putInt(8, length + 1); // ASCII length, including null termination
+ byte[] data;
+
+ try
+ {
+ data = text.getBytes("US-ASCII");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ data = new byte[length]; // shouldn't happen
+ }
+
+ for (int i = 0; i < length; i++)
+ buf.put(12 + i, data[i]);
+ buf.put(12 + length, (byte) 0); // null-terminate
+
+ for (int i = 0; i < 39; i++)
+ buf.putShort(13 + length + (i * 2), (short) 0); // 78 bytes we can ignore
+
+ return buf.array();
+ }
+
+ /**
+ * Creates a tag of TRC type (linear curve)
+ */
+ private byte[] makeTRC()
+ {
+ ByteBuffer buf = ByteBuffer.allocate(12);
+ buf.putInt(0, 0x63757276); // 'curv' type
+ buf.putInt(4, 0); // reserved
+ buf.putInt(8, 0);
+ return buf.array();
+ }
+
+ /**
+ * Creates a tag of TRC type (single gamma value)
+ */
+ private byte[] makeTRC(float gamma)
+ {
+ short gammaValue = (short) (gamma * 256f);
+ ByteBuffer buf = ByteBuffer.allocate(14);
+ buf.putInt(0, 0x63757276); // 'curv' type
+ buf.putInt(4, 0); // reserved
+ buf.putInt(8, 1);
+ buf.putShort(12, gammaValue); // 1.00 in u8fixed8
+ return buf.array();
+ }
+
+ /**
+ * Creates a tag of TRC type (TRC curve points)
+ */
+ private byte[] makeTRC(float[] trc)
+ {
+ ByteBuffer buf = ByteBuffer.allocate(12 + 2 * trc.length);
+ buf.putInt(0, 0x63757276); // 'curv' type
+ buf.putInt(4, 0); // reserved
+ buf.putInt(8, trc.length); // number of points
+
+ // put the curve values
+ for (int i = 0; i < trc.length; i++)
+ buf.putShort(12 + i * 2, (short) (trc[i] * 65535f));
+
+ return buf.array();
+ }
+
+ /**
+ * Creates an identity color lookup table.
+ */
+ private byte[] makeIdentityClut()
+ {
+ final int nIn = 3;
+ final int nOut = 3;
+ final int nInEntries = 256;
+ final int nOutEntries = 256;
+ final int gridpoints = 16;
+
+ // gridpoints**nIn
+ final int clutSize = 2 * nOut * gridpoints * gridpoints * gridpoints;
+ final int totalSize = clutSize + 2 * nInEntries * nIn
+ + 2 * nOutEntries * nOut + 52;
+
+ ByteBuffer buf = ByteBuffer.allocate(totalSize);
+ buf.putInt(0, 0x6D667432); // 'mft2'
+ buf.putInt(4, 0); // reserved
+ buf.put(8, (byte) nIn); // number input channels
+ buf.put(9, (byte) nOut); // number output channels
+ buf.put(10, (byte) gridpoints); // number gridpoints
+ buf.put(11, (byte) 0); // padding
+
+ // identity matrix
+ buf.putInt(12, 65536); // = 1 in s15.16 fixed point
+ buf.putInt(16, 0);
+ buf.putInt(20, 0);
+ buf.putInt(24, 0);
+ buf.putInt(28, 65536);
+ buf.putInt(32, 0);
+ buf.putInt(36, 0);
+ buf.putInt(40, 0);
+ buf.putInt(44, 65536);
+
+ buf.putShort(48, (short) nInEntries); // input table entries
+ buf.putShort(50, (short) nOutEntries); // output table entries
+
+ // write the linear input channels, unsigned 16.16 fixed point,
+ // from 0.0 to FF.FF
+ for (int channel = 0; channel < 3; channel++)
+ for (int i = 0; i < nInEntries; i++)
+ {
+ short n = (short) ((i << 8) | i); // assumes 256 entries
+ buf.putShort(52 + (channel * nInEntries + i) * 2, n);
+ }
+ int clutOffset = 52 + nInEntries * nIn * 2;
+
+ for (int x = 0; x < gridpoints; x++)
+ for (int y = 0; y < gridpoints; y++)
+ for (int z = 0; z < gridpoints; z++)
+ {
+ int offset = clutOffset + z * 2 * nOut + y * gridpoints * 2 * nOut
+ + x * gridpoints * gridpoints * 2 * nOut;
+ double xf = ((double) x) / ((double) gridpoints - 1.0);
+ double yf = ((double) y) / ((double) gridpoints - 1.0);
+ double zf = ((double) z) / ((double) gridpoints - 1.0);
+ buf.putShort(offset, (short) (xf * 65535.0));
+ buf.putShort(offset + 2, (short) (yf * 65535.0));
+ buf.putShort(offset + 4, (short) (zf * 65535.0));
+ }
+
+ for (int channel = 0; channel < 3; channel++)
+ for (int i = 0; i < nOutEntries; i++)
+ {
+ short n = (short) ((i << 8) | i); // assumes 256 entries
+ buf.putShort(clutOffset + clutSize + (channel * nOutEntries + i) * 2,
+ n);
+ }
+
+ return buf.array();
+ }
+
+ /**
+ * Creates profile data corresponding to the built-in colorspaces.
+ */
+ private void createProfile(int colorSpace) throws IllegalArgumentException
+ {
+ this.profileID = colorSpace;
+ header = new ProfileHeader();
+ tagTable = new Hashtable();
+
+ switch (colorSpace)
{
case ColorSpace.CS_sRGB:
+ createRGBProfile();
+ return;
case ColorSpace.CS_LINEAR_RGB:
+ createLinearRGBProfile();
+ return;
case ColorSpace.CS_CIEXYZ:
- return 3;
+ createCIEProfile();
+ return;
case ColorSpace.CS_GRAY:
- return 1;
- case ColorSpace.CS_PYCC: // have no clue about this one
+ createGrayProfile();
+ return;
+ case ColorSpace.CS_PYCC:
+ createPyccProfile();
+ return;
default:
- throw new UnsupportedOperationException("profile not implemented");
+ throw new IllegalArgumentException("Not a predefined color space!");
}
}
- protected Object readResolve() throws ObjectStreamException
+ /**
+ * Creates an ICC_Profile representing the sRGB color space
+ */
+ private void createRGBProfile()
{
- throw new Error("not implemented");
+ header.setColorSpace( ColorSpace.TYPE_RGB );
+ header.setProfileColorSpace( ColorSpace.TYPE_XYZ );
+ ICC_ColorSpace cs = new ICC_ColorSpace(this);
+
+ float[] r = { 1f, 0f, 0f };
+ float[] g = { 0f, 1f, 0f };
+ float[] b = { 0f, 0f, 1f };
+ float[] black = { 0f, 0f, 0f };
+
+ // CIE 1931 D50 white point (in Lab coordinates)
+ float[] white = D50;
+
+ // Get tristimulus values (matrix elements)
+ r = cs.toCIEXYZ(r);
+ g = cs.toCIEXYZ(g);
+ b = cs.toCIEXYZ(b);
+
+ // Generate the sRGB TRC curve, this is the linear->nonlinear
+ // RGB transform.
+ cs = new ICC_ColorSpace(getInstance(ICC_ColorSpace.CS_LINEAR_RGB));
+ float[] points = new float[TRC_POINTS];
+ float[] in = new float[3];
+ for (int i = 0; i < TRC_POINTS; i++)
+ {
+ in[0] = in[1] = in[2] = ((float) i) / ((float) TRC_POINTS - 1);
+ in = cs.fromRGB(in);
+ // Note this value is the same for all components.
+ points[i] = in[0];
+ }
+
+ setData(icSigRedColorantTag, makeXYZData(r));
+ setData(icSigGreenColorantTag, makeXYZData(g));
+ setData(icSigBlueColorantTag, makeXYZData(b));
+ setData(icSigMediaWhitePointTag, makeXYZData(white));
+ setData(icSigMediaBlackPointTag, makeXYZData(black));
+ setData(icSigRedTRCTag, makeTRC(points));
+ setData(icSigGreenTRCTag, makeTRC(points));
+ setData(icSigBlueTRCTag, makeTRC(points));
+ setData(icSigCopyrightTag, makeTextTag(copyrightNotice));
+ setData(icSigProfileDescriptionTag, makeDescTag("Generic sRGB"));
+ this.profileID = ColorSpace.CS_sRGB;
}
- private void readObject(ObjectInputStream s)
- throws IOException, ClassNotFoundException
+ /**
+ * Creates an linear sRGB profile
+ */
+ private void createLinearRGBProfile()
{
- throw new Error("not implemented");
+ header.setColorSpace(ColorSpace.TYPE_RGB);
+ header.setProfileColorSpace(ColorSpace.TYPE_XYZ);
+ ICC_ColorSpace cs = new ICC_ColorSpace(this);
+
+ float[] r = { 1f, 0f, 0f };
+ float[] g = { 0f, 1f, 0f };
+ float[] b = { 0f, 0f, 1f };
+ float[] black = { 0f, 0f, 0f };
+
+ float[] white = D50;
+
+ // Get tristimulus values (matrix elements)
+ r = cs.toCIEXYZ(r);
+ g = cs.toCIEXYZ(g);
+ b = cs.toCIEXYZ(b);
+
+ setData(icSigRedColorantTag, makeXYZData(r));
+ setData(icSigGreenColorantTag, makeXYZData(g));
+ setData(icSigBlueColorantTag, makeXYZData(b));
+
+ setData(icSigMediaWhitePointTag, makeXYZData(white));
+ setData(icSigMediaBlackPointTag, makeXYZData(black));
+
+ setData(icSigRedTRCTag, makeTRC());
+ setData(icSigGreenTRCTag, makeTRC());
+ setData(icSigBlueTRCTag, makeTRC());
+ setData(icSigCopyrightTag, makeTextTag(copyrightNotice));
+ setData(icSigProfileDescriptionTag, makeDescTag("Linear RGB"));
+ this.profileID = ColorSpace.CS_LINEAR_RGB;
}
- private void writeObject(ObjectOutputStream s) throws IOException
+ /**
+ * Creates an CIE XYZ identity profile
+ */
+ private void createCIEProfile()
+ {
+ header.setColorSpace( ColorSpace.TYPE_XYZ );
+ header.setProfileColorSpace( ColorSpace.TYPE_XYZ );
+ header.setProfileClass( CLASS_COLORSPACECONVERSION );
+ ICC_ColorSpace cs = new ICC_ColorSpace(this);
+
+ float[] white = D50;
+
+ setData(icSigMediaWhitePointTag, makeXYZData(white));
+ setData(icSigAToB0Tag, makeIdentityClut());
+ setData(icSigBToA0Tag, makeIdentityClut());
+ setData(icSigCopyrightTag, makeTextTag(copyrightNotice));
+ setData(icSigProfileDescriptionTag, makeDescTag("CIE XYZ identity profile"));
+ this.profileID = ColorSpace.CS_CIEXYZ;
+ }
+
+ /**
+ * Creates a linear gray ICC_Profile
+ */
+ private void createGrayProfile()
+ {
+ header.setColorSpace(ColorSpace.TYPE_GRAY);
+ header.setProfileColorSpace(ColorSpace.TYPE_XYZ);
+
+ // CIE 1931 D50 white point (in Lab coordinates)
+ float[] white = D50;
+
+ setData(icSigMediaWhitePointTag, makeXYZData(white));
+ setData(icSigGrayTRCTag, makeTRC(1.0f));
+ setData(icSigCopyrightTag, makeTextTag(copyrightNotice));
+ setData(icSigProfileDescriptionTag, makeDescTag("Linear grayscale"));
+ this.profileID = ColorSpace.CS_GRAY;
+ }
+
+ /**
+ * XXX Implement me
+ */
+ private void createPyccProfile()
{
- throw new Error("not implemented");
+ header.setColorSpace(ColorSpace.TYPE_3CLR);
+ header.setProfileColorSpace(ColorSpace.TYPE_XYZ);
+
+ // Create CLUTs here. :-)
+
+ setData(icSigCopyrightTag, makeTextTag(copyrightNotice));
+ setData(icSigProfileDescriptionTag, makeDescTag("Photo YCC"));
+ this.profileID = ColorSpace.CS_PYCC;
}
} // class ICC_Profile
Index: java/awt/color/ICC_ProfileGray.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/awt/color/ICC_ProfileGray.java,v
retrieving revision 1.1
diff -u -r1.1 ICC_ProfileGray.java
--- java/awt/color/ICC_ProfileGray.java 7 Nov 2002 15:40:04 -0000 1.1
+++ java/awt/color/ICC_ProfileGray.java 26 Oct 2004 12:57:11 -0000
@@ -1,45 +1,60 @@
/* ICC_ProfileGray.java -- the ICC profile for a Gray colorspace
Copyright (C) 2002 Free Software Foundation, Inc.
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
+ This file is part of GNU Classpath.
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
package java.awt.color;
+
/**
- * STUBBED
+ * ICC_ProfileGray - a special case of ICC_Profiles.
+ *
+ * The ICC_Profile.getInstance() method will return an instance of the
+ * ICC_ProfileGray subclass when all the following conditions are met:
+ * The device color space of the profile is TYPE_GRAY.
+ * The profile contains a gray TRCTag.
+ * The profile contains a mediaWhitePointTag.
+ *
+ * As per the ICC specification, the color space conversion can then
+ * be done through the following method:
+ * linearGray = grayTRC[deviceGray]
+ *
+ * Note that if the profile contains a CLUT for the color space conversion,
+ * it should be used instead, and the TRC information ignored.
+ *
+ * @author Sven de Marothy
* @since 1.2
*/
public class ICC_ProfileGray extends ICC_Profile
@@ -48,24 +63,71 @@
* Compatible with JDK 1.2+.
*/
private static final long serialVersionUID = -1124721290732002649L;
+ private transient float[] whitePoint;
+
+ /**
+ * Package-private constructor used by ICC_ColorSpace for creating an
+ * ICC_ProfileRGB from a predefined ColorSpace (CS_GRAY)
+ */
+ ICC_ProfileGray(int cspace)
+ {
+ super(cspace);
+ whitePoint = getXYZData(icSigMediaWhitePointTag);
+ }
- ICC_ProfileGray()
+ /**
+ * Package-private constructor used by ICC_ColorSpace for creating an
+ * ICC_ProfileGray from profile data.
+ */
+ ICC_ProfileGray(byte[] data)
{
- super(ColorSpace.CS_GRAY);
+ super(data);
+ whitePoint = getXYZData(icSigMediaWhitePointTag);
}
+
+ /**
+ * Returns the media white point of the profile.
+ */
public float[] getMediaWhitePoint()
{
- return null;
+ float[] wp = new float[3];
+ wp[0] = whitePoint[0];
+ wp[1] = whitePoint[1];
+ wp[2] = whitePoint[2];
+ return wp;
}
+ /**
+ * Returns the TRC gamma value.
+ * @throws IllegalArgumentException if the TRC is described by a lookup
+ * table and not a gamma value.
+ */
public float getGamma()
{
- return 0;
+ short[] data = getCurve(icSigGrayTRCTag);
+ if (data == null)
+ throw new IllegalArgumentException("Couldn't read Gray TRC data.");
+ if (data.length != 1)
+ throw new ProfileDataException("TRC is a table, not a gamma value.");
+
+ // convert the unsigned 7.8 fixed-point gamma to a float.
+ double gamma = (double) (data[0] & (0xFFFF)) / 256.0;
+ return (float) gamma;
}
+ /**
+ * Returns the TRC lookup table.
+ * @throws IllegalArgumentException if the TRC is described by a gamma value
+ * and not a lookup table.
+ */
public short[] getTRC()
{
- return null;
+ short[] data = getCurve(icSigGrayTRCTag);
+ if (data == null)
+ throw new IllegalArgumentException("Couldn't read Gray TRC data.");
+ if (data.length <= 1)
+ throw new ProfileDataException("Gamma value, not a TRC table.");
+ return data;
}
} // class ICC_ProfileGray
Index: java/awt/color/ICC_ProfileRGB.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/awt/color/ICC_ProfileRGB.java,v
retrieving revision 1.1
diff -u -r1.1 ICC_ProfileRGB.java
--- java/awt/color/ICC_ProfileRGB.java 7 Nov 2002 15:40:04 -0000 1.1
+++ java/awt/color/ICC_ProfileRGB.java 26 Oct 2004 12:57:11 -0000
@@ -1,45 +1,74 @@
/* ICC_ProfileRGB.java -- the ICC profile for a RGB colorspace
Copyright (C) 2002 Free Software Foundation, Inc.
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
+ This file is part of GNU Classpath.
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
package java.awt.color;
+import java.nio.ByteBuffer;
+
+
/**
- * STUBBED
+ * ICC_ProfileRGB - a special case of ICC_Profiles.
+ *
+ * The ICC_Profile.getInstance() method will return an instance of the
+ * ICC_ProfileRGB subclass when all the following conditions are met:
+ * The device color space of the profile is TYPE_RGB.
+ * The profile contains red, green and blue ColorantTags.
+ * The profile contains red, green and blue TRCTags.
+ * The profile contains a mediaWhitePointTag included.
+ *
+ * As per the ICC specification, the color space conversion can then
+ * be done through the following method:
+ * linearR = redTRC[deviceR]
+ * linearG = greenTRC[deviceG]
+ * linearB = blueTRC[deviceB]
+ * TRC curves are either a single gamma value, or a 1-dimensional lookup table.
+ *
+ * Followed by the matrix transform:
+ * PCS = M*linear
+ *
+ * Where PCS is the vector of profile color space (must be XYZ) coordinates,
+ * linear is the vector of linear RGB coordinates, and the matrix M is
+ * constructed from the ColorantTags, where the columns are red, green and
+ * blue respectively, and the rows are X, Y and Z.
+ *
+ * Note that if the profile contains a CLUT for the color space conversion,
+ * it should be used instead, and the TRC information ignored.
+ *
+ * @author Sven de Marothy
* @since 1.2
*/
public class ICC_ProfileRGB extends ICC_Profile
@@ -50,31 +79,151 @@
private static final long serialVersionUID = 8505067385152579334L;
public static final int REDCOMPONENT = 0;
+
public static final int GREENCOMPONENT = 1;
+
public static final int BLUECOMPONENT = 2;
- ICC_ProfileRGB()
+ private transient float[][] matrix;
+
+ private transient float[] gamma;
+
+ private transient float[] whitePoint;
+
+
+ /**
+ * Package-private constructor used by ICC_ColorSpace for creating an
+ * ICC_ProfileRGB from a predefined ColorSpace (CS_LINEAR_RGB and CS_sRGB)
+ */
+ ICC_ProfileRGB(int cspace)
+ {
+ super(cspace);
+ matrix = createMatrix();
+ whitePoint = getXYZData(icSigMediaWhitePointTag);
+ }
+
+ /**
+ * Package-private constructor used by ICC_ColorSpace for creating an
+ * ICC_ProfileRGB from profile data.
+ */
+ ICC_ProfileRGB(byte[] data)
{
- super(ColorSpace.CS_sRGB);
+ super(data);
+ matrix = createMatrix();
+ whitePoint = getXYZData(icSigMediaWhitePointTag);
}
+ /**
+ * Returns the media white point of the profile.
+ */
public float[] getMediaWhitePoint()
{
- return null;
+ float[] wp = new float[3];
+ wp[0] = whitePoint[0];
+ wp[1] = whitePoint[1];
+ wp[2] = whitePoint[2];
+ return wp;
}
+ /**
+ * Returns the colorant matrix of the conversion.
+ */
public float[][] getMatrix()
{
- return null;
+ float[][] mat = new float[3][3];
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ mat[i][j] = matrix[i][j];
+ return mat;
}
+ /**
+ * Returns the gamma value of a component
+ * @throws IllegalArgumentException if the TRC is described by a lookup
+ * table and not a gamma value.
+ */
public float getGamma(int component)
{
- return 0;
+ short[] data;
+ switch (component)
+ {
+ case REDCOMPONENT:
+ data = getCurve(icSigRedTRCTag);
+ break;
+ case GREENCOMPONENT:
+ data = getCurve(icSigGreenTRCTag);
+ break;
+ case BLUECOMPONENT:
+ data = getCurve(icSigBlueTRCTag);
+ break;
+ default:
+ throw new IllegalArgumentException("Not a valid component");
+ }
+ if (data == null)
+ throw new IllegalArgumentException("Error reading TRC");
+
+ if (data.length != 1)
+ throw new ProfileDataException("Not a single-gamma TRC");
+
+ // convert the unsigned 7.8 fixed-point gamma to a float.
+ float gamma = (float) (((int) data[0] & 0xFF00) >> 8);
+ double fraction = ((int) data[0] & 0x00FF) / 256.0;
+ gamma += (float) fraction;
+ return gamma;
}
+ /**
+ * Returns the TRC lookup table for a component
+ * @throws IllegalArgumentException if the TRC is described by a gamma
+ * value and not a lookup table.
+ */
public short[] getTRC(int component)
{
- return null;
+ short[] data;
+ switch (component)
+ {
+ case REDCOMPONENT:
+ data = getCurve(icSigRedTRCTag);
+ break;
+ case GREENCOMPONENT:
+ data = getCurve(icSigGreenTRCTag);
+ break;
+ case BLUECOMPONENT:
+ data = getCurve(icSigBlueTRCTag);
+ break;
+ default:
+ throw new IllegalArgumentException("Not a valid component");
+ }
+ if (data == null)
+ throw new IllegalArgumentException("Error reading TRC");
+
+ if (data.length <= 1)
+ throw new ProfileDataException("Gamma value, not a TRC table.");
+
+ return data;
+ }
+
+ /**
+ * Creates the colorspace conversion matrix from the RGB tristimulus
+ * values.
+ */
+ private float[][] createMatrix() throws IllegalArgumentException
+ {
+ float[][] mat = new float[3][3];
+ float[] r;
+ float[] g;
+ float[] b;
+ r = getXYZData(icSigRedColorantTag);
+ g = getXYZData(icSigGreenColorantTag);
+ b = getXYZData(icSigBlueColorantTag);
+ if (r == null || g == null || b == null)
+ throw new IllegalArgumentException("Error reading colorant tags!");
+ for (int i = 0; i < 3; i++)
+ {
+ mat[i][0] = r[i];
+ mat[i][1] = g[i];
+ mat[i][2] = b[i];
+ }
+ return mat;
}
} // class ICC_ProfileRGB