001/* ICC_ColorSpace.java -- the canonical color space implementation
002   Copyright (C) 2000, 2002, 2004 Free Software Foundation
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt.color;
040
041import gnu.java.awt.color.CieXyzConverter;
042import gnu.java.awt.color.ClutProfileConverter;
043import gnu.java.awt.color.ColorSpaceConverter;
044import gnu.java.awt.color.GrayProfileConverter;
045import gnu.java.awt.color.GrayScaleConverter;
046import gnu.java.awt.color.LinearRGBConverter;
047import gnu.java.awt.color.PyccConverter;
048import gnu.java.awt.color.RgbProfileConverter;
049import gnu.java.awt.color.SrgbConverter;
050
051import java.io.IOException;
052import 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 */
082public 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