001    /* ICC_ColorSpace.java -- the canonical color space implementation
002       Copyright (C) 2000, 2002, 2004 Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt.color;
040    
041    import gnu.java.awt.color.CieXyzConverter;
042    import gnu.java.awt.color.ClutProfileConverter;
043    import gnu.java.awt.color.ColorSpaceConverter;
044    import gnu.java.awt.color.GrayProfileConverter;
045    import gnu.java.awt.color.GrayScaleConverter;
046    import gnu.java.awt.color.LinearRGBConverter;
047    import gnu.java.awt.color.PyccConverter;
048    import gnu.java.awt.color.RgbProfileConverter;
049    import gnu.java.awt.color.SrgbConverter;
050    
051    import java.io.IOException;
052    import java.io.ObjectInputStream;
053    
054    /**
055     * ICC_ColorSpace - an implementation of ColorSpace
056     *
057     * While an ICC_Profile class abstracts the data in an ICC profile file
058     * an ICC_ColorSpace performs the color space conversions defined by
059     * an ICC_Profile instance.
060     *
061     * Typically, an ICC_Profile will either be created using getInstance,
062     * either from the built-in colorspaces, or from an ICC profile file.
063     * Then a ICC_Colorspace will be used to perform transforms from the
064     * device colorspace to and from the profile color space.
065     *
066     * The PCS used by ColorSpace is CIE XYZ relative a D50 white point.
067     * (Profiles using a CIE Lab PCS will have their input and output converted
068     * to D50 CIE XYZ accordingly.
069     *
070     * Note that a valid profile may not contain transforms in both directions,
071     * in which case the output may be undefined.
072     * All built-in colorspaces have bidirectional transforms, but developers
073     * using an ICC profile file may want to check the profile class using
074     * the ICC_Profile.getProfileClass() method. Input class profiles are
075     * guaranteed to have transforms to the PCS, output class profiles are
076     * guaranteed to have transforms from the PCS to device space.
077     *
078     * @author Sven de Marothy
079     * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
080     * @since 1.2
081     */
082    public class ICC_ColorSpace extends ColorSpace
083    {
084      /**
085       * Compatible with JDK 1.2+.
086       */
087      private static final long serialVersionUID = 3455889114070431483L;
088    
089      /**
090       * @serial
091       */
092      private ICC_Profile thisProfile;
093    
094      /**
095       * @serial
096       */
097      private float[] minVal;
098    
099      /**
100       * @serial
101       */
102      private float[] maxVal;
103    
104      /**
105       * @serial
106       */
107      private float[] diffMinMax;
108    
109      /**
110       * @serial
111       */
112      private float[] invDiffMinMax;
113    
114      /**
115       * @serial
116       */
117      private boolean needScaleInit;
118    
119      /**
120       * Tells us if the PCS is CIE LAB (must be CIEXYZ otherwise)
121       */
122      private transient int type;
123      private transient int nComponents;
124      private transient ColorSpaceConverter converter;
125    
126      /**
127       * Constructs a new ICC_ColorSpace from an ICC_Profile object.
128       *
129       * @exception IllegalArgumentException If profile is inappropriate for
130       * representing a ColorSpace.
131       */
132      public ICC_ColorSpace(ICC_Profile profile)
133      {
134        super(profile.getColorSpaceType(), profile.getNumComponents());
135    
136        converter = getConverter(profile);
137        thisProfile = profile;
138        nComponents = profile.getNumComponents();
139        type = profile.getColorSpaceType();
140        makeArrays();
141      }
142    
143      /**
144       * Return the profile
145       */
146      public ICC_Profile getProfile()
147      {
148        return thisProfile;
149      }
150    
151      /**
152       * Transforms a color value assumed to be in this ColorSpace into a value in
153       * the default CS_sRGB color space.
154       *
155       * @exception ArrayIndexOutOfBoundsException If array length is not at least
156       * the number of components in this ColorSpace.
157       */
158      public float[] toRGB(float[] colorvalue)
159      {
160        return converter.toRGB(colorvalue);
161      }
162    
163      /**
164       * Transforms a color value assumed to be in the default CS_sRGB color space
165       * into this ColorSpace.
166       *
167       * @exception ArrayIndexOutOfBoundsException If array length is not at
168       * least 3.
169       */
170      public float[] fromRGB(float[] rgbvalue)
171      {
172        return converter.fromRGB(rgbvalue);
173      }
174    
175      /**
176       * Transforms a color value assumed to be in this ColorSpace into the
177       * CS_CIEXYZ conversion color space.
178       *
179       * @exception ArrayIndexOutOfBoundsException If array length is not at
180       * least the number of components in this ColorSpace.
181       */
182      public float[] toCIEXYZ(float[] colorvalue)
183      {
184        return converter.toCIEXYZ(colorvalue);
185      }
186    
187      /**
188       * Transforms a color value assumed to be in the CS_CIEXYZ conversion color
189       * space into this ColorSpace.
190       *
191       * @exception ArrayIndexOutOfBoundsException If array length is not at
192       * least 3.
193       */
194      public float[] fromCIEXYZ(float[] colorvalue)
195      {
196        return converter.fromCIEXYZ(colorvalue);
197      }
198    
199      public boolean isCS_sRGB()
200      {
201        return converter instanceof SrgbConverter;
202      }
203    
204      /**
205       * Returns the minimum normalized color component value for the specified
206       * component.
207       *
208       * @exception IllegalArgumentException If component is less than 0 or greater
209       * than numComponents - 1.
210       *
211       * @since 1.4
212       */
213      public float getMinValue(int idx)
214      {
215        // FIXME: Not 100% certain of this.
216        if (type == ColorSpace.TYPE_Lab && (idx == 1 || idx == 2))
217          return -128f;
218    
219        if (idx < 0 || idx >= nComponents)
220          throw new IllegalArgumentException();
221        return 0;
222      }
223    
224      /**
225       * Returns the maximum normalized color component value for the specified
226       * component.
227       *
228       * @exception IllegalArgumentException If component is less than 0 or greater
229       * than numComponents - 1.
230       *
231       * @since 1.4
232       */
233      public float getMaxValue(int idx)
234      {
235        if (type == ColorSpace.TYPE_XYZ && idx >= 0 && idx <= 2)
236          return 1 + 32767 / 32768f;
237        else if (type == ColorSpace.TYPE_Lab)
238          {
239            if (idx == 0)
240              return 100;
241            if (idx == 1 || idx == 2)
242              return 127;
243          }
244        if (idx < 0 || idx >= nComponents)
245          throw new IllegalArgumentException();
246        return 1;
247      }
248    
249      /**
250       * Returns a colorspace converter suitable for a given profile
251       */
252      private ColorSpaceConverter getConverter(ICC_Profile profile)
253      {
254        ColorSpaceConverter converter;
255        switch (profile.isPredefined())
256          {
257          case CS_sRGB:
258            converter = new SrgbConverter();
259            break;
260          case CS_CIEXYZ:
261            converter = new CieXyzConverter();
262            break;
263          case CS_GRAY:
264            converter = new GrayScaleConverter();
265            break;
266          case CS_LINEAR_RGB:
267            converter = new LinearRGBConverter();
268            break;
269          case CS_PYCC:
270            converter = new PyccConverter();
271            break;
272          default:
273            if (profile instanceof ICC_ProfileRGB)
274              converter = new RgbProfileConverter((ICC_ProfileRGB) profile);
275            else if (profile instanceof ICC_ProfileGray)
276              converter = new GrayProfileConverter((ICC_ProfileGray) profile);
277            else
278              converter = new ClutProfileConverter(profile);
279            break;
280          }
281        return converter;
282      }
283    
284      /**
285       * Serialization compatibility requires these variable to be set,
286       * although we don't use them. Perhaps we should?
287       */
288      private void makeArrays()
289      {
290        minVal = new float[nComponents];
291        maxVal = new float[nComponents];
292    
293        invDiffMinMax = diffMinMax = null;
294        for (int i = 0; i < nComponents; i++)
295          {
296            minVal[i] = getMinValue(i);
297            maxVal[i] = getMaxValue(i);
298          }
299        needScaleInit = true;
300      }
301    
302      /**
303       * Deserializes the object
304       */
305      private void readObject(ObjectInputStream s)
306                       throws IOException, ClassNotFoundException
307      {
308        s.defaultReadObject();
309        // set up objects
310        converter = getConverter(thisProfile);
311        nComponents = thisProfile.getNumComponents();
312        type = thisProfile.getColorSpaceType();
313      }
314    } // class ICC_ColorSpace