1 /*
   2  * Copyright (c) 1995, 2001, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.image;
  27 
  28 import java.awt.color.ColorSpace;
  29 import java.awt.Transparency;
  30 
  31 /**
  32  * The <code>DirectColorModel</code> class is a <code>ColorModel</code>
  33  * class that works with pixel values that represent RGB
  34  * color and alpha information as separate samples and that pack all
  35  * samples for a single pixel into a single int, short, or byte quantity.
  36  * This class can be used only with ColorSpaces of type ColorSpace.TYPE_RGB.
  37  * In addition, for each component of the ColorSpace, the minimum
  38  * normalized component value obtained via the <code>getMinValue()</code>
  39  * method of ColorSpace must be 0.0, and the maximum value obtained via
  40  * the <code>getMaxValue()</code> method must be 1.0 (these min/max
  41  * values are typical for RGB spaces).
  42  * There must be three color samples in the pixel values and there can
  43  * be a single alpha sample.  For those methods that use a primitive array
  44  * pixel representation of type <code>transferType</code>, the array
  45  * length is always one.  The transfer
  46  * types supported are DataBuffer.TYPE_BYTE,
  47  * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT.
  48  * Color and alpha samples are stored in the single
  49  * element of the array in bits indicated by bit masks.  Each bit mask
  50  * must be contiguous and masks must not overlap.  The same masks apply to
  51  * the single int pixel representation used by other methods.  The
  52  * correspondence of masks and color/alpha samples is as follows:
  53  * <ul>
  54  * <li> Masks are identified by indices running from 0 through 2
  55  * if no alpha is present, or 3 if an alpha is present.
  56  * <li> The first three indices refer to color samples;
  57  * index 0 corresponds to red, index 1 to green, and index 2 to blue.
  58  * <li> Index 3 corresponds to the alpha sample, if present.
  59  * </ul>
  60  * <p>
  61  * The translation from pixel values to color/alpha components for
  62  * display or processing purposes is a one-to-one correspondence of
  63  * samples to components.  A <code>DirectColorModel</code> is
  64  * typically used with image data which uses masks to define packed
  65  * samples.  For example, a <code>DirectColorModel</code> can be used in
  66  * conjunction with a <code>SinglePixelPackedSampleModel</code> to
  67  * construct a {@link BufferedImage}.  Normally the masks used by the
  68  * {@link SampleModel} and the <code>ColorModel</code> would be the
  69  * same.  However, if they are different, the color interpretation
  70  * of pixel data will be done according to the masks of the
  71  * <code>ColorModel</code>.
  72  * <p>
  73  * A single int pixel representation is valid for all objects of this
  74  * class, since it is always possible to represent pixel values used with
  75  * this class in a single int.  Therefore, methods which use this
  76  * representation will not throw an <code>IllegalArgumentException</code>
  77  * due to an invalid pixel value.
  78  * <p>
  79  * This color model is similar to an X11 TrueColor visual.
  80  * The default RGB ColorModel specified by the
  81  * {@link ColorModel#getRGBdefault() getRGBdefault} method is a
  82  * <code>DirectColorModel</code> with the following parameters:
  83  * <pre>
  84  * Number of bits:        32
  85  * Red mask:              0x00ff0000
  86  * Green mask:            0x0000ff00
  87  * Blue mask:             0x000000ff
  88  * Alpha mask:            0xff000000
  89  * Color space:           sRGB
  90  * isAlphaPremultiplied:  False
  91  * Transparency:          Transparency.TRANSLUCENT
  92  * transferType:          DataBuffer.TYPE_INT
  93  * </pre>
  94  * <p>
  95  * Many of the methods in this class are final. This is because the
  96  * underlying native graphics code makes assumptions about the layout
  97  * and operation of this class and those assumptions are reflected in
  98  * the implementations of the methods here that are marked final.  You
  99  * can subclass this class for other reasons, but you cannot override
 100  * or modify the behavior of those methods.
 101  *
 102  * @see ColorModel
 103  * @see ColorSpace
 104  * @see SinglePixelPackedSampleModel
 105  * @see BufferedImage
 106  * @see ColorModel#getRGBdefault
 107  *
 108  */
 109 public class DirectColorModel extends PackedColorModel {
 110     private int red_mask;
 111     private int green_mask;
 112     private int blue_mask;
 113     private int alpha_mask;
 114     private int red_offset;
 115     private int green_offset;
 116     private int blue_offset;
 117     private int alpha_offset;
 118     private int red_scale;
 119     private int green_scale;
 120     private int blue_scale;
 121     private int alpha_scale;
 122     private boolean is_LinearRGB;
 123     private int lRGBprecision;
 124     private byte[] tosRGB8LUT;
 125     private byte[] fromsRGB8LUT8;
 126     private short[] fromsRGB8LUT16;
 127 
 128     /**
 129      * Constructs a <code>DirectColorModel</code> from the specified masks
 130      * that indicate which bits in an <code>int</code> pixel representation
 131      * contain the red, green and blue color samples.  As pixel values do not
 132      * contain alpha information, all pixels are treated as opaque, which
 133      * means that alpha&nbsp;=&nbsp;1.0.  All of the bits
 134      * in each mask must be contiguous and fit in the specified number
 135      * of least significant bits of an <code>int</code> pixel representation.
 136      *  The <code>ColorSpace</code> is the default sRGB space. The
 137      * transparency value is Transparency.OPAQUE.  The transfer type
 138      * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
 139      * or DataBuffer.TYPE_INT that can hold a single pixel.
 140      * @param bits the number of bits in the pixel values; for example,
 141      *         the sum of the number of bits in the masks.
 142      * @param rmask specifies a mask indicating which bits in an
 143      *         integer pixel contain the red component
 144      * @param gmask specifies a mask indicating which bits in an
 145      *         integer pixel contain the green component
 146      * @param bmask specifies a mask indicating which bits in an
 147      *         integer pixel contain the blue component
 148      *
 149      */
 150     public DirectColorModel(int bits,
 151                             int rmask, int gmask, int bmask) {
 152         this(bits, rmask, gmask, bmask, 0);
 153     }
 154 
 155     /**
 156      * Constructs a <code>DirectColorModel</code> from the specified masks
 157      * that indicate which bits in an <code>int</code> pixel representation
 158      * contain the red, green and blue color samples and the alpha sample,
 159      * if present.  If <code>amask</code> is 0, pixel values do not contain
 160      * alpha information and all pixels are treated as opaque, which means
 161      * that alpha&nbsp;=&nbsp;1.0.  All of the bits in each mask must
 162      * be contiguous and fit in the specified number of least significant bits
 163      * of an <code>int</code> pixel representation.  Alpha, if present, is not
 164      * premultiplied.  The <code>ColorSpace</code> is the default sRGB space.
 165      * The transparency value is Transparency.OPAQUE if no alpha is
 166      * present, or Transparency.TRANSLUCENT otherwise.  The transfer type
 167      * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
 168      * or DataBuffer.TYPE_INT that can hold a single pixel.
 169      * @param bits the number of bits in the pixel values; for example,
 170      *         the sum of the number of bits in the masks.
 171      * @param rmask specifies a mask indicating which bits in an
 172      *         integer pixel contain the red component
 173      * @param gmask specifies a mask indicating which bits in an
 174      *         integer pixel contain the green component
 175      * @param bmask specifies a mask indicating which bits in an
 176      *         integer pixel contain the blue component
 177      * @param amask specifies a mask indicating which bits in an
 178      *         integer pixel contain the alpha component
 179      */
 180     public DirectColorModel(int bits, int rmask, int gmask,
 181                             int bmask, int amask) {
 182         super (ColorSpace.getInstance(ColorSpace.CS_sRGB),
 183                bits, rmask, gmask, bmask, amask, false,
 184                amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT,
 185                ColorModel.getDefaultTransferType(bits));
 186         setFields();
 187     }
 188 
 189     /**
 190      * Constructs a <code>DirectColorModel</code> from the specified
 191      * parameters.  Color components are in the specified
 192      * <code>ColorSpace</code>, which must be of type ColorSpace.TYPE_RGB
 193      * and have minimum normalized component values which are all 0.0
 194      * and maximum values which are all 1.0.
 195      * The masks specify which bits in an <code>int</code> pixel
 196      * representation contain the red, green and blue color samples and
 197      * the alpha sample, if present.  If <code>amask</code> is 0, pixel
 198      * values do not contain alpha information and all pixels are treated
 199      * as opaque, which means that alpha&nbsp;=&nbsp;1.0.  All of the
 200      * bits in each mask must be contiguous and fit in the specified number
 201      * of least significant bits of an <code>int</code> pixel
 202      * representation.  If there is alpha, the <code>boolean</code>
 203      * <code>isAlphaPremultiplied</code> specifies how to interpret
 204      * color and alpha samples in pixel values.  If the <code>boolean</code>
 205      * is <code>true</code>, color samples are assumed to have been
 206      * multiplied by the alpha sample.  The transparency value is
 207      * Transparency.OPAQUE, if no alpha is present, or
 208      * Transparency.TRANSLUCENT otherwise.  The transfer type
 209      * is the type of primitive array used to represent pixel values and
 210      * must be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
 211      * DataBuffer.TYPE_INT.
 212      * @param space the specified <code>ColorSpace</code>
 213      * @param bits the number of bits in the pixel values; for example,
 214      *         the sum of the number of bits in the masks.
 215      * @param rmask specifies a mask indicating which bits in an
 216      *         integer pixel contain the red component
 217      * @param gmask specifies a mask indicating which bits in an
 218      *         integer pixel contain the green component
 219      * @param bmask specifies a mask indicating which bits in an
 220      *         integer pixel contain the blue component
 221      * @param amask specifies a mask indicating which bits in an
 222      *         integer pixel contain the alpha component
 223      * @param isAlphaPremultiplied <code>true</code> if color samples are
 224      *        premultiplied by the alpha sample; <code>false</code> otherwise
 225      * @param transferType the type of array used to represent pixel values
 226      * @throws IllegalArgumentException if <code>space</code> is not a
 227      *         TYPE_RGB space or if the min/max normalized component
 228      *         values are not 0.0/1.0.
 229      */
 230     public DirectColorModel(ColorSpace space, int bits, int rmask,
 231                             int gmask, int bmask, int amask,
 232                             boolean isAlphaPremultiplied,
 233                             int transferType) {
 234         super (space, bits, rmask, gmask, bmask, amask,
 235                isAlphaPremultiplied,
 236                amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT,
 237                transferType);
 238         if (ColorModel.isLinearRGBspace(colorSpace)) {
 239             is_LinearRGB = true;
 240             if (maxBits <= 8) {
 241                 lRGBprecision = 8;
 242                 tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT();
 243                 fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT();
 244             } else {
 245                 lRGBprecision = 16;
 246                 tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT();
 247                 fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT();
 248             }
 249         } else if (!is_sRGB) {
 250             for (int i = 0; i < 3; i++) {
 251                 // super constructor checks that space is TYPE_RGB
 252                 // check here that min/max are all 0.0/1.0
 253                 if ((space.getMinValue(i) != 0.0f) ||
 254                     (space.getMaxValue(i) != 1.0f)) {
 255                     throw new IllegalArgumentException(
 256                         "Illegal min/max RGB component value");
 257                 }
 258             }
 259         }
 260         setFields();
 261     }
 262 
 263     /**
 264      * Returns the mask indicating which bits in an <code>int</code> pixel
 265      * representation contain the red color component.
 266      * @return the mask, which indicates which bits of the <code>int</code>
 267      *         pixel representation contain the red color sample.
 268      */
 269     final public int getRedMask() {
 270         return maskArray[0];
 271     }
 272 
 273     /**
 274      * Returns the mask indicating which bits in an <code>int</code> pixel
 275      * representation contain the green color component.
 276      * @return the mask, which indicates which bits of the <code>int</code>
 277      *         pixel representation contain the green color sample.
 278      */
 279     final public int getGreenMask() {
 280         return maskArray[1];
 281     }
 282 
 283     /**
 284      * Returns the mask indicating which bits in an <code>int</code> pixel
 285      * representation contain the blue color component.
 286      * @return the mask, which indicates which bits of the <code>int</code>
 287      *         pixel representation contain the blue color sample.
 288      */
 289     final public int getBlueMask() {
 290         return maskArray[2];
 291     }
 292 
 293     /**
 294      * Returns the mask indicating which bits in an <code>int</code> pixel
 295      * representation contain the alpha component.
 296      * @return the mask, which indicates which bits of the <code>int</code>
 297      *         pixel representation contain the alpha sample.
 298      */
 299     final public int getAlphaMask() {
 300         if (supportsAlpha) {
 301             return maskArray[3];
 302         } else {
 303             return 0;
 304         }
 305     }
 306 
 307 
 308     /*
 309      * Given an int pixel in this ColorModel's ColorSpace, converts
 310      * it to the default sRGB ColorSpace and returns the R, G, and B
 311      * components as float values between 0.0 and 1.0.
 312      */
 313     private float[] getDefaultRGBComponents(int pixel) {
 314         int components[] = getComponents(pixel, null, 0);
 315         float norm[] = getNormalizedComponents(components, 0, null, 0);
 316         // Note that getNormalizedComponents returns non-premultiplied values
 317         return colorSpace.toRGB(norm);
 318     }
 319 
 320 
 321     private int getsRGBComponentFromsRGB(int pixel, int idx) {
 322         int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]);
 323         if (isAlphaPremultiplied) {
 324             int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
 325             c = (a == 0) ? 0 :
 326                          (int) (((c * scaleFactors[idx]) * 255.0f /
 327                                  (a * scaleFactors[3])) + 0.5f);
 328         } else if (scaleFactors[idx] != 1.0f) {
 329             c = (int) ((c * scaleFactors[idx]) + 0.5f);
 330         }
 331         return c;
 332     }
 333 
 334 
 335     private int getsRGBComponentFromLinearRGB(int pixel, int idx) {
 336         int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]);
 337         if (isAlphaPremultiplied) {
 338             float factor = (float) ((1 << lRGBprecision) - 1);
 339             int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
 340             c = (a == 0) ? 0 :
 341                          (int) (((c * scaleFactors[idx]) * factor /
 342                                  (a * scaleFactors[3])) + 0.5f);
 343         } else if (nBits[idx] != lRGBprecision) {
 344             if (lRGBprecision == 16) {
 345                 c = (int) ((c * scaleFactors[idx] * 257.0f) + 0.5f);
 346             } else {
 347                 c = (int) ((c * scaleFactors[idx]) + 0.5f);
 348             }
 349         }
 350         // now range of c is 0-255 or 0-65535, depending on lRGBprecision
 351         return tosRGB8LUT[c] & 0xff;
 352     }
 353 
 354 
 355     /**
 356      * Returns the red color component for the specified pixel, scaled
 357      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 358      * color conversion is done if necessary.  The pixel value is specified
 359      * as an <code>int</code>.
 360      * The returned value is a non pre-multiplied value.  Thus, if the
 361      * alpha is premultiplied, this method divides it out before returning
 362      * the value.  If the alpha value is 0, for example, the red value
 363      * is 0.
 364      * @param pixel the specified pixel
 365      * @return the red color component for the specified pixel, from
 366      *         0 to 255 in the sRGB <code>ColorSpace</code>.
 367      */
 368     final public int getRed(int pixel) {
 369         if (is_sRGB) {
 370             return getsRGBComponentFromsRGB(pixel, 0);
 371         } else if (is_LinearRGB) {
 372             return getsRGBComponentFromLinearRGB(pixel, 0);
 373         }
 374         float rgb[] = getDefaultRGBComponents(pixel);
 375         return (int) (rgb[0] * 255.0f + 0.5f);
 376     }
 377 
 378     /**
 379      * Returns the green color component for the specified pixel, scaled
 380      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 381      * color conversion is done if necessary.  The pixel value is specified
 382      * as an <code>int</code>.
 383      * The returned value is a non pre-multiplied value.  Thus, if the
 384      * alpha is premultiplied, this method divides it out before returning
 385      * the value.  If the alpha value is 0, for example, the green value
 386      * is 0.
 387      * @param pixel the specified pixel
 388      * @return the green color component for the specified pixel, from
 389      *         0 to 255 in the sRGB <code>ColorSpace</code>.
 390      */
 391     final public int getGreen(int pixel) {
 392         if (is_sRGB) {
 393             return getsRGBComponentFromsRGB(pixel, 1);
 394         } else if (is_LinearRGB) {
 395             return getsRGBComponentFromLinearRGB(pixel, 1);
 396         }
 397         float rgb[] = getDefaultRGBComponents(pixel);
 398         return (int) (rgb[1] * 255.0f + 0.5f);
 399     }
 400 
 401     /**
 402      * Returns the blue color component for the specified pixel, scaled
 403      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 404      * color conversion is done if necessary.  The pixel value is specified
 405      * as an <code>int</code>.
 406      * The returned value is a non pre-multiplied value.  Thus, if the
 407      * alpha is premultiplied, this method divides it out before returning
 408      * the value.  If the alpha value is 0, for example, the blue value
 409      * is 0.
 410      * @param pixel the specified pixel
 411      * @return the blue color component for the specified pixel, from
 412      *         0 to 255 in the sRGB <code>ColorSpace</code>.
 413      */
 414     final public int getBlue(int pixel) {
 415         if (is_sRGB) {
 416             return getsRGBComponentFromsRGB(pixel, 2);
 417         } else if (is_LinearRGB) {
 418             return getsRGBComponentFromLinearRGB(pixel, 2);
 419         }
 420         float rgb[] = getDefaultRGBComponents(pixel);
 421         return (int) (rgb[2] * 255.0f + 0.5f);
 422     }
 423 
 424     /**
 425      * Returns the alpha component for the specified pixel, scaled
 426      * from 0 to 255.  The pixel value is specified as an <code>int</code>.
 427      * @param pixel the specified pixel
 428      * @return the value of the alpha component of <code>pixel</code>
 429      *         from 0 to 255.
 430      */
 431     final public int getAlpha(int pixel) {
 432         if (!supportsAlpha) return 255;
 433         int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
 434         if (scaleFactors[3] != 1.0f) {
 435             a = (int)(a * scaleFactors[3] + 0.5f);
 436         }
 437         return a;
 438     }
 439 
 440     /**
 441      * Returns the color/alpha components of the pixel in the default
 442      * RGB color model format.  A color conversion is done if necessary.
 443      * The pixel value is specified as an <code>int</code>.
 444      * The returned value is in a non pre-multiplied format.  Thus, if
 445      * the alpha is premultiplied, this method divides it out of the
 446      * color components.  If the alpha value is 0, for example, the color
 447      * values are each 0.
 448      * @param pixel the specified pixel
 449      * @return the RGB value of the color/alpha components of the specified
 450      *         pixel.
 451      * @see ColorModel#getRGBdefault
 452      */
 453     final public int getRGB(int pixel) {
 454         if (is_sRGB || is_LinearRGB) {
 455             return (getAlpha(pixel) << 24)
 456                 | (getRed(pixel) << 16)
 457                 | (getGreen(pixel) << 8)
 458                 | (getBlue(pixel) << 0);
 459         }
 460         float rgb[] = getDefaultRGBComponents(pixel);
 461         return (getAlpha(pixel) << 24)
 462             | (((int) (rgb[0] * 255.0f + 0.5f)) << 16)
 463             | (((int) (rgb[1] * 255.0f + 0.5f)) << 8)
 464             | (((int) (rgb[2] * 255.0f + 0.5f)) << 0);
 465     }
 466 
 467     /**
 468      * Returns the red color component for the specified pixel, scaled
 469      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 470      * color conversion is done if necessary.  The pixel value is specified
 471      * by an array of data elements of type <code>transferType</code> passed
 472      * in as an object reference.
 473      * The returned value is a non pre-multiplied value.  Thus, if the
 474      * alpha is premultiplied, this method divides it out before returning
 475      * the value.  If the alpha value is 0, for example, the red value
 476      * is 0.
 477      * If <code>inData</code> is not a primitive array of type
 478      * <code>transferType</code>, a <code>ClassCastException</code> is
 479      * thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 480      * thrown if <code>inData</code> is not large enough to hold a
 481      * pixel value for this <code>ColorModel</code>.  Since
 482      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 483      * the implementation of this method and if they don't override it
 484      * then they throw an exception if they use an unsupported
 485      * <code>transferType</code>.
 486      * An <code>UnsupportedOperationException</code> is thrown if this
 487      * <code>transferType</code> is not supported by this
 488      * <code>ColorModel</code>.
 489      * @param inData the array containing the pixel value
 490      * @return the value of the red component of the specified pixel.
 491      * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
 492      *         large enough to hold a pixel value for this color model
 493      * @throws ClassCastException if <code>inData</code> is not a
 494      *         primitive array of type <code>transferType</code>
 495      * @throws UnsupportedOperationException if this <code>transferType</code>
 496      *         is not supported by this color model
 497      */
 498     public int getRed(Object inData) {
 499         int pixel=0;
 500         switch (transferType) {
 501             case DataBuffer.TYPE_BYTE:
 502                byte bdata[] = (byte[])inData;
 503                pixel = bdata[0] & 0xff;
 504             break;
 505             case DataBuffer.TYPE_USHORT:
 506                short sdata[] = (short[])inData;
 507                pixel = sdata[0] & 0xffff;
 508             break;
 509             case DataBuffer.TYPE_INT:
 510                int idata[] = (int[])inData;
 511                pixel = idata[0];
 512             break;
 513             default:
 514                throw new UnsupportedOperationException("This method has not been "+
 515                    "implemented for transferType " + transferType);
 516         }
 517         return getRed(pixel);
 518     }
 519 
 520 
 521     /**
 522      * Returns the green color component for the specified pixel, scaled
 523      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 524      * color conversion is done if necessary.  The pixel value is specified
 525      * by an array of data elements of type <code>transferType</code> passed
 526      * in as an object reference.
 527      * The returned value is a non pre-multiplied value.  Thus, if the
 528      * alpha is premultiplied, this method divides it out before returning
 529      * the value.  If the alpha value is 0, for example, the green value
 530      * is 0.  If <code>inData</code> is not a primitive array of type
 531      * <code>transferType</code>, a <code>ClassCastException</code> is thrown.
 532      *  An <code>ArrayIndexOutOfBoundsException</code> is
 533      * thrown if <code>inData</code> is not large enough to hold a pixel
 534      * value for this <code>ColorModel</code>.  Since
 535      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 536      * the implementation of this method and if they don't override it
 537      * then they throw an exception if they use an unsupported
 538      * <code>transferType</code>.
 539      * An <code>UnsupportedOperationException</code> is
 540      * thrown if this <code>transferType</code> is not supported by this
 541      * <code>ColorModel</code>.
 542      * @param inData the array containing the pixel value
 543      * @return the value of the green component of the specified pixel.
 544      * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
 545      *         large enough to hold a pixel value for this color model
 546      * @throws ClassCastException if <code>inData</code> is not a
 547      *         primitive array of type <code>transferType</code>
 548      * @throws UnsupportedOperationException if this <code>transferType</code>
 549      *         is not supported by this color model
 550      */
 551     public int getGreen(Object inData) {
 552         int pixel=0;
 553         switch (transferType) {
 554             case DataBuffer.TYPE_BYTE:
 555                byte bdata[] = (byte[])inData;
 556                pixel = bdata[0] & 0xff;
 557             break;
 558             case DataBuffer.TYPE_USHORT:
 559                short sdata[] = (short[])inData;
 560                pixel = sdata[0] & 0xffff;
 561             break;
 562             case DataBuffer.TYPE_INT:
 563                int idata[] = (int[])inData;
 564                pixel = idata[0];
 565             break;
 566             default:
 567                throw new UnsupportedOperationException("This method has not been "+
 568                    "implemented for transferType " + transferType);
 569         }
 570         return getGreen(pixel);
 571     }
 572 
 573 
 574     /**
 575      * Returns the blue color component for the specified pixel, scaled
 576      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 577      * color conversion is done if necessary.  The pixel value is specified
 578      * by an array of data elements of type <code>transferType</code> passed
 579      * in as an object reference.
 580      * The returned value is a non pre-multiplied value.  Thus, if the
 581      * alpha is premultiplied, this method divides it out before returning
 582      * the value.  If the alpha value is 0, for example, the blue value
 583      * is 0.  If <code>inData</code> is not a primitive array of type
 584      * <code>transferType</code>, a <code>ClassCastException</code> is thrown.
 585      *  An <code>ArrayIndexOutOfBoundsException</code> is
 586      * thrown if <code>inData</code> is not large enough to hold a pixel
 587      * value for this <code>ColorModel</code>.  Since
 588      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 589      * the implementation of this method and if they don't override it
 590      * then they throw an exception if they use an unsupported
 591      * <code>transferType</code>.
 592      * An <code>UnsupportedOperationException</code> is
 593      * thrown if this <code>transferType</code> is not supported by this
 594      * <code>ColorModel</code>.
 595      * @param inData the array containing the pixel value
 596      * @return the value of the blue component of the specified pixel.
 597      * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
 598      *         large enough to hold a pixel value for this color model
 599      * @throws ClassCastException if <code>inData</code> is not a
 600      *         primitive array of type <code>transferType</code>
 601      * @throws UnsupportedOperationException if this <code>transferType</code>
 602      *         is not supported by this color model
 603      */
 604     public int getBlue(Object inData) {
 605         int pixel=0;
 606         switch (transferType) {
 607             case DataBuffer.TYPE_BYTE:
 608                byte bdata[] = (byte[])inData;
 609                pixel = bdata[0] & 0xff;
 610             break;
 611             case DataBuffer.TYPE_USHORT:
 612                short sdata[] = (short[])inData;
 613                pixel = sdata[0] & 0xffff;
 614             break;
 615             case DataBuffer.TYPE_INT:
 616                int idata[] = (int[])inData;
 617                pixel = idata[0];
 618             break;
 619             default:
 620                throw new UnsupportedOperationException("This method has not been "+
 621                    "implemented for transferType " + transferType);
 622         }
 623         return getBlue(pixel);
 624     }
 625 
 626     /**
 627      * Returns the alpha component for the specified pixel, scaled
 628      * from 0 to 255.  The pixel value is specified by an array of data
 629      * elements of type <code>transferType</code> passed in as an object
 630      * reference.
 631      * If <code>inData</code> is not a primitive array of type
 632      * <code>transferType</code>, a <code>ClassCastException</code> is
 633      * thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 634      * thrown if <code>inData</code> is not large enough to hold a pixel
 635      * value for this <code>ColorModel</code>.  Since
 636      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 637      * the implementation of this method and if they don't override it
 638      * then they throw an exception if they use an unsupported
 639      * <code>transferType</code>.
 640      * If this <code>transferType</code> is not supported, an
 641      * <code>UnsupportedOperationException</code> is thrown.
 642      * @param inData the specified pixel
 643      * @return the alpha component of the specified pixel, scaled from
 644      *         0 to 255.
 645      * @exception <code>ClassCastException</code> if <code>inData</code>
 646      *  is not a primitive array of type <code>transferType</code>
 647      * @exception <code>ArrayIndexOutOfBoundsException</code> if
 648      *  <code>inData</code> is not large enough to hold a pixel value
 649      *  for this <code>ColorModel</code>
 650      * @exception <code>UnsupportedOperationException</code> if this
 651      *  <code>tranferType</code> is not supported by this
 652      *  <code>ColorModel</code>
 653      */
 654     public int getAlpha(Object inData) {
 655         int pixel=0;
 656         switch (transferType) {
 657             case DataBuffer.TYPE_BYTE:
 658                byte bdata[] = (byte[])inData;
 659                pixel = bdata[0] & 0xff;
 660             break;
 661             case DataBuffer.TYPE_USHORT:
 662                short sdata[] = (short[])inData;
 663                pixel = sdata[0] & 0xffff;
 664             break;
 665             case DataBuffer.TYPE_INT:
 666                int idata[] = (int[])inData;
 667                pixel = idata[0];
 668             break;
 669             default:
 670                throw new UnsupportedOperationException("This method has not been "+
 671                    "implemented for transferType " + transferType);
 672         }
 673         return getAlpha(pixel);
 674     }
 675 
 676     /**
 677      * Returns the color/alpha components for the specified pixel in the
 678      * default RGB color model format.  A color conversion is done if
 679      * necessary.  The pixel value is specified by an array of data
 680      * elements of type <code>transferType</code> passed in as an object
 681      * reference.  If <code>inData</code> is not a primitive array of type
 682      * <code>transferType</code>, a <code>ClassCastException</code> is
 683      * thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 684      * thrown if <code>inData</code> is not large enough to hold a pixel
 685      * value for this <code>ColorModel</code>.
 686      * The returned value is in a non pre-multiplied format.  Thus, if
 687      * the alpha is premultiplied, this method divides it out of the
 688      * color components.  If the alpha value is 0, for example, the color
 689      * values is 0.  Since <code>DirectColorModel</code> can be
 690      * subclassed, subclasses inherit the implementation of this method
 691      * and if they don't override it then
 692      * they throw an exception if they use an unsupported
 693      * <code>transferType</code>.
 694      *
 695      * @param inData the specified pixel
 696      * @return the color and alpha components of the specified pixel.
 697      * @exception UnsupportedOperationException if this
 698      *            <code>transferType</code> is not supported by this
 699      *            <code>ColorModel</code>
 700      * @see ColorModel#getRGBdefault
 701      */
 702     public int getRGB(Object inData) {
 703         int pixel=0;
 704         switch (transferType) {
 705             case DataBuffer.TYPE_BYTE:
 706                byte bdata[] = (byte[])inData;
 707                pixel = bdata[0] & 0xff;
 708             break;
 709             case DataBuffer.TYPE_USHORT:
 710                short sdata[] = (short[])inData;
 711                pixel = sdata[0] & 0xffff;
 712             break;
 713             case DataBuffer.TYPE_INT:
 714                int idata[] = (int[])inData;
 715                pixel = idata[0];
 716             break;
 717             default:
 718                throw new UnsupportedOperationException("This method has not been "+
 719                    "implemented for transferType " + transferType);
 720         }
 721         return getRGB(pixel);
 722     }
 723 
 724     /**
 725      * Returns a data element array representation of a pixel in this
 726      * <code>ColorModel</code>, given an integer pixel representation in the
 727      * default RGB color model.
 728      * This array can then be passed to the <code>setDataElements</code>
 729      * method of a <code>WritableRaster</code> object.  If the pixel variable
 730      * is <code>null</code>, a new array is allocated.  If <code>pixel</code>
 731      * is not <code>null</code>, it must be a primitive array of type
 732      * <code>transferType</code>; otherwise, a
 733      * <code>ClassCastException</code> is thrown.  An
 734      * <code>ArrayIndexOutOfBoundsException</code> is
 735      * thrown if <code>pixel</code> is not large enough to hold a pixel
 736      * value for this <code>ColorModel</code>.  The pixel array is returned.
 737      * Since <code>DirectColorModel</code> can be subclassed, subclasses
 738      * inherit the implementation of this method and if they don't
 739      * override it then they throw an exception if they use an unsupported
 740      * <code>transferType</code>.
 741      *
 742      * @param rgb the integer pixel representation in the default RGB
 743      *            color model
 744      * @param pixel the specified pixel
 745      * @return an array representation of the specified pixel in this
 746      *         <code>ColorModel</code>
 747      * @exception ClassCastException if <code>pixel</code>
 748      *  is not a primitive array of type <code>transferType</code>
 749      * @exception ArrayIndexOutOfBoundsException if
 750      *  <code>pixel</code> is not large enough to hold a pixel value
 751      *  for this <code>ColorModel</code>
 752      * @exception UnsupportedOperationException if this
 753      *  <code>transferType</code> is not supported by this
 754      *  <code>ColorModel</code>
 755      * @see WritableRaster#setDataElements
 756      * @see SampleModel#setDataElements
 757      */
 758     public Object getDataElements(int rgb, Object pixel) {
 759         //REMIND: maybe more efficient not to use int array for
 760         //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT
 761         int intpixel[] = null;
 762         if (transferType == DataBuffer.TYPE_INT &&
 763             pixel != null) {
 764             intpixel = (int[])pixel;
 765             intpixel[0] = 0;
 766         } else {
 767             intpixel = new int[1];
 768         }
 769 
 770         ColorModel defaultCM = ColorModel.getRGBdefault();
 771         if (this == defaultCM || equals(defaultCM)) {
 772             intpixel[0] = rgb;
 773             return intpixel;
 774         }
 775 
 776         int red, grn, blu, alp;
 777         red = (rgb>>16) & 0xff;
 778         grn = (rgb>>8) & 0xff;
 779         blu = rgb & 0xff;
 780         if (is_sRGB || is_LinearRGB) {
 781             int precision;
 782             float factor;
 783             if (is_LinearRGB) {
 784                 if (lRGBprecision == 8) {
 785                     red = fromsRGB8LUT8[red] & 0xff;
 786                     grn = fromsRGB8LUT8[grn] & 0xff;
 787                     blu = fromsRGB8LUT8[blu] & 0xff;
 788                     precision = 8;
 789                     factor = 1.0f / 255.0f;
 790                 } else {
 791                     red = fromsRGB8LUT16[red] & 0xffff;
 792                     grn = fromsRGB8LUT16[grn] & 0xffff;
 793                     blu = fromsRGB8LUT16[blu] & 0xffff;
 794                     precision = 16;
 795                     factor = 1.0f / 65535.0f;
 796                 }
 797             } else {
 798                 precision = 8;
 799                 factor = 1.0f / 255.0f;
 800             }
 801             if (supportsAlpha) {
 802                 alp = (rgb>>24) & 0xff;
 803                 if (isAlphaPremultiplied) {
 804                     factor *= (alp * (1.0f / 255.0f));
 805                     precision = -1;  // force component calculations below
 806                 }
 807                 if (nBits[3] != 8) {
 808                     alp = (int)
 809                         ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f);
 810                     if (alp > ((1<<nBits[3]) - 1)) {
 811                         // fix 4412670 - see comment below
 812                         alp = (1<<nBits[3]) - 1;
 813                     }
 814                 }
 815                 intpixel[0] = alp << maskOffsets[3];
 816             }
 817             if (nBits[0] != precision) {
 818                 red = (int) ((red * factor * ((1<<nBits[0]) - 1)) + 0.5f);
 819             }
 820             if (nBits[1] != precision) {
 821                 grn = (int) ((grn * factor * ((1<<nBits[1]) - 1)) + 0.5f);
 822             }
 823             if (nBits[2] != precision) {
 824                 blu = (int) ((blu * factor * ((1<<nBits[2]) - 1)) + 0.5f);
 825             }
 826         } else {
 827             // Need to convert the color
 828             float[] norm = new float[3];
 829             float factor = 1.0f / 255.0f;
 830             norm[0] = red * factor;
 831             norm[1] = grn * factor;
 832             norm[2] = blu * factor;
 833             norm = colorSpace.fromRGB(norm);
 834             if (supportsAlpha) {
 835                 alp = (rgb>>24) & 0xff;
 836                 if (isAlphaPremultiplied) {
 837                     factor *= alp;
 838                     for (int i = 0; i < 3; i++) {
 839                         norm[i] *= factor;
 840                     }
 841                 }
 842                 if (nBits[3] != 8) {
 843                     alp = (int)
 844                         ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f);
 845                     if (alp > ((1<<nBits[3]) - 1)) {
 846                         // fix 4412670 - see comment below
 847                         alp = (1<<nBits[3]) - 1;
 848                     }
 849                 }
 850                 intpixel[0] = alp << maskOffsets[3];
 851             }
 852             red = (int) ((norm[0] * ((1<<nBits[0]) - 1)) + 0.5f);
 853             grn = (int) ((norm[1] * ((1<<nBits[1]) - 1)) + 0.5f);
 854             blu = (int) ((norm[2] * ((1<<nBits[2]) - 1)) + 0.5f);
 855         }
 856 
 857         if (maxBits > 23) {
 858             // fix 4412670 - for components of 24 or more bits
 859             // some calculations done above with float precision
 860             // may lose enough precision that the integer result
 861             // overflows nBits, so we need to clamp.
 862             if (red > ((1<<nBits[0]) - 1)) {
 863                 red = (1<<nBits[0]) - 1;
 864             }
 865             if (grn > ((1<<nBits[1]) - 1)) {
 866                 grn = (1<<nBits[1]) - 1;
 867             }
 868             if (blu > ((1<<nBits[2]) - 1)) {
 869                 blu = (1<<nBits[2]) - 1;
 870             }
 871         }
 872 
 873         intpixel[0] |= (red << maskOffsets[0]) |
 874                        (grn << maskOffsets[1]) |
 875                        (blu << maskOffsets[2]);
 876 
 877         switch (transferType) {
 878             case DataBuffer.TYPE_BYTE: {
 879                byte bdata[];
 880                if (pixel == null) {
 881                    bdata = new byte[1];
 882                } else {
 883                    bdata = (byte[])pixel;
 884                }
 885                bdata[0] = (byte)(0xff&intpixel[0]);
 886                return bdata;
 887             }
 888             case DataBuffer.TYPE_USHORT:{
 889                short sdata[];
 890                if (pixel == null) {
 891                    sdata = new short[1];
 892                } else {
 893                    sdata = (short[])pixel;
 894                }
 895                sdata[0] = (short)(intpixel[0]&0xffff);
 896                return sdata;
 897             }
 898             case DataBuffer.TYPE_INT:
 899                return intpixel;
 900         }
 901         throw new UnsupportedOperationException("This method has not been "+
 902                  "implemented for transferType " + transferType);
 903 
 904     }
 905 
 906     /**
 907      * Returns an array of unnormalized color/alpha components given a pixel
 908      * in this <code>ColorModel</code>.  The pixel value is specified as an
 909      * <code>int</code>.  If the <code>components</code> array is
 910      * <code>null</code>, a new array is allocated.  The
 911      * <code>components</code> array is returned.  Color/alpha components are
 912      * stored in the <code>components</code> array starting at
 913      * <code>offset</code>, even if the array is allocated by this method.
 914      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
 915      * <code>components</code> array is not <code>null</code> and is not large
 916      * enough to hold all the color and alpha components, starting at
 917      * <code>offset</code>.
 918      * @param pixel the specified pixel
 919      * @param components the array to receive the color and alpha
 920      * components of the specified pixel
 921      * @param offset the offset into the <code>components</code> array at
 922      * which to start storing the color and alpha components
 923      * @return an array containing the color and alpha components of the
 924      * specified pixel starting at the specified offset.
 925      */
 926     final public int[] getComponents(int pixel, int[] components, int offset) {
 927         if (components == null) {
 928             components = new int[offset+numComponents];
 929         }
 930 
 931         for (int i=0; i < numComponents; i++) {
 932             components[offset+i] = (pixel & maskArray[i]) >>> maskOffsets[i];
 933         }
 934 
 935         return components;
 936     }
 937 
 938     /**
 939      * Returns an array of unnormalized color/alpha components given a pixel
 940      * in this <code>ColorModel</code>.  The pixel value is specified by an
 941      * array of data elements of type <code>transferType</code> passed in as
 942      * an object reference.  If <code>pixel</code> is not a primitive array
 943      * of type <code>transferType</code>, a <code>ClassCastException</code>
 944      * is thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 945      * thrown if <code>pixel</code> is not large enough to hold a
 946      * pixel value for this <code>ColorModel</code>.  If the
 947      * <code>components</code> array is <code>null</code>, a new
 948      * array is allocated.  The <code>components</code> array is returned.
 949      * Color/alpha components are stored in the <code>components</code> array
 950      * starting at <code>offset</code>, even if the array is allocated by
 951      * this method.  An <code>ArrayIndexOutOfBoundsException</code>
 952      * is thrown if the <code>components</code> array is not
 953      * <code>null</code> and is not large enough to hold all the color and
 954      * alpha components, starting at <code>offset</code>.
 955      * Since <code>DirectColorModel</code> can be subclassed, subclasses
 956      * inherit the implementation of this method and if they don't
 957      * override it then they throw an exception if they use an unsupported
 958      * <code>transferType</code>.
 959      * @param pixel the specified pixel
 960      * @param components the array to receive the color and alpha
 961      *        components of the specified pixel
 962      * @param offset the offset into the <code>components</code> array at
 963      *        which to start storing the color and alpha components
 964      * @return an array containing the color and alpha components of the
 965      * specified pixel starting at the specified offset.
 966      * @exception ClassCastException if <code>pixel</code>
 967      *  is not a primitive array of type <code>transferType</code>
 968      * @exception ArrayIndexOutOfBoundsException if
 969      *  <code>pixel</code> is not large enough to hold a pixel value
 970      *  for this <code>ColorModel</code>, or if <code>components</code>
 971      *  is not <code>null</code> and is not large enough to hold all the
 972      *  color and alpha components, starting at <code>offset</code>
 973      * @exception UnsupportedOperationException if this
 974      *            <code>transferType</code> is not supported by this
 975      *            color model
 976      */
 977     final public int[] getComponents(Object pixel, int[] components,
 978                                      int offset) {
 979         int intpixel=0;
 980         switch (transferType) {
 981             case DataBuffer.TYPE_BYTE:
 982                byte bdata[] = (byte[])pixel;
 983                intpixel = bdata[0] & 0xff;
 984             break;
 985             case DataBuffer.TYPE_USHORT:
 986                short sdata[] = (short[])pixel;
 987                intpixel = sdata[0] & 0xffff;
 988             break;
 989             case DataBuffer.TYPE_INT:
 990                int idata[] = (int[])pixel;
 991                intpixel = idata[0];
 992             break;
 993             default:
 994                throw new UnsupportedOperationException("This method has not been "+
 995                    "implemented for transferType " + transferType);
 996         }
 997         return getComponents(intpixel, components, offset);
 998     }
 999 
