/*
* @(#)ColorModel.java 1.38 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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.
*
* This program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package java.awt.image;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
/**
* A class that encapsulates the methods for translating from pixel values
* to alpha, red, green, and blue color components for an image. This
* class is abstract.
*
* @see IndexColorModel
* @see DirectColorModel
*
* @version 1.22 02/20/02
* @author Jim Graham
*/
public abstract class ColorModel implements Transparency {
private int pData;
protected int pixel_bits;
int transparency = Transparency.TRANSLUCENT;
int nBits[];
boolean supportsAlpha = true;
boolean isAlphaPremultiplied = false;
int numComponents = -1;
int numColorComponents = -1;
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
/**
* Data type of the array used to represent pixel values.
*/
private int transferType;
private static ColorModel RGBdefault;
/**
* Return a ColorModel which describes the default format for
* integer RGB values used throughout the AWT image interfaces.
* The format for the RGB values is an integer with 8 bits
* each of alpha, red, green, and blue color components ordered
* correspondingly from the most significant byte to the least
* significant byte, as in: 0xAARRGGBB
*/
public static ColorModel getRGBdefault() {
if (RGBdefault == null) {
RGBdefault = new DirectColorModel(32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0xff000000 // Alpha
);
}
return RGBdefault;
}
/**
* Returns whether or not alpha is supported in this
* <code>ColorModel</code>.
* @return <code>true</code> if alpha is supported in this
* <code>ColorModel</code>; <code>false</code> otherwise.
*/
final public boolean hasAlpha() {
return supportsAlpha;
}
/**
* Returns whether or not the alpha has been premultiplied in the
* pixel values to be translated by this <code>ColorModel</code>.
* If the boolean is <code>true</code>, this <code>ColorModel</code>
* is to be used to interpret pixel values in which color and alpha
* information are represented as separate spatial bands, and color
* samples are assumed to have been multiplied by the
* alpha sample.
* @return <code>true</code> if the alpha values are premultiplied
* in the pixel values to be translated by this
* <code>ColorModel</code>; <code>false</code> otherwise.
*/
final public boolean isAlphaPremultiplied() {
return isAlphaPremultiplied;
}
/**
* Constructs a ColorModel which describes a pixel of the specified
* number of bits.
*/
public ColorModel(int bits) {
pixel_bits = bits;
if (bits < 1) {
throw new IllegalArgumentException("Number of bits must be > 0");
}
numComponents = 4;
numColorComponents = 3;
//maxBits = bits;
// TODO: make sure transferType is set correctly
transferType = ColorModel.getDefaultTransferType(bits);
}
/**
* Constructs a <code>ColorModel</code> that translates pixel values
* to color/alpha components. Color components will be in the
* specified <code>ColorSpace</code>. <code>pixel_bits</code> is the
* number of bits in the pixel values. The bits array
* specifies the number of significant bits per color and alpha component.
* Its length should be the number of components in the
* <code>ColorSpace</code> if there is no alpha information in the
* pixel values, or one more than this number if there is alpha
* information. <code>hasAlpha</code> indicates whether or not alpha
* information is present. The <code>boolean</code>
* <code>isAlphaPremultiplied</code> specifies how to interpret pixel
* values in which color and alpha information are represented as
* separate spatial bands. If the <code>boolean</code>
* is <code>true</code>, color samples are assumed to have been
* multiplied by the alpha sample. The <code>transparency</code>
* specifies what alpha values can be represented by this color model.
* The transfer type is the type of primitive array used to represent
* pixel values. Note that the bits array contains the number of
* significant bits per color/alpha component after the translation
* from pixel values. For example, for an
* <code>IndexColorModel</code> with <code>pixel_bits</code> equal to
* 16, the bits array might have four elements with each element set
* to 8.
* @param pixel_bits the number of bits in the pixel values
* @param bits array that specifies the number of significant bits
* per color and alpha component
* @param cspace the specified <code>ColorSpace</code>
* @param hasAlpha <code>true</code> if alpha information is present;
* <code>false</code> otherwise
* @param isAlphaPremultiplied <code>true</code> if color samples are
* assumed to be premultiplied by the alpha samples;
* <code>false</code> otherwise
* @param transparency what alpha values can be represented by this
* color model
* @param transferType the type of the array used to represent pixel
* values
* @throws IllegalArgumentException if the length of
* the bit array is less than the number of color or alpha
* components in this <code>ColorModel</code>, or if the
* transparency is not a valid value.
* @throws IllegalArgumentException if the sum of the number
* of bits in <code>bits</code> is less than 1 or if
* any of the elements in <code>bits</code> is less than 0.
* @see java.awt.Transparency
*/
protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
boolean hasAlpha,
boolean isAlphaPremultiplied,
int transparency,
int transferType) {
colorSpace = cspace;
numColorComponents = cspace.getNumComponents();
numComponents = numColorComponents + (hasAlpha ? 1 : 0);
supportsAlpha = hasAlpha;
if (bits.length < numComponents) {
throw new IllegalArgumentException("Number of color/alpha " +
"components should be " +
numComponents +
" but length of bits array is " +
bits.length);
}
// 4186669
if (transparency < Transparency.OPAQUE ||
transparency > Transparency.TRANSLUCENT) {
throw new IllegalArgumentException("Unknown transparency: " +
transparency);
}
if (supportsAlpha == false) {
this.isAlphaPremultiplied = false;
this.transparency = Transparency.OPAQUE;
} else {
this.isAlphaPremultiplied = isAlphaPremultiplied;
this.transparency = transparency;
}
nBits = (int[]) bits.clone();
this.pixel_bits = pixel_bits;
if (pixel_bits <= 0) {
throw new IllegalArgumentException("Number of pixel bits must " +
"be > 0");
}
// Check for bits < 0
//maxBits = 0;
int maxBits = 0;
for (int i = 0; i < bits.length; i++) {
// bug 4304697
if (bits[i] < 0) {
throw new
IllegalArgumentException("Number of bits must be >= 0");
}
if (maxBits < bits[i]) {
maxBits = bits[i];
}
}
// Make sure that we don't have all 0-bit components
if (maxBits == 0) {
throw new IllegalArgumentException("There must be at least " +
"one component with > 0 " +
"pixel bits.");
}
// Save the transfer type
this.transferType = transferType;
}
/**
* Returns the number of bits per pixel described by this ColorModel.
*/
public int getPixelSize() {
return pixel_bits;
}
/**
* The subclass must provide a function which provides the red
* color compoment for the specified pixel.
* @return The red color component ranging from 0 to 255
*/
public abstract int getRed(int pixel);
/**
* The subclass must provide a function which provides the green
* color compoment for the specified pixel.
* @return The green color component ranging from 0 to 255
*/
public abstract int getGreen(int pixel);
/**
* The subclass must provide a function which provides the blue
* color compoment for the specified pixel.
* @return The blue color component ranging from 0 to 255
*/
public abstract int getBlue(int pixel);
/**
* The subclass must provide a function which provides the alpha
* color compoment for the specified pixel.
* @return The alpha transparency value ranging from 0 to 255
*/
public abstract int getAlpha(int pixel);
/**
* Returns the color of the pixel in the default RGB color model.
* @see ColorModel#getRGBdefault
*/
public int getRGB(int pixel) {
return (getAlpha(pixel) << 24)
| (getRed(pixel) << 16)
| (getGreen(pixel) << 8)
| (getBlue(pixel) << 0);
}
/**
* Tests if the specified <code>Object</code> is an instance of
* <code>ColorModel</code> and if it equals this
* <code>ColorModel</code>.
* @param obj the <code>Object</code> to test for equality
* @return <code>true</code> if the specified <code>Object</code>
* is an instance of <code>ColorModel</code> and equals this
* <code>ColorModel</code>; <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (!(obj instanceof ColorModel)) {
return false;
}
ColorModel cm = (ColorModel) obj;
if (this == cm) {
return true;
}
if (supportsAlpha != cm.hasAlpha() ||
isAlphaPremultiplied != cm.isAlphaPremultiplied() ||
transparency != cm.getTransparency() ||
pixel_bits != cm.getPixelSize()) {
return false;
}
return true;
}
/**
* Disposes of system resources associated with this
* <code>ColorModel</code> once this <code>ColorModel</code> is no
* longer referenced.
*/
public void finalize() {
}
/**
* Returns the hash code for this ColorModel.
*
* @return a hash code for this ColorModel.
*/
public int hashCode() {
int result = 0;
result = (supportsAlpha ? 2 : 3) +
(isAlphaPremultiplied ? 4 : 5) +
pixel_bits * 6 +
transparency * 7;
return result;
}
/**
* Returns the <code>ColorSpace</code> associated with this
* <code>ColorModel</code>.
* @return the <code>ColorSpace</code> of this
* <code>ColorModel</code>.
*/
final public ColorSpace getColorSpace() {
return colorSpace;
}
/**
* Returns the transparency. Returns either OPAQUE, BITMASK,
* or TRANSLUCENT.
* @return the transparency of this <code>ColorModel</code>.
* @see Transparency#OPAQUE
* @see Transparency#BITMASK
* @see Transparency#TRANSLUCENT
*/
public int getTransparency() {
return transparency;
}
/**
* Returns the number of bits for the specified color/alpha component.
* Color components are indexed in the order specified by the
* <code>ColorSpace</code>. Typically, this order reflects the name
* of the color space type. For example, for TYPE_RGB, index 0
* corresponds to red, index 1 to green, and index 2
* to blue. If this <code>ColorModel</code> supports alpha, the alpha
* component corresponds to the index following the last color
* component.
* @param componentIdx the index of the color/alpha component
* @return the number of bits for the color/alpha component at the
* specified index.
* @throws ArrayIndexOutOfBoundsException if <code>componentIdx</code>
* is greater than the number of components or
* less than zero
* @throws NullPointerException if the number of bits array is
* <code>null</code>
*/
public int getComponentSize(int componentIdx) {
// NOTE
if (nBits == null) {
throw new NullPointerException("Number of bits array is null.");
}
return nBits[componentIdx];
}
/**
* Returns an array of the number of bits per color/alpha component.
* The array contains the color components in the order specified by the
* <code>ColorSpace</code>, followed by the alpha component, if
* present.
* @return an array of the number of bits per color/alpha component
*/
public int[] getComponentSize() {
if (nBits != null) {
return (int[]) nBits.clone();
}
return null;
}
/**
* Returns the number of components, including alpha, in this
* <code>ColorModel</code>. This is equal to the number of color
* components, optionally plus one, if there is an alpha component.
* @return the number of components in this <code>ColorModel</code>
*/
public int getNumComponents() {
return numComponents;
}
/**
* Returns the number of color components in this
* <code>ColorModel</code>.
* This is the number of components returned by
* {@link ColorSpace#getNumComponents}.
* @return the number of color components in this
* <code>ColorModel</code>.
* @see ColorSpace#getNumComponents
*/
public int getNumColorComponents() {
return numColorComponents;
}
/**
* Returns the transfer type of this <code>ColorModel</code>.
* The transfer type is the type of primitive array used to represent
* pixel values as arrays.
* @return the transfer type.
*/
public final int getTransferType() {
return transferType;
}
static final int getDefaultTransferType(int pixel_bits) {
if (pixel_bits <= 8) {
return DataBuffer.TYPE_BYTE;
} else if (pixel_bits <= 16) {
return DataBuffer.TYPE_USHORT;
} else if (pixel_bits <= 32) {
return DataBuffer.TYPE_INT;
} else {
return DataBuffer.TYPE_UNDEFINED;
}
}
/**
* Returns the <code>String</code> representation of the contents of
* this <code>ColorModel</code>object.
* @return a <code>String</code> representing the contents of this
* <code>ColorModel</code> object.
*/
public String toString() {
return new String("ColorModel: #pixelBits = " + pixel_bits
+ " numComponents = " + numComponents
+ " color space = " + colorSpace
+ " transparency = " + transparency
+ " has alpha = " + supportsAlpha
+ " isAlphaPre = " + isAlphaPremultiplied
);
}
}