/* Copyright (C) 2000 Free Software Foundation This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.awt.image; import java.awt.Point; import java.awt.Transparency; import java.awt.color.ColorSpace; import gnu.gcj.awt.Buffers; /** * A color model operates with colors in several formats: * * * * @author Rolf W. Rasmussen */ public abstract class ColorModel implements Transparency { protected int pixel_bits; protected int transferType; int[] bits; ColorSpace cspace; int transparency; boolean hasAlpha; boolean isAlphaPremultiplied; static int[] nArray(int value, int times) { int[] array = new int[times]; java.util.Arrays.fill(array, value); return array; } static byte[] nArray(byte value, int times) { byte[] array = new byte[times]; java.util.Arrays.fill(array, value); return array; } public ColorModel(int bits) { this(bits * 4, // total bits, sRGB, four channels nArray(bits, 4), // bits for each channel null, // FIXME: should be sRGB true, // has alpha false, // not premultiplied TRANSLUCENT, Buffers.smallestAppropriateTransferType(bits * 4)); } protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, boolean hasAlpha, boolean isAlphaPremultiplied, int transparency, int transferType) { this.pixel_bits = pixel_bits; this.bits = bits; this.cspace = cspace; this.hasAlpha = hasAlpha; this.isAlphaPremultiplied = isAlphaPremultiplied; this.transparency = transparency; this.transferType = transferType; } public static ColorModel getRGBdefault() { return new DirectColorModel(8, 0xff0000, 0xff00, 0xff, 0xff000000); } public final boolean hasAlpha() { return hasAlpha; } public final boolean isAlphaPremultiplied() { return isAlphaPremultiplied; } public int getPixelSize() { return pixel_bits; } public int getComponentSize(int componentIdx) { return bits[componentIdx]; } public int[] getComponentSize() { return bits; } public int getTransparency() { return transparency; } public int getNumComponents() { return getNumColorComponents() + (hasAlpha ? 1 : 0); } public int getNumColorComponents() { return cspace.getNumComponents(); } /** * Converts pixel value to sRGB and extract red int sample scaled * to range [0, 255]. * * @param pixel pixel value that will be interpreted according to * the color model, (assumed alpha premultiplied if color model says * so.) * * @return red sample scaled to range [0, 255], from default color * space sRGB, alpha non-premultiplied. */ public abstract int getRed(int pixel); /** * Converts pixel value to sRGB and extract green int sample * scaled to range [0, 255]. * * @see #getRed(int) */ public abstract int getGreen(int pixel); /** * Converts pixel value to sRGB and extract blue int sample * scaled to range [0, 255]. * * @see #getRed(int) */ public abstract int getBlue(int pixel); /** * Extract alpha int sample from pixel value, scaled to [0, 255]. * * @param pixel pixel value that will be interpreted according to * the color model. * * @return alpha sample, scaled to range [0, 255]. */ public abstract int getAlpha(int pixel); /** * Converts a pixel int value of the color space of the color * model to a sRGB pixel int value. * * This method is typically overriden in subclasses to provide a * more efficient implementation. * * @param pixel pixel value that will be interpreted according to * the color model. * * @return a pixel in sRGB color space, encoded in default * 0xAARRGGBB format. */ public int getRGB(int pixel) { return ((getAlpha(pixel) & 0xff) << 24) | (( getRed(pixel) & 0xff) << 16) | ((getGreen(pixel) & 0xff) << 8) | (( getBlue(pixel) & 0xff) << 0); } /** * In this color model we know that the whole pixel value will * always be contained within the first element of the pixel * array. */ final int getPixelFromArray(Object inData) { DataBuffer data = Buffers.createBufferFromData(transferType, inData, 1); Object da = Buffers.getData(data); return data.getElem(0); } /** * Converts pixel in the given array to sRGB and extract blue int * sample scaled to range [0-255]. * * This method is typically overriden in subclasses to provide a * more efficient implementation. * * @param array of transferType containing a single pixel. The * pixel should be encoded in the natural way of the color model. */ public int getRed(Object inData) { return getRed(getPixelFromArray(inData)); } /** * @see #getRed(Object) */ public int getGreen(Object inData) { return getGreen(getPixelFromArray(inData)); } /** * @see #getRed(Object) */ public int getBlue(Object inData) { return getBlue(getPixelFromArray(inData)); } /** * @see #getRed(Object) */ public int getAlpha(Object inData) { return getBlue(getPixelFromArray(inData)); } /** * Converts a pixel in the given array of the color space of the * color model to an sRGB pixel int value. * *

This method performs the inverse function of * getDataElements(int rgb, Object pixel). * I.e. (rgb == cm.getRGB(cm.getDataElements(rgb, * null))). * * @param inData array of transferType containing a single pixel. The * pixel should be encoded in the natural way of the color model. * * @return a pixel in sRGB color space, encoded in default * 0xAARRGGBB format. * * @see #getDataElements(int, Object) */ public int getRGB(Object inData) { return ((getAlpha(inData) & 0xff) << 24) | (( getRed(inData) & 0xff) << 16) | ((getGreen(inData) & 0xff) << 8) | (( getBlue(inData) & 0xff) << 0); } /** * Converts an sRGB pixel int value to an array containing a * single pixel of the color space of the color model. * *

This method performs the inverse function of * getRGB(Object inData). * * Outline of conversion process: * *

    * *
  1. Convert rgb to normalized [0.0, 1.0] sRGB values.
  2. * *
  3. Convert to color space components using fromRGB in * ColorSpace.
  4. * *
  5. If color model has alpha and should be premultiplied, * multiply color space components with alpha value
  6. * *
  7. Scale the components to the correct number of bits.
  8. * *
  9. Arrange the components in the output array
  10. * *
* * @param rgb The color to be converted to dataElements. A pixel * in sRGB color space, encoded in default 0xAARRGGBB format, * assumed not alpha premultiplied. * * @param pixel to avoid needless creation of arrays, an array to * use to return the pixel can be given. If null, a suitable array * will be created. * * @return An array of transferType values representing the color, * in the color model format. The color model defines whether the * * @see #getRGB(Object) */ public Object getDataElements(int rgb, Object pixel) { // FIXME: implement throw new UnsupportedOperationException(); } /** * Fills an array with the unnormalized component samples from a * pixel value. I.e. decompose the pixel, but not perform any * color conversion. * * This method is typically overriden in subclasses to provide a * more efficient implementation. * * @param pixel pixel value encoded according to the color model. * * @return arrays of unnormalized component samples of single * pixel. The scale and multiplication state of the samples are * according to the color model. Each component sample is stored * as a separate element in the array. */ public int[] getComponents(int pixel, int[] components, int offset) { // FIXME: implement throw new UnsupportedOperationException(); } /** * Fills an array with the unnormalized component samples from an * array of transferType containing a single pixel. I.e. decompose * the pixel, but not perform any color conversion. * * This method is typically overriden in subclasses to provide a * more efficient implementation. * * @param array of transferType containing a single pixel. The * pixel should be encoded in the natural way of the color model. * * @return arrays of unnormalized component samples of single * pixel. The scale and multiplication state of the samples are * according to the color model. Each component sample is stored * as a separate element in the array. */ public int[] getComponents(Object pixel, int[] components, int offset) { throw new UnsupportedOperationException(); } /** * Convert normalized components to unnormalized components. */ public int[] getUnnormalizedComponents(float[] normComponents, int normOffset, int[] components, int offset) { int numComponents = getNumComponents(); if (components == null) { components = new int[offset + numComponents]; } for (int i=0; igetComponents(int pixel, int[] components, * int offset). I.e. * * (pixel == cm.getDataElement(cm.getComponents(pixel, null, * 0), 0)). * * This method is typically overriden in subclasses to provide a * more efficient implementation. * * @param arrays of unnormalized component samples of single * pixel. The scale and multiplication state of the samples are * according to the color model. Each component sample is stored * as a separate element in the array. * * @return pixel value encoded according to the color model. */ public int getDataElement(int[] components, int offset) { throw new UnsupportedOperationException(); } public Object getDataElements(int[] components, int offset, Object obj) { throw new UnsupportedOperationException(); } public boolean equals(Object obj) { if (!(obj instanceof ColorModel)) return false; ColorModel o = (ColorModel) obj; return (pixel_bits == o.pixel_bits) && (transferType == o.transferType) && (transparency == o.transparency) && (hasAlpha == o.hasAlpha) && (isAlphaPremultiplied == isAlphaPremultiplied) && (bits.equals(o.bits)) && (cspace.equals(o.cspace)); } public final ColorSpace getColorSpace() { return cspace; } // Typically overridden public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { if (this.isAlphaPremultiplied == isAlphaPremultiplied) return this; int w = raster.getWidth(); int h = raster.getHeight(); int x = raster.getMinX(); int y = raster.getMinY(); int size = w*h; int numColors = getNumColorComponents(); int numComponents = getNumComponents(); int alphaScale = (1<