You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1417 lines
						
					
					
						
							61 KiB
						
					
					
				
			
		
		
	
	
							1417 lines
						
					
					
						
							61 KiB
						
					
					
				| /*
 | |
|  * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
 | |
|  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  */
 | |
| 
 | |
| package java.awt.image;
 | |
| 
 | |
| import java.awt.color.ColorSpace;
 | |
| import java.awt.Transparency;
 | |
| 
 | |
| /**
 | |
|  * The <code>DirectColorModel</code> class is a <code>ColorModel</code>
 | |
|  * class that works with pixel values that represent RGB
 | |
|  * color and alpha information as separate samples and that pack all
 | |
|  * samples for a single pixel into a single int, short, or byte quantity.
 | |
|  * This class can be used only with ColorSpaces of type ColorSpace.TYPE_RGB.
 | |
|  * In addition, for each component of the ColorSpace, the minimum
 | |
|  * normalized component value obtained via the <code>getMinValue()</code>
 | |
|  * method of ColorSpace must be 0.0, and the maximum value obtained via
 | |
|  * the <code>getMaxValue()</code> method must be 1.0 (these min/max
 | |
|  * values are typical for RGB spaces).
 | |
|  * There must be three color samples in the pixel values and there can
 | |
|  * be a single alpha sample.  For those methods that use a primitive array
 | |
|  * pixel representation of type <code>transferType</code>, the array
 | |
|  * length is always one.  The transfer
 | |
|  * types supported are DataBuffer.TYPE_BYTE,
 | |
|  * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT.
 | |
|  * Color and alpha samples are stored in the single
 | |
|  * element of the array in bits indicated by bit masks.  Each bit mask
 | |
|  * must be contiguous and masks must not overlap.  The same masks apply to
 | |
|  * the single int pixel representation used by other methods.  The
 | |
|  * correspondence of masks and color/alpha samples is as follows:
 | |
|  * <ul>
 | |
|  * <li> Masks are identified by indices running from 0 through 2
 | |
|  * if no alpha is present, or 3 if an alpha is present.
 | |
|  * <li> The first three indices refer to color samples;
 | |
|  * index 0 corresponds to red, index 1 to green, and index 2 to blue.
 | |
|  * <li> Index 3 corresponds to the alpha sample, if present.
 | |
|  * </ul>
 | |
|  * <p>
 | |
|  * The translation from pixel values to color/alpha components for
 | |
|  * display or processing purposes is a one-to-one correspondence of
 | |
|  * samples to components.  A <code>DirectColorModel</code> is
 | |
|  * typically used with image data which uses masks to define packed
 | |
|  * samples.  For example, a <code>DirectColorModel</code> can be used in
 | |
|  * conjunction with a <code>SinglePixelPackedSampleModel</code> to
 | |
|  * construct a {@link BufferedImage}.  Normally the masks used by the
 | |
|  * {@link SampleModel} and the <code>ColorModel</code> would be the
 | |
|  * same.  However, if they are different, the color interpretation
 | |
|  * of pixel data will be done according to the masks of the
 | |
|  * <code>ColorModel</code>.
 | |
|  * <p>
 | |
|  * A single int pixel representation is valid for all objects of this
 | |
|  * class, since it is always possible to represent pixel values used with
 | |
|  * this class in a single int.  Therefore, methods which use this
 | |
|  * representation will not throw an <code>IllegalArgumentException</code>
 | |
|  * due to an invalid pixel value.
 | |
|  * <p>
 | |
|  * This color model is similar to an X11 TrueColor visual.
 | |
|  * The default RGB ColorModel specified by the
 | |
|  * {@link ColorModel#getRGBdefault() getRGBdefault} method is a
 | |
|  * <code>DirectColorModel</code> with the following parameters:
 | |
|  * <pre>
 | |
|  * Number of bits:        32
 | |
|  * Red mask:              0x00ff0000
 | |
|  * Green mask:            0x0000ff00
 | |
|  * Blue mask:             0x000000ff
 | |
|  * Alpha mask:            0xff000000
 | |
|  * Color space:           sRGB
 | |
|  * isAlphaPremultiplied:  False
 | |
|  * Transparency:          Transparency.TRANSLUCENT
 | |
|  * transferType:          DataBuffer.TYPE_INT
 | |
|  * </pre>
 | |
|  * <p>
 | |
|  * Many of the methods in this class are final. This is because the
 | |
|  * underlying native graphics code makes assumptions about the layout
 | |
|  * and operation of this class and those assumptions are reflected in
 | |
|  * the implementations of the methods here that are marked final.  You
 | |
|  * can subclass this class for other reasons, but you cannot override
 | |
|  * or modify the behavior of those methods.
 | |
|  *
 | |
|  * @see ColorModel
 | |
|  * @see ColorSpace
 | |
|  * @see SinglePixelPackedSampleModel
 | |
|  * @see BufferedImage
 | |
|  * @see ColorModel#getRGBdefault
 | |
|  *
 | |
|  */
 | |
