001: /*
002: * Copyright (C) 2005, 2006 data2c GmbH (www.data2c.com)
003: *
004: * Author: Wolfgang S. Kechel - wolfgang.kechel@data2c.com
005: *
006: * J2ME version of java.awt.Color.
007: */
008: //#ifndef j2se
009: package org.awt;
010:
011: /**
012: * The <code>Color</code> class is used encapsulate colors in the default
013: * sRGB color space or colors in arbitrary color spaces identified by a
014: * {@link ColorSpace}. Every color has an implicit alpha value of 1.0 or
015: * an explicit one provided in the constructor. The alpha value
016: * defines the transparency of a color and can be represented by
017: * a float value in the range 0.0 - 1.0 or 0 - 255.
018: * An alpha value of 1.0 or 255 means that the color is completely
019: * opaque and an alpha value of 0 or 0.0 means that the color is
020: * completely transparent.
021: * When constructing a <code>Color</code> with an explicit alpha or
022: * getting the color/alpha components of a <code>Color</code>, the color
023: * components are never premultiplied by the alpha component.
024: * <p>
025: * The default color space for the Java 2D(tm) API is sRGB, a proposed
026: * standard RGB color space. For further information on sRGB,
027: * see <A href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
028: * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html
029: * </A>.
030: * <p>
031: */
032: public class Color implements Transparency /*Paint, java.io.Serializable*/{
033:
034: /**
035: * The color white. In the default sRGB space.
036: */
037: public final static Color white = new Color(255, 255, 255);
038: public final static Color WHITE = white;
039:
040: /**
041: * The color light gray. In the default sRGB space.
042: */
043: public final static Color lightGray = new Color(192, 192, 192);
044: public final static Color LIGHT_GRAY = lightGray;
045:
046: /**
047: * The color gray. In the default sRGB space.
048: */
049: public final static Color gray = new Color(128, 128, 128);
050: public final static Color GRAY = gray;
051:
052: /**
053: * The color dark gray. In the default sRGB space.
054: */
055: public final static Color darkGray = new Color(64, 64, 64);
056: public final static Color DARK_GRAY = darkGray;
057:
058: /**
059: * The color black. In the default sRGB space.
060: */
061: public final static Color black = new Color(0, 0, 0);
062: public final static Color BLACK = black;
063:
064: /**
065: * The color red. In the default sRGB space.
066: */
067: public final static Color red = new Color(255, 0, 0);
068: public final static Color RED = red;
069:
070: /**
071: * The color pink. In the default sRGB space.
072: */
073: public final static Color pink = new Color(255, 175, 175);
074: public final static Color PINK = pink;
075:
076: /**
077: * The color orange. In the default sRGB space.
078: */
079: public final static Color orange = new Color(255, 200, 0);
080: public final static Color ORANGE = orange;
081:
082: /**
083: * The color yellow. In the default sRGB space.
084: */
085: public final static Color yellow = new Color(255, 255, 0);
086: public final static Color YELLOW = yellow;
087:
088: /**
089: * The color green. In the default sRGB space.
090: */
091: public final static Color green = new Color(0, 255, 0);
092: public final static Color GREEN = green;
093:
094: /**
095: * The color magenta. In the default sRGB space.
096: */
097: public final static Color magenta = new Color(255, 0, 255);
098: public final static Color MAGENTA = magenta;
099:
100: /**
101: * The color cyan. In the default sRGB space.
102: */
103: public final static Color cyan = new Color(0, 255, 255);
104: public final static Color CYAN = cyan;
105:
106: /**
107: * The color blue. In the default sRGB space.
108: */
109: public final static Color blue = new Color(0, 0, 255);
110: public final static Color BLUE = blue;
111:
112: /**
113: * The color value.
114: * @serial
115: * @see #getRGB
116: */
117: int value;
118:
119: /**
120: * Checks the color integer components supplied for validity.
121: * Throws an {@link IllegalArgumentException} if the value is out of
122: * range.
123: * @param r the Red component
124: * @param g the Green component
125: * @param b the Blue component
126: **/
127: private static void testColorValueRange(int r, int g, int b, int a) {
128: boolean rangeError = false;
129: String badComponentString = "";
130:
131: if (a < 0 || a > 255) {
132: rangeError = true;
133: badComponentString = badComponentString + " Alpha";
134: }
135: if (r < 0 || r > 255) {
136: rangeError = true;
137: badComponentString = badComponentString + " Red";
138: }
139: if (g < 0 || g > 255) {
140: rangeError = true;
141: badComponentString = badComponentString + " Green";
142: }
143: if (b < 0 || b > 255) {
144: rangeError = true;
145: badComponentString = badComponentString + " Blue";
146: }
147: if (rangeError == true) {
148: throw new IllegalArgumentException(
149: "Color parameter outside of expected range:"
150: + badComponentString);
151: }
152: }
153:
154: /**
155: * Creates an opaque sRGB color with the specified red, green,
156: * and blue values in the range (0 - 255).
157: * The actual color used in rendering depends
158: * on finding the best match given the color space
159: * available for a given output device.
160: * Alpha is defaulted to 255.
161: * @param r the red component
162: * @param g the green component
163: * @param b the blue component
164: * @see #getRed
165: * @see #getGreen
166: * @see #getBlue
167: * @see #getRGB
168: */
169: public Color(int r, int g, int b) {
170: this (r, g, b, 255);
171: }
172:
173: /**
174: * Creates an sRGB color with the specified red, green, blue, and alpha
175: * values in the range (0 - 255).
176: * @param r the red component
177: * @param g the green component
178: * @param b the blue component
179: * @param a the alpha component
180: * @see #getRed
181: * @see #getGreen
182: * @see #getBlue
183: * @see #getAlpha
184: * @see #getRGB
185: */
186: public Color(int r, int g, int b, int a) {
187: value = ((a & 0xFF) << 24) | ((r & 0xFF) << 16)
188: | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);
189: testColorValueRange(r, g, b, a);
190: }
191:
192: /**
193: * Creates an opaque sRGB color with the specified combined RGB value
194: * consisting of the red component in bits 16-23, the green component
195: * in bits 8-15, and the blue component in bits 0-7. The actual color
196: * used in rendering depends on finding the best match given the
197: * color space available for a particular output device. Alpha is
198: * defaulted to 255.
199: * @param rgb the combined RGB components
200: * @see java.awt.image.ColorModel#getRGBdefault
201: * @see #getRed
202: * @see #getGreen
203: * @see #getBlue
204: * @see #getRGB
205: */
206: public Color(int rgb) {
207: value = 0xff000000 | rgb;
208: }
209:
210: /**
211: * Creates an sRGB color with the specified combined RGBA value consisting
212: * of the alpha component in bits 24-31, the red component in bits 16-23,
213: * the green component in bits 8-15, and the blue component in bits 0-7.
214: * If the <code>hasalpha</code> argument is <code>false</code>, alpha
215: * is defaulted to 255.
216: * @param rgba the combined RGBA components
217: * @param hasalpha <code>true</code> if the alpha bits are valid;
218: * <code>false</code> otherwise
219: * @see java.awt.image.ColorModel#getRGBdefault
220: * @see #getRed
221: * @see #getGreen
222: * @see #getBlue
223: * @see #getAlpha
224: * @see #getRGB
225: */
226: public Color(int rgba, boolean hasalpha) {
227: if (hasalpha) {
228: value = rgba;
229: } else {
230: value = 0xff000000 | rgba;
231: }
232: }
233:
234: /**
235: * Returns the red component in the range 0-255 in the default sRGB
236: * space.
237: * @return the red component.
238: * @see #getRGB
239: */
240: public int getRed() {
241: return (getRGB() >> 16) & 0xFF;
242: }
243:
244: /**
245: * Returns the green component in the range 0-255 in the default sRGB
246: * space.
247: * @return the green component.
248: * @see #getRGB
249: */
250: public int getGreen() {
251: return (getRGB() >> 8) & 0xFF;
252: }
253:
254: /**
255: * Returns the blue component in the range 0-255 in the default sRGB
256: * space.
257: * @return the blue component.
258: * @see #getRGB
259: */
260: public int getBlue() {
261: return (getRGB() >> 0) & 0xFF;
262: }
263:
264: /**
265: * Returns the alpha component in the range 0-255.
266: * @return the alpha component.
267: * @see #getRGB
268: */
269: public int getAlpha() {
270: return (getRGB() >> 24) & 0xff;
271: }
272:
273: /**
274: * Returns the RGB value representing the color in the default sRGB
275: * {@link ColorModel}.
276: * (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are
277: * blue).
278: * @return the RGB value of the color in the default sRGB
279: * <code>ColorModel</code>.
280: * @see java.awt.image.ColorModel#getRGBdefault
281: * @see #getRed
282: * @see #getGreen
283: * @see #getBlue
284: * @since JDK1.0
285: */
286: public int getRGB() {
287: return value;
288: }
289:
290: private static final double FACTOR = 0.7;
291:
292: /**
293: * Creates a new <code>Color</code> that is a brighter version of this
294: * <code>Color</code>.
295: * <p>
296: * This method applies an arbitrary scale factor to each of the three RGB
297: * components of this <code>Color</code> to create a brighter version
298: * of this <code>Color</code>. Although <code>brighter</code> and
299: * <code>darker</code> are inverse operations, the results of a
300: * series of invocations of these two methods might be inconsistent
301: * because of rounding errors.
302: * @return a new <code>Color</code> object that is
303: * a brighter version of this <code>Color</code>.
304: * @see java.awt.Color#darker
305: * @since JDK1.0
306: */
307: public Color brighter() {
308: int r = getRed();
309: int g = getGreen();
310: int b = getBlue();
311:
312: /* From 2D group:
313: * 1. black.brighter() should return grey
314: * 2. applying brighter to blue will always return blue, brighter
315: * 3. non pure color (non zero rgb) will eventually return white
316: */
317: int i = (int) (1.0 / (1.0 - FACTOR));
318: if (r == 0 && g == 0 && b == 0) {
319: return new Color(i, i, i);
320: }
321: if (r > 0 && r < i)
322: r = i;
323: if (g > 0 && g < i)
324: g = i;
325: if (b > 0 && b < i)
326: b = i;
327:
328: return new Color(Math.min((int) (r / FACTOR), 255), Math.min(
329: (int) (g / FACTOR), 255), Math.min((int) (b / FACTOR),
330: 255));
331: }
332:
333: /**
334: * Creates a new <code>Color</code> that is a darker version of this
335: * <code>Color</code>.
336: * <p>
337: * This method applies an arbitrary scale factor to each of the three RGB
338: * components of this <code>Color</code> to create a darker version of
339: * this <code>Color</code>. Although <code>brighter</code> and
340: * <code>darker</code> are inverse operations, the results of a series
341: * of invocations of these two methods might be inconsistent because
342: * of rounding errors.
343: * @return a new <code>Color</code> object that is
344: * a darker version of this <code>Color</code>.
345: * @see java.awt.Color#brighter
346: * @since JDK1.0
347: */
348: public Color darker() {
349: return new Color(Math.max((int) (getRed() * FACTOR), 0), Math
350: .max((int) (getGreen() * FACTOR), 0), Math.max(
351: (int) (getBlue() * FACTOR), 0));
352: }
353:
354: /**
355: * Computes the hash code for this <code>Color</code>.
356: * @return a hash code value for this object.
357: * @since JDK1.0
358: */
359: public int hashCode() {
360: return value;
361: }
362:
363: /**
364: * Determines whether another object is equal to this
365: * <code>Color</code>.
366: * <p>
367: * The result is <code>true</code> if and only if the argument is not
368: * <code>null</code> and is a <code>Color</code> object that has the same
369: * red, green, blue, and alpha values as this object.
370: * @param obj the object to test for equality with this
371: * <code>Color</code>
372: * @return <code>true</code> if the objects are the same;
373: * <code>false</code> otherwise.
374: * @since JDK1.0
375: */
376: public boolean equals(Object obj) {
377: return obj instanceof Color
378: && ((Color) obj).value == this .value;
379: }
380:
381: /**
382: * Returns a string representation of this <code>Color</code>. This
383: * method is intended to be used only for debugging purposes. The
384: * content and format of the returned string might vary between
385: * implementations. The returned string might be empty but cannot
386: * be <code>null</code>.
387: *
388: * @return a string representation of this <code>Color</code>.
389: */
390: public String toString() {
391: return getClass().getName() + "[r=" + getRed() + ",g="
392: + getGreen() + ",b=" + getBlue() + "]";
393: }
394:
395: /**
396: * Converts a <code>String</code> to an integer and returns the
397: * specified opaque <code>Color</code>. This method handles string
398: * formats that are used to represent octal and hexidecimal numbers.
399: * @param nm a <code>String</code> that represents
400: * an opaque color as a 24-bit integer
401: * @return the new <code>Color</code> object.
402: * @see java.lang.Integer#decode
403: * @exception NumberFormatException if the specified string cannot
404: * be interpreted as a decimal,
405: * octal, or hexidecimal integer.
406: * @since JDK1.1
407: */
408: public static Color decode(String nm) throws NumberFormatException {
409: Integer intval = Integer.valueOf(nm);
410: int i = intval.intValue();
411: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
412: }
413:
414: //#ifdef notdef
415: /**
416: * Finds a color in the system properties.
417: * <p>
418: * The argument is treated as the name of a system property to
419: * be obtained. The string value of this property is then interpreted
420: * as an integer which is then converted to a <code>Color</code>
421: * object.
422: * <p>
423: * If the specified property is not found or could not be parsed as
424: * an integer then <code>null</code> is returned.
425: * @param nm the name of the color property
426: * @return the <code>Color</code> converted from the system
427: * property.
428: * @see java.lang.System#getProperty(java.lang.String)
429: * @see java.lang.Integer#getInteger(java.lang.String)
430: * @see java.awt.Color#Color(int)
431: * @since JDK1.0
432: */
433: public static Color getColor(String nm) {
434: return getColor(nm, null);
435: }
436:
437: /**
438: * Finds a color in the system properties.
439: * <p>
440: * The first argument is treated as the name of a system property to
441: * be obtained. The string value of this property is then interpreted
442: * as an integer which is then converted to a <code>Color</code>
443: * object.
444: * <p>
445: * If the specified property is not found or cannot be parsed as
446: * an integer then the <code>Color</code> specified by the second
447: * argument is returned instead.
448: * @param nm the name of the color property
449: * @param v the default <code>Color</code>
450: * @return the <code>Color</code> converted from the system
451: * property, or the specified <code>Color</code>.
452: * @see java.lang.System#getProperty(java.lang.String)
453: * @see java.lang.Integer#getInteger(java.lang.String)
454: * @see java.awt.Color#Color(int)
455: * @since JDK1.0
456: */
457: public static Color getColor(String nm, Color v) {
458: Integer intval = Integer.getInteger(nm);
459: if (intval == null) {
460: return v;
461: }
462: int i = intval.intValue();
463: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
464: }
465:
466: /**
467: * Finds a color in the system properties.
468: * <p>
469: * The first argument is treated as the name of a system property to
470: * be obtained. The string value of this property is then interpreted
471: * as an integer which is then converted to a <code>Color</code>
472: * object.
473: * <p>
474: * If the specified property is not found or could not be parsed as
475: * an integer then the integer value <code>v</code> is used instead,
476: * and is converted to a <code>Color</code> object.
477: * @param nm the name of the color property
478: * @param v the default color value, as an integer
479: * @return the <code>Color</code> converted from the system
480: * property or the <code>Color</code> converted from
481: * the specified integer.
482: * @see java.lang.System#getProperty(java.lang.String)
483: * @see java.lang.Integer#getInteger(java.lang.String)
484: * @see java.awt.Color#Color(int)
485: * @since JDK1.0
486: */
487: public static Color getColor(String nm, int v) {
488: Integer intval = Integer.getInteger(nm);
489: int i = (intval != null) ? intval.intValue() : v;
490: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF,
491: (i >> 0) & 0xFF);
492: }
493:
494: //#endif
495:
496: /**
497: * Converts the components of a color, as specified by the HSB
498: * model, to an equivalent set of values for the default RGB model.
499: * <p>
500: * The <code>saturation</code> and <code>brightness</code> components
501: * should be floating-point values between zero and one
502: * (numbers in the range 0.0-1.0). The <code>hue</code> component
503: * can be any floating-point number. The floor of this number is
504: * subtracted from it to create a fraction between 0 and 1. This
505: * fractional number is then multiplied by 360 to produce the hue
506: * angle in the HSB color model.
507: * <p>
508: * The integer that is returned by <code>HSBtoRGB</code> encodes the
509: * value of a color in bits 0-23 of an integer value that is the same
510: * format used by the method {@link #getRGB() <code>getRGB</code>}.
511: * This integer can be supplied as an argument to the
512: * <code>Color</code> constructor that takes a single integer argument.
513: * @param hue the hue component of the color
514: * @param saturation the saturation of the color
515: * @param brightness the brightness of the color
516: * @return the RGB value of the color with the indicated hue,
517: * saturation, and brightness.
518: * @see java.awt.Color#getRGB()
519: * @see java.awt.Color#Color(int)
520: * @see java.awt.image.ColorModel#getRGBdefault()
521: * @since JDK1.0
522: */
523: public static int HSBtoRGB(float hue, float saturation,
524: float brightness) {
525: int r = 0, g = 0, b = 0;
526: if (saturation == 0) {
527: r = g = b = (int) (brightness * 255.0f + 0.5f);
528: } else {
529: float h = (hue - (float) Math.floor(hue)) * 6.0f;
530: float f = h - (float) java.lang.Math.floor(h);
531: float p = brightness * (1.0f - saturation);
532: float q = brightness * (1.0f - saturation * f);
533: float t = brightness * (1.0f - (saturation * (1.0f - f)));
534: switch ((int) h) {
535: case 0:
536: r = (int) (brightness * 255.0f + 0.5f);
537: g = (int) (t * 255.0f + 0.5f);
538: b = (int) (p * 255.0f + 0.5f);
539: break;
540: case 1:
541: r = (int) (q * 255.0f + 0.5f);
542: g = (int) (brightness * 255.0f + 0.5f);
543: b = (int) (p * 255.0f + 0.5f);
544: break;
545: case 2:
546: r = (int) (p * 255.0f + 0.5f);
547: g = (int) (brightness * 255.0f + 0.5f);
548: b = (int) (t * 255.0f + 0.5f);
549: break;
550: case 3:
551: r = (int) (p * 255.0f + 0.5f);
552: g = (int) (q * 255.0f + 0.5f);
553: b = (int) (brightness * 255.0f + 0.5f);
554: break;
555: case 4:
556: r = (int) (t * 255.0f + 0.5f);
557: g = (int) (p * 255.0f + 0.5f);
558: b = (int) (brightness * 255.0f + 0.5f);
559: break;
560: case 5:
561: r = (int) (brightness * 255.0f + 0.5f);
562: g = (int) (p * 255.0f + 0.5f);
563: b = (int) (q * 255.0f + 0.5f);
564: break;
565: }
566: }
567: return 0xff000000 | (r << 16) | (g << 8) | (b << 0);
568: }
569:
570: /**
571: * Returns the transparency mode for this <code>Color</code>. This is
572: * required to implement the <code>Paint</code> interface.
573: * @return this <code>Color</code> object's transparency mode.
574: * @see Transparency
575: * @see #createContext
576: */
577: public int getTransparency() {
578: int alpha = getAlpha();
579: if (alpha == 0xff) {
580: return Transparency.OPAQUE;
581: } else if (alpha == 0) {
582: return Transparency.BITMASK;
583: } else {
584: return Transparency.TRANSLUCENT;
585: }
586: }
587:
588: }
589: //#endif
|