Source for java.awt.image.ColorModel

   1: /* ColorModel.java --
   2:    Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006  Free Software Foundation
   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.image;
  40: 
  41: import gnu.java.awt.Buffers;
  42: 
  43: import java.awt.Point;
  44: import java.awt.Transparency;
  45: import java.awt.color.ColorSpace;
  46: import java.util.Arrays;
  47: 
  48: /**
  49:  * A color model operates with colors in several formats:
  50:  *
  51:  * <ul>
  52:  * <li>normalized: component samples are in range [0.0, 1.0].</li>
  53:  *
  54:  * <li>color model pixel value: all the color component samples for a
  55:  * sigle pixel packed/encoded in a way natural for the color
  56:  * model.</li>
  57:  *
  58:  * <li>color model pixel int value: only makes sense if the natural
  59:  * encoding of a single pixel can fit in a single int value.</li>
  60:  *
  61:  * <li>array of transferType containing a single pixel: the pixel is
  62:  * encoded in the natural way of the color model, taking up as many
  63:  * array elements as needed.</li>
  64:  *
  65:  * <li>sRGB pixel int value: a pixel in sRGB color space, encoded in
  66:  * default 0xAARRGGBB format, assumed not alpha premultiplied.</li>
  67:  * 
  68:  * <li>single [0, 255] scaled int samples from default sRGB color
  69:  * space. These are always assumed to be alpha non-premultiplied.</li>
  70:  *
  71:  * <li>arrays of unnormalized component samples of single pixel: these
  72:  * samples are scaled and multiplied according to the color model, but
  73:  * is otherwise not packed or encoded. Each element of the array is one
  74:  * separate component sample. The color model only operate on the
  75:  * components from one pixel at a time, but using offsets, allows
  76:  * manipulation of arrays that contain the components of more than one
  77:  * pixel.</li>
  78:  *
  79:  * </ul>
  80:  *
  81:  * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
  82:  * @author C. Brian Jones (cbj@gnu.org)
  83:  */
  84: public abstract class ColorModel implements Transparency
  85: {
  86:   protected int pixel_bits;
  87:   protected int transferType;
  88: 
  89:   int[] bits;
  90:   ColorSpace cspace;
  91:   int transparency;
  92:   boolean hasAlpha;
  93:   boolean isAlphaPremultiplied;
  94: 
  95:   /**
  96:    * The standard color model for the common sRGB.
  97:    */
  98:   private static final ColorModel S_RGB_MODEL = new SRGBColorModel();
  99: 
 100:   static int[] nArray(int value, int times)
 101:   {
 102:     int[] array = new int[times];
 103:     java.util.Arrays.fill(array, value);
 104:     return array;
 105:   }
 106: 
 107:   static byte[] nArray(byte value, int times)
 108:   {
 109:     byte[] array = new byte[times];
 110:     java.util.Arrays.fill(array, value);
 111:     return array;
 112:   } 
 113: 
 114:   /**
 115:    * Constructs the default color model.  The default color model 
 116:    * can be obtained by calling <code>getRGBdefault</code> of this
 117:    * class.
 118:    * @param bits the number of bits wide used for bit size of pixel values
 119:    */
 120:   public ColorModel(int bits)
 121:   {
 122:     this(bits * 4, // total bits, sRGB, four channels
 123:      nArray(bits, 4), // bits for each channel
 124:      ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB
 125:      true, // has alpha
 126:      false, // not premultiplied
 127:      TRANSLUCENT,
 128:      Buffers.smallestAppropriateTransferType(bits * 4));
 129:   }
 130: 
 131:   /**
 132:    * Constructs a ColorModel that translates pixel values to
 133:    * color/alpha components.
 134:    *
 135:    * @exception IllegalArgumentException If the length of the bit array is less
 136:    * than the number of color or alpha components in this ColorModel, or if the
 137:    * transparency is not a valid value, or if the sum of the number of bits in
 138:    * bits is less than 1 or if any of the elements in bits is less than 0.
 139:    */
 140:   protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
 141:                boolean hasAlpha, boolean isAlphaPremultiplied,
 142:                int transparency, int transferType)
 143:   {
 144:     int bits_sum = 0;
 145:     for (int i = 0; i < bits.length; i++)
 146:       {
 147:         if (bits [i] < 0)
 148:           throw new IllegalArgumentException ();
 149: 
 150:         bits_sum |= bits [i];
 151:       }
 152:     
 153:     if ((bits.length < cspace.getNumComponents())
 154:         || (bits_sum < 1))
 155:       throw new IllegalArgumentException ();
 156: 
 157:     this.pixel_bits = pixel_bits;
 158:     this.bits = bits;
 159:     this.cspace = cspace;
 160:     this.hasAlpha = hasAlpha;
 161:     this.isAlphaPremultiplied = isAlphaPremultiplied;
 162:     this.transparency = transparency;
 163:     this.transferType = transferType;
 164:   }
 165:   
 166:   public void finalize()
 167:   {
 168:     // Do nothing here.
 169:   }
 170: 
 171:   /**
 172:    * Returns the default color model which in Sun's case is an instance
 173:    * of <code>DirectColorModel</code>.
 174:    */
 175:   public static ColorModel getRGBdefault()
 176:   {
 177:     return S_RGB_MODEL;
 178:   }
 179: 
 180:   public final boolean hasAlpha()
 181:   {
 182:     return hasAlpha;
 183:   }
 184: 
 185:   public final boolean isAlphaPremultiplied()
 186:   {
 187:     return isAlphaPremultiplied;
 188:   }
 189: 
 190:   /**
 191:    * Get get number of bits wide used for the bit size of pixel values
 192:    */
 193:   public int getPixelSize()
 194:   {
 195:     return pixel_bits;
 196:   }
 197:     
 198:   public int getComponentSize(int componentIdx)
 199:   {
 200:     return bits[componentIdx];
 201:   }
 202:     
 203:   public int[] getComponentSize()
 204:   {
 205:     return bits;
 206:   }
 207: 
 208:   public int getTransparency()
 209:   {
 210:     return transparency;
 211:   }
 212: 
 213:   public int getNumComponents()
 214:   {
 215:     return getNumColorComponents() + (hasAlpha ? 1 : 0);
 216:   }
 217: 
 218:   public int getNumColorComponents()
 219:   {
 220:     return cspace.getNumComponents();
 221:   }
 222: 
 223:   /**
 224:    * Converts pixel value to sRGB and extract red int sample scaled
 225:    * to range [0, 255].
 226:    *
 227:    * @param pixel pixel value that will be interpreted according to
 228:    * the color model, (assumed alpha premultiplied if color model says
 229:    * so.)
 230:    *
 231:    * @return red sample scaled to range [0, 255], from default color
 232:    * space sRGB, alpha non-premultiplied.
 233:    */
 234:   public abstract int getRed(int pixel);
 235: 
 236:   /**
 237:    * Converts pixel value to sRGB and extract green int sample
 238:    * scaled to range [0, 255].
 239:    *
 240:    * @see #getRed(int)
 241:    */
 242:   public abstract int getGreen(int pixel);
 243:     
 244:   /**
 245:    * Converts pixel value to sRGB and extract blue int sample
 246:    * scaled to range [0, 255].
 247:    *
 248:    * @see #getRed(int)
 249:    */
 250:   public abstract int getBlue(int pixel);
 251: 
 252:   /**
 253:    * Extract alpha int sample from pixel value, scaled to [0, 255].
 254:    *
 255:    * @param pixel pixel value that will be interpreted according to
 256:    * the color model.
 257:    *
 258:    * @return alpha sample, scaled to range [0, 255].
 259:    */
 260:   public abstract int getAlpha(int pixel);
 261: 
 262:   /**
 263:    * Converts a pixel int value of the color space of the color
 264:    * model to a sRGB pixel int value.
 265:    *
 266:    * This method is typically overriden in subclasses to provide a
 267:    * more efficient implementation.
 268:    * 
 269:    * @param pixel pixel value that will be interpreted according to
 270:    * the color model.
 271:    *
 272:    * @return a pixel in sRGB color space, encoded in default
 273:    * 0xAARRGGBB format.  */
 274:   public int getRGB(int pixel)
 275:   {
 276:     return 
 277:       ((getAlpha(pixel) & 0xff) << 24) |
 278:       ((  getRed(pixel) & 0xff) << 16) |
 279:       ((getGreen(pixel) & 0xff) <<  8) |
 280:       (( getBlue(pixel) & 0xff) <<  0);
 281:   }
 282:   
 283: 
 284:   /**
 285:    * In this color model we know that the whole pixel value will
 286:    * always be contained within the first element of the pixel
 287:    * array.
 288:    */
 289:   final int getPixelFromArray(Object inData) {
 290:     DataBuffer data =
 291:       Buffers.createBufferFromData(transferType, inData, 1);
 292:     Object da = Buffers.getData(data);
 293: 
 294:     return data.getElem(0);
 295:   }
 296: 
 297:   /** 
 298:    * Converts pixel in the given array to sRGB and extract blue int
 299:    * sample scaled to range [0-255].
 300:    *
 301:    * This method is typically overriden in subclasses to provide a
 302:    * more efficient implementation.
 303:    * 
 304:    * @param inData array of transferType containing a single pixel.  The
 305:    * pixel should be encoded in the natural way of the color model.
 306:    */
 307:   public int getRed(Object inData)
 308:   {
 309:     return getRed(getPixelFromArray(inData));
 310:   }
 311: 
 312:   /**
 313:    * @see #getRed(Object)
 314:    */
 315:   public int getGreen(Object inData)
 316:   {
 317:     return getGreen(getPixelFromArray(inData));
 318:   }
 319: 
 320:   /**
 321:    * @see #getRed(Object)
 322:    */
 323:   public int getBlue(Object inData) {
 324:     return getBlue(getPixelFromArray(inData));
 325:   }
 326: 
 327:   /**
 328:    * @see #getRed(Object)
 329:    */
 330:   public int getAlpha(Object inData) {
 331:     return getAlpha(getPixelFromArray(inData));
 332:   }
 333: 
 334:   /**
 335:    * Converts a pixel in the given array of the color space of the
 336:    * color model to an sRGB pixel int value.
 337:    *
 338:    * <p>This method performs the inverse function of
 339:    * <code>getDataElements(int rgb, Object pixel)</code>.
 340:    * I.e. <code>(rgb == cm.getRGB(cm.getDataElements(rgb,
 341:    * null)))</code>.
 342:    *
 343:    * @param inData array of transferType containing a single pixel. The
 344:    * pixel should be encoded in the natural way of the color model.
 345:    *
 346:    * @return a pixel in sRGB color space, encoded in default
 347:    * 0xAARRGGBB format.
 348:    *
 349:    * @see #getDataElements(int, Object)
 350:    */
 351:   public int getRGB(Object inData)
 352:   {
 353:     return 
 354:       ((getAlpha(inData) & 0xff) << 24) |
 355:       ((  getRed(inData) & 0xff) << 16) |
 356:       ((getGreen(inData) & 0xff) <<  8) |
 357:       (( getBlue(inData) & 0xff) <<  0);
 358:   }
 359: 
 360:   /**
 361:    * Converts an sRGB pixel int value to an array containing a
 362:    * single pixel of the color space of the color model.
 363:    * 
 364:    * <p>This method performs the inverse function of
 365:    * <code>getRGB(Object inData)</code>.
 366:    *
 367:    * Outline of conversion process:
 368:    *
 369:    * <ol>
 370:    *
 371:    * <li>Convert rgb to normalized [0.0, 1.0] sRGB values.</li>
 372:    *
 373:    * <li>Convert to color space components using fromRGB in
 374:    * ColorSpace.</li>
 375:    *
 376:    * <li>If color model has alpha and should be premultiplied,
 377:    * multiply color space components with alpha value</li>
 378:    *
 379:    * <li>Scale the components to the correct number of bits.</li>
 380:    *
 381:    * <li>Arrange the components in the output array</li>
 382:    * 
 383:    * </ol>
 384:    *
 385:    * @param rgb The color to be converted to dataElements.  A pixel
 386:    * in sRGB color space, encoded in default 0xAARRGGBB format,
 387:    * assumed not alpha premultiplied.
 388:    *
 389:    * @param pixel to avoid needless creation of arrays, an array to
 390:    * use to return the pixel can be given. If null, a suitable array
 391:    * will be created.
 392:    *
 393:    * @return An array of transferType values representing the color,
 394:    * in the color model format. The color model defines whether the
 395:    *  
 396:    * @see #getRGB(Object)
 397:    */
 398:   public Object getDataElements(int rgb, Object pixel)
 399:   {
 400:     // subclasses has to implement this method.
 401:     throw new UnsupportedOperationException();
 402:   }
 403: 
 404:   /**
 405:    * Fills an array with the unnormalized component samples from a
 406:    * pixel value. I.e. decompose the pixel, but not perform any
 407:    * color conversion. 
 408:    *
 409:    * This method is typically overriden in subclasses to provide a
 410:    * more efficient implementation.
 411:    * 
 412:    * @param pixel pixel value encoded according to the color model.
 413:    *
 414:    * @return arrays of unnormalized component samples of single
 415:    * pixel.  The scale and multiplication state of the samples are
 416:    * according to the color model. Each component sample is stored
 417:    * as a separate element in the array.
 418:    */
 419:   public int[] getComponents(int pixel, int[] components, int offset)
 420:   {
 421:     // subclasses has to implement this method.
 422:     throw new UnsupportedOperationException();
 423:   }
 424:   
 425:   /**
 426:    * Fills an array with the unnormalized component samples from an
 427:    * array of transferType containing a single pixel. I.e. decompose
 428:    * the pixel, but not perform any color conversion.
 429:    *
 430:    * This method is typically overriden in subclasses to provide a
 431:    * more efficient implementation.
 432:    *
 433:    * @param pixel an array of transferType containing a single pixel.  The
 434:    * pixel should be encoded in the natural way of the color model.  If
 435:    * this argument is not an array, as expected, a {@link ClassCastException}
 436:    * will be thrown.
 437:    * @param components an array that will be filled with the color component
 438:    * of the pixel.  If this is null, a new array will be allocated
 439:    * @param offset index into the components array at which the result
 440:    * will be stored
 441:    * 
 442:    * @return arrays of unnormalized component samples of single
 443:    * pixel.  The scale and multiplication state of the samples are
 444:    * according to the color model. Each component sample is stored
 445:    * as a separate element in the array.
 446:    */
 447:   public int[] getComponents(Object pixel, int[] components, int offset)
 448:   {
 449:     // subclasses has to implement this method.
 450:     throw new UnsupportedOperationException();
 451:   }
 452: 
 453:   /**
 454:    * Convert normalized components to unnormalized components.
 455:    */
 456:   public int[] getUnnormalizedComponents(float[] normComponents,
 457:                      int normOffset,
 458:                      int[] components,
 459:                      int offset)
 460:   {
 461:     int numComponents = getNumComponents();
 462:     if (components == null)
 463:     {
 464:       components = new int[offset + numComponents];
 465:     }
 466:     
 467:     for (int i=0; i<numComponents; i++)
 468:     {
 469:       float in = normComponents[normOffset++];
 470:       int out = (int) (in * ((1<<getComponentSize(i)) - 1));
 471:       components[offset++] = out;
 472:     }
 473:     return components;
 474:   }
 475: 
 476:   /**
 477:    * Convert unnormalized components to normalized components.
 478:    */
 479:   public float[] getNormalizedComponents(int[] components,
 480:                      int offset,
 481:                      float[] normComponents,
 482:                      int normOffset)
 483:   {
 484:     int numComponents = getNumComponents();
 485:     if (normComponents == null)
 486:     {
 487:       normComponents = new float[normOffset + numComponents];
 488:     }
 489: 
 490:     for (int i=0; i<numComponents; i++)
 491:     {
 492:       float in = components[offset++];
 493:       float out = in / ((1<<getComponentSize(i)) - 1);
 494:       normComponents[normOffset++] = out;
 495:     }
 496:     return normComponents;
 497:   }
 498: 
 499:   /**
 500:    * Convert unnormalized components to normalized components.
 501:    *
 502:    * @since 1.4
 503:    */
 504:   public float[] getNormalizedComponents (Object pixel,
 505:                                           float[] normComponents,
 506:                                           int normOffset)
 507:   {
 508:     int[] components = getComponents(pixel, null, 0);
 509:     return getNormalizedComponents(components, 0, normComponents, normOffset);
 510:   }
 511: 
 512:   /**
 513:    * Converts the unnormalized component samples from an array to a
 514:    * pixel value. I.e. composes the pixel from component samples, but
 515:    * does not perform any color conversion or scaling of the samples.
 516:    * 
 517:    * This method performs the inverse function of
 518:    * <code>getComponents(int pixel, int[] components,
 519:    *                   int offset)</code>. I.e.
 520:    *
 521:    * <code>(pixel == cm.getDataElement(cm.getComponents(pixel, null,
 522:    * 0), 0))</code>.
 523:    *
 524:    * This method is overriden in subclasses since this abstract class throws
 525:    * UnsupportedOperationException().
 526:    *
 527:    * @param components Array of unnormalized component samples of single
 528:    * pixel.  The scale and multiplication state of the samples are according
 529:    * to the color model. Each component sample is stored as a separate element
 530:    * in the array.
 531:    * @param offset Position of the first value of the pixel in components.
 532:    *
 533:    * @return pixel value encoded according to the color model.
 534:    */
 535:   public int getDataElement(int[] components, int offset)
 536:   {
 537:     // subclasses have to implement this method.
 538:     throw new UnsupportedOperationException();
 539:   }
 540: 
 541:   /**
 542:    * Converts the normalized component samples from an array to a pixel
 543:    * value. I.e. composes the pixel from component samples, but does not
 544:    * perform any color conversion or scaling of the samples.
 545:    * 
 546:    * This method is typically overriden in subclasses to provide a
 547:    * more efficient implementation.  The method provided by this abstract
 548:    * class converts the components to unnormalized form and returns
 549:    * getDataElement(int[], int).
 550:    *
 551:    * @param components Array of normalized component samples of single pixel.
 552:    * The scale and multiplication state of the samples are according to the
 553:    * color model. Each component sample is stored as a separate element in the
 554:    * array.
 555:    * @param offset Position of the first value of the pixel in components.
 556:    *
 557:    * @return pixel value encoded according to the color model.
 558:    * @since 1.4
 559:    */
 560:   public int getDataElement (float[] components, int offset)
 561:   {
 562:     return
 563:       getDataElement(getUnnormalizedComponents(components, offset, null, 0),
 564:              0);
 565:   }
 566:   
 567:   public Object getDataElements(int[] components, int offset, Object obj)
 568:   {
 569:     // subclasses have to implement this method.
 570:     throw new UnsupportedOperationException();
 571:   }
 572: 
 573:   /**
 574:    * Converts the normalized component samples from an array to an array of
 575:    * TransferType values. I.e. composes the pixel from component samples, but
 576:    * does not perform any color conversion or scaling of the samples.
 577:    *
 578:    * If obj is null, a new array of TransferType is allocated and returned.
 579:    * Otherwise the results are stored in obj and obj is returned.  If obj is
 580:    * not long enough, ArrayIndexOutOfBounds is thrown.  If obj is not an array
 581:    * of primitives, ClassCastException is thrown.
 582:    * 
 583:    * This method is typically overriden in subclasses to provide a
 584:    * more efficient implementation.  The method provided by this abstract
 585:    * class converts the components to unnormalized form and returns
 586:    * getDataElement(int[], int, Object).
 587:    *
 588:    * @param components Array of normalized component samples of single pixel.
 589:    * The scale and multiplication state of the samples are according to the
 590:    * color model. Each component sample is stored as a separate element in the
 591:    * array.
 592:    * @param offset Position of the first value of the pixel in components.
 593:    * @param obj Array of TransferType or null.
 594:    *
 595:    * @return pixel value encoded according to the color model.
 596:    * @throws ArrayIndexOutOfBoundsException
 597:    * @throws ClassCastException
 598:    * @since 1.4
 599:    */
 600:   public Object getDataElements(float[] components, int offset, Object obj)
 601:   {
 602:     return
 603:       getDataElements(getUnnormalizedComponents(components, offset, null, 0),
 604:               0, obj);
 605:   }
 606: 
 607:   public boolean equals(Object obj)
 608:   {
 609:     if (!(obj instanceof ColorModel)) return false;
 610: 
 611:     ColorModel o = (ColorModel) obj;
 612:     return 
 613:       (pixel_bits == o.pixel_bits) &&
 614:       (transferType == o.transferType) &&
 615:       (transparency == o.transparency) &&
 616:       (hasAlpha == o.hasAlpha) &&
 617:       (isAlphaPremultiplied == o.isAlphaPremultiplied) &&
 618:       Arrays.equals(bits, o.bits) &&
 619:       (cspace.equals(o.cspace));
 620:   }
 621: 
 622:   public final ColorSpace getColorSpace()
 623:   {
 624:     return cspace;
 625:   }
 626: 
 627:   public ColorModel coerceData(WritableRaster raster,
 628:                                boolean isAlphaPremultiplied)
 629:   {
 630:     // This method should always be overridden, but is not abstract.
 631:     throw new UnsupportedOperationException();
 632:   }
 633: 
 634:   protected void coerceDataWorker(WritableRaster raster,
 635:                                   boolean isAlphaPremultiplied)
 636:   {
 637:     int w = raster.getWidth();
 638:     int h = raster.getHeight();
 639:     int x = raster.getMinX();
 640:     int y = raster.getMinY();
 641:     int size = w * h;
 642:     int numColors = getNumColorComponents();
 643:     int numComponents = getNumComponents();
 644:     int alphaScale = (1 << getComponentSize(numColors)) - 1;
 645:     double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
 646: 
 647:     for (int i = 0; i < size; i++)
 648:       {
 649:         double alpha = pixels[i * numComponents + numColors] / alphaScale;
 650:         for (int c = 0; c < numColors; c++)
 651:           {
 652:             int offset = i * numComponents + c;
 653:             if (isAlphaPremultiplied)
 654:               pixels[offset] = Math.round(pixels[offset] * alpha);
 655:             else
 656:               pixels[offset] = Math.round(pixels[offset] / alpha);
 657:           }
 658:       }
 659: 
 660:     raster.setPixels(0, 0, w, h, pixels);
 661:   }
 662:     
 663:   /**
 664:    * Checks if the given raster has a compatible data-layout (SampleModel).
 665:    * @param raster The Raster to test.
 666:    * @return true if raster is compatible.
 667:    */ 
 668:   public boolean isCompatibleRaster(Raster raster)
 669:   {
 670:     SampleModel sampleModel = raster.getSampleModel();
 671:     return isCompatibleSampleModel(sampleModel);
 672:   }
 673: 
 674:   // Typically overridden
 675:   public WritableRaster createCompatibleWritableRaster(int w, int h)
 676:   {
 677:     return new WritableRaster(createCompatibleSampleModel(w, h),
 678:                   new Point(0, 0));
 679:   }
 680: 
 681:   // Typically overridden
 682:   public SampleModel createCompatibleSampleModel(int w, int h)
 683:   {
 684:     throw new UnsupportedOperationException();
 685:   }
 686: 
 687:   // Typically overridden
 688:   public boolean isCompatibleSampleModel(SampleModel sm)
 689:   {
 690:     return sm.getTransferType() == transferType;
 691:   }
 692: 
 693:   public final int getTransferType ()
 694:   {
 695:     return transferType;
 696:   }
 697: 
 698:   /**
 699:    * Subclasses must override this method if it is possible for the
 700:    * color model to have an alpha channel.
 701:    *
 702:    * @return null, as per JDK 1.3 doc. Subclasses will only return
 703:    * null if no alpha raster exists.
 704:    */
 705:   public WritableRaster getAlphaRaster(WritableRaster raster)
 706:   {
 707:     return null;
 708:     
 709:     /* It is a mystery to me why we couldn't use the following code...
 710:        
 711:        
 712:        if (!hasAlpha()) return null;
 713:        
 714:        SampleModel sm = raster.getSampleModel();
 715:        int[] alphaBand = { sm.getNumBands() - 1 };
 716:        SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
 717:        DataBuffer buffer = raster.getDataBuffer();
 718:        Point origin = new Point(0, 0);
 719:        return Raster.createWritableRaster(alphaModel, buffer, origin);
 720:        
 721: 
 722:        ...here, and avoided overriding the method in subclasses,
 723:        but the Sun docs state that this method always will return
 724:        null, and that overriding is required. Oh, well.
 725:     */
 726:   }
 727: 
 728:   String stringParam()
 729:   {
 730:     return "pixel_bits=" + pixel_bits +
 731:       ", cspace=" + cspace +
 732:       ", transferType=" + transferType +
 733:       ", transparency=" + transparency +
 734:       ", hasAlpha=" + hasAlpha +
 735:       ", isAlphaPremultiplied=" + isAlphaPremultiplied;
 736:   }
 737: 
 738:   public String toString()
 739:   {
 740:     return getClass().getName() + "[" + stringParam() + "]";
 741:   }
 742: 
 743:   /**
 744:    * A color model optimized for standard sRGB.
 745:    */
 746:   private static class SRGBColorModel
 747:     extends DirectColorModel
 748:   {
 749:     
 750:     SRGBColorModel()
 751:     {
 752:       super(32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
 753:     }
 754: 
 755:     public int getAlpha(Object inData)
 756:     {
 757:       return ((((int[]) inData)[0]) >> 24) & 0xFF;
 758:     }
 759: 
 760:     public int getBlue(Object inData)
 761:     {
 762:       return ((((int[]) inData)[0])) & 0xFF;
 763:     }
 764: 
 765:     public int getGreen(Object inData)
 766:     {
 767:       return ((((int[]) inData)[0]) >>  8) & 0xFF;
 768:     }
 769: 
 770:     public int getRed(Object inData)
 771:     {
 772:       return ((((int[]) inData)[0]) >> 16) & 0xFF;
 773:     }
 774: 
 775:     public int getRGB(Object inData)
 776:     {
 777:       return ((int[]) inData)[0];
 778:     }
 779: 
 780:     public Object getDataElements(int rgb, Object pixel)
 781:     {
 782:       if(pixel == null)
 783:         {
 784:           pixel = new int[]{rgb};  
 785:         }
 786:       else
 787:         {
 788:           ((int[]) pixel)[0] = rgb;  
 789:         }
 790:       
 791:       return pixel;
 792:     }
 793:   }
 794: }