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