| public class DirectColorModel extends PackedColorModel {
 | |
|     private int red_mask;
 | |
|     private int green_mask;
 | |
|     private int blue_mask;
 | |
|     private int alpha_mask;
 | |
|     private int red_offset;
 | |
|     private int green_offset;
 | |
|     private int blue_offset;
 | |
|     private int alpha_offset;
 | |
|     private int red_scale;
 | |
|     private int green_scale;
 | |
|     private int blue_scale;
 | |
|     private int alpha_scale;
 | |
|     private boolean is_LinearRGB;
 | |
|     private int lRGBprecision;
 | |
|     private byte[] tosRGB8LUT;
 | |
|     private byte[] fromsRGB8LUT8;
 | |
|     private short[] fromsRGB8LUT16;
 | |
| 
 | |
|     /**
 | |
|      * Constructs a <code>DirectColorModel</code> from the specified masks
 | |
|      * that indicate which bits in an <code>int</code> pixel representation
 | |
|      * contain the red, green and blue color samples.  As pixel values do not
 | |
|      * contain alpha information, all pixels are treated as opaque, which
 | |
|      * means that alpha = 1.0.  All of the bits
 | |
|      * in each mask must be contiguous and fit in the specified number
 | |
|      * of least significant bits of an <code>int</code> pixel representation.
 | |
|      *  The <code>ColorSpace</code> is the default sRGB space. The
 | |
|      * transparency value is Transparency.OPAQUE.  The transfer type
 | |
|      * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
 | |
|      * or DataBuffer.TYPE_INT that can hold a single pixel.
 | |
|      * @param bits the number of bits in the pixel values; for example,
 | |
|      *         the sum of the number of bits in the masks.
 | |
|      * @param rmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the red component
 | |
|      * @param gmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the green component
 | |
|      * @param bmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the blue component
 | |
|      *
 | |
|      */
 | |
|     public DirectColorModel(int bits,
 | |
|                             int rmask, int gmask, int bmask) {
 | |
|         this(bits, rmask, gmask, bmask, 0);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Constructs a <code>DirectColorModel</code> from the specified masks
 | |
|      * that indicate which bits in an <code>int</code> pixel representation
 | |
|      * contain the red, green and blue color samples and the alpha sample,
 | |
|      * if present.  If <code>amask</code> is 0, pixel values do not contain
 | |
|      * alpha information and all pixels are treated as opaque, which means
 | |
|      * that alpha = 1.0.  All of the bits in each mask must
 | |
|      * be contiguous and fit in the specified number of least significant bits
 | |
|      * of an <code>int</code> pixel representation.  Alpha, if present, is not
 | |
|      * premultiplied.  The <code>ColorSpace</code> is the default sRGB space.
 | |
|      * The transparency value is Transparency.OPAQUE if no alpha is
 | |
|      * present, or Transparency.TRANSLUCENT otherwise.  The transfer type
 | |
|      * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
 | |
|      * or DataBuffer.TYPE_INT that can hold a single pixel.
 | |
|      * @param bits the number of bits in the pixel values; for example,
 | |
|      *         the sum of the number of bits in the masks.
 | |
|      * @param rmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the red component
 | |
|      * @param gmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the green component
 | |
|      * @param bmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the blue component
 | |
|      * @param amask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the alpha component
 | |
|      */
 | |
|     public DirectColorModel(int bits, int rmask, int gmask,
 | |
|                             int bmask, int amask) {
 | |
|         super (ColorSpace.getInstance(ColorSpace.CS_sRGB),
 | |
|                bits, rmask, gmask, bmask, amask, false,
 | |
|                amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT,
 | |
|                ColorModel.getDefaultTransferType(bits));
 | |
|         setFields();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Constructs a <code>DirectColorModel</code> from the specified
 | |
|      * parameters.  Color components are in the specified
 | |
|      * <code>ColorSpace</code>, which must be of type ColorSpace.TYPE_RGB
 | |
|      * and have minimum normalized component values which are all 0.0
 | |
|      * and maximum values which are all 1.0.
 | |
|      * The masks specify which bits in an <code>int</code> pixel
 | |
|      * representation contain the red, green and blue color samples and
 | |
|      * the alpha sample, if present.  If <code>amask</code> is 0, pixel
 | |
|      * values do not contain alpha information and all pixels are treated
 | |
|      * as opaque, which means that alpha = 1.0.  All of the
 | |
|      * bits in each mask must be contiguous and fit in the specified number
 | |
|      * of least significant bits of an <code>int</code> pixel
 | |
|      * representation.  If there is alpha, the <code>boolean</code>
 | |
|      * <code>isAlphaPremultiplied</code> specifies how to interpret
 | |
|      * color and alpha samples in pixel values.  If the <code>boolean</code>
 | |
|      * is <code>true</code>, color samples are assumed to have been
 | |
|      * multiplied by the alpha sample.  The transparency value is
 | |
|      * Transparency.OPAQUE, if no alpha is present, or
 | |
|      * Transparency.TRANSLUCENT otherwise.  The transfer type
 | |
|      * is the type of primitive array used to represent pixel values and
 | |
|      * must be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
 | |
|      * DataBuffer.TYPE_INT.
 | |
|      * @param space the specified <code>ColorSpace</code>
 | |
|      * @param bits the number of bits in the pixel values; for example,
 | |
|      *         the sum of the number of bits in the masks.
 | |
|      * @param rmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the red component
 | |
|      * @param gmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the green component
 | |
|      * @param bmask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the blue component
 | |
|      * @param amask specifies a mask indicating which bits in an
 | |
|      *         integer pixel contain the alpha component
 | |
|      * @param isAlphaPremultiplied <code>true</code> if color samples are
 | |
|      *        premultiplied by the alpha sample; <code>false</code> otherwise
 | |
|      * @param transferType the type of array used to represent pixel values
 | |
|      * @throws IllegalArgumentException if <code>space</code> is not a
 | |
|      *         TYPE_RGB space or if the min/max normalized component
 | |
|      *         values are not 0.0/1.0.
 | |
|      */
 | |
|     public DirectColorModel(ColorSpace space, int bits, int rmask,
 | |
|                             int gmask, int bmask, int amask,
 | |
|                             boolean isAlphaPremultiplied,
 | |
|                             int transferType) {
 | |
|         super (space, bits, rmask, gmask, bmask, amask,
 | |
|                isAlphaPremultiplied,
 | |
|                amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT,
 | |
|                transferType);
 | |
|         if (ColorModel.isLinearRGBspace(colorSpace)) {
 | |
|             is_LinearRGB = true;
 | |
|             if (maxBits <= 8) {
 | |
|                 lRGBprecision = 8;
 | |
|                 tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT();
 | |
|                 fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT();
 | |
|             } else {
 | |
|                 lRGBprecision = 16;
 | |
|                 tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT();
 | |
|                 fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT();
 | |
|             }
 | |
|         } else if (!is_sRGB) {
 | |
|             for (int i = 0; i < 3; i++) {
 | |
|                 // super constructor checks that space is TYPE_RGB
 | |
|                 // check here that min/max are all 0.0/1.0
 | |
|                 if ((space.getMinValue(i) != 0.0f) ||
 | |
|                     (space.getMaxValue(i) != 1.0f)) {
 | |
|                     throw new IllegalArgumentException(
 | |
|                         "Illegal min/max RGB component value");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         setFields();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the mask indicating which bits in an <code>int</code> pixel
 | |
|      * representation contain the red color component.
 | |
|      * @return the mask, which indicates which bits of the <code>int</code>
 | |
|      *         pixel representation contain the red color sample.
 | |
|      */
 | |
|     final public int getRedMask() {
 | |
|         return maskArray[0];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the mask indicating which bits in an <code>int</code> pixel
 | |
|      * representation contain the green color component.
 | |
|      * @return the mask, which indicates which bits of the <code>int</code>
 | |
|      *         pixel representation contain the green color sample.
 | |
|      */
 | |
|     final public int getGreenMask() {
 | |
|         return maskArray[1];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the mask indicating which bits in an <code>int</code> pixel
 | |
|      * representation contain the blue color component.
 | |
|      * @return the mask, which indicates which bits of the <code>int</code>
 | |
|      *         pixel representation contain the blue color sample.
 | |
|      */
 | |
|     final public int getBlueMask() {
 | |
|         return maskArray[2];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the mask indicating which bits in an <code>int</code> pixel
 | |
|      * representation contain the alpha component.
 | |
|      * @return the mask, which indicates which bits of the <code>int</code>
 | |
|      *         pixel representation contain the alpha sample.
 | |
|      */
 | |
|     final public int getAlphaMask() {
 | |
|         if (supportsAlpha) {
 | |
|             return maskArray[3];
 | |
|         } else {
 | |
|             return 0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /*
 | |
|      * Given an int pixel in this ColorModel's ColorSpace, converts
 | |
|      * it to the default sRGB ColorSpace and returns the R, G, and B
 | |
|      * components as float values between 0.0 and 1.0.
 | |
|      */
 | |
|     private float[] getDefaultRGBComponents(int pixel) {
 | |
|         int components[] = getComponents(pixel, null, 0);
 | |
|         float norm[] = getNormalizedComponents(components, 0, null, 0);
 | |
|         // Note that getNormalizedComponents returns non-premultiplied values
 | |
|         return colorSpace.toRGB(norm);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     private int getsRGBComponentFromsRGB(int pixel, int idx) {
 | |
|         int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]);
 | |
|         if (isAlphaPremultiplied) {
 | |
|             int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
 | |
|             c = (a == 0) ? 0 :
 | |
|                          (int) (((c * scaleFactors[idx]) * 255.0f /
 | |
|                                  (a * scaleFactors[3])) + 0.5f);
 | |
|         } else if (scaleFactors[idx] != 1.0f) {
 | |
|             c = (int) ((c * scaleFactors[idx]) + 0.5f);
 | |
|         }
 | |
|         return c;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     private int getsRGBComponentFromLinearRGB(int pixel, int idx) {
 | |
|         int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]);
 | |
|         if (isAlphaPremultiplied) {
 | |
|             float factor = (float) ((1 << lRGBprecision) - 1);
 | |
|             int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
 | |
|             c = (a == 0) ? 0 :
 | |
|                          (int) (((c * scaleFactors[idx]) * factor /
 | |
|                                  (a * scaleFactors[3])) + 0.5f);
 | |
|         } else if (nBits[idx] != lRGBprecision) {
 | |
|             if (lRGBprecision == 16) {
 | |
|                 c = (int) ((c * scaleFactors[idx] * 257.0f) + 0.5f);
 | |
|             } else {
 | |
|                 c = (int) ((c * scaleFactors[idx]) + 0.5f);
 | |
|             }
 | |
|         }
 | |
|         // now range of c is 0-255 or 0-65535, depending on lRGBprecision
 | |
|         return tosRGB8LUT[c] & 0xff;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Returns the red color component for the specified pixel, scaled
 | |
|      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 | |
|      * color conversion is done if necessary.  The pixel value is specified
 | |
|      * as an <code>int</code>.
 | |
|      * The returned value is a non pre-multiplied value.  Thus, if the
 | |
|      * alpha is premultiplied, this method divides it out before returning
 | |
|      * the value.  If the alpha value is 0, for example, the red value
 | |
|      * is 0.
 | |
|      * @param pixel the specified pixel
 | |
|      * @return the red color component for the specified pixel, from
 | |
|      *         0 to 255 in the sRGB <code>ColorSpace</code>.
 | |
|      */
 | |
|     final public int getRed(int pixel) {
 | |
|         if (is_sRGB) {
 | |
|             return getsRGBComponentFromsRGB(pixel, 0);
 | |
|         } else if (is_LinearRGB) {
 | |
|             return getsRGBComponentFromLinearRGB(pixel, 0);
 | |
|         }
 | |
|         float rgb[] = getDefaultRGBComponents(pixel);
 | |
|         return (int) (rgb[0] * 255.0f + 0.5f);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the green color component for the specified pixel, scaled
 | |
|      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 | |
|      * color conversion is done if necessary.  The pixel value is specified
 | |
|      * as an <code>int</code>.
 | |
|      * The returned value is a non pre-multiplied value.  Thus, if the
 | |
|      * alpha is premultiplied, this method divides it out before returning
 | |
|      * the value.  If the alpha value is 0, for example, the green value
 | |
|      * is 0.
 | |
|      * @param pixel the specified pixel
 | |
|      * @return the green color component for the specified pixel, from
 | |
|      *         0 to 255 in the sRGB <code>ColorSpace</code>.
 | |
|      */
 | |
|     final public int getGreen(int pixel) {
 | |
|         if (is_sRGB) {
 | |
|             return getsRGBComponentFromsRGB(pixel, 1);
 | |
|         } else if (is_LinearRGB) {
 | |
|             return getsRGBComponentFromLinearRGB(pixel, 1);
 | |
|         }
 | |
|         float rgb[] = getDefaultRGBComponents(pixel);
 | |
|         return (int) (rgb[1] * 255.0f + 0.5f);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the blue color component for the specified pixel, scaled
 | |
|      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 | |
|      * color conversion is done if necessary.  The pixel value is specified
 | |
|      * as an <code>int</code>.
 | |
|      * The returned value is a non pre-multiplied value.  Thus, if the
 | |
|      * alpha is premultiplied, this method divides it out before returning
 | |
|      * the value.  If the alpha value is 0, for example, the blue value
 | |
|      * is 0.
 | |
|      * @param pixel the specified pixel
 | |
|      * @return the blue color component for the specified pixel, from
 | |
|      *         0 to 255 in the sRGB <code>ColorSpace</code>.
 | |
|      */
 | |
|     final public int getBlue(int pixel) {
 | |
|         if (is_sRGB) {
 | |
|             return getsRGBComponentFromsRGB(pixel, 2);
 | |
|         } else if (is_LinearRGB) {
 | |
|             return getsRGBComponentFromLinearRGB(pixel, 2);
 | |
|         }
 | |
|         float rgb[] = getDefaultRGBComponents(pixel);
 | |
|         return (int) (rgb[2] * 255.0f + 0.5f);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the alpha component for the specified pixel, scaled
 | |
|      * from 0 to 255.  The pixel value is specified as an <code>int</code>.
 | |
|      * @param pixel the specified pixel
 | |
|      * @return the value of the alpha component of <code>pixel</code>
 | |
|      *         from 0 to 255.
 | |
|      */
 | |
|     final public int getAlpha(int pixel) {
 | |
|         if (!supportsAlpha) return 255;
 | |
|         int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
 | |
|         if (scaleFactors[3] != 1.0f) {
 | |
|             a = (int)(a * scaleFactors[3] + 0.5f);
 | |
|         }
 | |
|         return a;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the color/alpha components of the pixel in the default
 | |
|      * RGB color model format.  A color conversion is done if necessary.
 | |
|      * The pixel value is specified as an <code>int</code>.
 | |
|      * The returned value is in a non pre-multiplied format.  Thus, if
 | |
|      * the alpha is premultiplied, this method divides it out of the
 | |
|      * color components.  If the alpha value is 0, for example, the color
 | |
|      * values are each 0.
 | |
|      * @param pixel the specified pixel
 | |
|      * @return the RGB value of the color/alpha components of the specified
 | |
|      *         pixel.
 | |
|      * @see ColorModel#getRGBdefault
 | |
|      */
 | |
|     final public int getRGB(int pixel) {
 | |
|         if (is_sRGB || is_LinearRGB) {
 | |
|             return (getAlpha(pixel) << 24)
 | |
|                 | (getRed(pixel) << 16)
 | |
|                 | (getGreen(pixel) << 8)
 | |
|                 | (getBlue(pixel) << 0);
 | |
|         }
 | |
|         float rgb[] = getDefaultRGBComponents(pixel);
 | |
|         return (getAlpha(pixel) << 24)
 | |
|             | (((int) (rgb[0] * 255.0f + 0.5f)) << 16)
 | |
|             | (((int) (rgb[1] * 255.0f + 0.5f)) << 8)
 | |
|             | (((int) (rgb[2] * 255.0f + 0.5f)) << 0);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the red color component for the specified pixel, scaled
 | |
|      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 | |
|      * color conversion is done if necessary.  The pixel value is specified
 | |
|      * by an array of data elements of type <code>transferType</code> passed
 | |
|      * in as an object reference.
 | |
|      * The returned value is a non pre-multiplied value.  Thus, if the
 | |
|      * alpha is premultiplied, this method divides it out before returning
 | |
|      * the value.  If the alpha value is 0, for example, the red value
 | |
|      * is 0.
 | |
|      * If <code>inData</code> is not a primitive array of type
 | |
|      * <code>transferType</code>, a <code>ClassCastException</code> is
 | |
|      * thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>inData</code> is not large enough to hold a
 | |
|      * pixel value for this <code>ColorModel</code>.  Since
 | |
|      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 | |
|      * the implementation of this method and if they don't override it
 | |
|      * then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      * An <code>UnsupportedOperationException</code> is thrown if this
 | |
|      * <code>transferType</code> is not supported by this
 | |
|      * <code>ColorModel</code>.
 | |
|      * @param inData the array containing the pixel value
 | |
|      * @return the value of the red component of the specified pixel.
 | |
|      * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
 | |
|      *         large enough to hold a pixel value for this color model
 | |
|      * @throws ClassCastException if <code>inData</code> is not a
 | |
|      *         primitive array of type <code>transferType</code>
 | |
|      * @throws UnsupportedOperationException if this <code>transferType</code>
 | |
|      *         is not supported by this color model
 | |
|      */
 | |
|     public int getRed(Object inData) {
 | |
|         int pixel=0;
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                byte bdata[] = (byte[])inData;
 | |
|                pixel = bdata[0] & 0xff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                short sdata[] = (short[])inData;
 | |
|                pixel = sdata[0] & 0xffff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                int idata[] = (int[])inData;
 | |
|                pixel = idata[0];
 | |
|             break;
 | |
|             default:
 | |
|                throw new UnsupportedOperationException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|         return getRed(pixel);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Returns the green color component for the specified pixel, scaled
 | |
|      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 | |
|      * color conversion is done if necessary.  The pixel value is specified
 | |
|      * by an array of data elements of type <code>transferType</code> passed
 | |
|      * in as an object reference.
 | |
|      * The returned value is a non pre-multiplied value.  Thus, if the
 | |
|      * alpha is premultiplied, this method divides it out before returning
 | |
|      * the value.  If the alpha value is 0, for example, the green value
 | |
|      * is 0.  If <code>inData</code> is not a primitive array of type
 | |
|      * <code>transferType</code>, a <code>ClassCastException</code> is thrown.
 | |
|      *  An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>inData</code> is not large enough to hold a pixel
 | |
|      * value for this <code>ColorModel</code>.  Since
 | |
|      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 | |
|      * the implementation of this method and if they don't override it
 | |
|      * then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      * An <code>UnsupportedOperationException</code> is
 | |
|      * thrown if this <code>transferType</code> is not supported by this
 | |
|      * <code>ColorModel</code>.
 | |
|      * @param inData the array containing the pixel value
 | |
|      * @return the value of the green component of the specified pixel.
 | |
|      * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
 | |
|      *         large enough to hold a pixel value for this color model
 | |
|      * @throws ClassCastException if <code>inData</code> is not a
 | |
|      *         primitive array of type <code>transferType</code>
 | |
|      * @throws UnsupportedOperationException if this <code>transferType</code>
 | |
|      *         is not supported by this color model
 | |
|      */
 | |
|     public int getGreen(Object inData) {
 | |
|         int pixel=0;
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                byte bdata[] = (byte[])inData;
 | |
|                pixel = bdata[0] & 0xff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                short sdata[] = (short[])inData;
 | |
|                pixel = sdata[0] & 0xffff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                int idata[] = (int[])inData;
 | |
|                pixel = idata[0];
 | |
|             break;
 | |
|             default:
 | |
|                throw new UnsupportedOperationException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|         return getGreen(pixel);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Returns the blue color component for the specified pixel, scaled
 | |
|      * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB.  A
 | |
|      * color conversion is done if necessary.  The pixel value is specified
 | |
|      * by an array of data elements of type <code>transferType</code> passed
 | |
|      * in as an object reference.
 | |
|      * The returned value is a non pre-multiplied value.  Thus, if the
 | |
|      * alpha is premultiplied, this method divides it out before returning
 | |
|      * the value.  If the alpha value is 0, for example, the blue value
 | |
|      * is 0.  If <code>inData</code> is not a primitive array of type
 | |
|      * <code>transferType</code>, a <code>ClassCastException</code> is thrown.
 | |
|      *  An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>inData</code> is not large enough to hold a pixel
 | |
|      * value for this <code>ColorModel</code>.  Since
 | |
|      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 | |
|      * the implementation of this method and if they don't override it
 | |
|      * then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      * An <code>UnsupportedOperationException</code> is
 | |
|      * thrown if this <code>transferType</code> is not supported by this
 | |
|      * <code>ColorModel</code>.
 | |
|      * @param inData the array containing the pixel value
 | |
|      * @return the value of the blue component of the specified pixel.
 | |
|      * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
 | |
|      *         large enough to hold a pixel value for this color model
 | |
|      * @throws ClassCastException if <code>inData</code> is not a
 | |
|      *         primitive array of type <code>transferType</code>
 | |
|      * @throws UnsupportedOperationException if this <code>transferType</code>
 | |
|      *         is not supported by this color model
 | |
|      */
 | |
|     public int getBlue(Object inData) {
 | |
|         int pixel=0;
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                byte bdata[] = (byte[])inData;
 | |
|                pixel = bdata[0] & 0xff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                short sdata[] = (short[])inData;
 | |
|                pixel = sdata[0] & 0xffff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                int idata[] = (int[])inData;
 | |
|                pixel = idata[0];
 | |
|             break;
 | |
|             default:
 | |
|                throw new UnsupportedOperationException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|         return getBlue(pixel);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the alpha component for the specified pixel, scaled
 | |
|      * from 0 to 255.  The pixel value is specified by an array of data
 | |
|      * elements of type <code>transferType</code> passed in as an object
 | |
|      * reference.
 | |
|      * If <code>inData</code> is not a primitive array of type
 | |
|      * <code>transferType</code>, a <code>ClassCastException</code> is
 | |
|      * thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>inData</code> is not large enough to hold a pixel
 | |
|      * value for this <code>ColorModel</code>.  Since
 | |
|      * <code>DirectColorModel</code> can be subclassed, subclasses inherit
 | |
|      * the implementation of this method and if they don't override it
 | |
|      * then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      * If this <code>transferType</code> is not supported, an
 | |
|      * <code>UnsupportedOperationException</code> is thrown.
 | |
|      * @param inData the specified pixel
 | |
|      * @return the alpha component of the specified pixel, scaled from
 | |
|      *         0 to 255.
 | |
|      * @exception ClassCastException if <code>inData</code>
 | |
|      *  is not a primitive array of type <code>transferType</code>
 | |
|      * @exception ArrayIndexOutOfBoundsException if
 | |
|      *  <code>inData</code> is not large enough to hold a pixel value
 | |
|      *  for this <code>ColorModel</code>
 | |
|      * @exception UnsupportedOperationException if this
 | |
|      *  <code>tranferType</code> is not supported by this
 | |
|      *  <code>ColorModel</code>
 | |
|      */
 | |
|     public int getAlpha(Object inData) {
 | |
|         int pixel=0;
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                byte bdata[] = (byte[])inData;
 | |
|                pixel = bdata[0] & 0xff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                short sdata[] = (short[])inData;
 | |
|                pixel = sdata[0] & 0xffff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                int idata[] = (int[])inData;
 | |
|                pixel = idata[0];
 | |
|             break;
 | |
|             default:
 | |
|                throw new UnsupportedOperationException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|         return getAlpha(pixel);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the color/alpha components for the specified pixel in the
 | |
|      * default RGB color model format.  A color conversion is done if
 | |
|      * necessary.  The pixel value is specified by an array of data
 | |
|      * elements of type <code>transferType</code> passed in as an object
 | |
|      * reference.  If <code>inData</code> is not a primitive array of type
 | |
|      * <code>transferType</code>, a <code>ClassCastException</code> is
 | |
|      * thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>inData</code> is not large enough to hold a pixel
 | |
|      * value for this <code>ColorModel</code>.
 | |
|      * The returned value is in a non pre-multiplied format.  Thus, if
 | |
|      * the alpha is premultiplied, this method divides it out of the
 | |
|      * color components.  If the alpha value is 0, for example, the color
 | |
|      * values is 0.  Since <code>DirectColorModel</code> can be
 | |
|      * subclassed, subclasses inherit the implementation of this method
 | |
|      * and if they don't override it then
 | |
|      * they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      *
 | |
|      * @param inData the specified pixel
 | |
|      * @return the color and alpha components of the specified pixel.
 | |
|      * @exception UnsupportedOperationException if this
 | |
|      *            <code>transferType</code> is not supported by this
 | |
|      *            <code>ColorModel</code>
 | |
|      * @see ColorModel#getRGBdefault
 | |
|      */
 | |
|     public int getRGB(Object inData) {
 | |
|         int pixel=0;
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                byte bdata[] = (byte[])inData;
 | |
|                pixel = bdata[0] & 0xff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                short sdata[] = (short[])inData;
 | |
|                pixel = sdata[0] & 0xffff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                int idata[] = (int[])inData;
 | |
|                pixel = idata[0];
 | |
|             break;
 | |
|             default:
 | |
|                throw new UnsupportedOperationException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|         return getRGB(pixel);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a data element array representation of a pixel in this
 | |
|      * <code>ColorModel</code>, given an integer pixel representation in the
 | |
|      * default RGB color model.
 | |
|      * This array can then be passed to the <code>setDataElements</code>
 | |
|      * method of a <code>WritableRaster</code> object.  If the pixel variable
 | |
|      * is <code>null</code>, a new array is allocated.  If <code>pixel</code>
 | |
|      * is not <code>null</code>, it must be a primitive array of type
 | |
|      * <code>transferType</code>; otherwise, a
 | |
|      * <code>ClassCastException</code> is thrown.  An
 | |
|      * <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>pixel</code> is not large enough to hold a pixel
 | |
|      * value for this <code>ColorModel</code>.  The pixel array is returned.
 | |
|      * Since <code>DirectColorModel</code> can be subclassed, subclasses
 | |
|      * inherit the implementation of this method and if they don't
 | |
|      * override it then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      *
 | |
|      * @param rgb the integer pixel representation in the default RGB
 | |
|      *            color model
 | |
|      * @param pixel the specified pixel
 | |
|      * @return an array representation of the specified pixel in this
 | |
|      *         <code>ColorModel</code>
 | |
|      * @exception ClassCastException if <code>pixel</code>
 | |
|      *  is not a primitive array of type <code>transferType</code>
 | |
|      * @exception ArrayIndexOutOfBoundsException if
 | |
|      *  <code>pixel</code> is not large enough to hold a pixel value
 | |
|      *  for this <code>ColorModel</code>
 | |
|      * @exception UnsupportedOperationException if this
 | |
|      *  <code>transferType</code> is not supported by this
 | |
|      *  <code>ColorModel</code>
 | |
|      * @see WritableRaster#setDataElements
 | |
|      * @see SampleModel#setDataElements
 | |
|      */
 | |
|     public Object getDataElements(int rgb, Object pixel) {
 | |
|         //REMIND: maybe more efficient not to use int array for
 | |
|         //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT
 | |
|         int intpixel[] = null;
 | |
|         if (transferType == DataBuffer.TYPE_INT &&
 | |
|             pixel != null) {
 | |
|             intpixel = (int[])pixel;
 | |
|             intpixel[0] = 0;
 | |
|         } else {
 | |
|             intpixel = new int[1];
 | |
|         }
 | |
| 
 | |
|         ColorModel defaultCM = ColorModel.getRGBdefault();
 | |
|         if (this == defaultCM || equals(defaultCM)) {
 | |
|             intpixel[0] = rgb;
 | |
|             return intpixel;
 | |
|         }
 | |
| 
 | |
|         int red, grn, blu, alp;
 | |
|         red = (rgb>>16) & 0xff;
 | |
|         grn = (rgb>>8) & 0xff;
 | |
|         blu = rgb & 0xff;
 | |
|         if (is_sRGB || is_LinearRGB) {
 | |
|             int precision;
 | |
|             float factor;
 | |
|             if (is_LinearRGB) {
 | |
|                 if (lRGBprecision == 8) {
 | |
|                     red = fromsRGB8LUT8[red] & 0xff;
 | |
|                     grn = fromsRGB8LUT8[grn] & 0xff;
 | |
|                     blu = fromsRGB8LUT8[blu] & 0xff;
 | |
|                     precision = 8;
 | |
|                     factor = 1.0f / 255.0f;
 | |
|                 } else {
 | |
|                     red = fromsRGB8LUT16[red] & 0xffff;
 | |
|                     grn = fromsRGB8LUT16[grn] & 0xffff;
 | |
|                     blu = fromsRGB8LUT16[blu] & 0xffff;
 | |
|                     precision = 16;
 | |
|                     factor = 1.0f / 65535.0f;
 | |
|                 }
 | |
|             } else {
 | |
|                 precision = 8;
 | |
|                 factor = 1.0f / 255.0f;
 | |
|             }
 | |
|             if (supportsAlpha) {
 | |
|                 alp = (rgb>>24) & 0xff;
 | |
|                 if (isAlphaPremultiplied) {
 | |
|                     factor *= (alp * (1.0f / 255.0f));
 | |
|                     precision = -1;  // force component calculations below
 | |
|                 }
 | |
|                 if (nBits[3] != 8) {
 | |
|                     alp = (int)
 | |
|                         ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f);
 | |
|                     if (alp > ((1<<nBits[3]) - 1)) {
 | |
|                         // fix 4412670 - see comment below
 | |
|                         alp = (1<<nBits[3]) - 1;
 | |
|                     }
 | |
|                 }
 | |
|                 intpixel[0] = alp << maskOffsets[3];
 | |
|             }
 | |
|             if (nBits[0] != precision) {
 | |
|                 red = (int) ((red * factor * ((1<<nBits[0]) - 1)) + 0.5f);
 | |
|             }
 | |
|             if (nBits[1] != precision) {
 | |
|                 grn = (int) ((grn * factor * ((1<<nBits[1]) - 1)) + 0.5f);
 | |
|             }
 | |
|             if (nBits[2] != precision) {
 | |
|                 blu = (int) ((blu * factor * ((1<<nBits[2]) - 1)) + 0.5f);
 | |
|             }
 | |
|         } else {
 | |
|             // Need to convert the color
 | |
|             float[] norm = new float[3];
 | |
|             float factor = 1.0f / 255.0f;
 | |
|             norm[0] = red * factor;
 | |
|             norm[1] = grn * factor;
 | |
|             norm[2] = blu * factor;
 | |
|             norm = colorSpace.fromRGB(norm);
 | |
|             if (supportsAlpha) {
 | |
|                 alp = (rgb>>24) & 0xff;
 | |
|                 if (isAlphaPremultiplied) {
 | |
|                     factor *= alp;
 | |
|                     for (int i = 0; i < 3; i++) {
 | |
|                         norm[i] *= factor;
 | |
|                     }
 | |
|                 }
 | |
|                 if (nBits[3] != 8) {
 | |
|                     alp = (int)
 | |
|                         ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f);
 | |
|                     if (alp > ((1<<nBits[3]) - 1)) {
 | |
|                         // fix 4412670 - see comment below
 | |
|                         alp = (1<<nBits[3]) - 1;
 | |
|                     }
 | |
|                 }
 | |
|                 intpixel[0] = alp << maskOffsets[3];
 | |
|             }
 | |
|             red = (int) ((norm[0] * ((1<<nBits[0]) - 1)) + 0.5f);
 | |
|             grn = (int) ((norm[1] * ((1<<nBits[1]) - 1)) + 0.5f);
 | |
|             blu = (int) ((norm[2] * ((1<<nBits[2]) - 1)) + 0.5f);
 | |
|         }
 | |
| 
 | |
|         if (maxBits > 23) {
 | |
|             // fix 4412670 - for components of 24 or more bits
 | |
|             // some calculations done above with float precision
 | |
|             // may lose enough precision that the integer result
 | |
|             // overflows nBits, so we need to clamp.
 | |
|             if (red > ((1<<nBits[0]) - 1)) {
 | |
|                 red = (1<<nBits[0]) - 1;
 | |
|             }
 | |
|             if (grn > ((1<<nBits[1]) - 1)) {
 | |
|                 grn = (1<<nBits[1]) - 1;
 | |
|             }
 | |
|             if (blu > ((1<<nBits[2]) - 1)) {
 | |
|                 blu = (1<<nBits[2]) - 1;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         intpixel[0] |= (red << maskOffsets[0]) |
 | |
|                        (grn << maskOffsets[1]) |
 | |
|                        (blu << maskOffsets[2]);
 | |
| 
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE: {
 | |
|                byte bdata[];
 | |
|                if (pixel == null) {
 | |
|                    bdata = new byte[1];
 | |
|                } else {
 | |
|                    bdata = (byte[])pixel;
 | |
|                }
 | |
|                bdata[0] = (byte)(0xff&intpixel[0]);
 | |
|                return bdata;
 | |
|             }
 | |
|             case DataBuffer.TYPE_USHORT:{
 | |
|                short sdata[];
 | |
|                if (pixel == null) {
 | |
|                    sdata = new short[1];
 | |
|                } else {
 | |
|                    sdata = (short[])pixel;
 | |
|                }
 | |
|                sdata[0] = (short)(intpixel[0]&0xffff);
 | |
|                return sdata;
 | |
|             }
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                return intpixel;
 | |
|         }
 | |
|         throw new UnsupportedOperationException("This method has not been "+
 | |
|                  "implemented for transferType " + transferType);
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns an array of unnormalized color/alpha components given a pixel
 | |
|      * in this <code>ColorModel</code>.  The pixel value is specified as an
 | |
|      * <code>int</code>.  If the <code>components</code> array is
 | |
|      * <code>null</code>, a new array is allocated.  The
 | |
|      * <code>components</code> array is returned.  Color/alpha components are
 | |
|      * stored in the <code>components</code> array starting at
 | |
|      * <code>offset</code>, even if the array is allocated by this method.
 | |
|      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
 | |
|      * <code>components</code> array is not <code>null</code> and is not large
 | |
|      * enough to hold all the color and alpha components, starting at
 | |
|      * <code>offset</code>.
 | |
|      * @param pixel the specified pixel
 | |
|      * @param components the array to receive the color and alpha
 | |
|      * components of the specified pixel
 | |
|      * @param offset the offset into the <code>components</code> array at
 | |
|      * which to start storing the color and alpha components
 | |
|      * @return an array containing the color and alpha components of the
 | |
|      * specified pixel starting at the specified offset.
 | |
|      */
 | |
|     final public int[] getComponents(int pixel, int[] components, int offset) {
 | |
|         if (components == null) {
 | |
|             components = new int[offset+numComponents];
 | |
|         }
 | |
| 
 | |
|         for (int i=0; i < numComponents; i++) {
 | |
|             components[offset+i] = (pixel & maskArray[i]) >>> maskOffsets[i];
 | |
|         }
 | |
| 
 | |
|         return components;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns an array of unnormalized color/alpha components given a pixel
 | |
|      * in this <code>ColorModel</code>.  The pixel value is specified by an
 | |
|      * array of data elements of type <code>transferType</code> passed in as
 | |
|      * an object reference.  If <code>pixel</code> is not a primitive array
 | |
|      * of type <code>transferType</code>, a <code>ClassCastException</code>
 | |
|      * is thrown.  An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if <code>pixel</code> is not large enough to hold a
 | |
|      * pixel value for this <code>ColorModel</code>.  If the
 | |
|      * <code>components</code> array is <code>null</code>, a new
 | |
|      * array is allocated.  The <code>components</code> array is returned.
 | |
|      * Color/alpha components are stored in the <code>components</code> array
 | |
|      * starting at <code>offset</code>, even if the array is allocated by
 | |
|      * this method.  An <code>ArrayIndexOutOfBoundsException</code>
 | |
|      * is thrown if the <code>components</code> array is not
 | |
|      * <code>null</code> and is not large enough to hold all the color and
 | |
|      * alpha components, starting at <code>offset</code>.
 | |
|      * Since <code>DirectColorModel</code> can be subclassed, subclasses
 | |
|      * inherit the implementation of this method and if they don't
 | |
|      * override it then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      * @param pixel the specified pixel
 | |
|      * @param components the array to receive the color and alpha
 | |
|      *        components of the specified pixel
 | |
|      * @param offset the offset into the <code>components</code> array at
 | |
|      *        which to start storing the color and alpha components
 | |
|      * @return an array containing the color and alpha components of the
 | |
|      * specified pixel starting at the specified offset.
 | |
|      * @exception ClassCastException if <code>pixel</code>
 | |
|      *  is not a primitive array of type <code>transferType</code>
 | |
|      * @exception ArrayIndexOutOfBoundsException if
 | |
|      *  <code>pixel</code> is not large enough to hold a pixel value
 | |
|      *  for this <code>ColorModel</code>, or if <code>components</code>
 | |
|      *  is not <code>null</code> and is not large enough to hold all the
 | |
|      *  color and alpha components, starting at <code>offset</code>
 | |
|      * @exception UnsupportedOperationException if this
 | |
|      *            <code>transferType</code> is not supported by this
 | |
|      *            color model
 | |
|      */
 | |
|     final public int[] getComponents(Object pixel, int[] components,
 | |
|                                      int offset) {
 | |
|         int intpixel=0;
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                byte bdata[] = (byte[])pixel;
 | |
|                intpixel = bdata[0] & 0xff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                short sdata[] = (short[])pixel;
 | |
|                intpixel = sdata[0] & 0xffff;
 | |
|             break;
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                int idata[] = (int[])pixel;
 | |
|                intpixel = idata[0];
 | |
|             break;
 | |
|             default:
 | |
|                throw new UnsupportedOperationException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|         return getComponents(intpixel, components, offset);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Creates a <code>WritableRaster</code> with the specified width and
 | |
|      * height that has a data layout (<code>SampleModel</code>) compatible
 | |
|      * with this <code>ColorModel</code>.
 | |
|      * @param w the width to apply to the new <code>WritableRaster</code>
 | |
|      * @param h the height to apply to the new <code>WritableRaster</code>
 | |
|      * @return a <code>WritableRaster</code> object with the specified
 | |
|      * width and height.
 | |
|      * @throws IllegalArgumentException if <code>w</code> or <code>h</code>
 | |
|      *         is less than or equal to zero
 | |
|      * @see WritableRaster
 | |
|      * @see SampleModel
 | |
|      */
 | |
|     final public WritableRaster createCompatibleWritableRaster (int w,
 | |
|                                                                 int h) {
 | |
|         if ((w <= 0) || (h <= 0)) {
 | |
|             throw new IllegalArgumentException("Width (" + w + ") and height (" + h +
 | |
|                                                ") cannot be <= 0");
 | |
|         }
 | |
|         int[] bandmasks;
 | |
|         if (supportsAlpha) {
 | |
|             bandmasks = new int[4];
 | |
|             bandmasks[3] = alpha_mask;
 | |
|         }
 | |
|         else {
 | |
|             bandmasks = new int[3];
 | |
|         }
 | |
|         bandmasks[0] = red_mask;
 | |
|         bandmasks[1] = green_mask;
 | |
|         bandmasks[2] = blue_mask;
 | |
| 
 | |
|         if (pixel_bits > 16) {
 | |
|             return Raster.createPackedRaster(DataBuffer.TYPE_INT,
 | |
|                                              w,h,bandmasks,null);
 | |
|         }
 | |
|         else if (pixel_bits > 8) {
 | |
|             return Raster.createPackedRaster(DataBuffer.TYPE_USHORT,
 | |
|                                              w,h,bandmasks,null);
 | |
|         }
 | |
|         else {
 | |
|             return Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
 | |
|                                              w,h,bandmasks,null);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a pixel value represented as an <code>int</code> in this
 | |
|      * <code>ColorModel</code>, given an array of unnormalized color/alpha
 | |
|      * components.   An <code>ArrayIndexOutOfBoundsException</code> is
 | |
|      * thrown if the <code>components</code> array is
 | |
|      * not large enough to hold all the color and alpha components, starting
 | |
|      * at <code>offset</code>.
 | |
|      * @param components an array of unnormalized color and alpha
 | |
|      * components
 | |
|      * @param offset the index into <code>components</code> at which to
 | |
|      * begin retrieving the color and alpha components
 | |
|      * @return an <code>int</code> pixel value in this
 | |
|      * <code>ColorModel</code> corresponding to the specified components.
 | |
|      * @exception ArrayIndexOutOfBoundsException if
 | |
|      *  the <code>components</code> array is not large enough to
 | |
|      *  hold all of the color and alpha components starting at
 | |
|      *  <code>offset</code>
 | |
|      */
 | |
|     public int getDataElement(int[] components, int offset) {
 | |
|         int pixel = 0;
 | |
|         for (int i=0; i < numComponents; i++) {
 | |
|             pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]);
 | |
|         }
 | |
|         return pixel;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a data element array representation of a pixel in this
 | |
|      * <code>ColorModel</code>, given an array of unnormalized color/alpha
 | |
|      * components.
 | |
|      * This array can then be passed to the <code>setDataElements</code>
 | |
|      * method of a <code>WritableRaster</code> object.
 | |
|      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
 | |
|      * <code>components</code> array
 | |
|      * is not large enough to hold all the color and alpha components,
 | |
|      * starting at offset.  If the <code>obj</code> variable is
 | |
|      * <code>null</code>, a new array is allocated.  If <code>obj</code> is
 | |
|      * not <code>null</code>, it must be a primitive array
 | |
|      * of type <code>transferType</code>; otherwise, a
 | |
|      * <code>ClassCastException</code> is thrown.
 | |
|      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if
 | |
|      * <code>obj</code> is not large enough to hold a pixel value for this
 | |
|      * <code>ColorModel</code>.
 | |
|      * Since <code>DirectColorModel</code> can be subclassed, subclasses
 | |
|      * inherit the implementation of this method and if they don't
 | |
|      * override it then they throw an exception if they use an unsupported
 | |
|      * <code>transferType</code>.
 | |
|      * @param components an array of unnormalized color and alpha
 | |
|      * components
 | |
|      * @param offset the index into <code>components</code> at which to
 | |
|      * begin retrieving color and alpha components
 | |
|      * @param obj the <code>Object</code> representing an array of color
 | |
|      * and alpha components
 | |
|      * @return an <code>Object</code> representing an array of color and
 | |
|      * alpha components.
 | |
|      * @exception ClassCastException if <code>obj</code>
 | |
|      *  is not a primitive array of type <code>transferType</code>
 | |
|      * @exception ArrayIndexOutOfBoundsException if
 | |
|      *  <code>obj</code> is not large enough to hold a pixel value
 | |
|      *  for this <code>ColorModel</code> or the <code>components</code>
 | |
|      *  array is not large enough to hold all of the color and alpha
 | |
|      *  components starting at <code>offset</code>
 | |
|      * @exception UnsupportedOperationException if this
 | |
|      *            <code>transferType</code> is not supported by this
 | |
|      *            color model
 | |
|      * @see WritableRaster#setDataElements
 | |
|      * @see SampleModel#setDataElements
 | |
|      */
 | |
|     public Object getDataElements(int[] components, int offset, Object obj) {
 | |
|         int pixel = 0;
 | |
|         for (int i=0; i < numComponents; i++) {
 | |
|             pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]);
 | |
|         }
 | |
|         switch (transferType) {
 | |
|             case DataBuffer.TYPE_BYTE:
 | |
|                if (obj instanceof byte[]) {
 | |
|                    byte bdata[] = (byte[])obj;
 | |
|                    bdata[0] = (byte)(pixel&0xff);
 | |
|                    return bdata;
 | |
|                } else {
 | |
|                    byte bdata[] = {(byte)(pixel&0xff)};
 | |
|                    return bdata;
 | |
|                }
 | |
|             case DataBuffer.TYPE_USHORT:
 | |
|                if (obj instanceof short[]) {
 | |
|                    short sdata[] = (short[])obj;
 | |
|                    sdata[0] = (short)(pixel&0xffff);
 | |
|                    return sdata;
 | |
|                } else {
 | |
|                    short sdata[] = {(short)(pixel&0xffff)};
 | |
|                    return sdata;
 | |
|                }
 | |
|             case DataBuffer.TYPE_INT:
 | |
|                if (obj instanceof int[]) {
 | |
|                    int idata[] = (int[])obj;
 | |
|                    idata[0] = pixel;
 | |
|                    return idata;
 | |
|                } else {
 | |
|                    int idata[] = {pixel};
 | |
|                    return idata;
 | |
|                }
 | |
|             default:
 | |
|                throw new ClassCastException("This method has not been "+
 | |
|                    "implemented for transferType " + transferType);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Forces the raster data to match the state specified in the
 | |
|      * <code>isAlphaPremultiplied</code> variable, assuming the data is
 | |
|      * currently correctly described by this <code>ColorModel</code>.  It
 | |
|      * may multiply or divide the color raster data by alpha, or do
 | |
|      * nothing if the data is in the correct state.  If the data needs to
 | |
|      * be coerced, this method will also return an instance of this
 | |
|      * <code>ColorModel</code> with the <code>isAlphaPremultiplied</code>
 | |
|      * flag set appropriately.  This method will throw a
 | |
|      * <code>UnsupportedOperationException</code> if this transferType is
 | |
|      * not supported by this <code>ColorModel</code>.  Since
 | |
|      * <code>ColorModel</code> can be subclassed, subclasses inherit the
 | |
|      * implementation of this method and if they don't override it then
 | |
|      * they throw an exception if they use an unsupported transferType.
 | |
|      *
 | |
|      * @param raster the <code>WritableRaster</code> data
 | |
|      * @param isAlphaPremultiplied <code>true</code> if the alpha is
 | |
|      * premultiplied; <code>false</code> otherwise
 | |
|      * @return a <code>ColorModel</code> object that represents the
 | |
|      * coerced data.
 | |
|      * @exception UnsupportedOperationException if this
 | |
|      *            <code>transferType</code> is not supported by this
 | |
|      *            color model
 | |
|      */
 | |
|     final public ColorModel coerceData (WritableRaster raster,
 | |
|                                         boolean isAlphaPremultiplied)
 | |
|     {
 | |
|         if (!supportsAlpha ||
 | |
|             this.isAlphaPremultiplied() == isAlphaPremultiplied) {
 | |
|             return this;
 | |
|         }
 | |
| 
 | |
|         int w = raster.getWidth();
 | |
|         int h = raster.getHeight();
 | |
|         int aIdx = numColorComponents;
 | |
|         float normAlpha;
 | |
|         float alphaScale = 1.0f / ((float) ((1 << nBits[aIdx]) - 1));
 | |
| 
 | |
|         int rminX = raster.getMinX();
 | |
|         int rY = raster.getMinY();
 | |
|         int rX;
 | |
|         int pixel[] = null;
 | |
|         int zpixel[] = null;
 | |
| 
 | |
|         if (isAlphaPremultiplied) {
 | |
|             // Must mean that we are currently not premultiplied so
 | |
|             // multiply by alpha
 | |
|             switch (transferType) {
 | |
|                 case DataBuffer.TYPE_BYTE: {
 | |
|                     for (int y = 0; y < h; y++, rY++) {
 | |
|                         rX = rminX;
 | |
|                         for (int x = 0; x < w; x++, rX++) {
 | |
|                             pixel = raster.getPixel(rX, rY, pixel);
 | |
|                             normAlpha = pixel[aIdx] * alphaScale;
 | |
|                             if (normAlpha != 0.f) {
 | |
|                                 for (int c=0; c < aIdx; c++) {
 | |
|                                     pixel[c] = (int) (pixel[c] * normAlpha +
 | |
|                                                       0.5f);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, pixel);
 | |
|                             } else {
 | |
|                                 if (zpixel == null) {
 | |
|                                     zpixel = new int[numComponents];
 | |
|                                     java.util.Arrays.fill(zpixel, 0);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, zpixel);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|                 case DataBuffer.TYPE_USHORT: {
 | |
|                     for (int y = 0; y < h; y++, rY++) {
 | |
|                         rX = rminX;
 | |
|                         for (int x = 0; x < w; x++, rX++) {
 | |
|                             pixel = raster.getPixel(rX, rY, pixel);
 | |
|                             normAlpha = pixel[aIdx] * alphaScale;
 | |
|                             if (normAlpha != 0.f) {
 | |
|                                 for (int c=0; c < aIdx; c++) {
 | |
|                                     pixel[c] = (int) (pixel[c] * normAlpha +
 | |
|                                                       0.5f);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, pixel);
 | |
|                             } else {
 | |
|                                 if (zpixel == null) {
 | |
|                                     zpixel = new int[numComponents];
 | |
|                                     java.util.Arrays.fill(zpixel, 0);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, zpixel);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|                 case DataBuffer.TYPE_INT: {
 | |
|                     for (int y = 0; y < h; y++, rY++) {
 | |
|                         rX = rminX;
 | |
|                         for (int x = 0; x < w; x++, rX++) {
 | |
|                             pixel = raster.getPixel(rX, rY, pixel);
 | |
|                             normAlpha = pixel[aIdx] * alphaScale;
 | |
|                             if (normAlpha != 0.f) {
 | |
|                                 for (int c=0; c < aIdx; c++) {
 | |
|                                     pixel[c] = (int) (pixel[c] * normAlpha +
 | |
|                                                       0.5f);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, pixel);
 | |
|                             } else {
 | |
|                                 if (zpixel == null) {
 | |
|                                     zpixel = new int[numComponents];
 | |
|                                     java.util.Arrays.fill(zpixel, 0);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, zpixel);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|                 default:
 | |
|                     throw new UnsupportedOperationException("This method has not been "+
 | |
|                          "implemented for transferType " + transferType);
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             // We are premultiplied and want to divide it out
 | |
|             switch (transferType) {
 | |
|                 case DataBuffer.TYPE_BYTE: {
 | |
|                     for (int y = 0; y < h; y++, rY++) {
 | |
|                         rX = rminX;
 | |
|                         for (int x = 0; x < w; x++, rX++) {
 | |
|                             pixel = raster.getPixel(rX, rY, pixel);
 | |
|                             normAlpha = pixel[aIdx] * alphaScale;
 | |
|                             if (normAlpha != 0.0f) {
 | |
|                                 float invAlpha = 1.0f / normAlpha;
 | |
|                                 for (int c=0; c < aIdx; c++) {
 | |
|                                     pixel[c] = (int) (pixel[c] * invAlpha +
 | |
|                                                       0.5f);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, pixel);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|                 case DataBuffer.TYPE_USHORT: {
 | |
|                     for (int y = 0; y < h; y++, rY++) {
 | |
|                         rX = rminX;
 | |
|                         for (int x = 0; x < w; x++, rX++) {
 | |
|                             pixel = raster.getPixel(rX, rY, pixel);
 | |
|                             normAlpha = pixel[aIdx] * alphaScale;
 | |
|                             if (normAlpha != 0) {
 | |
|                                 float invAlpha = 1.0f / normAlpha;
 | |
|                                 for (int c=0; c < aIdx; c++) {
 | |
|                                     pixel[c] = (int) (pixel[c] * invAlpha +
 | |
|                                                       0.5f);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, pixel);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|                 case DataBuffer.TYPE_INT: {
 | |
|                     for (int y = 0; y < h; y++, rY++) {
 | |
|                         rX = rminX;
 | |
|                         for (int x = 0; x < w; x++, rX++) {
 | |
|                             pixel = raster.getPixel(rX, rY, pixel);
 | |
|                             normAlpha = pixel[aIdx] * alphaScale;
 | |
|                             if (normAlpha != 0) {
 | |
|                                 float invAlpha = 1.0f / normAlpha;
 | |
|                                 for (int c=0; c < aIdx; c++) {
 | |
|                                     pixel[c] = (int) (pixel[c] * invAlpha +
 | |
|                                                       0.5f);
 | |
|                                 }
 | |
|                                 raster.setPixel(rX, rY, pixel);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|                 default:
 | |
|                     throw new UnsupportedOperationException("This method has not been "+
 | |
|                          "implemented for transferType " + transferType);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Return a new color model
 | |
|         return new DirectColorModel(colorSpace, pixel_bits, maskArray[0],
 | |
|                                     maskArray[1], maskArray[2], maskArray[3],
 | |
|                                     isAlphaPremultiplied,
 | |
|                                     transferType);
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|       * Returns <code>true</code> if <code>raster</code> is compatible
 | |
|       * with this <code>ColorModel</code> and <code>false</code> if it is
 | |
|       * not.
 | |
|       * @param raster the {@link Raster} object to test for compatibility
 | |
|       * @return <code>true</code> if <code>raster</code> is compatible
 | |
|       * with this <code>ColorModel</code>; <code>false</code> otherwise.
 | |
|       */
 | |
|     public boolean isCompatibleRaster(Raster raster) {
 | |
|         SampleModel sm = raster.getSampleModel();
 | |
|         SinglePixelPackedSampleModel spsm;
 | |
|         if (sm instanceof SinglePixelPackedSampleModel) {
 | |
|             spsm = (SinglePixelPackedSampleModel) sm;
 | |
|         }
 | |
|         else {
 | |
|             return false;
 | |
|         }
 | |
|         if (spsm.getNumBands() != getNumComponents()) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         int[] bitMasks = spsm.getBitMasks();
 | |
|         for (int i=0; i<numComponents; i++) {
 | |
|             if (bitMasks[i] != maskArray[i]) {
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return (raster.getTransferType() == transferType);
 | |
|     }
 | |
| 
 | |
|     private void setFields() {
 | |
|         // Set the private fields
 | |
|         // REMIND: Get rid of these from the native code
 | |
|         red_mask     = maskArray[0];
 | |
|         red_offset   = maskOffsets[0];
 | |
|         green_mask   = maskArray[1];
 | |
|         green_offset = maskOffsets[1];
 | |
|         blue_mask    = maskArray[2];
 | |
|         blue_offset  = maskOffsets[2];
 | |
|         if (nBits[0] < 8) {
 | |
|             red_scale = (1 << nBits[0]) - 1;
 | |
|         }
 | |
|         if (nBits[1] < 8) {
 | |
|             green_scale = (1 << nBits[1]) - 1;
 | |
|         }
 | |
|         if (nBits[2] < 8) {
 | |
|             blue_scale = (1 << nBits[2]) - 1;
 | |
|         }
 | |
|         if (supportsAlpha) {
 | |
|             alpha_mask   = maskArray[3];
 | |
|             alpha_offset = maskOffsets[3];
 | |
|             if (nBits[3] < 8) {
 | |
|                 alpha_scale = (1 << nBits[3]) - 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a <code>String</code> that represents this
 | |
|      * <code>DirectColorModel</code>.
 | |
|      * @return a <code>String</code> representing this
 | |
|      * <code>DirectColorModel</code>.
 | |
|      */
 | |
|     public String toString() {
 | |
|         return new String("DirectColorModel: rmask="
 | |
|                           +Integer.toHexString(red_mask)+" gmask="
 | |
|                           +Integer.toHexString(green_mask)+" bmask="
 | |
|                           +Integer.toHexString(blue_mask)+" amask="
 | |
|                           +Integer.toHexString(alpha_mask));
 | |
|     }
 | |
| }
 |