Source for java.awt.image.ColorModel

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