/* * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt.image; import java.awt.color.ColorSpace; import java.awt.Transparency; /** * The DirectColorModel class is a ColorModel * 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 getMinValue() * method of ColorSpace must be 0.0, and the maximum value obtained via * the getMaxValue() 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 transferType, 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: * *

* 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 DirectColorModel is * typically used with image data which uses masks to define packed * samples. For example, a DirectColorModel can be used in * conjunction with a SinglePixelPackedSampleModel to * construct a {@link BufferedImage}. Normally the masks used by the * {@link SampleModel} and the ColorModel would be the * same. However, if they are different, the color interpretation * of pixel data will be done according to the masks of the * ColorModel. *

* 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 IllegalArgumentException * due to an invalid pixel value. *

* This color model is similar to an X11 TrueColor visual. * The default RGB ColorModel specified by the * {@link ColorModel#getRGBdefault() getRGBdefault} method is a * DirectColorModel with the following parameters: *

 * 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
 * 
*

* 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 DirectColorModel from the specified masks * that indicate which bits in an int 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 int pixel representation. * The ColorSpace 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 DirectColorModel from the specified masks * that indicate which bits in an int pixel representation * contain the red, green and blue color samples and the alpha sample, * if present. If amask 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 int pixel representation. Alpha, if present, is not * premultiplied. The ColorSpace 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 DirectColorModel from the specified * parameters. Color components are in the specified * ColorSpace, 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 int pixel * representation contain the red, green and blue color samples and * the alpha sample, if present. If amask 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 int pixel * representation. If there is alpha, the boolean * isAlphaPremultiplied specifies how to interpret * color and alpha samples in pixel values. If the boolean * is true, 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 ColorSpace * @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 true if color samples are * premultiplied by the alpha sample; false otherwise * @param transferType the type of array used to represent pixel values * @throws IllegalArgumentException if space 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 int pixel * representation contain the red color component. * @return the mask, which indicates which bits of the int * pixel representation contain the red color sample. */ public final int getRedMask() { return maskArray[0]; } /** * Returns the mask indicating which bits in an int pixel * representation contain the green color component. * @return the mask, which indicates which bits of the int * pixel representation contain the green color sample. */ public final int getGreenMask() { return maskArray[1]; } /** * Returns the mask indicating which bits in an int pixel * representation contain the blue color component. * @return the mask, which indicates which bits of the int * pixel representation contain the blue color sample. */ public final int getBlueMask() { return maskArray[2]; } /** * Returns the mask indicating which bits in an int pixel * representation contain the alpha component. * @return the mask, which indicates which bits of the int * pixel representation contain the alpha sample. */ public final 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 ColorSpace, sRGB. A * color conversion is done if necessary. The pixel value is specified * as an int. * 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 ColorSpace. */ public final 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 ColorSpace, sRGB. A * color conversion is done if necessary. The pixel value is specified * as an int. * 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 ColorSpace. */ public final 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 ColorSpace, sRGB. A * color conversion is done if necessary. The pixel value is specified * as an int. * 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 ColorSpace. */ public final 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 int. * @param pixel the specified pixel * @return the value of the alpha component of pixel * from 0 to 255. */ public final 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 int. * 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 */ public final 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 ColorSpace, sRGB. A * color conversion is done if necessary. The pixel value is specified * by an array of data elements of type transferType 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 inData is not a primitive array of type * transferType, a ClassCastException is * thrown. An ArrayIndexOutOfBoundsException is * thrown if inData is not large enough to hold a * pixel value for this ColorModel. Since * DirectColorModel 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. * An UnsupportedOperationException is thrown if this * transferType is not supported by this * ColorModel. * @param inData the array containing the pixel value * @return the value of the red component of the specified pixel. * @throws ArrayIndexOutOfBoundsException if inData is not * large enough to hold a pixel value for this color model * @throws ClassCastException if inData is not a * primitive array of type transferType * @throws UnsupportedOperationException if this transferType * 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 ColorSpace, sRGB. A * color conversion is done if necessary. The pixel value is specified * by an array of data elements of type transferType 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 inData is not a primitive array of type * transferType, a ClassCastException is thrown. * An ArrayIndexOutOfBoundsException is * thrown if inData is not large enough to hold a pixel * value for this ColorModel. Since * DirectColorModel 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. * An UnsupportedOperationException is * thrown if this transferType is not supported by this * ColorModel. * @param inData the array containing the pixel value * @return the value of the green component of the specified pixel. * @throws ArrayIndexOutOfBoundsException if inData is not * large enough to hold a pixel value for this color model * @throws ClassCastException if inData is not a * primitive array of type transferType * @throws UnsupportedOperationException if this transferType * 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 ColorSpace, sRGB. A * color conversion is done if necessary. The pixel value is specified * by an array of data elements of type transferType 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 inData is not a primitive array of type * transferType, a ClassCastException is thrown. * An ArrayIndexOutOfBoundsException is * thrown if inData is not large enough to hold a pixel * value for this ColorModel. Since * DirectColorModel 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. * An UnsupportedOperationException is * thrown if this transferType is not supported by this * ColorModel. * @param inData the array containing the pixel value * @return the value of the blue component of the specified pixel. * @throws ArrayIndexOutOfBoundsException if inData is not * large enough to hold a pixel value for this color model * @throws ClassCastException if inData is not a * primitive array of type transferType * @throws UnsupportedOperationException if this transferType * 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 transferType passed in as an object * reference. * If inData is not a primitive array of type * transferType, a ClassCastException is * thrown. An ArrayIndexOutOfBoundsException is * thrown if inData is not large enough to hold a pixel * value for this ColorModel. Since * DirectColorModel 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. * If this transferType is not supported, an * UnsupportedOperationException is thrown. * @param inData the specified pixel * @return the alpha component of the specified pixel, scaled from * 0 to 255. * @exception ClassCastException if inData * is not a primitive array of type transferType * @exception ArrayIndexOutOfBoundsException if * inData is not large enough to hold a pixel value * for this ColorModel * @exception UnsupportedOperationException if this * tranferType is not supported by this * ColorModel */ 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 transferType passed in as an object * reference. If inData is not a primitive array of type * transferType, a ClassCastException is * thrown. An ArrayIndexOutOfBoundsException is * thrown if inData is not large enough to hold a pixel * value for this ColorModel. * 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 DirectColorModel 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 inData the specified pixel * @return the color and alpha components of the specified pixel. * @exception UnsupportedOperationException if this * transferType is not supported by this * ColorModel * @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 * ColorModel, given an integer pixel representation in the * default RGB color model. * This array can then be passed to the setDataElements * method of a WritableRaster object. If the pixel variable * is null, a new array is allocated. If pixel * is not null, it must be a primitive array of type * transferType; otherwise, a * ClassCastException is thrown. An * ArrayIndexOutOfBoundsException is * thrown if pixel is not large enough to hold a pixel * value for this ColorModel. The pixel array is returned. * Since DirectColorModel 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 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 * ColorModel * @exception ClassCastException if pixel * is not a primitive array of type transferType * @exception ArrayIndexOutOfBoundsException if * pixel is not large enough to hold a pixel value * for this ColorModel * @exception UnsupportedOperationException if this * transferType is not supported by this * ColorModel * @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< ((1<>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< ((1< 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< ((1< ((1<ColorModel. The pixel value is specified as an * int. If the components array is * null, a new array is allocated. The * components array is returned. Color/alpha components are * stored in the components array starting at * offset, even if the array is allocated by this method. * An ArrayIndexOutOfBoundsException is thrown if the * components array is not null and is not large * enough to hold all the color and alpha components, starting at * offset. * @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 components 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. */ public final 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 ColorModel. The pixel value is specified by an * array of data elements of type transferType passed in as * an object reference. If pixel is not a primitive array * of type transferType, a ClassCastException * is thrown. An ArrayIndexOutOfBoundsException is * thrown if pixel is not large enough to hold a * pixel value for this ColorModel. If the * components array is null, a new * array is allocated. The components array is returned. * Color/alpha components are stored in the components array * starting at offset, even if the array is allocated by * this method. An ArrayIndexOutOfBoundsException * is thrown if the components array is not * null and is not large enough to hold all the color and * alpha components, starting at offset. * Since DirectColorModel 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 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 components 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 pixel * is not a primitive array of type transferType * @exception ArrayIndexOutOfBoundsException if * pixel is not large enough to hold a pixel value * for this ColorModel, or if components * is not null and is not large enough to hold all the * color and alpha components, starting at offset * @exception UnsupportedOperationException if this * transferType is not supported by this * color model */ public final 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 WritableRaster with the specified width and * height that has a data layout (SampleModel) compatible * with this ColorModel. * @param w the width to apply to the new WritableRaster * @param h the height to apply to the new WritableRaster * @return a WritableRaster object with the specified * width and height. * @throws IllegalArgumentException if w or h * is less than or equal to zero * @see WritableRaster * @see SampleModel */ public final 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 int in this * ColorModel, given an array of unnormalized color/alpha * components. An ArrayIndexOutOfBoundsException is * thrown if the components array is * not large enough to hold all the color and alpha components, starting * at offset. * @param components an array of unnormalized color and alpha * components * @param offset the index into components at which to * begin retrieving the color and alpha components * @return an int pixel value in this * ColorModel corresponding to the specified components. * @exception ArrayIndexOutOfBoundsException if * the components array is not large enough to * hold all of the color and alpha components starting at * offset */ public int getDataElement(int[] components, int offset) { int pixel = 0; for (int i=0; i < numComponents; i++) { pixel |= ((components[offset+i]<ColorModel, given an array of unnormalized color/alpha * components. * This array can then be passed to the setDataElements * method of a WritableRaster object. * An ArrayIndexOutOfBoundsException is thrown if the * components array * is not large enough to hold all the color and alpha components, * starting at offset. If the obj variable is * null, a new array is allocated. If obj is * not null, it must be a primitive array * of type transferType; otherwise, a * ClassCastException is thrown. * An ArrayIndexOutOfBoundsException is thrown if * obj is not large enough to hold a pixel value for this * ColorModel. * Since DirectColorModel 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 components an array of unnormalized color and alpha * components * @param offset the index into components at which to * begin retrieving color and alpha components * @param obj the Object representing an array of color * and alpha components * @return an Object representing an array of color and * alpha components. * @exception ClassCastException if obj * is not a primitive array of type transferType * @exception ArrayIndexOutOfBoundsException if * obj is not large enough to hold a pixel value * for this ColorModel or the components * array is not large enough to hold all of the color and alpha * components starting at offset * @exception UnsupportedOperationException if this * transferType 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]<isAlphaPremultiplied variable, assuming the data is * currently correctly described by this ColorModel. 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 * ColorModel with the isAlphaPremultiplied * flag set appropriately. This method will throw a * UnsupportedOperationException if this transferType is * not supported by this ColorModel. Since * ColorModel 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 WritableRaster data * @param isAlphaPremultiplied true if the alpha is * premultiplied; false otherwise * @return a ColorModel object that represents the * coerced data. * @exception UnsupportedOperationException if this * transferType is not supported by this * color model */ public final 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 true if raster is compatible * with this ColorModel and false if it is * not. * @param raster the {@link Raster} object to test for compatibility * @return true if raster is compatible * with this ColorModel; false 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; iString that represents this * DirectColorModel. * @return a String representing this * DirectColorModel. */ 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)); } }