Source for java.awt.Color

   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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
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