1 /*
2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /* ********************************************************************
27  **********************************************************************
28  **********************************************************************
29  *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
30  *** As  an unpublished  work pursuant to Title 17 of the United    ***
31  *** States Code.  All rights reserved.                             ***
32  **********************************************************************
33  **********************************************************************
34  **********************************************************************/
35 
36 package java.awt.color;
37 
38 import java.lang.annotation.Native;
39 
40 import sun.java2d.cmm.CMSManager;
41 
42 /**
43  * This abstract class is used to serve as a color space tag to identify the
44  * specific color space of a {@code Color} object or, via a {@code ColorModel}
45  * object, of an {@code Image}, a {@code BufferedImage}, or a
46  * {@code GraphicsDevice}. It contains methods that transform colors in a
47  * specific color space to/from sRGB and to/from a well-defined CIEXYZ color
48  * space.
49  * <p>
50  * For purposes of the methods in this class, colors are represented as arrays
51  * of color components represented as floats in a normalized range defined by
52  * each {@code ColorSpace}. For many {@code ColorSpaces} (e.g. sRGB), this range
53  * is 0.0 to 1.0. However, some {@code ColorSpaces} have components whose values
54  * have a different range. Methods are provided to inquire per component minimum
55  * and maximum normalized values.
56  * <p>
57  * Several variables are defined for purposes of referring to color space types
58  * (e.g. {@code TYPE_RGB}, {@code TYPE_XYZ}, etc.) and to refer to specific
59  * color spaces (e.g. {@code CS_sRGB} and {@code CS_CIEXYZ}). sRGB is a proposed
60  * standard RGB color space. For more information, see
61  * <a href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
62  * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html</a>.
63  * <p>
64  * The purpose of the methods to transform to/from the well-defined CIEXYZ color
65  * space is to support conversions between any two color spaces at a reasonably
66  * high degree of accuracy. It is expected that particular implementations of
67  * subclasses of {@code ColorSpace} (e.g. {@code ICC_ColorSpace}) will support
68  * high performance conversion based on underlying platform color management
69  * systems.
70  * <p>
71  * The {@code CS_CIEXYZ} space used by the {@code toCIEXYZ/fromCIEXYZ} methods
72  * can be described as follows:
73  * <pre>
74  *
75  * &nbsp;   CIEXYZ
76  * &nbsp;   viewing illuminance: 200 lux
77  * &nbsp;   viewing white point: CIE D50
78  * &nbsp;   media white point: "that of a perfectly reflecting diffuser" -- D50
79  * &nbsp;   media black point: 0 lux or 0 Reflectance
80  * &nbsp;   flare: 1 percent
81  * &nbsp;   surround: 20percent of the media white point
82  * &nbsp;   media description: reflection print (i.e., RLAB, Hunt viewing media)
83  * &nbsp;   note: For developers creating an ICC profile for this conversion
84  * &nbsp;         space, the following is applicable. Use a simple Von Kries
85  * &nbsp;         white point adaptation folded into the 3X3 matrix parameters
86  * &nbsp;         and fold the flare and surround effects into the three
87  * &nbsp;         one-dimensional lookup tables (assuming one uses the minimal
88  * &nbsp;         model for monitors).
89  *
90  * </pre>
91  *
92  * @see ICC_ColorSpace
93  */
94 public abstract class ColorSpace implements java.io.Serializable {
95 
96     static final long serialVersionUID = -409452704308689724L;
97 
98     private int type;
99     private int numComponents;
100     private transient String [] compName = null;
101 
102     // Cache of singletons for the predefined color spaces.
103     private static ColorSpace sRGBspace;
104     private static ColorSpace XYZspace;
105     private static ColorSpace PYCCspace;
106     private static ColorSpace GRAYspace;
107     private static ColorSpace LINEAR_RGBspace;
108 
109     /**
110      * Any of the family of XYZ color spaces.
111      */
112     @Native public static final int TYPE_XYZ = 0;
113 
114     /**
115      * Any of the family of Lab color spaces.
116      */
117     @Native public static final int TYPE_Lab = 1;
118 
119     /**
120      * Any of the family of Luv color spaces.
121      */
122     @Native public static final int TYPE_Luv = 2;
123 
124     /**
125      * Any of the family of YCbCr color spaces.
126      */
127     @Native public static final int TYPE_YCbCr = 3;
128 
129     /**
130      * Any of the family of Yxy color spaces.
131      */
132     @Native public static final int TYPE_Yxy = 4;
133 
134     /**
135      * Any of the family of RGB color spaces.
136      */
137     @Native public static final int TYPE_RGB = 5;
138 
139     /**
140      * Any of the family of GRAY color spaces.
141      */
142     @Native public static final int TYPE_GRAY = 6;
143 
144     /**
145      * Any of the family of HSV color spaces.
146      */
147     @Native public static final int TYPE_HSV = 7;
148 
149     /**
150      * Any of the family of HLS color spaces.
151      */
152     @Native public static final int TYPE_HLS = 8;
153 
154     /**
155      * Any of the family of CMYK color spaces.
156      */
157     @Native public static final int TYPE_CMYK = 9;
158 
159     /**
160      * Any of the family of CMY color spaces.
161      */
162     @Native public static final int TYPE_CMY = 11;
163 
164     /**
165      * Generic 2 component color spaces.
166      */
167     @Native public static final int TYPE_2CLR = 12;
168 
169     /**
170      * Generic 3 component color spaces.
171      */
172     @Native public static final int TYPE_3CLR = 13;
173 
174     /**
175      * Generic 4 component color spaces.
176      */
177     @Native public static final int TYPE_4CLR = 14;
178 
179     /**
180      * Generic 5 component color spaces.
181      */
182     @Native public static final int TYPE_5CLR = 15;
183 
184     /**
185      * Generic 6 component color spaces.
186      */
187     @Native public static final int TYPE_6CLR = 16;
188 
189     /**
190      * Generic 7 component color spaces.
191      */
192     @Native public static final int TYPE_7CLR = 17;
193 
194     /**
195      * Generic 8 component color spaces.
196      */
197     @Native public static final int TYPE_8CLR = 18;
198 
199     /**
200      * Generic 9 component color spaces.
201      */
202     @Native public static final int TYPE_9CLR = 19;
203 
204     /**
205      * Generic 10 component color spaces.
206      */
207     @Native public static final int TYPE_ACLR = 20;
208 
209     /**
210      * Generic 11 component color spaces.
211      */
212     @Native public static final int TYPE_BCLR = 21;
213 
214     /**
215      * Generic 12 component color spaces.
216      */
217     @Native public static final int TYPE_CCLR = 22;
218 
219     /**
220      * Generic 13 component color spaces.
221      */
222     @Native public static final int TYPE_DCLR = 23;
223 
224     /**
225      * Generic 14 component color spaces.
226      */
227     @Native public static final int TYPE_ECLR = 24;
228 
229     /**
230      * Generic 15 component color spaces.
231      */
232     @Native public static final int TYPE_FCLR = 25;
233 
234     /**
235      * The sRGB color space defined at
236      * <a href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
237      * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html</a>.
238      */
239     @Native public static final int CS_sRGB = 1000;
240 
241     /**
242      * A built-in linear RGB color space. This space is based on the same RGB
243      * primaries as {@code CS_sRGB}, but has a linear tone reproduction curve.
244      */
245     @Native public static final int CS_LINEAR_RGB = 1004;
246 
247     /**
248      * The CIEXYZ conversion color space defined above.
249      */
250     @Native public static final int CS_CIEXYZ = 1001;
251 
252     /**
253      * The Photo YCC conversion color space.
254      */
255     @Native public static final int CS_PYCC = 1002;
256 
257     /**
258      * The built-in linear gray scale color space.
259      */
260     @Native public static final int CS_GRAY = 1003;
261 
262     /**
263      * Constructs a {@code ColorSpace} object given a color space type and the
264      * number of components.
265      *
266      * @param  type one of the {@code ColorSpace} type constants
267      * @param  numcomponents the number of components in the color space
268      */
ColorSpace(int type, int numcomponents)269     protected ColorSpace(int type, int numcomponents) {
270         this.type = type;
271         this.numComponents = numcomponents;
272     }
273 
274     /**
275      * Returns a {@code ColorSpace} representing one of the specific predefined
276      * color spaces.
277      *
278      * @param  colorspace a specific color space identified by one of the
279      *         predefined class constants (e.g. {@code CS_sRGB},
280      *         {@code CS_LINEAR_RGB}, {@code CS_CIEXYZ}, {@code CS_GRAY}, or
281      *         {@code CS_PYCC})
282      * @return the requested {@code ColorSpace} object
283      */
284     // NOTE: This method may be called by privileged threads.
285     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
getInstance(int colorspace)286     public static ColorSpace getInstance (int colorspace)
287     {
288     ColorSpace    theColorSpace;
289 
290         switch (colorspace) {
291         case CS_sRGB:
292             synchronized(ColorSpace.class) {
293                 if (sRGBspace == null) {
294                     ICC_Profile theProfile = ICC_Profile.getInstance (CS_sRGB);
295                     sRGBspace = new ICC_ColorSpace (theProfile);
296                 }
297 
298                 theColorSpace = sRGBspace;
299             }
300             break;
301 
302         case CS_CIEXYZ:
303             synchronized(ColorSpace.class) {
304                 if (XYZspace == null) {
305                     ICC_Profile theProfile =
306                         ICC_Profile.getInstance (CS_CIEXYZ);
307                     XYZspace = new ICC_ColorSpace (theProfile);
308                 }
309 
310                 theColorSpace = XYZspace;
311             }
312             break;
313 
314         case CS_PYCC:
315             synchronized(ColorSpace.class) {
316                 if (PYCCspace == null) {
317                     ICC_Profile theProfile = ICC_Profile.getInstance (CS_PYCC);
318                     PYCCspace = new ICC_ColorSpace (theProfile);
319                 }
320 
321                 theColorSpace = PYCCspace;
322             }
323             break;
324 
325 
326         case CS_GRAY:
327             synchronized(ColorSpace.class) {
328                 if (GRAYspace == null) {
329                     ICC_Profile theProfile = ICC_Profile.getInstance (CS_GRAY);
330                     GRAYspace = new ICC_ColorSpace (theProfile);
331                     /* to allow access from java.awt.ColorModel */
332                     CMSManager.GRAYspace = GRAYspace;
333                 }
334 
335                 theColorSpace = GRAYspace;
336             }
337             break;
338 
339 
340         case CS_LINEAR_RGB:
341             synchronized(ColorSpace.class) {
342                 if (LINEAR_RGBspace == null) {
343                     ICC_Profile theProfile =
344                         ICC_Profile.getInstance(CS_LINEAR_RGB);
345                     LINEAR_RGBspace = new ICC_ColorSpace (theProfile);
346                     /* to allow access from java.awt.ColorModel */
347                     CMSManager.LINEAR_RGBspace = LINEAR_RGBspace;
348                 }
349 
350                 theColorSpace = LINEAR_RGBspace;
351             }
352             break;
353 
354 
355         default:
356             throw new IllegalArgumentException ("Unknown color space");
357         }
358 
359         return theColorSpace;
360     }
361 
362     /**
363      * Returns true if the {@code ColorSpace} is {@code CS_sRGB}.
364      *
365      * @return {@code true} if this is a {@code CS_sRGB} color space,
366      *         {@code false} if it is not
367      */
isCS_sRGB()368     public boolean isCS_sRGB () {
369         /* REMIND - make sure we know sRGBspace exists already */
370         return (this == sRGBspace);
371     }
372 
373     /**
374      * Transforms a color value assumed to be in this {@code ColorSpace} into a
375      * value in the default {@code CS_sRGB} color space.
376      * <p>
377      * This method transforms color values using algorithms designed to produce
378      * the best perceptual match between input and output colors. In order to do
379      * colorimetric conversion of color values, you should use the
380      * {@code toCIEXYZ} method of this color space to first convert from the
381      * input color space to the CS_CIEXYZ color space, and then use the
382      * {@code fromCIEXYZ} method of the {@code CS_sRGB} color space to convert
383      * from {@code CS_CIEXYZ} to the output color space. See
384      * {@link #toCIEXYZ(float[]) toCIEXYZ} and
385      * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
386      *
387      * @param  colorvalue a float array with length of at least the number of
388      *         components in this {@code ColorSpace}
389      * @return a float array of length 3
390      * @throws ArrayIndexOutOfBoundsException if array length is not at least
391      *         the number of components in this {@code ColorSpace}
392      */
toRGB(float[] colorvalue)393     public abstract float[] toRGB(float[] colorvalue);
394 
395     /**
396      * Transforms a color value assumed to be in the default {@code CS_sRGB}
397      * color space into this {@code ColorSpace}.
398      * <p>
399      * This method transforms color values using algorithms designed to produce
400      * the best perceptual match between input and output colors. In order to do
401      * colorimetric conversion of color values, you should use the
402      * {@code toCIEXYZ} method of the {@code CS_sRGB} color space to first
403      * convert from the input color space to the {@code CS_CIEXYZ} color space,
404      * and then use the {@code fromCIEXYZ} method of this color space to convert
405      * from {@code CS_CIEXYZ} to the output color space. See
406      * {@link #toCIEXYZ(float[]) toCIEXYZ} and
407      * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
408      *
409      * @param  rgbvalue a float array with length of at least 3
410      * @return a float array with length equal to the number of components in
411      *         this {@code ColorSpace}
412      * @throws ArrayIndexOutOfBoundsException if array length is not at least 3
413      */
fromRGB(float[] rgbvalue)414     public abstract float[] fromRGB(float[] rgbvalue);
415 
416     /**
417      * Transforms a color value assumed to be in this {@code ColorSpace} into
418      * the {@code CS_CIEXYZ} conversion color space.
419      * <p>
420      * This method transforms color values using relative colorimetry, as
421      * defined by the International Color Consortium standard. This means that
422      * the XYZ values returned by this method are represented relative to the
423      * D50 white point of the {@code CS_CIEXYZ} color space. This representation
424      * is useful in a two-step color conversion process in which colors are
425      * transformed from an input color space to {@code CS_CIEXYZ} and then to an
426      * output color space. This representation is not the same as the XYZ values
427      * that would be measured from the given color value by a colorimeter. A
428      * further transformation is necessary to compute the XYZ values that would
429      * be measured using current CIE recommended practices. See the
430      * {@link ICC_ColorSpace#toCIEXYZ(float[]) toCIEXYZ} method of
431      * {@code ICC_ColorSpace} for further information.
432      *
433      * @param colorvalue a float array with length of at least the number of
434      *        components in this {@code ColorSpace}
435      * @return a float array of length 3
436      * @throws ArrayIndexOutOfBoundsException if array length is not at least
437      *         the number of components in this {@code ColorSpace}.
438      */
toCIEXYZ(float[] colorvalue)439     public abstract float[] toCIEXYZ(float[] colorvalue);
440 
441     /**
442      * Transforms a color value assumed to be in the {@code CS_CIEXYZ}
443      * conversion color space into this {@code ColorSpace}.
444      * <p>
445      * This method transforms color values using relative colorimetry, as
446      * defined by the International Color Consortium standard. This means that
447      * the XYZ argument values taken by this method are represented relative to
448      * the D50 white point of the {@code CS_CIEXYZ} color space. This
449      * representation is useful in a two-step color conversion process in which
450      * colors are transformed from an input color space to {@code CS_CIEXYZ} and
451      * then to an output color space. The color values returned by this method
452      * are not those that would produce the XYZ value passed to the method when
453      * measured by a colorimeter. If you have XYZ values corresponding to
454      * measurements made using current CIE recommended practices, they must be
455      * converted to D50 relative values before being passed to this method. See
456      * the {@link ICC_ColorSpace#fromCIEXYZ(float[]) fromCIEXYZ} method of
457      * {@code ICC_ColorSpace} for further information.
458      *
459      * @param  colorvalue a float array with length of at least 3
460      * @return a float array with length equal to the number of components in
461      *         this {@code ColorSpace}
462      * @throws ArrayIndexOutOfBoundsException if array length is not at least 3
463      */
fromCIEXYZ(float[] colorvalue)464     public abstract float[] fromCIEXYZ(float[] colorvalue);
465 
466     /**
467      * Returns the color space type of this {@code ColorSpace} (for example
468      * {@code TYPE_RGB}, {@code TYPE_XYZ}, ...). The type defines the number of
469      * components of the color space and the interpretation, e.g.
470      * {@code TYPE_RGB} identifies a color space with three components - red,
471      * green, and blue. It does not define the particular color characteristics
472      * of the space, e.g. the chromaticities of the primaries.
473      *
474      * @return the type constant that represents the type of this
475      *         {@code ColorSpace}
476      */
getType()477     public int getType() {
478         return type;
479     }
480 
481     /**
482      * Returns the number of components of this ColorSpace.
483      *
484      * @return the number of components in this {@code ColorSpace}
485      */
getNumComponents()486     public int getNumComponents() {
487         return numComponents;
488     }
489 
490     /**
491      * Returns the name of the component given the component index.
492      *
493      * @param  idx the component index
494      * @return the name of the component at the specified index
495      * @throws IllegalArgumentException if {@code idx} is less than 0 or greater
496      *         than {@code numComponents - 1}
497      */
getName(int idx)498     public String getName (int idx) {
499         /* REMIND - handle common cases here */
500         if ((idx < 0) || (idx > numComponents - 1)) {
501             throw new IllegalArgumentException(
502                 "Component index out of range: " + idx);
503         }
504 
505         if (compName == null) {
506             switch (type) {
507                 case ColorSpace.TYPE_XYZ:
508                     compName = new String[] {"X", "Y", "Z"};
509                     break;
510                 case ColorSpace.TYPE_Lab:
511                     compName = new String[] {"L", "a", "b"};
512                     break;
513                 case ColorSpace.TYPE_Luv:
514                     compName = new String[] {"L", "u", "v"};
515                     break;
516                 case ColorSpace.TYPE_YCbCr:
517                     compName = new String[] {"Y", "Cb", "Cr"};
518                     break;
519                 case ColorSpace.TYPE_Yxy:
520                     compName = new String[] {"Y", "x", "y"};
521                     break;
522                 case ColorSpace.TYPE_RGB:
523                     compName = new String[] {"Red", "Green", "Blue"};
524                     break;
525                 case ColorSpace.TYPE_GRAY:
526                     compName = new String[] {"Gray"};
527                     break;
528                 case ColorSpace.TYPE_HSV:
529                     compName = new String[] {"Hue", "Saturation", "Value"};
530                     break;
531                 case ColorSpace.TYPE_HLS:
532                     compName = new String[] {"Hue", "Lightness",
533                                              "Saturation"};
534                     break;
535                 case ColorSpace.TYPE_CMYK:
536                     compName = new String[] {"Cyan", "Magenta", "Yellow",
537                                              "Black"};
538                     break;
539                 case ColorSpace.TYPE_CMY:
540                     compName = new String[] {"Cyan", "Magenta", "Yellow"};
541                     break;
542                 default:
543                     String [] tmp = new String[numComponents];
544                     for (int i = 0; i < tmp.length; i++) {
545                         tmp[i] = "Unnamed color component(" + i + ")";
546                     }
547                     compName = tmp;
548             }
549         }
550         return compName[idx];
551     }
552 
553     /**
554      * Returns the minimum normalized color component value for the specified
555      * component. The default implementation in this abstract class returns 0.0
556      * for all components. Subclasses should override this method if necessary.
557      *
558      * @param  component the component index
559      * @return the minimum normalized component value
560      * @throws IllegalArgumentException if component is less than 0 or greater
561      *         than {@code numComponents - 1}
562      * @since 1.4
563      */
getMinValue(int component)564     public float getMinValue(int component) {
565         if ((component < 0) || (component > numComponents - 1)) {
566             throw new IllegalArgumentException(
567                 "Component index out of range: " + component);
568         }
569         return 0.0f;
570     }
571 
572     /**
573      * Returns the maximum normalized color component value for the specified
574      * component. The default implementation in this abstract class returns 1.0
575      * for all components. Subclasses should override this method if necessary.
576      *
577      * @param  component the component index
578      * @return the maximum normalized component value
579      * @throws IllegalArgumentException if component is less than 0 or greater
580      *         than {@code numComponents - 1}
581      * @since 1.4
582      */
getMaxValue(int component)583     public float getMaxValue(int component) {
584         if ((component < 0) || (component > numComponents - 1)) {
585             throw new IllegalArgumentException(
586                 "Component index out of range: " + component);
587         }
588         return 1.0f;
589     }
590 
591     /*
592      * Returns {@code true} if {@code cspace} is the XYZspace.
593      */
isCS_CIEXYZ(ColorSpace cspace)594     static boolean isCS_CIEXYZ(ColorSpace cspace) {
595         return (cspace == XYZspace);
596     }
597 }
598