1000     /**
1001      * Creates a <code>WritableRaster</code> with the specified width and
1002      * height that has a data layout (<code>SampleModel</code>) compatible
1003      * with this <code>ColorModel</code>.
1004      * @param w the width to apply to the new <code>WritableRaster</code>
1005      * @param h the height to apply to the new <code>WritableRaster</code>
1006      * @return a <code>WritableRaster</code> object with the specified
1007      * width and height.
1008      * @throws IllegalArgumentException if <code>w</code> or <code>h</code>
1009      *         is less than or equal to zero
1010      * @see WritableRaster
1011      * @see SampleModel
1012      */
1013     final public WritableRaster createCompatibleWritableRaster (int w,
1014                                                                 int h) {
1015         if ((w <= 0) || (h <= 0)) {
1016             throw new IllegalArgumentException("Width (" + w + ") and height (" + h +
1017                                                ") cannot be <= 0");
1018         }
1019         int[] bandmasks;
1020         if (supportsAlpha) {
1021             bandmasks = new int[4];
1022             bandmasks[3] = alpha_mask;
1023         }
1024         else {
1025             bandmasks = new int[3];
1026         }
1027         bandmasks[0] = red_mask;
1028         bandmasks[1] = green_mask;
1029         bandmasks[2] = blue_mask;
1030 
1031         if (pixel_bits > 16) {
1032             return Raster.createPackedRaster(DataBuffer.TYPE_INT,
1033                                              w,h,bandmasks,null);
1034         }
1035         else if (pixel_bits > 8) {
1036             return Raster.createPackedRaster(DataBuffer.TYPE_USHORT,
1037                                              w,h,bandmasks,null);
1038         }
1039         else {
1040             return Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
1041                                              w,h,bandmasks,null);
1042         }
1043     }
1044 
1045     /**
1046      * Returns a pixel value represented as an <code>int</code> in this
1047      * <code>ColorModel</code>, given an array of unnormalized color/alpha
1048      * components.   An <code>ArrayIndexOutOfBoundsException</code> is
1049      * thrown if the <code>components</code> array is
1050      * not large enough to hold all the color and alpha components, starting
1051      * at <code>offset</code>.
1052      * @param components an array of unnormalized color and alpha
1053      * components
1054      * @param offset the index into <code>components</code> at which to
1055      * begin retrieving the color and alpha components
1056      * @return an <code>int</code> pixel value in this
1057      * <code>ColorModel</code> corresponding to the specified components.
1058      * @exception <code>ArrayIndexOutOfBoundsException</code> if
1059      *  the <code>components</code> array is not large enough to
1060      *  hold all of the color and alpha components starting at
1061      *  <code>offset</code>
1062      */
1063     public int getDataElement(int[] components, int offset) {
1064         int pixel = 0;
1065         for (int i=0; i < numComponents; i++) {
1066             pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]);
1067         }
1068         return pixel;
1069     }
1070 
1071     /**
1072      * Returns a data element array representation of a pixel in this
1073      * <code>ColorModel</code>, given an array of unnormalized color/alpha
1074      * components.
1075      * This array can then be passed to the <code>setDataElements</code>
1076      * method of a <code>WritableRaster</code> object.
1077      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
1078      * <code>components</code> array
1079      * is not large enough to hold all the color and alpha components,
1080      * starting at offset.  If the <code>obj</code> variable is
1081      * <code>null</code>, a new array is allocated.  If <code>obj</code> is
1082      * not <code>null</code>, it must be a primitive array
1083      * of type <code>transferType</code>; otherwise, a
1084      * <code>ClassCastException</code> is thrown.
1085      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if
1086      * <code>obj</code> is not large enough to hold a pixel value for this
1087      * <code>ColorModel</code>.
1088      * Since <code>DirectColorModel</code> can be subclassed, subclasses
1089      * inherit the implementation of this method and if they don't
1090      * override it then they throw an exception if they use an unsupported
1091      * <code>transferType</code>.
1092      * @param components an array of unnormalized color and alpha
1093      * components
1094      * @param offset the index into <code>components</code> at which to
1095      * begin retrieving color and alpha components
1096      * @param obj the <code>Object</code> representing an array of color
1097      * and alpha components
1098      * @return an <code>Object</code> representing an array of color and
1099      * alpha components.
1100      * @exception <code>ClassCastException</code> if <code>obj</code>
1101      *  is not a primitive array of type <code>transferType</code>
1102      * @exception <code>ArrayIndexOutOfBoundsException</code> if
1103      *  <code>obj</code> is not large enough to hold a pixel value
1104      *  for this <code>ColorModel</code> or the <code>components</code>
1105      *  array is not large enough to hold all of the color and alpha
1106      *  components starting at <code>offset</code>
1107      * @exception UnsupportedOperationException if this
1108      *            <code>transferType</code> is not supported by this
1109      *            color model
1110      * @see WritableRaster#setDataElements
1111      * @see SampleModel#setDataElements
1112      */
1113     public Object getDataElements(int[] components, int offset, Object obj) {
1114         int pixel = 0;
1115         for (int i=0; i < numComponents; i++) {
1116             pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]);
1117         }
1118         switch (transferType) {
1119             case DataBuffer.TYPE_BYTE:
1120                if (obj instanceof byte[]) {
1121                    byte bdata[] = (byte[])obj;
1122                    bdata[0] = (byte)(pixel&0xff);
1123                    return bdata;
1124                } else {
1125                    byte bdata[] = {(byte)(pixel&0xff)};
1126                    return bdata;
1127                }
1128             case DataBuffer.TYPE_USHORT:
1129                if (obj instanceof short[]) {
1130                    short sdata[] = (short[])obj;
1131                    sdata[0] = (short)(pixel&0xffff);
1132                    return sdata;
1133                } else {
1134                    short sdata[] = {(short)(pixel&0xffff)};
1135                    return sdata;
1136                }
1137             case DataBuffer.TYPE_INT:
1138                if (obj instanceof int[]) {
1139                    int idata[] = (int[])obj;
1140                    idata[0] = pixel;
1141                    return idata;
1142                } else {
1143                    int idata[] = {pixel};
1144                    return idata;
1145                }
1146             default:
1147                throw new ClassCastException("This method has not been "+
1148                    "implemented for transferType " + transferType);
1149         }
1150     }
1151 
1152     /**
1153      * Forces the raster data to match the state specified in the
1154      * <code>isAlphaPremultiplied</code> variable, assuming the data is
1155      * currently correctly described by this <code>ColorModel</code>.  It
1156      * may multiply or divide the color raster data by alpha, or do
1157      * nothing if the data is in the correct state.  If the data needs to
1158      * be coerced, this method will also return an instance of this
1159      * <code>ColorModel</code> with the <code>isAlphaPremultiplied</code>
1160      * flag set appropriately.  This method will throw a
1161      * <code>UnsupportedOperationException</code> if this transferType is
1162      * not supported by this <code>ColorModel</code>.  Since
1163      * <code>ColorModel</code> can be subclassed, subclasses inherit the
1164      * implementation of this method and if they don't override it then
1165      * they throw an exception if they use an unsupported transferType.
1166      *
1167      * @param raster the <code>WritableRaster</code> data
1168      * @param isAlphaPremultiplied <code>true</code> if the alpha is
1169      * premultiplied; <code>false</code> otherwise
1170      * @return a <code>ColorModel</code> object that represents the
1171      * coerced data.
1172      * @exception UnsupportedOperationException if this
1173      *            <code>transferType</code> is not supported by this
1174      *            color model
1175      */
1176     final public ColorModel coerceData (WritableRaster raster,
1177                                         boolean isAlphaPremultiplied)
1178     {
1179         if (!supportsAlpha ||
1180             this.isAlphaPremultiplied() == isAlphaPremultiplied) {
1181             return this;
1182         }
1183 
1184         int w = raster.getWidth();
1185         int h = raster.getHeight();
1186         int aIdx = numColorComponents;
1187         float normAlpha;
1188         float alphaScale = 1.0f / ((float) ((1 << nBits[aIdx]) - 1));
1189 
1190         int rminX = raster.getMinX();
1191         int rY = raster.getMinY();
1192         int rX;
1193         int pixel[] = null;
1194         int zpixel[] = null;
1195 
1196         if (isAlphaPremultiplied) {
1197             // Must mean that we are currently not premultiplied so
1198             // multiply by alpha
1199             switch (transferType) {
1200                 case DataBuffer.TYPE_BYTE: {
1201                     for (int y = 0; y < h; y++, rY++) {
1202                         rX = rminX;
1203                         for (int x = 0; x < w; x++, rX++) {
1204                             pixel = raster.getPixel(rX, rY, pixel);
1205                             normAlpha = pixel[aIdx] * alphaScale;
1206                             if (normAlpha != 0.f) {
1207                                 for (int c=0; c < aIdx; c++) {
1208                                     pixel[c] = (int) (pixel[c] * normAlpha +
1209                                                       0.5f);
1210                                 }
1211                                 raster.setPixel(rX, rY, pixel);
1212                             } else {
1213                                 if (zpixel == null) {
1214                                     zpixel = new int[numComponents];
1215                                     java.util.Arrays.fill(zpixel, 0);
1216                                 }
1217                                 raster.setPixel(rX, rY, zpixel);
1218                             }
1219                         }
1220                     }
1221                 }
1222                 break;
1223                 case DataBuffer.TYPE_USHORT: {
1224                     for (int y = 0; y < h; y++, rY++) {
1225                         rX = rminX;
1226                         for (int x = 0; x < w; x++, rX++) {
1227                             pixel = raster.getPixel(rX, rY, pixel);
1228                             normAlpha = pixel[aIdx] * alphaScale;
1229                             if (normAlpha != 0.f) {
1230                                 for (int c=0; c < aIdx; c++) {
1231                                     pixel[c] = (int) (pixel[c] * normAlpha +
1232                                                       0.5f);
1233                                 }
1234                                 raster.setPixel(rX, rY, pixel);
1235                             } else {
1236                                 if (zpixel == null) {
1237                                     zpixel = new int[numComponents];
1238                                     java.util.Arrays.fill(zpixel, 0);
1239                                 }
1240                                 raster.setPixel(rX, rY, zpixel);
1241                             }
1242                         }
1243                     }
1244                 }
1245                 break;
1246                 case DataBuffer.TYPE_INT: {
1247                     for (int y = 0; y < h; y++, rY++) {
1248                         rX = rminX;
1249                         for (int x = 0; x < w; x++, rX++) {
1250                             pixel = raster.getPixel(rX, rY, pixel);
1251                             normAlpha = pixel[aIdx] * alphaScale;
1252                             if (normAlpha != 0.f) {
1253                                 for (int c=0; c < aIdx; c++) {
1254                                     pixel[c] = (int) (pixel[c] * normAlpha +
1255                                                       0.5f);
1256                                 }
1257                                 raster.setPixel(rX, rY, pixel);
1258                             } else {
1259                                 if (zpixel == null) {
1260                                     zpixel = new int[numComponents];
1261                                     java.util.Arrays.fill(zpixel, 0);
1262                                 }
1263                                 raster.setPixel(rX, rY, zpixel);
1264                             }
1265                         }
1266                     }
1267                 }
1268                 break;
1269                 default:
1270                     throw new UnsupportedOperationException("This method has not been "+
1271                          "implemented for transferType " + transferType);
1272             }
1273         }
1274         else {
1275             // We are premultiplied and want to divide it out
1276             switch (transferType) {
1277                 case DataBuffer.TYPE_BYTE: {
1278                     for (int y = 0; y < h; y++, rY++) {
1279                         rX = rminX;
1280                         for (int x = 0; x < w; x++, rX++) {
1281                             pixel = raster.getPixel(rX, rY, pixel);
1282                             normAlpha = pixel[aIdx] * alphaScale;
1283                             if (normAlpha != 0.0f) {
1284                                 float invAlpha = 1.0f / normAlpha;
1285                                 for (int c=0; c < aIdx; c++) {
1286                                     pixel[c] = (int) (pixel[c] * invAlpha +
1287                                                       0.5f);
1288                                 }
1289                                 raster.setPixel(rX, rY, pixel);
1290                             }
1291                         }
1292                     }
1293                 }
1294                 break;
1295                 case DataBuffer.TYPE_USHORT: {
1296                     for (int y = 0; y < h; y++, rY++) {
1297                         rX = rminX;
1298                         for (int x = 0; x < w; x++, rX++) {
1299                             pixel = raster.getPixel(rX, rY, pixel);
1300                             normAlpha = pixel[aIdx] * alphaScale;
1301                             if (normAlpha != 0) {
1302                                 float invAlpha = 1.0f / normAlpha;
1303                                 for (int c=0; c < aIdx; c++) {
1304                                     pixel[c] = (int) (pixel[c] * invAlpha +
1305                                                       0.5f);
1306                                 }
1307                                 raster.setPixel(rX, rY, pixel);
1308                             }
1309                         }
1310                     }
1311                 }
1312                 break;
1313                 case DataBuffer.TYPE_INT: {
1314                     for (int y = 0; y < h; y++, rY++) {
1315                         rX = rminX;
1316                         for (int x = 0; x < w; x++, rX++) {
1317                             pixel = raster.getPixel(rX, rY, pixel);
1318                             normAlpha = pixel[aIdx] * alphaScale;
1319                             if (normAlpha != 0) {
1320                                 float invAlpha = 1.0f / normAlpha;
1321                                 for (int c=0; c < aIdx; c++) {
1322                                     pixel[c] = (int) (pixel[c] * invAlpha +
1323                                                       0.5f);
1324                                 }
1325                                 raster.setPixel(rX, rY, pixel);
1326                             }
1327                         }
1328                     }
1329                 }
1330                 break;
1331                 default:
1332                     throw new UnsupportedOperationException("This method has not been "+
1333                          "implemented for transferType " + transferType);
1334             }
1335         }
1336 
1337         // Return a new color model
1338         return new DirectColorModel(colorSpace, pixel_bits, maskArray[0],
1339                                     maskArray[1], maskArray[2], maskArray[3],
1340                                     isAlphaPremultiplied,
1341                                     transferType);
1342 
1343     }
1344 
1345     /**
1346       * Returns <code>true</code> if <code>raster</code> is compatible
1347       * with this <code>ColorModel</code> and <code>false</code> if it is
1348       * not.
1349       * @param raster the {@link Raster} object to test for compatibility
1350       * @return <code>true</code> if <code>raster</code> is compatible
1351       * with this <code>ColorModel</code>; <code>false</code> otherwise.
1352       */
1353     public boolean isCompatibleRaster(Raster raster) {
1354         SampleModel sm = raster.getSampleModel();
1355         SinglePixelPackedSampleModel spsm;
1356         if (sm instanceof SinglePixelPackedSampleModel) {
1357             spsm = (SinglePixelPackedSampleModel) sm;
1358         }
1359         else {
1360             return false;
1361         }
1362         if (spsm.getNumBands() != getNumComponents()) {
1363             return false;
1364         }
1365 
1366         int[] bitMasks = spsm.getBitMasks();
1367         for (int i=0; i<numComponents; i++) {
1368             if (bitMasks[i] != maskArray[i]) {
1369                 return false;
1370             }
1371         }
1372 
1373         return (raster.getTransferType() == transferType);
1374     }
1375 
1376     private void setFields() {
1377         // Set the private fields
1378         // REMIND: Get rid of these from the native code
1379         red_mask     = maskArray[0];
1380         red_offset   = maskOffsets[0];
1381         green_mask   = maskArray[1];
1382         green_offset = maskOffsets[1];
1383         blue_mask    = maskArray[2];
1384         blue_offset  = maskOffsets[2];
1385         if (nBits[0] < 8) {
1386             red_scale = (1 << nBits[0]) - 1;
1387         }
1388         if (nBits[1] < 8) {
1389             green_scale = (1 << nBits[1]) - 1;
1390         }
1391         if (nBits[2] < 8) {
1392             blue_scale = (1 << nBits[2]) - 1;
1393         }
1394         if (supportsAlpha) {
1395             alpha_mask   = maskArray[3];
1396             alpha_offset = maskOffsets[3];
1397             if (nBits[3] < 8) {
1398                 alpha_scale = (1 << nBits[3]) - 1;
1399             }
1400         }
1401     }
1402 
1403     /**
1404      * Returns a <code>String</code> that represents this
1405      * <code>DirectColorModel</code>.
1406      * @return a <code>String</code> representing this
1407      * <code>DirectColorModel</code>.
1408      */
1409     public String toString() {
1410         return new String("DirectColorModel: rmask="
1411                           +Integer.toHexString(red_mask)+" gmask="
1412                           +Integer.toHexString(green_mask)+" bmask="
1413                           +Integer.toHexString(blue_mask)+" amask="
1414                           +Integer.toHexString(alpha_mask));
1415     }
1416 }