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