0001: /*
0002: * $RCSfile: FloatDoubleColorModel.java,v $
0003: *
0004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Use is subject to license terms.
0007: *
0008: * $Revision: 1.2 $
0009: * $Date: 2005/11/16 00:26:52 $
0010: * $State: Exp $
0011: */
0012: package javax.media.jai;
0013:
0014: import java.awt.Point;
0015: import java.awt.Transparency;
0016: import java.awt.color.ColorSpace;
0017: import java.awt.image.ColorModel;
0018: import java.awt.image.ComponentColorModel;
0019: import java.awt.image.ComponentSampleModel;
0020: import java.awt.image.DataBuffer;
0021: import java.awt.image.Raster;
0022: import java.awt.image.SampleModel;
0023: import java.awt.image.WritableRaster;
0024:
0025: /**
0026: * A <code>ColorModel</code> class that works with pixel values that
0027: * represent color and alpha information as separate samples, using
0028: * float or double elements. This class can be used with an arbitrary
0029: * <code>ColorSpace</code>. The number of color samples in the pixel
0030: * values must be same as the number of color components in the
0031: * <code>ColorSpace</code>. There may be a single alpha sample.
0032: *
0033: * <p> Sample values are taken as ranging from 0.0 to 1.0; that is,
0034: * when converting to 8-bit RGB, a multiplication by 255 is performed
0035: * and values outside of the range 0-255 are clamped at the closest
0036: * endpoint.
0037: *
0038: * <p> For maximum efficiency, pixel data being interpreted by this
0039: * class should be in the sRGB color space. This will result in
0040: * only the trivial conversion (scaling by 255 and dividing by any
0041: * premultiplied alpha) to be performed. Other color spaces require
0042: * more general conversions.
0043: *
0044: * <p> For those methods that use a primitive array pixel
0045: * representation of type <code>transferType</code>, the array length
0046: * is the same as the number of color and alpha samples. Color
0047: * samples are stored first in the array followed by the alpha sample,
0048: * if present. The order of the color samples is specified by the
0049: * <code>ColorSpace</code>. Typically, this order reflects the name
0050: * of the color space type. For example, for <code>TYPE_RGB</code>,
0051: * index 0 corresponds to red, index 1 to green, and index 2 to blue.
0052: * The transfer types supported are
0053: * <code>DataBuffer.TYPE_FLOAT</code>,
0054: * <code>DataBuffer.TYPE_DOUBLE</code>.
0055: *
0056: * <p> The translation from pixel values to color/alpha components for
0057: * display or processing purposes is a one-to-one correspondence of
0058: * samples to components.
0059: *
0060: * <p> Methods that use a single int pixel representation throw an
0061: * <code>IllegalArgumentException</code>.
0062: *
0063: * <p> A <code>FloatDoubleColorModel</code> can be used in
0064: * conjunction with a <code>ComponentSampleModelJAI</code>.
0065: *
0066: * @see java.awt.image.ColorModel
0067: * @see java.awt.color.ColorSpace
0068: * @see java.awt.image.ComponentSampleModel
0069: * @see ComponentSampleModelJAI
0070: */
0071: public class FloatDoubleColorModel extends ComponentColorModel {
0072:
0073: /**
0074: * The associated <code>ColorSpace</code>.
0075: *
0076: * @since JAI 1.1
0077: */
0078: protected ColorSpace colorSpace;
0079:
0080: /**
0081: * The type or family of the associated <code>ColorSpace</code>.
0082: *
0083: * @since JAI 1.1
0084: */
0085: protected int colorSpaceType;
0086:
0087: /**
0088: * The number of components of the associated <code>ColorSpace</code>.
0089: *
0090: * @since JAI 1.1
0091: */
0092: protected int numColorComponents;
0093:
0094: /**
0095: * The number of components represented by this <code>ColorModel</code>.
0096: * This will differ from the number of components of the associated
0097: * <code>ColorSpace</code> if there is an alpha channel.
0098: *
0099: * @since JAI 1.1
0100: */
0101: protected int numComponents;
0102:
0103: /**
0104: * Specifies what alpha values can be represented by this
0105: * <code>ColorModel</code>.
0106: *
0107: * @since JAI 1.1
0108: */
0109: protected int transparency;
0110:
0111: /**
0112: * Whether this <code>ColorModel</code> supports alpha.
0113: *
0114: * @since JAI 1.1
0115: */
0116: protected boolean hasAlpha;
0117:
0118: /**
0119: * Whether alpha is premultiplied.
0120: *
0121: * @since JAI 1.1
0122: */
0123: protected boolean isAlphaPremultiplied;
0124:
0125: private static int[] bitsHelper(int transferType,
0126: ColorSpace colorSpace, boolean hasAlpha) {
0127: int numBits = (transferType == DataBuffer.TYPE_FLOAT) ? 32 : 64;
0128: int numComponents = colorSpace.getNumComponents();
0129: if (hasAlpha) {
0130: ++numComponents;
0131: }
0132: int[] bits = new int[numComponents];
0133: for (int i = 0; i < numComponents; i++) {
0134: bits[i] = numBits;
0135: }
0136:
0137: return bits;
0138: }
0139:
0140: /**
0141: * Constructs a <code>ComponentColorModel</code> from the
0142: * specified parameters. Color components will be in the specified
0143: * <code>ColorSpace</code>. <code>hasAlpha</code> indicates
0144: * whether alpha information is present. If <code>hasAlpha</code>
0145: * is true, then the boolean <code>isAlphaPremultiplied</code>
0146: * specifies how to interpret color and alpha samples in pixel
0147: * values. If the boolean is <code>true</code>, color samples are
0148: * assumed to have been multiplied by the alpha sample. The
0149: * <code>transparency</code> specifies what alpha values can be
0150: * represented by this color model. The <code>transferType</code>
0151: * is the type of primitive array used to represent pixel values.
0152: *
0153: * @param colorSpace The <code>ColorSpace</code> associated with
0154: * this color model.
0155: * @param hasAlpha If true, this color model supports alpha.
0156: * @param isAlphaPremultiplied If true, alpha is premultiplied.
0157: * @param transparency Specifies what alpha values can be represented
0158: * by this color model.
0159: * @param transferType Specifies the type of primitive array used to
0160: * represent pixel values, one of
0161: * DataBuffer.TYPE_FLOAT or TYPE_DOUBLE.
0162: * @throws IllegalArgumentException If the transfer type is not
0163: * DataBuffer.TYPE_FLOAT or TYPE_DOUBLE.
0164: *
0165: * @see java.awt.color.ColorSpace
0166: * @see java.awt.Transparency
0167: */
0168: public FloatDoubleColorModel(ColorSpace colorSpace,
0169: boolean hasAlpha, boolean isAlphaPremultiplied,
0170: int transparency, int transferType) {
0171: super (colorSpace,
0172: bitsHelper(transferType, colorSpace, hasAlpha),
0173: hasAlpha, isAlphaPremultiplied, transparency,
0174: transferType);
0175:
0176: if (transferType != DataBuffer.TYPE_FLOAT
0177: && transferType != DataBuffer.TYPE_DOUBLE) {
0178: throw new IllegalArgumentException(JaiI18N
0179: .getString("FloatDoubleColorModel0"));
0180: }
0181:
0182: this .colorSpace = colorSpace;
0183: this .colorSpaceType = colorSpace.getType();
0184: this .numComponents = this .numColorComponents = colorSpace
0185: .getNumComponents();
0186: if (hasAlpha) {
0187: ++numComponents;
0188: }
0189: this .transparency = transparency;
0190: this .hasAlpha = hasAlpha;
0191: this .isAlphaPremultiplied = isAlphaPremultiplied;
0192: }
0193:
0194: /**
0195: * Throws an <code>IllegalArgumentException</code>, since pixel
0196: * values for this <code>ColorModel</code> are not conveniently
0197: * representable as a single <code>int</code>.
0198: */
0199: public int getRed(int pixel) {
0200: throw new IllegalArgumentException(JaiI18N
0201: .getString("FloatDoubleColorModel1"));
0202: }
0203:
0204: /**
0205: * Throws an <code>IllegalArgumentException</code>, since pixel
0206: * values for this <code>ColorModel</code> are not conveniently
0207: * representable as a single <code>int</code>.
0208: */
0209: public int getGreen(int pixel) {
0210: throw new IllegalArgumentException(JaiI18N
0211: .getString("FloatDoubleColorModel2"));
0212: }
0213:
0214: /**
0215: * Throws an <code>IllegalArgumentException</code>, since pixel
0216: * values for this <code>ColorModel</code> are not conveniently
0217: * representable as a single <code>int</code>.
0218: */
0219: public int getBlue(int pixel) {
0220: throw new IllegalArgumentException(JaiI18N
0221: .getString("FloatDoubleColorModel3"));
0222: }
0223:
0224: /**
0225: * Throws an <code>IllegalArgumentException</code>, since pixel
0226: * values for this <code>ColorModel</code> are not conveniently
0227: * representable as a single <code>int</code>.
0228: */
0229: public int getAlpha(int pixel) {
0230: throw new IllegalArgumentException(JaiI18N
0231: .getString("FloatDoubleColorModel4"));
0232: }
0233:
0234: /**
0235: * Throws an <code>IllegalArgumentException</code>, since pixel
0236: * values for this <code>ColorModel</code> are not conveniently
0237: * representable as a single <code>int</code>.
0238: */
0239: public int getRGB(int pixel) {
0240: throw new IllegalArgumentException(JaiI18N
0241: .getString("FloatDoubleColorModel5"));
0242: }
0243:
0244: private final int clamp(float value) {
0245: // Ensure NaN maps to 0
0246: return (value >= 0.0F) ? ((value > 255.0F) ? 255 : (int) value)
0247: : 0;
0248: }
0249:
0250: private final int clamp(double value) {
0251: // Ensure NaN maps to 0
0252: return (value >= 0.0) ? ((value > 255.0) ? 255 : (int) value)
0253: : 0;
0254: }
0255:
0256: private int getSample(Object inData, int sample) {
0257: boolean needAlpha = (hasAlpha && isAlphaPremultiplied);
0258: int type = colorSpaceType;
0259:
0260: boolean is_sRGB = colorSpace.isCS_sRGB();
0261:
0262: if (type == ColorSpace.TYPE_GRAY) {
0263: sample = 0;
0264: is_sRGB = true;
0265: }
0266:
0267: if (is_sRGB) {
0268: if (transferType == DataBuffer.TYPE_FLOAT) {
0269: float[] fdata = (float[]) inData;
0270: float fsample = fdata[sample] * 255;
0271: if (needAlpha) {
0272: float falp = fdata[numColorComponents];
0273: if (falp == 0.0)
0274: return 0;
0275: else
0276: return clamp(fsample / falp);
0277: } else {
0278: return clamp(fsample);
0279: }
0280: } else {
0281: double[] ddata = (double[]) inData;
0282: double dsample = ddata[sample] * 255.0;
0283: if (needAlpha) {
0284: double dalp = ddata[numColorComponents];
0285: if (dalp == 0.0)
0286: return 0;
0287: else
0288: return clamp(dsample / dalp);
0289: } else {
0290: return clamp(dsample);
0291: }
0292: }
0293: }
0294:
0295: // Not TYPE_GRAY or TYPE_RGB ColorSpace
0296: float[] norm;
0297: float[] rgb;
0298: if (transferType == DataBuffer.TYPE_FLOAT) {
0299: float[] fdata = (float[]) inData;
0300: if (needAlpha) {
0301: float falp = fdata[numColorComponents];
0302: if (falp == 0.0)
0303: return 0;
0304: norm = new float[numColorComponents];
0305: for (int i = 0; i < numColorComponents; i++) {
0306: norm[i] = fdata[i] / falp;
0307: }
0308: rgb = colorSpace.toRGB(norm);
0309: } else {
0310: rgb = colorSpace.toRGB(fdata);
0311: }
0312: return (int) (rgb[sample] * 255 + 0.5F);
0313: } else {
0314: double[] ddata = (double[]) inData;
0315: norm = new float[numColorComponents];
0316: if (needAlpha) {
0317: double dalp = ddata[numColorComponents];
0318: if (dalp == 0.0)
0319: return 0;
0320: for (int i = 0; i < numColorComponents; i++) {
0321: norm[i] = (float) (ddata[i] / dalp);
0322: }
0323: rgb = colorSpace.toRGB(norm);
0324: } else {
0325: for (int i = 0; i < numColorComponents; i++) {
0326: norm[i] = (float) ddata[i];
0327: }
0328: rgb = colorSpace.toRGB(norm);
0329: }
0330: return (int) (rgb[sample] * 255 + 0.5);
0331: }
0332: }
0333:
0334: /**
0335: * Returns the red color component for the specified pixel, scaled
0336: * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A color
0337: * conversion is done if necessary. The <code>pixel</code> value
0338: * is specified by an array of data elements of type
0339: * <code>transferType</code> passed in as an object reference. The
0340: * returned value will be a non pre-multiplied value. If the alpha
0341: * is premultiplied, this method divides it out before returning
0342: * the value (if the alpha value is 0, the red value will be 0).
0343: *
0344: * @param inData The pixel from which to get the red
0345: * color component, specified by an array of data elements of type
0346: * <code>transferType</code>.
0347: *
0348: * @return The red color component for the specified pixel, as an
0349: * int.
0350: *
0351: * @throws ClassCastException If <code>inData</code> is not a
0352: * primitive array of type <code>transferType</code>.
0353: * @throws ArrayIndexOutOfBoundsException if <code>inData</code>
0354: * is not large enough to hold a pixel value for this
0355: * <code>ColorModel</code>.
0356: */
0357: public int getRed(Object inData) {
0358: return getSample(inData, 0);
0359: }
0360:
0361: /**
0362: * Returns the green color component for the specified pixel, scaled
0363: * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A color
0364: * conversion is done if necessary. The <code>pixel</code> value
0365: * is specified by an array of data elements of type
0366: * <code>transferType</code> passed in as an object reference. The
0367: * returned value will be a non pre-multiplied value. If the alpha
0368: * is premultiplied, this method divides it out before returning
0369: * the value (if the alpha value is 0, the green value will be 0).
0370: *
0371: * @param inData The pixel from which to get the green
0372: * color component, specified by an array of data elements of type
0373: * <code>transferType</code>.
0374: *
0375: * @return The green color component for the specified pixel, as an
0376: * int.
0377: *
0378: * @throws ClassCastException If <code>inData</code> is not a
0379: * primitive array of type <code>transferType</code>.
0380: * @throws ArrayIndexOutOfBoundsException if <code>inData</code>
0381: * is not large enough to hold a pixel value for this
0382: * <code>ColorModel</code>.
0383: */
0384: public int getGreen(Object inData) {
0385: return getSample(inData, 1);
0386: }
0387:
0388: /**
0389: * Returns the blue color component for the specified pixel, scaled
0390: * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A color
0391: * conversion is done if necessary. The <code>pixel</code> value
0392: * is specified by an array of data elements of type
0393: * <code>transferType</code> passed in as an object reference. The
0394: * returned value will be a non pre-multiplied value. If the alpha
0395: * is premultiplied, this method divides it out before returning
0396: * the value (if the alpha value is 0, the blue value will be 0).
0397: *
0398: * @param inData The pixel from which to get the blue
0399: * color component, specified by an array of data elements of type
0400: * <code>transferType</code>.
0401: *
0402: * @return The blue color component for the specified pixel, as an
0403: * int.
0404: *
0405: * @throws ClassCastException If <code>inData</code> is not a
0406: * primitive array of type <code>transferType</code>.
0407: * @throws ArrayIndexOutOfBoundsException if <code>inData</code>
0408: * is not large enough to hold a pixel value for this
0409: * <code>ColorModel</code>.
0410: */
0411: public int getBlue(Object inData) {
0412: return getSample(inData, 2);
0413: }
0414:
0415: /**
0416: * Returns the alpha component for the specified pixel, scaled
0417: * from 0 to 255. The pixel value is specified by an array of
0418: * data elements of type <code>transferType</code> passed in as an
0419: * object reference. If the <code>ColorModel</code> does not have
0420: * alpha, 255 is returned.
0421: *
0422: * @param inData The pixel from which to get the alpha
0423: * component, specified by an array of data elements of type
0424: * <code>transferType</code>.
0425: *
0426: * @return The alpha component for the specified pixel, as an int.
0427: *
0428: * @throws IllegalArgumentException if <code>inData</code> is
0429: * <code>null</code> and the <code>colorModel</code> has alpha.
0430: * @throws ClassCastException If <code>inData</code> is not a
0431: * primitive array of type <code>transferType</code> and the
0432: * <code>ColorModel</code> has alpha.
0433: * @throws ArrayIndexOutOfBoundsException if <code>inData</code>
0434: * is not large enough to hold a pixel value for this
0435: * <code>ColorModel</code> and the <code>ColorModel</code> has
0436: * alpha.
0437: */
0438: public int getAlpha(Object inData) {
0439: if (inData == null) {
0440: throw new IllegalArgumentException(JaiI18N
0441: .getString("Generic0"));
0442: }
0443:
0444: if (hasAlpha == false) {
0445: return 255;
0446: }
0447:
0448: if (transferType == DataBuffer.TYPE_FLOAT) {
0449: float[] fdata = (float[]) inData;
0450: return (int) (fdata[numColorComponents] * 255.0F + 0.5F);
0451: } else {
0452: double[] ddata = (double[]) inData;
0453: return (int) (ddata[numColorComponents] * 255.0 + 0.5);
0454: }
0455: }
0456:
0457: /**
0458: * Returns the color/alpha components for the specified pixel in
0459: * the default RGB color model format. A color conversion is done
0460: * if necessary. The pixel value is specified by an array of data
0461: * elements of type <code>transferType</code> passed in as an
0462: * object reference. The returned value is in a non
0463: * pre-multiplied format. If the alpha is premultiplied, this
0464: * method divides it out of the color components (if the alpha
0465: * value is 0, the color values will be 0).
0466: *
0467: * @param inData The pixel from which to get the
0468: * color/alpha components, specified by an array of data elements
0469: * of type <code>transferType</code>.
0470: *
0471: * @return The color/alpha components for the specified pixel, as an int.
0472: *
0473: * @throws ClassCastException If <code>inData</code> is not a
0474: * primitive array of type <code>transferType</code>.
0475: * @throws ArrayIndexOutOfBoundsException if <code>inData</code>
0476: * is not large enough to hold a pixel value for this
0477: * <code>ColorModel</code>.
0478: */
0479: public int getRGB(Object inData) {
0480: boolean needAlpha = (hasAlpha && isAlphaPremultiplied);
0481: int alpha = 255;
0482: int red, green, blue;
0483:
0484: if (colorSpace.isCS_sRGB()) {
0485: if (transferType == DataBuffer.TYPE_FLOAT) {
0486: float[] fdata = (float[]) inData;
0487: float fred = fdata[0];
0488: float fgreen = fdata[1];
0489: float fblue = fdata[2];
0490: float fscale = 255.0F;
0491: if (needAlpha) {
0492: float falpha = fdata[3];
0493: fscale /= falpha;
0494: alpha = clamp(255.0F * falpha);
0495: }
0496:
0497: red = clamp(fred * fscale);
0498: green = clamp(fgreen * fscale);
0499: blue = clamp(fblue * fscale);
0500: } else {
0501: double[] ddata = (double[]) inData;
0502: double dred = ddata[0];
0503: double dgreen = ddata[1];
0504: double dblue = ddata[2];
0505: double dscale = 255.0;
0506: if (needAlpha) {
0507: double dalpha = ddata[3];
0508: dscale /= dalpha;
0509: alpha = clamp(255.0 * dalpha);
0510: }
0511:
0512: red = clamp(dred * dscale);
0513: green = clamp(dgreen * dscale);
0514: blue = clamp(dblue * dscale);
0515: }
0516: } else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
0517: if (transferType == DataBuffer.TYPE_FLOAT) {
0518: float[] fdata = (float[]) inData;
0519: float fgray = fdata[0];
0520: if (needAlpha) {
0521: float falp = fdata[1];
0522: red = green = blue = clamp(fgray * 255.0F / falp);
0523: alpha = clamp(255.0F * falp);
0524: } else {
0525: red = green = blue = clamp(fgray * 255.0F);
0526: }
0527: } else {
0528: double[] ddata = (double[]) inData;
0529: double dgray = ddata[0];
0530: if (needAlpha) {
0531: double dalp = ddata[1];
0532: red = green = blue = clamp(dgray * 255.0 / dalp);
0533: alpha = clamp(255.0 * dalp);
0534: } else {
0535: red = green = blue = clamp(dgray * 255.0);
0536: }
0537: }
0538: } else {
0539: // Not Gray or sRGB
0540: float[] norm;
0541: float[] rgb;
0542: if (transferType == DataBuffer.TYPE_FLOAT) {
0543: float[] fdata = (float[]) inData;
0544: if (needAlpha) {
0545: float falp = fdata[numColorComponents];
0546: float invfalp = 1.0F / falp;
0547: norm = new float[numColorComponents];
0548: for (int i = 0; i < numColorComponents; i++) {
0549: norm[i] = fdata[i] * invfalp;
0550: }
0551: alpha = clamp(255.0F * falp);
0552: } else {
0553: norm = fdata;
0554: }
0555: } else {
0556: double[] ddata = (double[]) inData;
0557: norm = new float[numColorComponents];
0558: if (needAlpha) {
0559: double dalp = ddata[numColorComponents];
0560: double invdalp = 1.0 / dalp;
0561: for (int i = 0; i < numColorComponents; i++) {
0562: norm[i] = (float) (ddata[i] * invdalp);
0563: }
0564: alpha = clamp(255.0 * dalp);
0565: } else {
0566: for (int i = 0; i < numColorComponents; i++) {
0567: norm[i] = (float) ddata[i];
0568: }
0569: }
0570: }
0571:
0572: // Perform color conversion
0573: rgb = colorSpace.toRGB(norm);
0574:
0575: red = clamp(rgb[0] * 255.0F);
0576: green = clamp(rgb[1] * 255.0F);
0577: blue = clamp(rgb[2] * 255.0F);
0578: }
0579:
0580: return (alpha << 24) | (red << 16) | (green << 8) | blue;
0581: }
0582:
0583: /**
0584: * Returns a data element array representation of a pixel in this
0585: * <code>ColorModel</code>, given an integer pixel representation
0586: * in the default RGB color model. This array can then be passed
0587: * to the <code>setDataElements</code> method of a
0588: * <code>WritableRaster</code> object. If the <code>pixel</code>
0589: * parameter is null, a new array is allocated.
0590: * If the colorSpaceType is of TYPE_GRAY then the rgb components
0591: * are converted to gray using appropriate weights
0592: *
0593: * @param rgb An ARGB value packed into an int.
0594: * @param pixel The float or double array representation of the pixel.
0595: *
0596: * @throws ClassCastException If <code>pixel</code> is not null and
0597: * is not a primitive array of type <code>transferType</code>.
0598: *
0599: * @throws ArrayIndexOutOfBoundsException If <code>pixel</code> is
0600: * not large enough to hold a pixel value for this
0601: * <code>ColorModel</code>.
0602: */
0603: public Object getDataElements(int rgb, Object pixel) {
0604: if (transferType == DataBuffer.TYPE_FLOAT) {
0605: float[] floatPixel;
0606:
0607: if (pixel == null) {
0608: floatPixel = new float[numComponents];
0609: } else {
0610: if (!(pixel instanceof float[])) {
0611: throw new ClassCastException(JaiI18N
0612: .getString("FloatDoubleColorModel7"));
0613: }
0614: floatPixel = (float[]) pixel;
0615: if (floatPixel.length < numComponents) {
0616: throw new ArrayIndexOutOfBoundsException(JaiI18N
0617: .getString("FloatDoubleColorModel8"));
0618: }
0619: }
0620:
0621: float inv255 = 1.0F / 255.0F;
0622: if (colorSpace.isCS_sRGB()) {
0623: int alp = (rgb >> 24) & 0xff;
0624: int red = (rgb >> 16) & 0xff;
0625: int grn = (rgb >> 8) & 0xff;
0626: int blu = (rgb) & 0xff;
0627: float norm = inv255;
0628: if (isAlphaPremultiplied) {
0629: norm *= alp;
0630: }
0631: floatPixel[0] = red * norm;
0632: floatPixel[1] = grn * norm;
0633: floatPixel[2] = blu * norm;
0634: if (hasAlpha) {
0635: floatPixel[3] = alp * inv255;
0636: }
0637: } else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
0638: float gray = ((((rgb >> 16) & 0xff) * (.299F * inv255))
0639: + (((rgb >> 8) & 0xff) * (.587F * inv255)) + (((rgb) & 0xff) * (.114F * inv255)));
0640:
0641: floatPixel[0] = gray;
0642:
0643: if (hasAlpha) {
0644: int alpha = (rgb >> 24) & 0xff;
0645: floatPixel[1] = alpha * inv255;
0646: }
0647: } else {
0648: // Need to convert the color
0649: float[] norm = new float[3];
0650: norm[0] = ((rgb >> 16) & 0xff) * inv255;
0651: norm[1] = ((rgb >> 8) & 0xff) * inv255;
0652: norm[2] = ((rgb) & 0xff) * inv255;
0653:
0654: norm = colorSpace.fromRGB(norm);
0655: for (int i = 0; i < numColorComponents; i++) {
0656: floatPixel[i] = norm[i];
0657: }
0658: if (hasAlpha) {
0659: int alpha = (rgb >> 24) & 0xff;
0660: floatPixel[numColorComponents] = alpha * inv255;
0661: }
0662: }
0663:
0664: return floatPixel;
0665: } else { // transferType == DataBuffer.TYPE_DOUBLE
0666: double[] doublePixel;
0667:
0668: if (pixel == null) {
0669: doublePixel = new double[numComponents];
0670: } else {
0671: if (!(pixel instanceof double[])) {
0672: throw new ClassCastException(JaiI18N
0673: .getString("FloatDoubleColorModel7"));
0674: }
0675: doublePixel = (double[]) pixel;
0676: if (doublePixel.length < numComponents) {
0677: throw new ArrayIndexOutOfBoundsException(JaiI18N
0678: .getString("FloatDoubleColorModel8"));
0679: }
0680: }
0681:
0682: double inv255 = 1.0 / 255.0;
0683: if (colorSpace.isCS_sRGB()) {
0684: int alp = (rgb >> 24) & 0xff;
0685: int red = (rgb >> 16) & 0xff;
0686: int grn = (rgb >> 8) & 0xff;
0687: int blu = (rgb) & 0xff;
0688: double norm = inv255;
0689: if (isAlphaPremultiplied) {
0690: norm *= alp;
0691: }
0692: doublePixel[0] = red * norm;
0693: doublePixel[1] = grn * norm;
0694: doublePixel[2] = blu * norm;
0695: if (hasAlpha) {
0696: doublePixel[3] = alp * inv255;
0697: }
0698: } else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
0699: double gray = ((((rgb >> 16) & 0xff) * (.299 * inv255))
0700: + (((rgb >> 8) & 0xff) * (.587 * inv255)) + (((rgb) & 0xff) * (.114 * inv255)));
0701:
0702: doublePixel[0] = gray;
0703:
0704: if (hasAlpha) {
0705: int alpha = (rgb >> 24) & 0xff;
0706: doublePixel[1] = alpha * inv255;
0707: }
0708: } else {
0709: float inv255F = 1.0F / 255.0F;
0710:
0711: // Need to convert the color, need data in float form
0712: float[] norm = new float[3];
0713: norm[0] = ((rgb >> 16) & 0xff) * inv255F;
0714: norm[1] = ((rgb >> 8) & 0xff) * inv255F;
0715: norm[2] = ((rgb) & 0xff) * inv255F;
0716:
0717: norm = colorSpace.fromRGB(norm);
0718: for (int i = 0; i < numColorComponents; i++) {
0719: doublePixel[i] = (double) norm[i];
0720: }
0721: if (hasAlpha) {
0722: int alpha = (rgb >> 24) & 0xff;
0723: doublePixel[numColorComponents] = alpha * inv255;
0724: }
0725: }
0726:
0727: return doublePixel;
0728: }
0729: }
0730:
0731: /**
0732: * Throws an <code>IllegalArgumentException</code>, since pixel
0733: * values for this <code>ColorModel</code> are not conveniently
0734: * representable as a single <code>int</code>.
0735: */
0736: public int[] getComponents(int pixel, int[] components, int offset) {
0737: throw new IllegalArgumentException(JaiI18N
0738: .getString("FloatDoubleColorModel9"));
0739: }
0740:
0741: /**
0742: * Throws an <code>IllegalArgumentException</code> since
0743: * the pixel values cannot be placed into an <code>int</code> array.
0744: */
0745: public int[] getComponents(Object pixel, int[] components,
0746: int offset) {
0747: throw new IllegalArgumentException(JaiI18N
0748: .getString("FloatDoubleColorModel9"));
0749: }
0750:
0751: /**
0752: * Throws an <code>IllegalArgumentException</code>, since pixel
0753: * values for this <code>ColorModel</code> are not conveniently
0754: * representable as a single <code>int</code>.
0755: */
0756: public int getDataElement(int[] components, int offset) {
0757: throw new IllegalArgumentException(JaiI18N
0758: .getString("FloatDoubleColorModel9"));
0759: }
0760:
0761: /**
0762: * Returns a data element array representation of a pixel in this
0763: * <code>ColorModel</code>, given an array of unnormalized
0764: * color/alpha components. This array can then be passed to the
0765: * <code>setDataElements</code> method of a
0766: * <code>WritableRaster</code> object.
0767: *
0768: * @param components An array of unnormalized color/alpha
0769: * components.
0770: * @param offset The integer offset into the
0771: * <code>components</code> array.
0772: * @param obj The object in which to store the data element array
0773: * representation of the pixel. If <code>obj</code> variable is
0774: * null, a new array is allocated. If <code>obj</code> is not
0775: * null, it must be a primitive array of type
0776: * <code>transferType</code>. An
0777: * <code>ArrayIndexOutOfBoundsException</code> is thrown if
0778: * <code>obj</code> is not large enough to hold a pixel value for
0779: * this <code>ColorModel</code>.
0780: *
0781: * @return The data element array representation of a pixel
0782: * in this <code>ColorModel</code>.
0783: *
0784: * @throws IllegalArgumentException If the components array
0785: * is not large enough to hold all the color and alpha components
0786: * (starting at offset).
0787: * @throws ClassCastException If <code>obj</code> is not null and
0788: * is not a primitive array of type <code>transferType</code>.
0789: * @throws ArrayIndexOutOfBoundsException If <code>obj</code> is
0790: * not large enough to hold a pixel value for this
0791: * <code>ColorModel</code>.
0792: */
0793: public Object getDataElements(int[] components, int offset,
0794: Object obj) {
0795: if ((components.length - offset) < numComponents) {
0796: throw new IllegalArgumentException(numComponents + " "
0797: + JaiI18N.getString("FloatDoubleColorModel10"));
0798: }
0799: if (transferType == DataBuffer.TYPE_FLOAT) {
0800: float[] pixel;
0801: if (obj == null) {
0802: pixel = new float[components.length];
0803: } else {
0804: pixel = (float[]) obj;
0805: }
0806: for (int i = 0; i < numComponents; i++) {
0807: pixel[i] = (float) (components[offset + i]);
0808: }
0809:
0810: return pixel;
0811: } else {
0812: double[] pixel;
0813: if (obj == null) {
0814: pixel = new double[components.length];
0815: } else {
0816: pixel = (double[]) obj;
0817: }
0818: for (int i = 0; i < numComponents; i++) {
0819: pixel[i] = (double) (components[offset + i]);
0820: }
0821:
0822: return pixel;
0823: }
0824: }
0825:
0826: /**
0827: * Forces the <code>raster</code> data to match the state specified in the
0828: * <code>isAlphaPremultiplied</code> variable, assuming the data
0829: * is currently correctly described by this <code>ColorModel</code>.
0830: * It may multiply or divide the color <code>raster</code> data by alpha, or
0831: * do nothing if the data is in the correct state. If the data needs
0832: * to be coerced, this method also returns an instance of
0833: * <code>FloatDoubleColorModel</code> with
0834: * the <code>isAlphaPremultiplied</code> flag set appropriately.
0835: *
0836: * @throws IllegalArgumentException if transfer type of
0837: * <code>raster</code> is not the same as that of this
0838: * <code>FloatDoubleColorModel</code>.
0839: */
0840: public ColorModel coerceData(WritableRaster raster,
0841: boolean isAlphaPremultiplied) {
0842: if ((hasAlpha == false)
0843: || (this .isAlphaPremultiplied == isAlphaPremultiplied)) {
0844: // Nothing to do
0845: return this ;
0846: }
0847:
0848: int w = raster.getWidth();
0849: int h = raster.getHeight();
0850: int aIdx = raster.getNumBands() - 1;
0851: int rminX = raster.getMinX();
0852: int rY = raster.getMinY();
0853: int rX;
0854:
0855: if (raster.getTransferType() != transferType) {
0856: throw new IllegalArgumentException(JaiI18N
0857: .getString("FloatDoubleColorModel6"));
0858: }
0859:
0860: if (isAlphaPremultiplied) {
0861: switch (transferType) {
0862: case DataBuffer.TYPE_FLOAT: {
0863: float pixel[] = null;
0864: for (int y = 0; y < h; y++, rY++) {
0865: rX = rminX;
0866: for (int x = 0; x < w; x++, rX++) {
0867: pixel = (float[]) raster.getDataElements(rX,
0868: rY, pixel);
0869: float fAlpha = pixel[aIdx];
0870: if (fAlpha != 0) {
0871: for (int c = 0; c < aIdx; c++) {
0872: pixel[c] *= fAlpha;
0873: }
0874: raster.setDataElements(rX, rY, pixel);
0875: }
0876: }
0877: }
0878: }
0879: break;
0880:
0881: case DataBuffer.TYPE_DOUBLE: {
0882: double pixel[] = null;
0883: for (int y = 0; y < h; y++, rY++) {
0884: rX = rminX;
0885: for (int x = 0; x < w; x++, rX++) {
0886: pixel = (double[]) raster.getDataElements(rX,
0887: rY, pixel);
0888: double dAlpha = pixel[aIdx];
0889: if (dAlpha != 0) {
0890: for (int c = 0; c < aIdx; c++) {
0891: pixel[c] *= dAlpha;
0892: }
0893: raster.setDataElements(rX, rY, pixel);
0894: }
0895: }
0896: }
0897: }
0898: break;
0899:
0900: default:
0901: throw new RuntimeException(JaiI18N
0902: .getString("FloatDoubleColorModel0"));
0903: }
0904:
0905: if (isAlphaPremultiplied) {
0906:
0907: }
0908: } else {
0909: // We are premultiplied and want to divide it out
0910: switch (transferType) {
0911: case DataBuffer.TYPE_FLOAT: {
0912: for (int y = 0; y < h; y++, rY++) {
0913: rX = rminX;
0914: for (int x = 0; x < w; x++, rX++) {
0915: float pixel[] = null;
0916: pixel = (float[]) raster.getDataElements(rX,
0917: rY, pixel);
0918: float fAlpha = pixel[aIdx];
0919: if (fAlpha != 0) {
0920: float invFAlpha = 1.0F / fAlpha;
0921: for (int c = 0; c < aIdx; c++) {
0922: pixel[c] *= invFAlpha;
0923: }
0924: }
0925: raster.setDataElements(rX, rY, pixel);
0926: }
0927: }
0928: }
0929: break;
0930:
0931: case DataBuffer.TYPE_DOUBLE: {
0932: for (int y = 0; y < h; y++, rY++) {
0933: rX = rminX;
0934: for (int x = 0; x < w; x++, rX++) {
0935: double pixel[] = null;
0936: pixel = (double[]) raster.getDataElements(rX,
0937: rY, pixel);
0938: double dAlpha = pixel[aIdx];
0939: if (dAlpha != 0) {
0940: double invDAlpha = 1.0 / dAlpha;
0941: for (int c = 0; c < aIdx; c++) {
0942: pixel[c] *= invDAlpha;
0943: }
0944: }
0945: raster.setDataElements(rX, rY, pixel);
0946: }
0947: }
0948: }
0949: break;
0950:
0951: default:
0952: throw new RuntimeException(JaiI18N
0953: .getString("FloatDoubleColorModel0"));
0954: }
0955: }
0956:
0957: // Return a new color model
0958: return new FloatDoubleColorModel(colorSpace, hasAlpha,
0959: isAlphaPremultiplied, transparency, transferType);
0960: }
0961:
0962: /**
0963: * Returns <code>true</code> if the supplied <code>Raster</code>'s
0964: * <code>SampleModel</code> is compatible with this
0965: * <code>FloatDoubleColorModel</code>.
0966: *
0967: * @param raster a <code>Raster</code>to be checked for compatibility.
0968: */
0969: public boolean isCompatibleRaster(Raster raster) {
0970: SampleModel sm = raster.getSampleModel();
0971: return isCompatibleSampleModel(sm);
0972: }
0973:
0974: /**
0975: * Creates a <code>WritableRaster</code> with the specified width
0976: * and height, that has a data layout (<code>SampleModel</code>)
0977: * compatible with this <code>ColorModel</code>. The returned
0978: * <code>WritableRaster</code>'s <code>SampleModel</code> will be
0979: * an instance of <code>ComponentSampleModel</code>.
0980: *
0981: * @param w The width of the <code>WritableRaster</code>
0982: * @param h The height of the <code>WritableRaster</code>
0983: *
0984: * @return A <code>WritableRaster</code> that is compatible with
0985: * this <code>ColorModel</code>.
0986: *
0987: * @see java.awt.image.WritableRaster
0988: * @see java.awt.image.SampleModel
0989: */
0990: public WritableRaster createCompatibleWritableRaster(int w, int h) {
0991: SampleModel sm = createCompatibleSampleModel(w, h);
0992: return RasterFactory.createWritableRaster(sm, new Point(0, 0));
0993: }
0994:
0995: /**
0996: * Creates a <code>SampleModel</code> with the specified width and
0997: * height that has a data layout compatible with this
0998: * <code>ColorModel</code>. The returned <code>SampleModel</code>
0999: * will be an instance of <code>ComponentSampleModel</code>.
1000: *
1001: * @param w The width of the <code>SampleModel</code>.
1002: * @param h The height of the <code>SampleModel</code>.
1003: *
1004: * @return A <code>SampleModel</code> that is compatible with this
1005: * <code>ColorModel</code>.
1006: *
1007: * @see java.awt.image.SampleModel
1008: * @see java.awt.image.ComponentSampleModel
1009: */
1010: public SampleModel createCompatibleSampleModel(int w, int h) {
1011: int[] bandOffsets = new int[numComponents];
1012: for (int i = 0; i < numComponents; i++) {
1013: bandOffsets[i] = i;
1014: }
1015: return new ComponentSampleModelJAI(transferType, w, h,
1016: numComponents, w * numComponents, bandOffsets);
1017: }
1018:
1019: /**
1020: * Checks whether or not the specified <code>SampleModel</code> is
1021: * compatible with this <code>ColorModel</code>. A
1022: * <code>SampleModel</code> is compatible if it is an instance of
1023: * <code>ComponentSampleModel</code>, has the sample number of
1024: * bands as the total number of components (including alpha) in
1025: * the <code>ColorSpace</code> used by this
1026: * <code>ColorModel</code>, and has the same data type (float or
1027: * double) as this <code>ColorModel</code>.
1028: *
1029: * @param sm The <code>SampleModel</code> to test for compatibility.
1030: *
1031: * @return <code>true</code> if the <code>SampleModel</code> is
1032: * compatible with this <code>ColorModel</code>,
1033: * <code>false</code> if it is not.
1034: *
1035: * @see java.awt.image.SampleModel
1036: * @see java.awt.image.ComponentSampleModel
1037: */
1038: public boolean isCompatibleSampleModel(SampleModel sm) {
1039: if (sm instanceof ComponentSampleModel) {
1040: if (sm.getNumBands() != getNumComponents()) {
1041: return false;
1042: }
1043: if (sm.getDataType() != transferType) {
1044: return false;
1045: }
1046: return true;
1047: } else {
1048: return false;
1049: }
1050: }
1051:
1052: /** Returns a <code>String</code> containing the values of all valid fields. */
1053: public String toString() {
1054: return "FloatDoubleColorModel: " + super.toString();
1055: }
1056: }
|