001: /*
002: * @(#)Color.java 1.51 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program 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 version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: package java.awt;
028:
029: import java.io.*;
030: import java.lang.*;
031: import java.awt.color.ColorSpace;
032:
033: /**
034: * This class encapsulates colors using the RGB format. In RGB
035: * format, the red, blue, and green components of a color are each
036: * represented by an integer in the range 0-255. The value 0
037: * indicates no contribution from this primary color. The value 255
038: * indicates the maximum intensity of this color component.
039: * <p>
040: * Although the <code>Color</code> class is based on the
041: * three-component RGB model, the class provides a set of convenience
042: * methods for converting between RGB and HSB colors. For a
043: * definition of the RGB and HSB color models, see Foley, van Dam,
044: * Feiner, and Hughes, <cite>Computer Graphics: Principles
045: * and Practice</cite>.
046: *
047: * @version 1.46, 08/19/02
048: * @author Sami Shaio
049: * @author Arthur van Hoff
050: * @since JDK1.0
051: */
052: public class Color implements java.io.Serializable, Transparency {
053: /**
054: * The color white.
055: */
056: public final static Color white = new Color(255, 255, 255);
057: /**
058: * The color white. In the default sRGB space.
059: */
060: public final static Color WHITE = white;
061: /**
062: * The color light gray.
063: */
064: public final static Color lightGray = new Color(192, 192, 192);
065:
066: /**
067: * The color light gray. In the default sRGB space.
068: */
069: public final static Color LIGHT_GRAY = lightGray;
070:
071: /**
072: * The color gray.
073: */
074: public final static Color gray = new Color(128, 128, 128);
075:
076: /**
077: * The color gray. In the default sRGB space.
078: */
079: public final static Color GRAY = gray;
080:
081: /**
082: * The color dark gray.
083: */
084: public final static Color darkGray = new Color(64, 64, 64);
085:
086: /**
087: * The color dark gray. In the default sRGB space.
088: */
089: public final static Color DARK_GRAY = darkGray;
090:
091: /**
092: * The color black.
093: */
094: public final static Color black = new Color(0, 0, 0);
095:
096: /**
097: * The color black. In the default sRGB space.
098: */
099: public final static Color BLACK = black;
100:
101: /**
102: * The color red.
103: */
104: public final static Color red = new Color(255, 0, 0);
105:
106: /**
107: * The color red. In the default sRGB space.
108: */
109: public final static Color RED = red;
110:
111: /**
112: * The color pink.
113: */
114: public final static Color pink = new Color(255, 175, 175);
115:
116: /**
117: * The color pink. In the default sRGB space.
118: */
119: public final static Color PINK = pink;
120:
121: /**
122: * The color orange.
123: */
124: public final static Color orange = new Color(255, 200, 0);
125:
126: /**
127: * The color orange. In the default sRGB space.
128: */
129: public final static Color ORANGE = orange;
130:
131: /**
132: * The color yellow.
133: */
134: public final static Color yellow = new Color(255, 255, 0);
135:
136: /**
137: * The color yellow. In the default sRGB space.
138: */
139: public final static Color YELLOW = yellow;
140:
141: /**
142: * The color green.
143: */
144: public final static Color green = new Color(0, 255, 0);
145:
146: /**
147: * The color green. In the default sRGB space.
148: */
149: public final static Color GREEN = green;
150:
151: /**
152: * The color magenta.
153: */
154: public final static Color magenta = new Color(255, 0, 255);
155:
156: /**
157: * The color magenta. In the default sRGB space.
158: */
159: public final static Color MAGENTA = magenta;
160:
161: /**
162: * The color cyan.
163: */
164: public final static Color cyan = new Color(0, 255, 255);
165:
166: /**
167: * The color cyan. In the default sRGB space.
168: */
169: public final static Color CYAN = cyan;
170:
171: /**
172: * The color blue.
173: */
174: public final static Color blue = new Color(0, 0, 255);
175:
176: /**
177: * The color blue. In the default sRGB space.
178: */
179: public final static Color BLUE = blue;
180:
181: /**
182: * Private data.
183: */
184: transient private int pData;
185: /**
186: * The color value.
187: */
188: int value;
189: /**
190: * The color value in the default sRGB <code>ColorSpace</code> as
191: * <code>float</code> components (no alpha).
192: * If <code>null</code> after object construction, this must be an
193: * sRGB color constructed with 8-bit precision, so compute from the
194: * <code>int</code> color value.
195: * @serial
196: * @see #getRGBColorComponents
197: * @see #getRGBComponents
198: */
199: private float frgbvalue[] = null;
200: /**
201: * The color value in the native <code>ColorSpace</code> as
202: * <code>float</code> components (no alpha).
203: * If <code>null</code> after object construction, this must be an
204: * sRGB color constructed with 8-bit precision, so compute from the
205: * <code>int</code> color value.
206: * @serial
207: * @see #getRGBColorComponents
208: * @see #getRGBComponents
209: */
210: private float fvalue[] = null;
211: /**
212: * The alpha value as a <code>float</code> component.
213: * If <code>frgbvalue</code> is <code>null</code>, this is not valid
214: * data, so compute from the <code>int</code> color value.
215: * @serial
216: * @see #getRGBComponents
217: * @see #getComponents
218: */
219: private float falpha = 0.0f;
220: /**
221: * The <code>ColorSpace</code>. If <code>null</code>, then it's
222: * default is sRGB.
223: * @serial
224: * @see #getColor
225: * @see #getColorSpace
226: * @see #getColorComponents
227: */
228: private ColorSpace cs = null;
229: /*
230: * JDK 1.1 serialVersionUID
231: */
232: private static final long serialVersionUID = 118526816881161077L;
233:
234: /**
235: * Checks the color integer components supplied for validity.
236: * Throws an IllegalArgumentException if the value is out of range.
237: * @param r the Red component
238: * @param g the Green component
239: * @param b the Blue component
240: **/
241: private static void testColorValueRange(int r, int g, int b, int a) {
242: boolean rangeError = false;
243: String badComponentString = "";
244: if (a < 0 || a > 255) {
245: rangeError = true;
246: badComponentString = badComponentString + " Alpha";
247: }
248: if (r < 0 || r > 255) {
249: rangeError = true;
250: badComponentString = badComponentString + " Red";
251: }
252: if (g < 0 || g > 255) {
253: rangeError = true;
254: badComponentString = badComponentString + " Green";
255: }
256: if (b < 0 || b > 255) {
257: rangeError = true;
258: badComponentString = badComponentString + " Blue";
259: }
260: if (rangeError == true) {
261: throw new IllegalArgumentException(
262: "Color parameter outside of expected range:"
263: + badComponentString);
264: }
265: }
266:
267: /**
268: * Checks the color float components supplied for validity.
269: * Throws an IllegalArgumentException if the value is out of range.
270: * @param r the Red component
271: * @param g the Green component
272: * @param b the Blue component
273: **/
274: private static void testColorValueRange(float r, float g, float b,
275: float a) {
276: boolean rangeError = false;
277: String badComponentString = "";
278: if (a < 0 || a > 1.0) {
279: rangeError = true;
280: badComponentString = badComponentString + " Alpha";
281: }
282: if (r < 0.0 || r > 1.0) {
283: rangeError = true;
284: badComponentString = badComponentString + " Red";
285: }
286: if (g < 0.0 || g > 1.0) {
287: rangeError = true;
288: badComponentString = badComponentString + " Green";
289: }
290: if (b < 0.0 || b > 1.0) {
291: rangeError = true;
292: badComponentString = badComponentString + " Blue";
293: }
294: if (rangeError == true) {
295: throw new IllegalArgumentException(
296: "Color parameter outside of expected range:"
297: + badComponentString);
298: }
299: }
300:
301: /**
302: * Creates a color with the specified red, green, and blue
303: * components. The three arguments must each be in the range
304: * 0-255.
305: * <p>
306: * The actual color used in rendering depends on finding the best
307: * match given the color space available for a given output device.
308: * @param r the red component.
309: * @param g the green component.
310: * @param b the blue component.
311: * @see java.awt.Color#getRed
312: * @see java.awt.Color#getGreen
313: * @see java.awt.Color#getBlue
314: * @see java.awt.Color#getRGB
315: * @since JDK1.0
316: */
317: public Color(int r, int g, int b) {
318: this (((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0));
319: testColorValueRange(r, g, b, 255);
320: }
321:
322: /**
323: * Creates an sRGB color with the specified red, green, blue, and alpha
324: * values in the range (0 - 255).
325: * @param r the red component
326: * @param g the green component
327: * @param b the blue component
328: * @param a the alpha component
329: * @see #getRed
330: * @see #getGreen
331: * @see #getBlue
332: * @see #getAlpha
333: * @see #getRGB
334: */
335: public Color(int r, int g, int b, int a) {
336: value = ((a & 0xFF) << 24) | ((r & 0xFF) << 16)
337: | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);
338: testColorValueRange(r, g, b, a);
339: }
340:
341: /**
342: * Creates a color with the specified RGB value, where the red
343: * component is in bits 16-23 of the argument, the green
344: * component is in bits 8-15 of the argument, and the blue
345: * component is in bits 0-7. The value zero indicates no
346: * contribution from the primary color component.
347: * <p>
348: * The actual color used in rendering depends on finding the best
349: * match given the color space available for a given output device.
350: * @param rgb an integer giving the red, green, and blue components.
351: * @see java.awt.image.ColorModel#getRGBdefault
352: * @see java.awt.Color#getRed
353: * @see java.awt.Color#getGreen
354: * @see java.awt.Color#getBlue
355: * @see java.awt.Color#getRGB
356: * @since JDK1.0
357: */
358: public Color(int rgb) {
359: value = 0xff000000 | rgb;
360: }
361:
362: /**
363: * Creates an sRGB color with the specified combined RGBA value consisting
364: * of the alpha component in bits 24-31, the red component in bits 16-23,
365: * the green component in bits 8-15, and the blue component in bits 0-7.
366: * If the <code>hasalpha</code> argument is <code>false</code>, alpha
367: * is defaulted to 255.
368: * @param rgba the combined RGBA components
369: * @param hasalpha <code>true</code> if the alpha bits are valid;
370: * <code>false</code> otherwise
371: * @see java.awt.image.ColorModel#getRGBdefault
372: * @see #getRed
373: * @see #getGreen
374: * @see #getBlue
375: * @see #getAlpha
376: * @see #getRGB
377: */
378: public Color(int rgba, boolean hasalpha) {
379: if (hasalpha) {
380: value = rgba;
381: } else {
382: value = 0xff000000 | rgba;
383: }
384: }
385:
386: /**
387: * Creates a color with the specified red, green, and blue values,
388: * where each of the values is in the range 0.0-1.0. The value
389: * 0.0 indicates no contribution from the primary color component.
390: * The value 1.0 indicates the maximum intensity of the primary color
391: * component.
392: * <p>
393: * The actual color used in rendering depends on finding the best
394: * match given the color space available for a given output device.
395: * @param r the red component
396: * @param g the red component
397: * @param b the red component
398: * @see java.awt.Color#getRed
399: * @see java.awt.Color#getGreen
400: * @see java.awt.Color#getBlue
401: * @see java.awt.Color#getRGB
402: * @since JDK1.0
403: */
404: public Color(float r, float g, float b) {
405: this (r, g, b, 1.0f);
406: }
407:
408: /**
409: * Creates an sRGB color with the specified red, green, blue, and
410: * alpha values in the range (0.0 - 1.0). The actual color
411: * used in rendering depends on finding the best match given the
412: * color space available for a particular output device.
413: * @param r the red component
414: * @param g the green component
415: * @param b the blue component
416: * @param a the alpha component
417: * @see #getRed
418: * @see #getGreen
419: * @see #getBlue
420: * @see #getAlpha
421: * @see #getRGB
422: */
423: public Color(float r, float g, float b, float a) {
424: this ((int) (r * 255 + 0.5), (int) (g * 255 + 0.5),
425: (int) (b * 255 + 0.5), (int) (a * 255 + 0.5));
426: testColorValueRange(r, g, b, a);
427: frgbvalue = new float[3];
428: frgbvalue[0] = r;
429: frgbvalue[1] = g;
430: frgbvalue[2] = b;
431: falpha = a;
432: fvalue = frgbvalue;
433: }
434:
435: /**
436: * Gets the red component of this color. The result is
437: * an integer in the range 0 to 255.
438: * @return the red component of this color.
439: * @see java.awt.Color#getRGB
440: * @since JDK1.0
441: */
442: public int getRed() {
443: return (getRGB() >> 16) & 0xFF;
444: }
445:
446: /**
447: * Gets the green component of this color. The result is
448: * an integer in the range 0 to 255.
449: * @return the green component of this color.
450: * @see java.awt.Color#getRGB
451: * @since JDK1.0
452: */
453: public int getGreen() {
454: return (getRGB() >> 8) & 0xFF;
455: }
456:
457: /**
458: * Gets the blue component of this color. The result is
459: * an integer in the range 0 to 255.
460: * @return the blue component of this color.
461: * @see java.awt.Color#getRGB
462: * @since JDK1.0
463: */
464: public int getBlue() {
465: return (getRGB() >> 0) & 0xFF;
466: }
467:
468: /**
469: * Returns the alpha component in the range 0-255.
470: * @return the alpha component.
471: * @see #getRGB
472: */
473: public int getAlpha() {
474: return (getRGB() >> 24) & 0xff;
475: }
476:
477: /**
478: * Gets the RGB value representing the color in the default RGB ColorModel.
479: * The red, green, and blue components of the color are each scaled to be
480: * a value between 0 (abscence of the color) and 255 (complete saturation).
481: * Bits 24-31 of the returned integer are 0xff, bits 16-23 are the red
482: * value, bit 8-15 are the green value, and bits 0-7 are the blue value.
483: * @see java.awt.image.ColorModel#getRGBdefault
484: * @see #getRed
485: * @see #getGreen
486: * @see #getBlue
487: * @since JDK1.0
488: */
489: public int getRGB() {
490: return value;
491: }
492:
493: private static final int FACTOR = 70;
494:
495: /**
496: * Creates a brighter version of this color.
497: * <p>
498: * This method applies an arbitrary scale factor to each of the three RGB
499: * components of the color to create a brighter version of the same
500: * color. Although <code>brighter</code> and <code>darker</code> are
501: * inverse operations, the results of a series of invocations of
502: * these two methods may be inconsistent because of rounding errors.
503: * @return a new <code>Color</code> object,
504: * a brighter version of this color.
505: * @see java.awt.Color#darker
506: * @since JDK1.0
507: */
508: public Color brighter() {
509: int r = getRed();
510: int g = getGreen();
511: int b = getBlue();
512: /* From 2D group:
513: * 1. black.brighter() should return grey
514: * 2. applying brighter to blue will always return blue, brighter
515: * 3. non pure color (non zero rgb) will eventually return white
516: */
517: int i = (int) (100 / (100 - FACTOR));
518: if (r == 0 && g == 0 && b == 0) {
519: return new Color(i, i, i);
520: }
521: if (r > 0 && r < i)
522: r = i;
523: if (g > 0 && g < i)
524: g = i;
525: if (b > 0 && b < i)
526: b = i;
527: return new Color(Math.min((r * 100) / FACTOR, 255), Math.min(
528: (g * 100) / FACTOR, 255), Math.min((b * 100) / FACTOR,
529: 255));
530: }
531:
532: /**
533: * Creates a darker version of this color.
534: * <p>
535: * This method applies an arbitrary scale factor to each of the three RGB
536: * components of the color to create a darker version of the same
537: * color. Although <code>brighter</code> and <code>darker</code> are
538: * inverse operations, the results of a series of invocations of
539: * these two methods may be inconsistent because of rounding errors.
540: * @return a new <code>Color</code> object,
541: * a darker version of this color.
542: * @see java.awt.Color#brighter
543: * @since JDK1.0
544: */
545: public Color darker() {
546: return new Color(Math.max((getRed() * FACTOR) / 100, 0), Math
547: .max((getGreen() * FACTOR) / 100, 0), Math.max(
548: (getBlue() * FACTOR) / 100, 0));
549: }
550:
551: /**
552: * Computes the hash code for this color.
553: * @return a hash code value for this object.
554: * @since JDK1.0
555: */
556: public int hashCode() {
557: return value;
558: }
559:
560: /**
561: * Determines whether another object is equal to this color.
562: * <p>
563: * The result is <code>true</code> if and only if the argument is not
564: * <code>null</code> and is a <code>Color</code> object that has the same
565: * red, green, and blue values as this object.
566: * @param obj the object to compare with.
567: * @return <code>true</code> if the objects are the same;
568: * <code>false</code> otherwise.
569: * @since JDK1.0
570: */
571: public boolean equals(Object obj) {
572: return obj instanceof Color
573: && ((Color) obj).value == this .value;
574: }
575:
576: /**
577: * Creates a string that represents this color and indicates the
578: * values of its RGB components.
579: * @return a representation of this color as a
580: * <code>String</code> object.
581: * @since JDK1.0
582: */
583: public String toString() {
584: return getClass().getName() + "[r=" + getRed() + ",g="
585: + getGreen() + ",b=" + getBlue() + "]";
586: }
587:
588: /**
589: * Converts a string to an integer and returns the
590: * specified color. This method handles string formats that
591: * are used to represent octal and hexidecimal numbers.
592: * @param nm a string that represents
593: * a color as a 24-bit integer.
594: * @return the new color
595: * @see java.lang.Integer#decode
596: * @exception NumberFormatException if the specified string cannot
597: * be interpreted as a decimal,
598: * octal, or hexidecimal integer.
599: * @since JDK1.1
600: */
601: public static Color decode(String nm) throws NumberFormatException {
602: Integer intval = Integer.decode(nm);
603: int i = intval.intValue();
604: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
605: }
606:
607: /**
608: * Finds a color in the system properties.
609: * <p>
610: * The argument is treated as the name of a system property to
611: * be obtained. The string value of this property is then interpreted
612: * as an integer which is then converted to a color.
613: * <p>
614: * If the specified property is not found, or could not be parsed as
615: * an integer, then <code>null</code> is returned.
616: * @param nm the name of the color property
617: * @return the color value of the property.
618: * @see java.lang.System#getProperty(java.lang.String)
619: * @see java.lang.Integer#getInteger(java.lang.String)
620: * @see java.awt.Color#Color(int)
621: * @since JDK1.0
622: */
623: public static Color getColor(String nm) {
624: return getColor(nm, null);
625: }
626:
627: /**
628: * Finds a color in the system properties.
629: * <p>
630: * The first argument is treated as the name of a system property to
631: * be obtained. The string value of this property is then interpreted
632: * as an integer which is then converted to a color.
633: * <p>
634: * If the specified property is not found, or cannot be parsed as
635: * an integer, then the color specified by the second argument is
636: * returned instead.
637: * @param nm the name of the color property
638: * @param v the default color value.
639: * @return the color value of the property.
640: * @see java.lang.System#getProperty(java.lang.String)
641: * @see java.lang.Integer#getInteger(java.lang.String)
642: * @see java.awt.Color#Color(int)
643: * @since JDK1.0
644: */
645: public static Color getColor(String nm, Color v) {
646: Integer intval = Integer.getInteger(nm);
647: if (intval == null) {
648: return v;
649: }
650: int i = intval.intValue();
651: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
652: }
653:
654: /**
655: * Finds a color in the system properties.
656: * <p>
657: * The first argument is treated as the name of a system property to
658: * be obtained. The string value of this property is then interpreted
659: * as an integer which is then converted to a color.
660: * <p>
661: * If the specified property is not found, or could not be parsed as
662: * an integer, then the integer value <code>v</code> is used instead,
663: * and is converted to a color.
664: * @param nm the name of the color property.
665: * @param v the default color value, as an integer.
666: * @return the color value of the property.
667: * @see java.lang.System#getProperty(java.lang.String)
668: * @see java.lang.Integer#getInteger(java.lang.String)
669: * @see java.awt.Color#Color(int)
670: * @since JDK1.0
671: */
672: public static Color getColor(String nm, int v) {
673: Integer intval = Integer.getInteger(nm);
674: int i = (intval != null) ? intval.intValue() : v;
675: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF,
676: (i >> 0) & 0xFF);
677: }
678:
679: /**
680: * Converts the components of a color, as specified by the HSB
681: * model, to an equivalent set of values for the RGB model.
682: * <p>
683: * The integer that is returned by <code>HSBtoRGB</code> encodes the
684: * value of a color in bits 0&endash;23 of an integer value, the same
685: * format used by the method <code>getRGB</code>. This integer can be
686: * supplied as an argument to the <code>Color</code> constructor that
687: * takes a single integer argument.
688: * @param hue the hue component of the color.
689: * @param saturation the saturation of the color.
690: * @param brightness the brightness of the color.
691: * @return the RGB value of the color with the indicated hue,
692: * saturation, and brightness.
693: * @see java.awt.Color#getRGB()
694: * @see java.awt.Color#Color(int)
695: * @since JDK1.0
696: */
697: public static int HSBtoRGB(float hue, float saturation,
698: float brightness) {
699: int r = 0, g = 0, b = 0;
700: if (saturation == 0) {
701: r = g = b = (int) (brightness * 255);
702: } else {
703: double h = (hue - Math.floor(hue)) * 6.0;
704: double f = h - java.lang.Math.floor(h);
705: double p = brightness * (1.0 - saturation);
706: double q = brightness * (1.0 - saturation * f);
707: double t = brightness * (1.0 - (saturation * (1.0 - f)));
708: switch ((int) h) {
709: case 0:
710: r = (int) (brightness * 255);
711: g = (int) (t * 255);
712: b = (int) (p * 255);
713: break;
714:
715: case 1:
716: r = (int) (q * 255);
717: g = (int) (brightness * 255);
718: b = (int) (p * 255);
719: break;
720:
721: case 2:
722: r = (int) (p * 255);
723: g = (int) (brightness * 255);
724: b = (int) (t * 255);
725: break;
726:
727: case 3:
728: r = (int) (p * 255);
729: g = (int) (q * 255);
730: b = (int) (brightness * 255);
731: break;
732:
733: case 4:
734: r = (int) (t * 255);
735: g = (int) (p * 255);
736: b = (int) (brightness * 255);
737: break;
738:
739: case 5:
740: r = (int) (brightness * 255);
741: g = (int) (p * 255);
742: b = (int) (q * 255);
743: break;
744: }
745: }
746: return 0xff000000 | (r << 16) | (g << 8) | (b << 0);
747: }
748:
749: /**
750: * Converts the components of a color, as specified by the RGB
751: * model, to an equivalent set of values for hue, saturation, and
752: * brightness, the three components of the HSB model.
753: * <p>
754: * If the <code>hsbvals</code> argument is <code>null</code>, then a
755: * new array is allocated to return the result. Otherwise, the method
756: * returns the array <code>hsbvals</code>, with the values put into
757: * that array.
758: * @param r the red component of the color.
759: * @param g the green component of the color.
760: * @param b the blue component of the color.
761: * @param hsbvals the array to be used to return the
762: * three HSB values, or <code>null</code>.
763: * @return an array of three elements containing the hue, saturation,
764: * and brightness (in that order), of the color with
765: * the indicated red, green, and blue components.
766: * @see java.awt.Color#getRGB()
767: * @see java.awt.Color#Color(int)
768: * @since JDK1.0
769: */
770: public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) {
771: float hue, saturation, brightness;
772: if (hsbvals == null) {
773: hsbvals = new float[3];
774: }
775: int cmax = (r > g) ? r : g;
776: if (b > cmax)
777: cmax = b;
778: int cmin = (r < g) ? r : g;
779: if (b < cmin)
780: cmin = b;
781: brightness = ((float) cmax) / 255.0f;
782: if (cmax != 0)
783: saturation = ((float) (cmax - cmin)) / ((float) cmax);
784: else
785: saturation = 0;
786: if (saturation == 0)
787: hue = 0;
788: else {
789: float redc = ((float) (cmax - r)) / ((float) (cmax - cmin));
790: float greenc = ((float) (cmax - g))
791: / ((float) (cmax - cmin));
792: float bluec = ((float) (cmax - b))
793: / ((float) (cmax - cmin));
794: if (r == cmax)
795: hue = bluec - greenc;
796: else if (g == cmax)
797: hue = 2.0f + redc - bluec;
798: else
799: hue = 4.0f + greenc - redc;
800: hue = hue / 6.0f;
801: if (hue < 0)
802: hue = hue + 1.0f;
803: }
804: hsbvals[0] = hue;
805: hsbvals[1] = saturation;
806: hsbvals[2] = brightness;
807: return hsbvals;
808: }
809:
810: /**
811: * Creates a <code>Color</code> object based on values supplied
812: * for the HSB color model.
813: * <p>
814: * Each of the three components should be a floating-point
815: * value between zero and one (a number in the range
816: * <code>0.0</code> ≤ <code>h</code>, <code>s</code>,
817: * <code>b</code> ≤ <code>1.0). </code>
818: * @param h the hue component.
819: * @param s the saturation of the color.
820: * @param b the brightness of the color.
821: * @return a <code>Color</code> object with the specified hue,
822: * saturation, and brightness.
823: * @since JDK1.0
824: */
825: public static Color getHSBColor(float h, float s, float b) {
826: return new Color(HSBtoRGB(h, s, b));
827: }
828:
829: /**
830: * Returns a <code>float</code> array containing the color and alpha
831: * components of the <code>Color</code>, as represented in the default
832: * sRGB color space.
833: * If <code>compArray</code> is <code>null</code>, an array of length
834: * 4 is created for the return value. Otherwise,
835: * <code>compArray</code> must have length 4 or greater,
836: * and it is filled in with the components and returned.
837: * @param compArray an array that this method fills with
838: * color and alpha components and returns
839: * @return the RGBA components in a <code>float</code> array.
840: */
841: public float[] getRGBComponents(float[] compArray) {
842: float[] f;
843: if (compArray == null) {
844: f = new float[4];
845: } else {
846: f = compArray;
847: }
848: if (frgbvalue == null) {
849: f[0] = ((float) getRed()) / 255f;
850: f[1] = ((float) getGreen()) / 255f;
851: f[2] = ((float) getBlue()) / 255f;
852: f[3] = ((float) getAlpha()) / 255f;
853: } else {
854: f[0] = frgbvalue[0];
855: f[1] = frgbvalue[1];
856: f[2] = frgbvalue[2];
857: f[3] = falpha;
858: }
859: return f;
860: }
861:
862: /**
863: * Returns a <code>float</code> array containing only the color
864: * components of the <code>Color</code>, in the default sRGB color
865: * space. If <code>compArray</code> is <code>null</code>, an array of
866: * length 3 is created for the return value. Otherwise,
867: * <code>compArray</code> must have length 3 or greater, and it is
868: * filled in with the components and returned.
869: * @param compArray an array that this method fills with color
870: * components and returns
871: * @return the RGB components in a <code>float</code> array.
872: */
873: public float[] getRGBColorComponents(float[] compArray) {
874: float[] f;
875: if (compArray == null) {
876: f = new float[3];
877: } else {
878: f = compArray;
879: }
880: if (frgbvalue == null) {
881: f[0] = ((float) getRed()) / 255f;
882: f[1] = ((float) getGreen()) / 255f;
883: f[2] = ((float) getBlue()) / 255f;
884: } else {
885: f[0] = frgbvalue[0];
886: f[1] = frgbvalue[1];
887: f[2] = frgbvalue[2];
888: }
889: return f;
890: }
891:
892: /**
893: * Returns a <code>float</code> array containing the color and alpha
894: * components of the <code>Color</code>, in the
895: * <code>ColorSpace</code> of the <code>Color</code>.
896: * If <code>compArray</code> is <code>null</code>, an array with
897: * length equal to the number of components in the associated
898: * <code>ColorSpace</code> plus one is created for
899: * the return value. Otherwise, <code>compArray</code> must have at
900: * least this length and it is filled in with the components and
901: * returned.
902: * @param compArray an array that this method fills with the color and
903: * alpha components of this <code>Color</code> in its
904: * <code>ColorSpace</code> and returns
905: * @return the color and alpha components in a <code>float</code>
906: * array.
907: */
908: public float[] getComponents(float[] compArray) {
909: if (fvalue == null)
910: return getRGBComponents(compArray);
911: float[] f;
912: int n = fvalue.length;
913: if (compArray == null) {
914: f = new float[n + 1];
915: } else {
916: f = compArray;
917: }
918: for (int i = 0; i < n; i++) {
919: f[i] = fvalue[i];
920: }
921: f[n] = falpha;
922: return f;
923: }
924:
925: /**
926: * Returns a <code>float</code> array containing only the color
927: * components of the <code>Color</code>, in the
928: * <code>ColorSpace</code> of the <code>Color</code>.
929: * If <code>compArray</code> is <code>null</code>, an array with
930: * length equal to the number of components in the associated
931: * <code>ColorSpace</code> is created for
932: * the return value. Otherwise, <code>compArray</code> must have at
933: * least this length and it is filled in with the components and
934: * returned.
935: * @param compArray an array that this method fills with the color
936: * components of this <code>Color</code> in its
937: * <code>ColorSpace</code> and returns
938: * @return the color components in a <code>float</code> array.
939: */
940: public float[] getColorComponents(float[] compArray) {
941: if (fvalue == null)
942: return getRGBColorComponents(compArray);
943: float[] f;
944: int n = fvalue.length;
945: if (compArray == null) {
946: f = new float[n];
947: } else {
948: f = compArray;
949: }
950: for (int i = 0; i < n; i++) {
951: f[i] = fvalue[i];
952: }
953: return f;
954: }
955:
956: /**
957: * Returns the transparency mode for this <code>Color</code>. This is
958: * required to implement the <code>Paint</code> interface.
959: * @return this <code>Color</code> object's transparency mode.
960: * @see Paint
961: * @see Transparency
962: * @see #createContext
963: */
964: public int getTransparency() {
965: int alpha = getAlpha();
966: if (alpha == 0xff) {
967: return Transparency.OPAQUE;
968: } else if (alpha == 0) {
969: return Transparency.BITMASK;
970: } else {
971: return Transparency.TRANSLUCENT;
972: }
973: }
974:
975: /**
976: * Returns the <code>ColorSpace</code> of this <code>Color</code>.
977: * @return this <code>Color</code> object's <code>ColorSpace</code>.
978: */
979: public ColorSpace getColorSpace() {
980: if (cs == null) {
981: cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
982: }
983: return cs;
984: }
985: }
|