1 /* Color.java -- represents a color in Java
2    Copyright (C) 1999, 2002, 2005  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.awt;
40 
41 import java.awt.color.ColorSpace;
42 import java.awt.geom.AffineTransform;
43 import java.awt.geom.Rectangle2D;
44 import java.awt.image.ColorModel;
45 import java.io.Serializable;
46 
47 /**
48  * This class represents a color value in the AWT system. It uses the sRGB
49  * (standard Red-Green-Blue) system, along with an alpha value ranging from
50  * transparent (0.0f or 0) and opaque (1.0f or 255). The color is not
51  * pre-multiplied by the alpha value an any of the accessor methods. Further
52  * information about sRGB can be found at
53  * <a href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
54  * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html</a>.
55  *
56  * @author Aaron M. Renn (arenn@urbanophile.com)
57  * @see ColorSpace
58  * @see AlphaComposite
59  * @since 1.0
60  * @status updated to 1.4
61  */
62 public class Color implements Paint, Serializable
63 {
64   /**
65    * Compatible with JDK 1.0+.
66    */
67   private static final long serialVersionUID = 118526816881161077L;
68 
69   /** Constant for the color white: R=255, G=255, B=255. */
70   public static final Color white = new Color(0xffffff, false);
71 
72   /**
73    * Constant for the color white: R=255, G=255, B=255.
74    *
75    * @since 1.4
76    */
77   public static final Color WHITE = white;
78 
79   /** Constant for the color light gray: R=192, G=192, B=192. */
80   public static final Color lightGray = new Color(0xc0c0c0, false);
81 
82   /**
83    * Constant for the color light gray: R=192, G=192, B=192.
84    *
85    * @since 1.4
86    */
87   public static final Color LIGHT_GRAY = lightGray;
88 
89   /** Constant for the color gray: R=128, G=128, B=128. */
90   public static final Color gray = new Color(0x808080, false);
91 
92   /**
93    * Constant for the color gray: R=128, G=128, B=128.
94    *
95    * @since 1.4
96    */
97   public static final Color GRAY = gray;
98 
99   /** Constant for the color dark gray: R=64, G=64, B=64. */
100   public static final Color darkGray = new Color(0x404040, false);
101 
102   /**
103    * Constant for the color dark gray: R=64, G=64, B=64.
104    *
105    * @since 1.4
106    */
107   public static final Color DARK_GRAY = darkGray;
108 
109   /** Constant for the color black: R=0, G=0, B=0. */
110   public static final Color black = new Color(0x000000, false);
111 
112   /**
113    * Constant for the color black: R=0, G=0, B=0.
114    *
115    * @since 1.4
116    */
117   public static final Color BLACK = black;
118 
119   /** Constant for the color red: R=255, G=0, B=0. */
120   public static final Color red = new Color(0xff0000, false);
121 
122   /**
123    * Constant for the color red: R=255, G=0, B=0.
124    *
125    * @since 1.4
126    */
127   public static final Color RED = red;
128 
129   /** Constant for the color pink: R=255, G=175, B=175. */
130   public static final Color pink = new Color(0xffafaf, false);
131 
132   /**
133    * Constant for the color pink: R=255, G=175, B=175.
134    *
135    * @since 1.4
136    */
137   public static final Color PINK = pink;
138 
139   /** Constant for the color orange: R=255, G=200, B=0. */
140   public static final Color orange = new Color(0xffc800, false);
141 
142   /**
143    * Constant for the color orange: R=255, G=200, B=0.
144    *
145    * @since 1.4
146    */
147   public static final Color ORANGE = orange;
148 
149   /** Constant for the color yellow: R=255, G=255, B=0. */
150   public static final Color yellow = new Color(0xffff00, false);
151 
152   /**
153    * Constant for the color yellow: R=255, G=255, B=0.
154    *
155    * @since 1.4
156    */
157   public static final Color YELLOW = yellow;
158 
159   /** Constant for the color green: R=0, G=255, B=0. */
160   public static final Color green = new Color(0x00ff00, false);
161 
162   /**
163    * Constant for the color green: R=0, G=255, B=0.
164    *
165    * @since 1.4
166    */
167   public static final Color GREEN = green;
168 
169   /** Constant for the color magenta: R=255, G=0, B=255. */
170   public static final Color magenta = new Color(0xff00ff, false);
171 
172   /**
173    * Constant for the color magenta: R=255, G=0, B=255.
174    *
175    * @since 1.4
176    */
177   public static final Color MAGENTA = magenta;
178 
179   /** Constant for the color cyan: R=0, G=255, B=255. */
180   public static final Color cyan = new Color(0x00ffff, false);
181 
182   /**
183    * Constant for the color cyan: R=0, G=255, B=255.
184    *
185    * @since 1.4
186    */
187   public static final Color CYAN = cyan;
188 
189   /** Constant for the color blue: R=0, G=0, B=255. */
190   public static final Color blue = new Color(0x0000ff, false);
191 
192   /**
193    * Constant for the color blue: R=0, G=0, B=255.
194    *
195    * @since 1.4
196    */
197   public static final Color BLUE = blue;
198 
199   /** Internal mask for red. */
200   private static final int RED_MASK = 255 << 16;
201 
202   /** Internal mask for green. */
203   private static final int GREEN_MASK = 255 << 8;
204 
205   /** Internal mask for blue. */
206   private static final int BLUE_MASK = 255;
207 
208   /** Internal mask for alpha. Package visible for use in subclass. */
209   static final int ALPHA_MASK = 255 << 24;
210 
211   /** Amount to scale a color by when brightening or darkening. */
212   private static final float BRIGHT_SCALE = 0.7f;
213 
214   /**
215    * The color value, in sRGB. Note that the actual color may be more
216    * precise if frgbvalue or fvalue is non-null. This class stores alpha, red,
217    * green, and blue, each 0-255, packed in an int. However, the subclass
218    * SystemColor stores an index into an array. Therefore, for serial
219    * compatibility (and because of poor design on Sun's part), this value
220    * cannot be used directly; instead you must use <code>getRGB()</code>.
221    *
222    * @see #getRGB()
223    * @serial the value of the color, whether an RGB literal or array index
224    */
225   final int value;
226 
227   /**
228    * The color value, in sRGB. This may be null if the color was constructed
229    * with ints; and it does not include alpha. This stores red, green, and
230    * blue, in the range 0.0f - 1.0f.
231    *
232    * @see #getRGBColorComponents(float[])
233    * @see #getRGBComponents(float[])
234    * @serial the rgb components of the value
235    * @since 1.2
236    */
237   private float[] frgbvalue;
238 
239   /**
240    * The color value, in the native ColorSpace components. This may be null
241    * if the color was constructed with ints or in the sRGB color space; and
242    * it does not include alpha.
243    *
244    * @see #getRGBColorComponents(float[])
245    * @see #getRGBComponents(float[])
246    * @serial the original color space components of the color
247    * @since 1.2
248    */
249   private float[] fvalue;
250 
251   /**
252    * The alpha value. This is in the range 0.0f - 1.0f, but is invalid if
253    * deserialized as 0.0 when frgbvalue is null.
254    *
255    * @see #getRGBComponents(float[])
256    * @see #getComponents(float[])
257    * @serial the alpha component of this color
258    * @since 1.2
259    */
260   private final float falpha;
261 
262   /**
263    * The ColorSpace. Null means the default sRGB space.
264    *
265    * @see #getColor(String)
266    * @see #getColorSpace()
267    * @see #getColorComponents(float[])
268    * @serial the color space for this color
269    * @since 1.2
270    */
271   private final ColorSpace cs;
272 
273   /**
274    * The paint context for this solid color. Package visible for use in
275    * subclass.
276    */
277   transient ColorPaintContext context;
278 
279   /**
280    * Initializes a new instance of <code>Color</code> using the specified
281    * red, green, and blue values, which must be given as integers in the
282    * range of 0-255. Alpha will default to 255 (opaque). When drawing to
283    * screen, the actual color may be adjusted to the best match of hardware
284    * capabilities.
285    *
286    * @param red the red component of the RGB value
287    * @param green the green component of the RGB value
288    * @param blue the blue component of the RGB value
289    * @throws IllegalArgumentException if the values are out of range 0-255
290    * @see #getRed()
291    * @see #getGreen()
292    * @see #getBlue()
293    * @see #getRGB()
294    * @see #Color(int, int, int, int)
295    */
Color(int red, int green, int blue)296   public Color(int red, int green, int blue)
297   {
298     this(red, green, blue, 255);
299   }
300 
301   /**
302    * Initializes a new instance of <code>Color</code> using the specified
303    * red, green, blue, and alpha values, which must be given as integers in
304    * the range of 0-255. When drawing to screen, the actual color may be
305    * adjusted to the best match of hardware capabilities.
306    *
307    * @param red the red component of the RGB value
308    * @param green the green component of the RGB value
309    * @param blue the blue component of the RGB value
310    * @param alpha the alpha value of the color
311    * @throws IllegalArgumentException if the values are out of range 0-255
312    * @see #getRed()
313    * @see #getGreen()
314    * @see #getBlue()
315    * @see #getAlpha()
316    * @see #getRGB()
317    */
Color(int red, int green, int blue, int alpha)318   public Color(int red, int green, int blue, int alpha)
319   {
320     if ((red & 255) != red || (green & 255) != green || (blue & 255) != blue
321         || (alpha & 255) != alpha)
322       throw new IllegalArgumentException("Bad RGB values"
323                                         +" red=0x"+Integer.toHexString(red)
324                                         +" green=0x"+Integer.toHexString(green)
325                                         +" blue=0x"+Integer.toHexString(blue)
326                                         +" alpha=0x"+Integer.toHexString(alpha)  );
327 
328     value = (alpha << 24) | (red << 16) | (green << 8) | blue;
329     falpha = 1;
330     cs = null;
331   }
332 
333   /**
334    * Initializes a new instance of <code>Color</code> using the specified
335    * RGB value. The blue value is in bits 0-7, green in bits 8-15, and
336    * red in bits 16-23. The other bits are ignored. The alpha value is set
337    * to 255 (opaque). When drawing to screen, the actual color may be
338    * adjusted to the best match of hardware capabilities.
339    *
340    * @param value the RGB value
341    * @see ColorModel#getRGBdefault()
342    * @see #getRed()
343    * @see #getGreen()
344    * @see #getBlue()
345    * @see #getRGB()
346    * @see #Color(int, boolean)
347    */
Color(int value)348   public Color(int value)
349   {
350     this(value, false);
351   }
352 
353   /**
354    * Initializes a new instance of <code>Color</code> using the specified
355    * RGB value. The blue value is in bits 0-7, green in bits 8-15, and
356    * red in bits 16-23. The alpha value is in bits 24-31, unless hasalpha
357    * is false, in which case alpha is set to 255. When drawing to screen, the
358    * actual color may be adjusted to the best match of hardware capabilities.
359    *
360    * @param value the RGB value
361    * @param hasalpha true if value includes the alpha
362    * @see ColorModel#getRGBdefault()
363    * @see #getRed()
364    * @see #getGreen()
365    * @see #getBlue()
366    * @see #getAlpha()
367    * @see #getRGB()
368    */
Color(int value, boolean hasalpha)369   public Color(int value, boolean hasalpha)
370   {
371     // Note: SystemColor calls this constructor, setting falpha to 0; but
372     // code in getRGBComponents correctly reports falpha as 1.0 to the user
373     // for all instances of SystemColor since frgbvalue is left null here.
374     if (hasalpha)
375       falpha = ((value & ALPHA_MASK) >> 24) / 255f;
376     else
377       {
378         value |= ALPHA_MASK;
379         falpha = 1;
380       }
381     this.value = value;
382     cs = null;
383   }
384 
385   /**
386    * Initializes a new instance of <code>Color</code> using the specified
387    * RGB values. These must be in the range of 0.0-1.0. Alpha is assigned
388    * the value of 1.0 (opaque). When drawing to screen, the actual color may
389    * be adjusted to the best match of hardware capabilities.
390    *
391    * @param red the red component of the RGB value
392    * @param green the green component of the RGB value
393    * @param blue the blue component of the RGB value
394    * @throws IllegalArgumentException tf the values are out of range 0.0f-1.0f
395    * @see #getRed()
396    * @see #getGreen()
397    * @see #getBlue()
398    * @see #getRGB()
399    * @see #Color(float, float, float, float)
400    */
Color(float red, float green, float blue)401   public Color(float red, float green, float blue)
402   {
403     this(red, green, blue, 1.0f);
404   }
405 
406   /**
407    * Initializes a new instance of <code>Color</code> using the specified
408    * RGB and alpha values. These must be in the range of 0.0-1.0. When drawing
409    * to screen, the actual color may be adjusted to the best match of
410    * hardware capabilities.
411    *
412    * @param red the red component of the RGB value
413    * @param green the green component of the RGB value
414    * @param blue the blue component of the RGB value
415    * @param alpha the alpha value of the color
416    * @throws IllegalArgumentException tf the values are out of range 0.0f-1.0f
417    * @see #getRed()
418    * @see #getGreen()
419    * @see #getBlue()
420    * @see #getAlpha()
421    * @see #getRGB()
422    */
Color(float red, float green, float blue, float alpha)423   public Color(float red, float green, float blue, float alpha)
424   {
425     value = convert(red, green, blue, alpha);
426     frgbvalue = new float[] {red, green, blue};
427     falpha = alpha;
428     cs = null;
429   }
430 
431   /**
432    * Creates a color in the given ColorSpace with the specified alpha. The
433    * array must be non-null and have enough elements for the color space
434    * (for example, RGB requires 3 elements, CMYK requires 4). When drawing
435    * to screen, the actual color may be adjusted to the best match of
436    * hardware capabilities.
437    *
438    * @param space the color space of components
439    * @param components the color components, except alpha
440    * @param alpha the alpha value of the color
441    * @throws NullPointerException if cpsace or components is null
442    * @throws ArrayIndexOutOfBoundsException if components is too small
443    * @throws IllegalArgumentException if alpha or any component is out of range
444    * @see #getComponents(float[])
445    * @see #getColorComponents(float[])
446    */
Color(ColorSpace space, float[] components, float alpha)447   public Color(ColorSpace space, float[] components, float alpha)
448   {
449     frgbvalue = space.toRGB(components);
450     fvalue = components;
451     falpha = alpha;
452     cs = space;
453     value = convert(frgbvalue[0], frgbvalue[1], frgbvalue[2], alpha);
454   }
455 
456   /**
457    * Returns the red value for this color, as an integer in the range 0-255
458    * in the sRGB color space.
459    *
460    * @return the red value for this color
461    * @see #getRGB()
462    */
getRed()463   public int getRed()
464   {
465     // Do not inline getRGB() to value, because of SystemColor.
466     return (getRGB() & RED_MASK) >> 16;
467   }
468 
469   /**
470    * Returns the green value for this color, as an integer in the range 0-255
471    * in the sRGB color space.
472    *
473    * @return the green value for this color
474    * @see #getRGB()
475    */
getGreen()476   public int getGreen()
477   {
478     // Do not inline getRGB() to value, because of SystemColor.
479     return (getRGB() & GREEN_MASK) >> 8;
480   }
481 
482   /**
483    * Returns the blue value for this color, as an integer in the range 0-255
484    * in the sRGB color space.
485    *
486    * @return the blue value for this color
487    * @see #getRGB()
488    */
getBlue()489   public int getBlue()
490   {
491     // Do not inline getRGB() to value, because of SystemColor.
492     return getRGB() & BLUE_MASK;
493   }
494 
495   /**
496    * Returns the alpha value for this color, as an integer in the range 0-255.
497    *
498    * @return the alpha value for this color
499    * @see #getRGB()
500    */
getAlpha()501   public int getAlpha()
502   {
503     // Do not inline getRGB() to value, because of SystemColor.
504     return (getRGB() & ALPHA_MASK) >>> 24;
505   }
506 
507   /**
508    * Returns the RGB value for this color, in the sRGB color space. The blue
509    * value will be in bits 0-7, green in 8-15, red in 16-23, and alpha value in
510    * 24-31.
511    *
512    * @return the RGB value for this color
513    * @see ColorModel#getRGBdefault()
514    * @see #getRed()
515    * @see #getGreen()
516    * @see #getBlue()
517    * @see #getAlpha()
518    */
getRGB()519   public int getRGB()
520   {
521     return value;
522   }
523 
524   /**
525    * Returns a brighter version of this color. This is done by increasing the
526    * RGB values by an arbitrary scale factor. The new color is opaque (an
527    * alpha of 255). Note that this method and the <code>darker()</code>
528    * method are not necessarily inverses.
529    *
530    * @return a brighter version of this color
531    * @see #darker()
532    */
brighter()533   public Color brighter()
534   {
535     // Do not inline getRGB() to this.value, because of SystemColor.
536     int value = getRGB();
537     int[] hues = new int[3];
538     hues[0] = (value & RED_MASK) >> 16;
539     hues[1] = (value & GREEN_MASK) >> 8;
540     hues[2] = value & BLUE_MASK;
541 
542     // (0,0,0) is a special case.
543     if (hues[0] == 0 && hues[1] == 0 && hues[2] ==0)
544       {
545         hues[0] = 3;
546         hues[1] = 3;
547         hues[2] = 3;
548       }
549     else
550       {
551         for (int index = 0; index < 3; index++)
552           {
553 
554             if (hues[index] > 2)
555               hues[index] = (int) Math.min(255, hues[index]/0.7f);
556             if (hues[index] == 1 || hues[index] == 2)
557               hues[index] = 4;
558           }
559       }
560 
561     return new Color(hues[0], hues[1], hues[2], 255);
562   }
563 
564   /**
565    * Returns a darker version of this color. This is done by decreasing the
566    * RGB values by an arbitrary scale factor. The new color is opaque (an
567    * alpha of 255). Note that this method and the <code>brighter()</code>
568    * method are not necessarily inverses.
569    *
570    * @return a darker version of this color
571    * @see #brighter()
572    */
darker()573   public Color darker()
574   {
575     // Do not inline getRGB() to this.value, because of SystemColor.
576     int value = getRGB();
577     return new Color((int) (((value & RED_MASK) >> 16) * BRIGHT_SCALE),
578                      (int) (((value & GREEN_MASK) >> 8) * BRIGHT_SCALE),
579                      (int) ((value & BLUE_MASK) * BRIGHT_SCALE), 255);
580   }
581 
582   /**
583    * Returns a hash value for this color. This is simply the color in 8-bit
584    * precision, in the format 0xAARRGGBB (alpha, red, green, blue).
585    *
586    * @return a hash value for this color
587    */
hashCode()588   public int hashCode()
589   {
590     return value;
591   }
592 
593   /**
594    * Tests this object for equality against the specified object.  This will
595    * be true if and only if the specified object is an instance of
596    * <code>Color</code> and has the same 8-bit integer red, green, and blue
597    * values as this object. Note that two colors may be slightly different
598    * as float values, but round to the same integer values. Also note that
599    * this does not accurately compare SystemColors, since that class does
600    * not store its internal data in RGB format like regular colors.
601    *
602    * @param obj the object to compare to
603    * @return true if the specified object is semantically equal to this one
604    */
equals(Object obj)605   public boolean equals(Object obj)
606   {
607     return obj instanceof Color && ((Color) obj).value == value;
608   }
609 
610   /**
611    * Returns a string representation of this object. Subclasses may return
612    * any desired format, except for null, but this implementation returns
613    * <code>getClass().getName() + "[r=" + getRed() + ",g=" + getGreen()
614    * + ",b=" + getBlue() + ']'</code>.
615    *
616    * @return a string representation of this object
617    */
toString()618   public String toString()
619   {
620     return getClass().getName() + "[r=" + ((value & RED_MASK) >> 16)
621       + ",g=" + ((value & GREEN_MASK) >> 8) + ",b=" + (value & BLUE_MASK)
622       + ']';
623   }
624 
625   /**
626    * Converts the specified string to a number, using Integer.decode, and
627    * creates a new instance of <code>Color</code> from the value. The alpha
628    * value will be 255 (opaque).
629    *
630    * @param str the numeric color string
631    * @return a new instance of <code>Color</code> for the string
632    * @throws NumberFormatException if the string cannot be parsed
633    * @throws NullPointerException if the string is null
634    * @see Integer#decode(String)
635    * @see #Color(int)
636    * @since 1.1
637    */
decode(String str)638   public static Color decode(String str)
639   {
640     return new Color(Integer.decode(str).intValue(), false);
641   }
642 
643   /**
644    * Returns a new instance of <code>Color</code> from the value of the
645    * system property named by the specified string.  If the property does not
646    * exist, or cannot be parsed, then <code>null</code> will be returned.
647    *
648    * @param prop the system property to retrieve
649    * @throws SecurityException if getting the property is denied
650    * @see #getColor(String, Color)
651    * @see Integer#getInteger(String)
652    */
getColor(String prop)653   public static Color getColor(String prop)
654   {
655     return getColor(prop, null);
656   }
657 
658   /**
659    * Returns a new instance of <code>Color</code> from the value of the
660    * system property named by the specified string.  If the property does
661    * not exist, or cannot be parsed, then the default color value will be
662    * returned.
663    *
664    * @param prop the system property to retrieve
665    * @param defcolor the default color
666    * @throws SecurityException if getting the property is denied
667    * @see Integer#getInteger(String)
668    */
getColor(String prop, Color defcolor)669   public static Color getColor(String prop, Color defcolor)
670   {
671     Integer val = Integer.getInteger(prop, null);
672     return val == null ? defcolor
673       : new Color(val.intValue(), false);
674   }
675 
676   /**
677    * Returns a new instance of <code>Color</code> from the value of the
678    * system property named by the specified string.  If the property does
679    * not exist, or cannot be parsed, then the default RGB value will be
680    * used to create a return value.
681    *
682    * @param prop the system property to retrieve
683    * @param defrgb the default RGB value
684    * @throws SecurityException if getting the property is denied
685    * @see #getColor(String, Color)
686    * @see Integer#getInteger(String, int)
687    */
getColor(String prop, int defrgb)688   public static Color getColor(String prop, int defrgb)
689   {
690     Color c = getColor(prop, null);
691     return c == null ? new Color(defrgb, false) : c;
692   }
693 
694   /**
695    * Converts from the HSB (hue, saturation, brightness) color model to the
696    * RGB (red, green, blue) color model. The hue may be any floating point;
697    * it's fractional portion is used to select the angle in the HSB model.
698    * The saturation and brightness must be between 0 and 1. The result is
699    * suitable for creating an RGB color with the one-argument constructor.
700    *
701    * @param hue the hue of the HSB value
702    * @param saturation the saturation of the HSB value
703    * @param brightness the brightness of the HSB value
704    * @return the RGB value
705    * @see #getRGB()
706    * @see #Color(int)
707    * @see ColorModel#getRGBdefault()
708    */
HSBtoRGB(float hue, float saturation, float brightness)709   public static int HSBtoRGB(float hue, float saturation, float brightness)
710   {
711     if (saturation == 0)
712       return convert(brightness, brightness, brightness, 0);
713     if (saturation < 0 || saturation > 1 || brightness < 0 || brightness > 1)
714       throw new IllegalArgumentException();
715     hue = hue - (float) Math.floor(hue);
716     int i = (int) (6 * hue);
717     float f = 6 * hue - i;
718     float p = brightness * (1 - saturation);
719     float q = brightness * (1 - saturation * f);
720     float t = brightness * (1 - saturation * (1 - f));
721     switch (i)
722       {
723       case 0:
724         return convert(brightness, t, p, 0);
725       case 1:
726         return convert(q, brightness, p, 0);
727       case 2:
728         return convert(p, brightness, t, 0);
729       case 3:
730         return convert(p, q, brightness, 0);
731       case 4:
732         return convert(t, p, brightness, 0);
733       case 5:
734         return convert(brightness, p, q, 0);
735       default:
736         throw new InternalError("impossible");
737       }
738   }
739 
740   /**
741    * Converts from the RGB (red, green, blue) color model to the HSB (hue,
742    * saturation, brightness) color model. If the array is null, a new one
743    * is created, otherwise it is recycled. The results will be in the range
744    * 0.0-1.0 if the inputs are in the range 0-255.
745    *
746    * @param red the red part of the RGB value
747    * @param green the green part of the RGB value
748    * @param blue the blue part of the RGB value
749    * @param array an array for the result (at least 3 elements), or null
750    * @return the array containing HSB value
751    * @throws ArrayIndexOutOfBoundsException of array is too small
752    * @see #getRGB()
753    * @see #Color(int)
754    * @see ColorModel#getRGBdefault()
755    */
RGBtoHSB(int red, int green, int blue, float array[])756   public static float[] RGBtoHSB(int red, int green, int blue, float array[])
757   {
758     if (array == null)
759       array = new float[3];
760     // Calculate brightness.
761     int min;
762     int max;
763     if (red < green)
764       {
765         min = red;
766         max = green;
767       }
768     else
769       {
770         min = green;
771         max = red;
772       }
773     if (blue > max)
774       max = blue;
775     else if (blue < min)
776       min = blue;
777     array[2] = max / 255f;
778     // Calculate saturation.
779     if (max == 0)
780       array[1] = 0;
781     else
782       array[1] = ((float) (max - min)) / ((float) max);
783     // Calculate hue.
784     if (array[1] == 0)
785       array[0] = 0;
786     else
787       {
788         float delta = (max - min) * 6;
789         if (red == max)
790           array[0] = (green - blue) / delta;
791         else if (green == max)
792           array[0] = 1f / 3 + (blue - red) / delta;
793         else
794           array[0] = 2f / 3 + (red - green) / delta;
795         if (array[0] < 0)
796           array[0]++;
797       }
798     return array;
799   }
800 
801   /**
802    * Returns a new instance of <code>Color</code> based on the specified
803    * HSB values. The hue may be any floating point; it's fractional portion
804    * is used to select the angle in the HSB model. The saturation and
805    * brightness must be between 0 and 1.
806    *
807    * @param hue the hue of the HSB value
808    * @param saturation the saturation of the HSB value
809    * @param brightness the brightness of the HSB value
810    * @return the new <code>Color</code> object
811    */
getHSBColor(float hue, float saturation, float brightness)812   public static Color getHSBColor(float hue, float saturation,
813                                   float brightness)
814   {
815     return new Color(HSBtoRGB(hue, saturation, brightness), false);
816   }
817 
818   /**
819    * Returns a float array with the red, green, and blue components, and the
820    * alpha value, in the default sRGB space, with values in the range 0.0-1.0.
821    * If the array is null, a new one is created, otherwise it is recycled.
822    *
823    * @param array the array to put results into (at least 4 elements), or null
824    * @return the RGB components and alpha value
825    * @throws ArrayIndexOutOfBoundsException if array is too small
826    */
getRGBComponents(float[] array)827   public float[] getRGBComponents(float[] array)
828   {
829     if (array == null)
830       array = new float[4];
831     getRGBColorComponents(array);
832     // Stupid serialization issues require this check.
833     array[3] = (falpha == 0 && frgbvalue == null
834                 ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha);
835     return array;
836   }
837 
838   /**
839    * Returns a float array with the red, green, and blue components, in the
840    * default sRGB space, with values in the range 0.0-1.0. If the array is
841    * null, a new one is created, otherwise it is recycled.
842    *
843    * @param array the array to put results into (at least 3 elements), or null
844    * @return the RGB components
845    * @throws ArrayIndexOutOfBoundsException if array is too small
846    */
getRGBColorComponents(float[] array)847   public float[] getRGBColorComponents(float[] array)
848   {
849     if (array == null)
850       array = new float[3];
851     else if (array == frgbvalue)
852       return array; // Optimization for getColorComponents(float[]).
853     if (frgbvalue == null)
854       {
855         // Do not inline getRGB() to this.value, because of SystemColor.
856         int value = getRGB();
857         frgbvalue = new float[] { ((value & RED_MASK) >> 16) / 255f,
858                                   ((value & GREEN_MASK) >> 8) / 255f,
859                                   (value & BLUE_MASK) / 255f };
860       }
861     array[0] = frgbvalue[0];
862     array[1] = frgbvalue[1];
863     array[2] = frgbvalue[2];
864     return array;
865   }
866 
867   /**
868    * Returns a float array containing the color and alpha components of this
869    * color in the ColorSpace it was created with (the constructors which do
870    * not take a ColorSpace parameter use a default sRGB ColorSpace). If the
871    * array is null, a new one is created, otherwise it is recycled, and must
872    * have at least one more position than components used in the color space.
873    *
874    * @param array the array to put results into, or null
875    * @return the original color space components and alpha value
876    * @throws ArrayIndexOutOfBoundsException if array is too small
877    */
getComponents(float[] array)878   public float[] getComponents(float[] array)
879   {
880     int numComponents = cs == null ? 3 : cs.getNumComponents();
881     if (array == null)
882       array = new float[1 + numComponents];
883     getColorComponents(array);
884     // Stupid serialization issues require this check.
885     array[numComponents] = (falpha == 0 && frgbvalue == null
886                             ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha);
887     return array;
888   }
889 
890   /**
891    * Returns a float array containing the color components of this color in
892    * the ColorSpace it was created with (the constructors which do not take
893    * a ColorSpace parameter use a default sRGB ColorSpace). If the array is
894    * null, a new one is created, otherwise it is recycled, and must have at
895    * least as many positions as used in the color space.
896    *
897    * @param array the array to put results into, or null
898    * @return the original color space components
899    * @throws ArrayIndexOutOfBoundsException if array is too small
900    */
getColorComponents(float[] array)901   public float[] getColorComponents(float[] array)
902   {
903     int numComponents = cs == null ? 3 : cs.getNumComponents();
904     if (array == null)
905       array = new float[numComponents];
906     if (fvalue == null) // If fvalue is null, cs should be null too.
907       fvalue = getRGBColorComponents(frgbvalue);
908     System.arraycopy(fvalue, 0, array, 0, numComponents);
909     return array;
910   }
911 
912   /**
913    * Returns a float array containing the color and alpha components of this
914    * color in the given ColorSpace. If the array is null, a new one is
915    * created, otherwise it is recycled, and must have at least one more
916    * position than components used in the color space.
917    *
918    * @param space the color space to translate to
919    * @param array the array to put results into, or null
920    * @return the color space components and alpha value
921    * @throws ArrayIndexOutOfBoundsException if array is too small
922    * @throws NullPointerException if space is null
923    */
getComponents(ColorSpace space, float[] array)924   public float[] getComponents(ColorSpace space, float[] array)
925   {
926     int numComponents = space.getNumComponents();
927     if (array == null)
928       array = new float[1 + numComponents];
929     getColorComponents(space, array);
930     // Stupid serialization issues require this check.
931     array[numComponents] = (falpha == 0 && frgbvalue == null
932                             ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha);
933     return array;
934   }
935 
936   /**
937    * Returns a float array containing the color components of this color in
938    * the given ColorSpace. If the array is null, a new one is created,
939    * otherwise it is recycled, and must have at least as many positions as
940    * used in the color space.
941    *
942    * @param space the color space to translate to
943    * @return the color space components
944    * @throws ArrayIndexOutOfBoundsException if array is too small
945    * @throws NullPointerException if space is null
946    */
getColorComponents(ColorSpace space, float[] array)947   public float[] getColorComponents(ColorSpace space, float[] array)
948   {
949     float[] components = space.fromRGB(getRGBColorComponents(frgbvalue));
950     if (array == null)
951       return components;
952     System.arraycopy(components, 0, array, 0, components.length);
953     return array;
954   }
955 
956   /**
957    * Returns the color space of this color. Except for the constructor which
958    * takes a ColorSpace argument, this will be an implementation of
959    * ColorSpace.CS_sRGB.
960    *
961    * @return the color space
962    */
getColorSpace()963   public ColorSpace getColorSpace()
964   {
965     return cs == null ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : cs;
966   }
967 
968   /**
969    * Returns a paint context, used for filling areas of a raster scan with
970    * this color. Since the color is constant across the entire rectangle, and
971    * since it is always in sRGB space, this implementation returns the same
972    * object, regardless of the parameters. Subclasses, however, may have a
973    * mutable result.
974    *
975    * @param cm the requested color model
976    * @param deviceBounds the bounding box in device coordinates, ignored
977    * @param userBounds the bounding box in user coordinates, ignored
978    * @param xform the bounds transformation, ignored
979    * @param hints any rendering hints, ignored
980    * @return a context for painting this solid color
981    */
createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints)982   public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
983                                     Rectangle2D userBounds,
984                                     AffineTransform xform,
985                                     RenderingHints hints)
986   {
987     if (context == null || !context.getColorModel().equals(cm))
988       context = new ColorPaintContext(cm,value);
989     return context;
990   }
991 
992   /**
993    * Returns the transparency level of this color.
994    *
995    * @return one of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}
996    */
getTransparency()997   public int getTransparency()
998   {
999     // Do not inline getRGB() to this.value, because of SystemColor.
1000     int alpha = getRGB() & ALPHA_MASK;
1001     return alpha == (255 << 24) ? OPAQUE : alpha == 0 ? BITMASK : TRANSLUCENT;
1002   }
1003 
1004   /**
1005    * Converts float values to integer value.
1006    *
1007    * @param red the red value
1008    * @param green the green value
1009    * @param blue the blue value
1010    * @param alpha the alpha value
1011    * @return the integer value made of 8-bit sections
1012    * @throws IllegalArgumentException if parameters are out of range 0.0-1.0
1013    */
convert(float red, float green, float blue, float alpha)1014   private static int convert(float red, float green, float blue, float alpha)
1015   {
1016     if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1
1017         || alpha < 0 || alpha > 1)
1018       throw new IllegalArgumentException("Bad RGB values");
1019     int redval = Math.round(255 * red);
1020     int greenval = Math.round(255 * green);
1021     int blueval = Math.round(255 * blue);
1022     int alphaval = Math.round(255 * alpha);
1023     return (alphaval << 24) | (redval << 16) | (greenval << 8) | blueval;
1024   }
1025 } // class Color
1026