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