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 red = (value & RED_MASK) >> 16;
 538:     int green = (value & GREEN_MASK) >> 8;
 539:     int blue = value & BLUE_MASK;
 540:     // We have to special case 0-2 because they won't scale by division.
 541:     red = red < 3 ? 3 : (int) Math.min(255, red / BRIGHT_SCALE);
 542:     green = green < 3 ? 3 : (int) Math.min(255, green / BRIGHT_SCALE);
 543:     blue = blue < 3 ? 3 : (int) Math.min(255, blue / BRIGHT_SCALE);
 544:     return new Color(red, green, blue, 255);
 545:   }
 546: 
 547:   /**
 548:    * Returns a darker version of this color. This is done by decreasing the
 549:    * RGB values by an arbitrary scale factor. The new color is opaque (an
 550:    * alpha of 255). Note that this method and the <code>brighter()</code>
 551:    * method are not necessarily inverses.
 552:    *
 553:    * @return a darker version of this color
 554:    * @see #brighter()
 555:    */
 556:   public Color darker()
 557:   {
 558:     // Do not inline getRGB() to this.value, because of SystemColor.
 559:     int value = getRGB();
 560:     return new Color((int) (((value & RED_MASK) >> 16) * BRIGHT_SCALE),
 561:                      (int) (((value & GREEN_MASK) >> 8) * BRIGHT_SCALE),
 562:                      (int) ((value & BLUE_MASK) * BRIGHT_SCALE), 255);
 563:   }
 564: 
 565:   /**
 566:    * Returns a hash value for this color. This is simply the color in 8-bit
 567:    * precision, in the format 0xAARRGGBB (alpha, red, green, blue).
 568:    *
 569:    * @return a hash value for this color
 570:    */
 571:   public int hashCode()
 572:   {
 573:     return value;
 574:   }
 575: 
 576:   /**
 577:    * Tests this object for equality against the specified object.  This will
 578:    * be true if and only if the specified object is an instance of
 579:    * <code>Color</code> and has the same 8-bit integer red, green, and blue
 580:    * values as this object. Note that two colors may be slightly different
 581:    * as float values, but round to the same integer values. Also note that
 582:    * this does not accurately compare SystemColors, since that class does
 583:    * not store its internal data in RGB format like regular colors.
 584:    *
 585:    * @param obj the object to compare to
 586:    * @return true if the specified object is semantically equal to this one
 587:    */
 588:   public boolean equals(Object obj)
 589:   {
 590:     return obj instanceof Color && ((Color) obj).value == value;
 591:   }
 592: 
 593:   /**
 594:    * Returns a string representation of this object. Subclasses may return
 595:    * any desired format, except for null, but this implementation returns
 596:    * <code>getClass().getName() + "[r=" + getRed() + ",g=" + getGreen()
 597:    * + ",b=" + getBlue() + ']'</code>.
 598:    *
 599:    * @return a string representation of this object
 600:    */
 601:   public String toString()
 602:   {
 603:     return getClass().getName() + "[r=" + ((value & RED_MASK) >> 16)
 604:       + ",g=" + ((value & GREEN_MASK) >> 8) + ",b=" + (value & BLUE_MASK)
 605:       + ']';
 606:   }
 607: 
 608:   /**
 609:    * Converts the specified string to a number, using Integer.decode, and
 610:    * creates a new instance of <code>Color</code> from the value. The alpha
 611:    * value will be 255 (opaque).
 612:    *
 613:    * @param str the numeric color string
 614:    * @return a new instance of <code>Color</code> for the string
 615:    * @throws NumberFormatException if the string cannot be parsed
 616:    * @throws NullPointerException if the string is null
 617:    * @see Integer#decode(String)
 618:    * @see #Color(int)
 619:    * @since 1.1
 620:    */
 621:   public static Color decode(String str)
 622:   {
 623:     return new Color(Integer.decode(str).intValue(), false);
 624:   }
 625: 
 626:   /**
 627:    * Returns a new instance of <code>Color</code> from the value of the
 628:    * system property named by the specified string.  If the property does not
 629:    * exist, or cannot be parsed, then <code>null</code> will be returned.
 630:    *
 631:    * @param prop the system property to retrieve
 632:    * @throws SecurityException if getting the property is denied
 633:    * @see #getColor(String, Color)
 634:    * @see Integer#getInteger(String)
 635:    */
 636:   public static Color getColor(String prop)
 637:   {
 638:     return getColor(prop, null);
 639:   }
 640: 
 641:   /**
 642:    * Returns a new instance of <code>Color</code> from the value of the
 643:    * system property named by the specified string.  If the property does
 644:    * not exist, or cannot be parsed, then the default color value will be
 645:    * returned.
 646:    *
 647:    * @param prop the system property to retrieve
 648:    * @param defcolor the default color
 649:    * @throws SecurityException if getting the property is denied
 650:    * @see Integer#getInteger(String)
 651:    */
 652:   public static Color getColor(String prop, Color defcolor)
 653:   {
 654:     Integer val = Integer.getInteger(prop, null);
 655:     return val == null ? defcolor
 656:       : new Color(val.intValue(), false);
 657:   }
 658: 
 659:   /**
 660:    * Returns a new instance of <code>Color</code> from the value of the
 661:    * system property named by the specified string.  If the property does
 662:    * not exist, or cannot be parsed, then the default RGB value will be
 663:    * used to create a return value.
 664:    *
 665:    * @param prop the system property to retrieve
 666:    * @param defrgb the default RGB value
 667:    * @throws SecurityException if getting the property is denied
 668:    * @see #getColor(String, Color)
 669:    * @see Integer#getInteger(String, int)
 670:    */
 671:   public static Color getColor(String prop, int defrgb)
 672:   {
 673:     Color c = getColor(prop, null);
 674:     return c == null ? new Color(defrgb, false) : c;
 675:   }
 676: 
 677:   /**
 678:    * Converts from the HSB (hue, saturation, brightness) color model to the
 679:    * RGB (red, green, blue) color model. The hue may be any floating point;
 680:    * it's fractional portion is used to select the angle in the HSB model.
 681:    * The saturation and brightness must be between 0 and 1. The result is
 682:    * suitable for creating an RGB color with the one-argument constructor.
 683:    *
 684:    * @param hue the hue of the HSB value
 685:    * @param saturation the saturation of the HSB value
 686:    * @param brightness the brightness of the HSB value
 687:    * @return the RGB value
 688:    * @see #getRGB()
 689:    * @see #Color(int)
 690:    * @see ColorModel#getRGBdefault()
 691:    */
 692:   public static int HSBtoRGB(float hue, float saturation, float brightness)
 693:   {
 694:     if (saturation == 0)
 695:       return convert(brightness, brightness, brightness, 0);
 696:     if (saturation < 0 || saturation > 1 || brightness < 0 || brightness > 1)
 697:       throw new IllegalArgumentException();
 698:     hue = hue - (float) Math.floor(hue);
 699:     int i = (int) (6 * hue);
 700:     float f = 6 * hue - i;
 701:     float p = brightness * (1 - saturation);
 702:     float q = brightness * (1 - saturation * f);
 703:     float t = brightness * (1 - saturation * (1 - f));
 704:     switch (i)
 705:       {
 706:       case 0:
 707:         return convert(brightness, t, p, 0);
 708:       case 1:
 709:         return convert(q, brightness, p, 0);
 710:       case 2:
 711:         return convert(p, brightness, t, 0);
 712:       case 3:
 713:         return convert(p, q, brightness, 0);
 714:       case 4:
 715:         return convert(t, p, brightness, 0);
 716:       case 5:
 717:         return convert(brightness, p, q, 0);
 718:       default:
 719:         throw new InternalError("impossible");
 720:       }
 721:   }
 722: 
 723:   /**
 724:    * Converts from the RGB (red, green, blue) color model to the HSB (hue,
 725:    * saturation, brightness) color model. If the array is null, a new one
 726:    * is created, otherwise it is recycled. The results will be in the range
 727:    * 0.0-1.0 if the inputs are in the range 0-255.
 728:    *
 729:    * @param red the red part of the RGB value
 730:    * @param green the green part of the RGB value
 731:    * @param blue the blue part of the RGB value
 732:    * @param array an array for the result (at least 3 elements), or null
 733:    * @return the array containing HSB value
 734:    * @throws ArrayIndexOutOfBoundsException of array is too small
 735:    * @see #getRGB()
 736:    * @see #Color(int)
 737:    * @see ColorModel#getRGBdefault()
 738:    */
 739:   public static float[] RGBtoHSB(int red, int green, int blue, float array[])
 740:   {
 741:     if (array == null)
 742:       array = new float[3];
 743:     // Calculate brightness.
 744:     int min;
 745:     int max;
 746:     if (red < green)
 747:       {
 748:         min = red;
 749:         max = green;
 750:       }
 751:     else
 752:       {
 753:         min = green;
 754:         max = red;
 755:       }
 756:     if (blue > max)
 757:       max = blue;
 758:     else if (blue < min)
 759:       min = blue;
 760:     array[2] = max / 255f;
 761:     // Calculate saturation.
 762:     if (max == 0)
 763:       array[1] = 0;
 764:     else
 765:       array[1] = ((float) (max - min)) / ((float) max);
 766:     // Calculate hue.
 767:     if (array[1] == 0)
 768:       array[0] = 0;
 769:     else
 770:       {
 771:         float delta = (max - min) * 6;
 772:         if (red == max)
 773:           array[0] = (green - blue) / delta;
 774:         else if (green == max)
 775:           array[0] = 1f / 3 + (blue - red) / delta;
 776:         else
 777:           array[0] = 2f / 3 + (red - green) / delta;
 778:         if (array[0] < 0)
 779:           array[0]++;
 780:       }
 781:     return array;
 782:   }
 783: 
 784:   /**
 785:    * Returns a new instance of <code>Color</code> based on the specified
 786:    * HSB values. The hue may be any floating point; it's fractional portion
 787:    * is used to select the angle in the HSB model. The saturation and
 788:    * brightness must be between 0 and 1.
 789:    *
 790:    * @param hue the hue of the HSB value
 791:    * @param saturation the saturation of the HSB value
 792:    * @param brightness the brightness of the HSB value
 793:    * @return the new <code>Color</code> object
 794:    */
 795:   public static Color getHSBColor(float hue, float saturation,
 796:                                   float brightness)
 797:   {
 798:     return new Color(HSBtoRGB(hue, saturation, brightness), false);
 799:   }
 800: 
 801:   /**
 802:    * Returns a float array with the red, green, and blue components, and the
 803:    * alpha value, in the default sRGB space, with values in the range 0.0-1.0.
 804:    * If the array is null, a new one is created, otherwise it is recycled.
 805:    *
 806:    * @param array the array to put results into (at least 4 elements), or null
 807:    * @return the RGB components and alpha value
 808:    * @throws ArrayIndexOutOfBoundsException if array is too small
 809:    */
 810:   public float[] getRGBComponents(float[] array)
 811:   {
 812:     if (array == null)
 813:       array = new float[4];
 814:     getRGBColorComponents(array);
 815:     // Stupid serialization issues require this check.
 816:     array[3] = (falpha == 0 && frgbvalue == null
 817:                 ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha);
 818:     return array;
 819:   }
 820: 
 821:   /**
 822:    * Returns a float array with the red, green, and blue components, in the
 823:    * default sRGB space, with values in the range 0.0-1.0. If the array is
 824:    * null, a new one is created, otherwise it is recycled.
 825:    *
 826:    * @param array the array to put results into (at least 3 elements), or null
 827:    * @return the RGB components
 828:    * @throws ArrayIndexOutOfBoundsException if array is too small
 829:    */
 830:   public float[] getRGBColorComponents(float[] array)
 831:   {
 832:     if (array == null)
 833:       array = new float[3];
 834:     else if (array == frgbvalue)
 835:       return array; // Optimization for getColorComponents(float[]).
 836:     if (frgbvalue == null)
 837:       {
 838:         // Do not inline getRGB() to this.value, because of SystemColor.
 839:         int value = getRGB();
 840:         frgbvalue = new float[] { ((value & RED_MASK) >> 16) / 255f,
 841:                                   ((value & GREEN_MASK) >> 8) / 255f,
 842:                                   (value & BLUE_MASK) / 255f };
 843:       }
 844:     array[0] = frgbvalue[0];
 845:     array[1] = frgbvalue[1];
 846:     array[2] = frgbvalue[2];
 847:     return array;
 848:   }
 849: 
 850:   /**
 851:    * Returns a float array containing the color and alpha components of this
 852:    * color in the ColorSpace it was created with (the constructors which do
 853:    * not take a ColorSpace parameter use a default sRGB ColorSpace). If the
 854:    * array is null, a new one is created, otherwise it is recycled, and must
 855:    * have at least one more position than components used in the color space.
 856:    *
 857:    * @param array the array to put results into, or null
 858:    * @return the original color space components and alpha value
 859:    * @throws ArrayIndexOutOfBoundsException if array is too small
 860:    */
 861:   public float[] getComponents(float[] array)
 862:   {
 863:     int numComponents = cs == null ? 3 : cs.getNumComponents();
 864:     if (array == null)
 865:       array = new float[1 + numComponents];
 866:     getColorComponents(array);
 867:     // Stupid serialization issues require this check.
 868:     array[numComponents] = (falpha == 0 && frgbvalue == null
 869:                             ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha);
 870:     return array;
 871:   }
 872: 
 873:   /**
 874:    * Returns a float array containing the color components of this color in
 875:    * the ColorSpace it was created with (the constructors which do not take
 876:    * a ColorSpace parameter use a default sRGB ColorSpace). If the array is
 877:    * null, a new one is created, otherwise it is recycled, and must have at
 878:    * least as many positions as used in the color space.
 879:    *
 880:    * @param array the array to put results into, or null
 881:    * @return the original color space components
 882:    * @throws ArrayIndexOutOfBoundsException if array is too small
 883:    */
 884:   public float[] getColorComponents(float[] array)
 885:   {
 886:     int numComponents = cs == null ? 3 : cs.getNumComponents();
 887:     if (array == null)
 888:       array = new float[numComponents];
 889:     if (fvalue == null) // If fvalue is null, cs should be null too.
 890:       fvalue = getRGBColorComponents(frgbvalue);
 891:     System.arraycopy(fvalue, 0, array, 0, numComponents);
 892:     return array;
 893:   }
 894: 
 895:   /**
 896:    * Returns a float array containing the color and alpha components of this
 897:    * color in the given ColorSpace. If the array is null, a new one is
 898:    * created, otherwise it is recycled, and must have at least one more
 899:    * position than components used in the color space.
 900:    *
 901:    * @param space the color space to translate to
 902:    * @param array the array to put results into, or null
 903:    * @return the color space components and alpha value
 904:    * @throws ArrayIndexOutOfBoundsException if array is too small
 905:    * @throws NullPointerException if space is null
 906:    */
 907:   public float[] getComponents(ColorSpace space, float[] array)
 908:   {
 909:     int numComponents = space.getNumComponents();
 910:     if (array == null)
 911:       array = new float[1 + numComponents];
 912:     getColorComponents(space, array);
 913:     // Stupid serialization issues require this check.
 914:     array[numComponents] = (falpha == 0 && frgbvalue == null
 915:                             ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha);
 916:     return array;
 917:   }
 918: 
 919:   /**
 920:    * Returns a float array containing the color components of this color in
 921:    * the given ColorSpace. If the array is null, a new one is created,
 922:    * otherwise it is recycled, and must have at least as many positions as
 923:    * used in the color space.
 924:    *
 925:    * @param space the color space to translate to
 926:    * @return the color space components
 927:    * @throws ArrayIndexOutOfBoundsException if array is too small
 928:    * @throws NullPointerException if space is null
 929:    */
 930:   public float[] getColorComponents(ColorSpace space, float[] array)
 931:   {
 932:     float[] components = space.fromRGB(getRGBColorComponents(frgbvalue));
 933:     if (array == null)
 934:       return components;
 935:     System.arraycopy(components, 0, array, 0, components.length);
 936:     return array;
 937:   }
 938: 
 939:   /**
 940:    * Returns the color space of this color. Except for the constructor which
 941:    * takes a ColorSpace argument, this will be an implementation of
 942:    * ColorSpace.CS_sRGB.
 943:    *
 944:    * @return the color space
 945:    */
 946:   public ColorSpace getColorSpace()
 947:   {
 948:     return cs == null ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : cs;
 949:   }
 950: 
 951:   /**
 952:    * Returns a paint context, used for filling areas of a raster scan with
 953:    * this color. Since the color is constant across the entire rectangle, and
 954:    * since it is always in sRGB space, this implementation returns the same
 955:    * object, regardless of the parameters. Subclasses, however, may have a
 956:    * mutable result.
 957:    *
 958:    * @param cm the requested color model
 959:    * @param deviceBounds the bounding box in device coordinates, ignored
 960:    * @param userBounds the bounding box in user coordinates, ignored
 961:    * @param xform the bounds transformation, ignored
 962:    * @param hints any rendering hints, ignored
 963:    * @return a context for painting this solid color
 964:    */
 965:   public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
 966:                                     Rectangle2D userBounds,
 967:                                     AffineTransform xform,
 968:                                     RenderingHints hints)
 969:   {
 970:     if (context == null || !context.getColorModel().equals(cm))
 971:       context = new ColorPaintContext(cm,value);
 972:     return context;
 973:   }
 974: 
 975:   /**
 976:    * Returns the transparency level of this color.
 977:    *
 978:    * @return one of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}
 979:    */
 980:   public int getTransparency()
 981:   {
 982:     // Do not inline getRGB() to this.value, because of SystemColor.
 983:     int alpha = getRGB() & ALPHA_MASK;
 984:     return alpha == (255 << 24) ? OPAQUE : alpha == 0 ? BITMASK : TRANSLUCENT;
 985:   }
 986: 
 987:   /**
 988:    * Converts float values to integer value.
 989:    *
 990:    * @param red the red value
 991:    * @param green the green value
 992:    * @param blue the blue value
 993:    * @param alpha the alpha value
 994:    * @return the integer value made of 8-bit sections
 995:    * @throws IllegalArgumentException if parameters are out of range 0.0-1.0
 996:    */
 997:   private static int convert(float red, float green, float blue, float alpha)
 998:   {
 999:     if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1
1000:         || alpha < 0 || alpha > 1)
1001:       throw new IllegalArgumentException("Bad RGB values");
1002:     int redval = Math.round(255 * red);
1003:     int greenval = Math.round(255 * green);
1004:     int blueval = Math.round(255 * blue);
1005:     int alphaval = Math.round(255 * alpha);
1006:     return (alphaval << 24) | (redval << 16) | (greenval << 8) | blueval;
1007:   }
1008: } // class Color