0001: /*
0002: * $RCSfile: PixelAccessor.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.1 $
0009: * $Date: 2005/02/11 04:57:15 $
0010: * $State: Exp $
0011: */
0012: package javax.media.jai;
0013:
0014: import java.awt.Rectangle;
0015: import java.awt.image.ColorModel;
0016: import java.awt.image.ComponentColorModel;
0017: import java.awt.image.ComponentSampleModel;
0018: import java.awt.image.DataBuffer;
0019: import java.awt.image.DataBufferByte;
0020: import java.awt.image.DataBufferInt;
0021: import java.awt.image.DataBufferShort;
0022: import java.awt.image.DataBufferUShort;
0023: import java.awt.image.IndexColorModel;
0024: import java.awt.image.MultiPixelPackedSampleModel;
0025: import java.awt.image.PackedColorModel;
0026: import java.awt.image.Raster;
0027: import java.awt.image.RenderedImage;
0028: import java.awt.image.SampleModel;
0029: import java.awt.image.SinglePixelPackedSampleModel;
0030: import java.awt.image.WritableRaster;
0031: import java.util.Vector;
0032: import com.sun.media.jai.util.DataBufferUtils;
0033: import com.sun.media.jai.util.ImageUtil;
0034: import com.sun.media.jai.util.JDKWorkarounds;
0035:
0036: /**
0037: * This is a utility class that may be used to access the pixel data
0038: * stored in a <code>RenderedImage</code>'s <code>Raster</code>s, as
0039: * well as performing pixel-to-color data translation based on the
0040: * image's <code>SampleModel</code> and <code>ColorModel</code>. It
0041: * also provides several static methods to determine information about
0042: * the image data.
0043: *
0044: * <p> This class is intended to help classes that need to access the
0045: * pixel and/or color data of a <code>RenderedImage</code>, such as an
0046: * <code>OpImage</code>, in an optimized fashion. Most of the variables
0047: * defined in this class are public so that other classes may use them
0048: * directly. However, the variables are also declared <code>final</code>
0049: * so that other classes can not modify their values.
0050: *
0051: * <p> In general, the pixel data of a <code>RenderedImage</code> may
0052: * be obtained by calling the <code>getPixels()</code> method. By
0053: * definition, the <i>pixel data</i> of an image are the data described
0054: * by the image's <code>SampleModel</code> and stored in the image's
0055: * <code>Raster</code>s. No consideration of any kind is given to the
0056: * image's <code>ColorModel</code>. If no error is found, the pixel
0057: * data are returned in the primitive arrays of the type specified by
0058: * the caller in an unpacked format, along with access information.
0059: * Therefore, the specified data type must be one of the valid types
0060: * defined in <code>DataBuffer</code> and large enough (in bit depth)
0061: * to hold the pixel data of the image.
0062: *
0063: * <p> The pixel data of a binary image may be obtained in a packed
0064: * format by calling the <code>getPackedPixels()</code> method. It
0065: * returns the data in a packed <code>byte</code> array, with 8 pixels
0066: * packed into 1 byte. The format of the data in the array is
0067: * similar to the format described by the
0068: * <code>MultiPixelPackedSampleModel</code>, where the end of each
0069: * scanline is padded to the end of the byte if necessary. Note that this
0070: * method returns a valid result only if and only if the image is a
0071: * single-band bit image, that is, each pixel has only 1 sample with a
0072: * sample size of 1 bit.
0073: *
0074: * <p> Two corresponding "set" methods are also provided for setting the
0075: * computed pixel data back into the <code>Raster</code>'s
0076: * <code>DataBuffer</code>: <code>setPixels()</code> for unpacked data,
0077: * and <code>setPackedPixels()</code> for packed data. It is very
0078: * important that the caller uses the correct "set" method that matches
0079: * the "get" method used to obtain the data, or errors will occur.
0080: *
0081: * <p> The color/alpha data of the <code>RenderedImage</code> may be
0082: * obtained by calling the <code>getComponents()</code> method which
0083: * returns the unnormalized data in the <code>ColorSpace</code> specified
0084: * in the <code>ColorModel</code>, or the <code>getComponentsRGB()</code>
0085: * method which returns the data scaled from 0 to 255 in the default sRGB
0086: * <code>ColorSpace</code>. These methods retrieve the pixel data from
0087: * the <code>Raster</code>, and perform the pixel-to-color translation.
0088: * Therefore, in order for these two methods to return a valid result, the
0089: * image must have a valid <code>ColorModel</code>.
0090: *
0091: * <p> Similarly, two "set" methods may be used to perform the
0092: * color-to-pixel translation, and set the pixel data back to the
0093: * <code>Raster</code>'s <code>DataBuffer</code>. Again, it is important
0094: * that the "get" and "set" methods are matched up correctly.
0095: *
0096: * <p> In addition, several static methods are included in this class
0097: * for the convenience of <code>OpImage</code> developers, who may use them to
0098: * help determine the appropriate destination <code>SampleModel</code>
0099: * type.
0100: *
0101: * @since JAI 1.1
0102: *
0103: */
0104: public final class PixelAccessor {
0105:
0106: /** Tag for single-bit data type. */
0107: public static final int TYPE_BIT = -1;
0108:
0109: /** The image's <code>SampleModel</code>. */
0110: public final SampleModel sampleModel;
0111:
0112: /** The image's <code>ColorModel</code>. */
0113: public final ColorModel colorModel;
0114:
0115: // The following information comes from the image's SampleModel.
0116:
0117: /**
0118: * <code>true</code> if the image has a
0119: * <code>ComponentSampleModel</code>;
0120: * <code>false</code> otherwise.
0121: */
0122: public final boolean isComponentSM;
0123:
0124: /**
0125: * <code>true</code> if the image has a
0126: * <code>MultiPixelPackedSampleModel</code>;
0127: * <code>false</code> otherwise.
0128: */
0129: public final boolean isMultiPixelPackedSM;
0130:
0131: /**
0132: * <code>true</code> if the image has a
0133: * <code>SinglePixelPackedSampleModel</code>;
0134: * <code>false</code> otherwise.
0135: */
0136: public final boolean isSinglePixelPackedSM;
0137:
0138: /** The data type of the pixel samples, determined based on the sample size. */
0139: public final int sampleType;
0140:
0141: /**
0142: * The type of the <code>DataBuffer</code>'s data array used to store the
0143: * pixel data by the image's <code>SampleModel</code>. This is the same
0144: * value as that returned by <code>SampleModel.getDataType()</code>.
0145: */
0146: public final int bufferType;
0147:
0148: /**
0149: * The type of the primitive array used to transfer the pixel data by
0150: * the image's <code>SampleModel</code>. This is the same value as
0151: * that returned by <code>SampleModel.getTransferType()</code>.
0152: */
0153: public final int transferType;
0154:
0155: /**
0156: * The number of bands (samples) per pixel. This is the same value
0157: * as that returned by <code>SampleModel.getNumBands()</code>.
0158: */
0159: public final int numBands;
0160:
0161: /**
0162: * The size, in number of bits, of all the pixel samples. This is
0163: * the same array as that returned by
0164: * <code>SampleModel.getSampleSize()</code>.
0165: */
0166: public final int[] sampleSize;
0167:
0168: /**
0169: * Set to <code>true</code> if the pixel data of this image may be
0170: * packed into a <code>byte</code> array. That is, each pixel has
0171: * 1 sample (1 band) with a sample size of 1 bit. If this variable
0172: * is <code>true</code>, <code>getPackedPixels()</code> should return
0173: * a valid result, with 8 pixels packed into 1 byte.
0174: */
0175: public final boolean isPacked;
0176:
0177: // The following information come from the image's ColorModel.
0178:
0179: /**
0180: * Set to <code>true</code> if the image has a non-null
0181: * <code>ColorModel</code> which is compatible with the image's
0182: * <code>SampleModel</code>; <code>false</code> otherwise.
0183: */
0184: public final boolean hasCompatibleCM;
0185:
0186: /**
0187: * Set to <code>true</code> if the image has a
0188: * <code>ComponentColorModel</code>;
0189: * <code>false</code> otherwise.
0190: */
0191: public final boolean isComponentCM;
0192:
0193: /**
0194: * Set to <code>true</code> if the image has an
0195: * <code>IndexColorModel</code>;
0196: * <code>false</code> otherwise.
0197: */
0198: public final boolean isIndexCM;
0199:
0200: /**
0201: * Set to <code>true</code> if the image has a
0202: * <code>PackedColorModel</code>;
0203: * <code>false</code> otherwise.
0204: */
0205: public final boolean isPackedCM;
0206:
0207: /**
0208: * The type of the color/alpha components, determined based on the
0209: * component size.
0210: */
0211: public final int componentType;
0212:
0213: /**
0214: * The total number of color/alpha components in the image's
0215: * <code>ColorModel</code>. This is the same value as that
0216: * returned by <code>ColorModel.getNumComponents()</code>.
0217: */
0218: public final int numComponents;
0219:
0220: /**
0221: * The size, in number of bits, of all the color/alpha components.
0222: * This is the same array as that returned by
0223: * <code>ColorModel.getComponentSize()</code>.
0224: */
0225: public final int[] componentSize;
0226:
0227: /**
0228: * Returns the image's <code>SampleModel</code>.
0229: *
0230: * @throws IllegalArgumentException if <code>image</code> is
0231: * <code>null</code>.
0232: */
0233: private static SampleModel getSampleModel(RenderedImage image) {
0234: if (image == null) {
0235: throw new IllegalArgumentException(JaiI18N
0236: .getString("Generic0"));
0237: }
0238: return image.getSampleModel();
0239: }
0240:
0241: /**
0242: * Constructs a <code>PixelAccessor</code> from a
0243: * <code>RenderedImage</code>.
0244: * The <code>RenderedImage</code> must have a valid
0245: * <code>SampleModel</code>, but may or may not have a valid
0246: * <code>ColorModel</code>.
0247: *
0248: * @param image The image whose data are to be accessed.
0249: *
0250: * @throws IllegalArgumentException If <code>image</code> is
0251: * <code>null</code>, or if the image does not have a valid
0252: * <code>SampleModel</code>.
0253: */
0254: public PixelAccessor(RenderedImage image) {
0255: this (getSampleModel(image), image.getColorModel());
0256: }
0257:
0258: /**
0259: * Constructs a <code>PixelAccessor</code> given a valid
0260: * <code>SampleModel</code> and a (possibly <code>null</code>)
0261: * <code>ColorModel</code>.
0262: *
0263: * @param sm The <code>SampleModel</code> for the image to be accessed.
0264: * Must be valid.
0265: * @param cm The <code>ColorModel</code> for the image to be accessed.
0266: * May be null.
0267: * @throws IllegalArgumentException If <code>sm</code> is <code>null</code>.
0268: */
0269: public PixelAccessor(SampleModel sm, ColorModel cm) {
0270:
0271: if (sm == null) {
0272: throw new IllegalArgumentException(JaiI18N
0273: .getString("Generic0"));
0274: }
0275:
0276: sampleModel = sm;
0277: colorModel = cm;
0278:
0279: // Information from the SampleModel.
0280: isComponentSM = sampleModel instanceof ComponentSampleModel;
0281: isMultiPixelPackedSM = sampleModel instanceof MultiPixelPackedSampleModel;
0282: isSinglePixelPackedSM = sampleModel instanceof SinglePixelPackedSampleModel;
0283:
0284: bufferType = sampleModel.getDataType();
0285: transferType = sampleModel.getTransferType();
0286: numBands = sampleModel.getNumBands();
0287: sampleSize = sampleModel.getSampleSize();
0288: sampleType = isComponentSM ? bufferType : getType(sampleSize);
0289:
0290: // Indicates whether the pixel data may be stored in packed format.
0291: isPacked = sampleType == TYPE_BIT && numBands == 1;
0292:
0293: // Information from the ColorModel.
0294: hasCompatibleCM = colorModel != null
0295: && JDKWorkarounds.areCompatibleDataModels(sampleModel,
0296: colorModel);
0297:
0298: if (hasCompatibleCM) {
0299: isComponentCM = colorModel instanceof ComponentColorModel;
0300: isIndexCM = colorModel instanceof IndexColorModel;
0301: isPackedCM = colorModel instanceof PackedColorModel;
0302:
0303: numComponents = colorModel.getNumComponents();
0304: componentSize = colorModel.getComponentSize();
0305: int tempType = getType(componentSize);
0306:
0307: componentType = (tempType == TYPE_BIT) ? DataBuffer.TYPE_BYTE
0308: : tempType;
0309: } else {
0310: isComponentCM = false;
0311: isIndexCM = false;
0312: isPackedCM = false;
0313: numComponents = numBands;
0314: componentSize = sampleSize;
0315: componentType = sampleType;
0316: }
0317: }
0318:
0319: /**
0320: * Determines the data type based on the data sizes in number of bits.
0321: * Note that for data size between 9 and 16, this method returns
0322: * <code>TYPE_USHORT</code>, and for size between 17 and 32, this
0323: * method returns <code>TYPE_INT</code>. The minimum valid size is 1,
0324: * and the maximum valid size is 64.
0325: *
0326: * @param size An array containing the bit width of each band.
0327: * @return The minimum size data type which can hold any band.
0328: */
0329: private static int getType(int[] size) {
0330: int maxSize = size[0]; // maximum sample size
0331: for (int i = 1; i < size.length; i++) {
0332: maxSize = Math.max(maxSize, size[i]);
0333: }
0334:
0335: int type;
0336: if (maxSize < 1) {
0337: type = DataBuffer.TYPE_UNDEFINED;
0338: } else if (maxSize == 1) {
0339: type = TYPE_BIT;
0340: } else if (maxSize <= 8) {
0341: type = DataBuffer.TYPE_BYTE;
0342: } else if (maxSize <= 16) {
0343: type = DataBuffer.TYPE_USHORT;
0344: } else if (maxSize <= 32) {
0345: type = DataBuffer.TYPE_INT;
0346: } else if (maxSize <= 64) {
0347: type = DataBuffer.TYPE_DOUBLE;
0348: } else {
0349: type = DataBuffer.TYPE_UNDEFINED;
0350: }
0351: return type;
0352: }
0353:
0354: /**
0355: * Determines the pixel type based on the <code>SampleModel</code>.
0356: * The pixel type signifies the data type for a <code>PixelAccessor</code>.
0357: * For <code>ComponentSampleModel</code>, the pixel type is the same
0358: * as the type of the <code>DataBuffer</code> used to store the pixel
0359: * data. For all other types of <code>SampleModel</code>, the pixel
0360: * type is determined based on the sample sizes.
0361: *
0362: * @param sm The <code>SampleModel</code> of the image.
0363: * @return The pixel type for this sample model.
0364: */
0365: public static int getPixelType(SampleModel sm) {
0366: return sm instanceof ComponentSampleModel ? sm.getDataType()
0367: : getType(sm.getSampleSize());
0368: }
0369:
0370: /**
0371: * Returns the largest data type of all the sources. This method
0372: * may be used to determine the pixel sample type of a destination
0373: * in the default situation. It guarantees that the destination can
0374: * store the resulting pixel values without losing any precision.
0375: * The pixel type signifies the data type for a <code>PixelAccessor</code>.
0376: *
0377: * <p> If all the sources are single-bit images, this method returns
0378: * <code>TYPE_BIT</code> (defined in this class) so that the
0379: * destination does not use unnecessary memory for some operations.
0380: * This includes all images whose <code>SampleModel</code> is
0381: * single-banded and whose sample size is 1, regardless of the type
0382: * of <code>ColorModel</code> the image may have.
0383: * If an operation does not wish to deal with packed data, it
0384: * should use <code>TYPE_BYTE</code> for pixel computation.
0385: *
0386: * <p> If there is no object in the source <code>Vector</code>, this
0387: * method returns <code>TYPE_UNDEFINED</code>. All the objects in
0388: * the source <code>Vector</code> must be <code>RenderedImage</code>s.
0389: *
0390: * <p> When determining the result, only information from each image's
0391: * <code>SampleModel</code> is used. No consideration is given to the
0392: * image's <code>ColorModel</code>.
0393: *
0394: * @param sources A <code>Vector</code> of <code>RenderedImage</code>
0395: * sources.
0396: * @return The largest data type which can accomodate all sources.
0397: * @throws IllegalArgumentException If <code>sources</code> is
0398: * <code>null</code>.
0399: * @throws ClassCastException If any object in <code>sources</code>
0400: * is not a <code>RenderedImage</code>.
0401: */
0402: public static int getDestPixelType(Vector sources) {
0403:
0404: if (sources == null) {
0405: throw new IllegalArgumentException(JaiI18N
0406: .getString("Generic0"));
0407: }
0408:
0409: int type = DataBuffer.TYPE_UNDEFINED;
0410: int size = sources.size();
0411:
0412: if (size > 0) {
0413: RenderedImage src = (RenderedImage) sources.get(0);
0414: SampleModel sm = src.getSampleModel();
0415:
0416: type = getPixelType(sm);
0417:
0418: for (int i = 1; i < size; i++) {
0419: src = (RenderedImage) sources.get(i);
0420: sm = src.getSampleModel();
0421:
0422: int t = getPixelType(sm);
0423:
0424: // Only int can handle ushort/short combination.
0425: type = (type == DataBuffer.TYPE_USHORT && t == DataBuffer.TYPE_SHORT)
0426: || (type == DataBuffer.TYPE_SHORT && t == DataBuffer.TYPE_USHORT) ? DataBuffer.TYPE_INT
0427: : Math.max(type, t);
0428: }
0429: }
0430: return type;
0431: }
0432:
0433: /**
0434: * Returns the smallest number of bands of all the sources.
0435: * This method may be used to determine the number of bands a
0436: * destination should have in the default situation. It guarantees
0437: * that every destination band has a corresponding source band.
0438: *
0439: * <p> In general, if an operation has multiple sources, and some
0440: * sources have 1 band and others have multiple bands, the single
0441: * band may be applied to the multiple bands one at a time. (An
0442: * example of this would be the <code>MultiplyOpImage</code>). Therefore,
0443: * in such a case, this method returns the smallest band count among the
0444: * multi-band sources.
0445: *
0446: * <p> If there is no object in the source <code>Vector</code>, this
0447: * method returns 0. All the objects in the source <code>Vector</code>
0448: * must be <code>RenderedImage</code>s.
0449: *
0450: * <p> When determining the result, only information from each image's
0451: * <code>SampleModel</code> are used. No consideration is given to the
0452: * image's <code>ColorModel</code>.
0453: *
0454: * @param sources A <code>Vector</code> of <code>RenderedImage</code>
0455: * sources.
0456: * @return The minimum number of destination bands.
0457: * @throws IllegalArgumentException If <code>sources</code> is
0458: * <code>null</code>.
0459: * @throws ClassCastException If any object in <code>sources</code>
0460: * is not a <code>RenderedImage</code>.
0461: */
0462: public static int getDestNumBands(Vector sources) {
0463:
0464: if (sources == null) {
0465: throw new IllegalArgumentException(JaiI18N
0466: .getString("Generic0"));
0467: }
0468:
0469: int bands = 0;
0470: int size = sources.size();
0471:
0472: if (size > 0) {
0473: RenderedImage src = (RenderedImage) sources.get(0);
0474: SampleModel sm = src.getSampleModel();
0475:
0476: bands = sm.getNumBands();
0477:
0478: for (int i = 1; i < size; i++) {
0479: src = (RenderedImage) sources.get(i);
0480: sm = src.getSampleModel();
0481:
0482: int b = sm.getNumBands();
0483:
0484: bands = bands == 1 || b == 1 ? Math.max(bands, b)
0485: : Math.min(bands, b);
0486: }
0487: }
0488: return bands;
0489: }
0490:
0491: /**
0492: * Returns <code>true</code> if the destination and/or all the
0493: * sources are single-bit, single-band images, and their pixel
0494: * data may be packed into a <code>byte</code> array.
0495: * If so, then the operations may be done in the packed format.
0496: * @param srcs The array of source <code>PixelAccesor</code>s.
0497: * @param dst The destination <code>PixelAccesor</code>.
0498: * @return <code>true</code> if a packed operation is possible.
0499: */
0500: public static boolean isPackedOperation(PixelAccessor[] srcs,
0501: PixelAccessor dst) {
0502: boolean canBePacked = dst.isPacked;
0503: if (canBePacked && srcs != null) {
0504: for (int i = 0; i < srcs.length; i++) {
0505: canBePacked = canBePacked && srcs[i].isPacked;
0506: if (!canBePacked) { // no need to check further
0507: break;
0508: }
0509: }
0510: }
0511: return canBePacked;
0512: }
0513:
0514: /**
0515: * Returns <code>true</code> if the destination and the source
0516: * are both single-bit, single-band images, and their pixel
0517: * data may be packed into a <code>byte</code> array.
0518: * If so, then the operations may be done in the packed format.
0519: * @param srcs The source <code>PixelAccesor</code>.
0520: * @param dst The destination <code>PixelAccesor</code>.
0521: * @return <code>true</code> if a packed operation is possible.
0522: */
0523: public static boolean isPackedOperation(PixelAccessor src,
0524: PixelAccessor dst) {
0525: return src.isPacked && dst.isPacked;
0526: }
0527:
0528: /**
0529: * Returns <code>true</code> if the destination and both sources
0530: * are all single-bit, single-band images, and their pixel
0531: * data may be packed into a <code>byte</code> array.
0532: * If so, then the operations may be done in the packed format.
0533: * @param src1 The first source <code>PixelAccesor</code>.
0534: * @param src2 The second source <code>PixelAccesor</code>.
0535: * @param dst The destination <code>PixelAccesor</code>.
0536: * @return <code>true</code> if a packed operation is possible.
0537: */
0538: public static boolean isPackedOperation(PixelAccessor src1,
0539: PixelAccessor src2, PixelAccessor dst) {
0540: return src1.isPacked && src2.isPacked && dst.isPacked;
0541: }
0542:
0543: /**
0544: * Returns a region of the pixel data within a <code>Raster</code>
0545: * in an unpacked primitive array. The returned data are
0546: * retrieved from the <code>Raster</code>'s <code>DataBuffer</code>;
0547: * no pixel-to-color translation is performed.
0548: *
0549: * <p> The primitive array is of the type specified by the
0550: * <code>type</code> argument. It must be one of the valid data
0551: * types defined in <code>DataBuffer</code> and large (in bit depth)
0552: * enough to hold the pixel samples, or an exception will be thrown.
0553: * This means <code>type</code> should be greater than or equal to
0554: * <code>sampleType</code>.
0555: *
0556: * <p> The <code>Rectangle</code> specifies the region of interest
0557: * within which the pixel data are to be retrieved. It must be
0558: * completely inside the <code>Raster</code>'s boundary, or else
0559: * this method throws an exception.
0560: *
0561: * <p> This method tries to avoid copying data as much as possible.
0562: * If it is unable to reformat the pixel data in the way requested,
0563: * or if the pixels do not have enough data to satisfy the request,
0564: * this method throws an exception.
0565: *
0566: * @param raster The <code>Raster</code> that contains the pixel data.
0567: * @param rect The region of interest within the <code>Raster</code>
0568: * where the pixels are accessed.
0569: * @param type The type of the primitive array used to return the
0570: * pixel samples.
0571: * @param isDest Indicates whether this <code>Raster</code> is a
0572: * destination <code>Raster</code>. That is, its pixels have
0573: * not been computed.
0574: *
0575: * @return The pixel data in an <code>UnpackedImageData</code> object.
0576: * @throws IllegalArgumentException If <code>type</code> is not a
0577: * valid data type defined in <code>DataBuffer</code>, or
0578: * is not large enough to hold the pixel samples from the
0579: * specified <code>Raster</code>.
0580: * @throws IllegalArgumentException If <code>rect</code> is not
0581: * contained by the bounds of the specified <code>Raster</code>.
0582: */
0583: public UnpackedImageData getPixels(Raster raster, Rectangle rect,
0584: int type, boolean isDest) {
0585: if (!raster.getBounds().contains(rect)) {
0586: throw new IllegalArgumentException(JaiI18N
0587: .getString("PixelAccessor0"));
0588: }
0589:
0590: if (type < DataBuffer.TYPE_BYTE
0591: || type > DataBuffer.TYPE_DOUBLE) { // unknown data type
0592: throw new IllegalArgumentException(JaiI18N
0593: .getString("PixelAccessor1"));
0594: }
0595:
0596: if (type < sampleType
0597: || (sampleType == DataBuffer.TYPE_USHORT && type == DataBuffer.TYPE_SHORT)) { // type not large enough
0598: throw new IllegalArgumentException(JaiI18N
0599: .getString("PixelAccessor2"));
0600: }
0601:
0602: if (isComponentSM) {
0603: return getPixelsCSM(raster, rect, type, isDest);
0604:
0605: } else {
0606: // The total number of data elements needed.
0607: int size = rect.width * rect.height * numBands;
0608:
0609: Object data = null;
0610:
0611: switch (type) {
0612: case DataBuffer.TYPE_BYTE:
0613: byte[] bd;
0614:
0615: if (isDest) {
0616: bd = new byte[size];
0617: } else {
0618: if (isMultiPixelPackedSM
0619: && transferType == DataBuffer.TYPE_BYTE) {
0620: bd = (byte[]) raster.getDataElements(rect.x,
0621: rect.y, rect.width, rect.height, null);
0622: } else {
0623: bd = new byte[size];
0624: int[] d = raster.getPixels(rect.x, rect.y,
0625: rect.width, rect.height, (int[]) null);
0626: for (int i = 0; i < size; i++) {
0627: bd[i] = (byte) (d[i] & 0xff);
0628: }
0629: }
0630: }
0631:
0632: data = repeatBand(bd, numBands);
0633: break;
0634:
0635: case DataBuffer.TYPE_USHORT:
0636: short[] usd;
0637:
0638: if (isDest) {
0639: usd = new short[size];
0640: } else {
0641: if (isMultiPixelPackedSM
0642: && transferType == DataBuffer.TYPE_USHORT) {
0643: usd = (short[]) raster.getDataElements(rect.x,
0644: rect.y, rect.width, rect.height, null);
0645: } else {
0646: usd = new short[size];
0647: int[] d = raster.getPixels(rect.x, rect.y,
0648: rect.width, rect.height, (int[]) null);
0649: for (int i = 0; i < size; i++) {
0650: usd[i] = (short) (d[i] & 0xffff);
0651: }
0652: }
0653: }
0654:
0655: data = repeatBand(usd, numBands);
0656: break;
0657:
0658: case DataBuffer.TYPE_SHORT:
0659: short[] sd = new short[size];
0660:
0661: if (!isDest) {
0662: int[] d = raster.getPixels(rect.x, rect.y,
0663: rect.width, rect.height, (int[]) null);
0664: for (int i = 0; i < size; i++) {
0665: sd[i] = (short) d[i];
0666: }
0667: }
0668:
0669: data = repeatBand(sd, numBands);
0670: break;
0671:
0672: case DataBuffer.TYPE_INT:
0673: return getPixelsInt(raster, rect, isDest);
0674:
0675: case DataBuffer.TYPE_FLOAT:
0676: return getPixelsFloat(raster, rect, isDest);
0677:
0678: case DataBuffer.TYPE_DOUBLE:
0679: return getPixelsDouble(raster, rect, isDest);
0680: }
0681:
0682: return new UnpackedImageData(raster, rect, type, data,
0683: numBands, numBands * rect.width,
0684: getInterleavedOffsets(numBands), isDest
0685: & (raster instanceof WritableRaster));
0686: }
0687: }
0688:
0689: /**
0690: * Returns the pixel data in a pixel-interleaved, unpacked array
0691: * where the <code>Raster</code> has a <code>ComponentSampleModel</code>.
0692: * @return The pixel data in an <code>UnpackedImageData</code> object.
0693: */
0694: private UnpackedImageData getPixelsCSM(Raster raster,
0695: Rectangle rect, int type, boolean isDest) {
0696: Object data = null;
0697: int pixelStride, lineStride;
0698: int[] offsets;
0699: boolean set;
0700:
0701: //ComponentSampleModel sm = (ComponentSampleModel)sampleModel;
0702: // For bug 4696966: when the raster bounds is not coincide with a
0703: // tile bounds.
0704: ComponentSampleModel sm = (ComponentSampleModel) raster
0705: .getSampleModel();
0706:
0707: if (type == sampleType) {
0708: // Data are stored in the requested array type; no need to copy.
0709:
0710: DataBuffer db = raster.getDataBuffer();
0711: int[] bankIndices = sm.getBankIndices();
0712:
0713: switch (sampleType) {
0714: case DataBuffer.TYPE_BYTE:
0715: byte[][] bbd = ((DataBufferByte) db).getBankData();
0716: byte[][] bd = new byte[numBands][];
0717:
0718: for (int b = 0; b < numBands; b++) {
0719: bd[b] = bbd[bankIndices[b]];
0720: }
0721: data = bd;
0722: break;
0723:
0724: case DataBuffer.TYPE_USHORT:
0725: case DataBuffer.TYPE_SHORT:
0726: short[][] sbd = sampleType == DataBuffer.TYPE_USHORT ? ((DataBufferUShort) db)
0727: .getBankData()
0728: : ((DataBufferShort) db).getBankData();
0729: short[][] sd = new short[numBands][];
0730:
0731: for (int b = 0; b < numBands; b++) {
0732: sd[b] = sbd[bankIndices[b]];
0733: }
0734: data = sd;
0735: break;
0736:
0737: case DataBuffer.TYPE_INT:
0738: int[][] ibd = ((DataBufferInt) db).getBankData();
0739: int[][] id = new int[numBands][];
0740:
0741: for (int b = 0; b < numBands; b++) {
0742: id[b] = ibd[bankIndices[b]];
0743: }
0744: data = id;
0745: break;
0746:
0747: case DataBuffer.TYPE_FLOAT:
0748: float[][] fbd = DataBufferUtils.getBankDataFloat(db);
0749: float[][] fd = new float[numBands][];
0750:
0751: for (int b = 0; b < numBands; b++) {
0752: fd[b] = fbd[bankIndices[b]];
0753: }
0754: data = fd;
0755: break;
0756:
0757: case DataBuffer.TYPE_DOUBLE:
0758: double[][] dbd = DataBufferUtils.getBankDataDouble(db);
0759: double[][] dd = new double[numBands][];
0760:
0761: for (int b = 0; b < numBands; b++) {
0762: dd[b] = dbd[bankIndices[b]];
0763: }
0764: data = dd;
0765: break;
0766: }
0767:
0768: pixelStride = sm.getPixelStride();
0769: lineStride = sm.getScanlineStride();
0770:
0771: // Determine offsets.
0772: int[] dbOffsets = db.getOffsets(); // DataBuffer offsets
0773: int x = rect.x - raster.getSampleModelTranslateX();
0774: int y = rect.y - raster.getSampleModelTranslateY();
0775:
0776: offsets = new int[numBands];
0777: for (int b = 0; b < numBands; b++) {
0778: offsets[b] = sm.getOffset(x, y, b)
0779: + dbOffsets[bankIndices[b]];
0780: }
0781:
0782: set = false; // no need to copy
0783:
0784: } else { // need to reformat data
0785: switch (type) {
0786: case DataBuffer.TYPE_INT:
0787: return getPixelsInt(raster, rect, isDest);
0788:
0789: case DataBuffer.TYPE_FLOAT:
0790: return getPixelsFloat(raster, rect, isDest);
0791:
0792: case DataBuffer.TYPE_DOUBLE:
0793: return getPixelsDouble(raster, rect, isDest);
0794:
0795: /*
0796: * Since the requested type must be greater than or equal to
0797: * sampleType, if type is byte, sampleType must also be byte,
0798: * because the smallest sampleType of ComponentSampleModel is
0799: * byte. This case falls into the above uncopied case.
0800: *
0801: * If the Raster is a destination, then the pixel data have
0802: * not been computed and stored in the buffer yet.
0803: * Just create a new array, but no need to copy anything.
0804: */
0805: default: // byte to ushort or short
0806: // The total number of data elements needed.
0807: int size = rect.width * rect.height * numBands;
0808:
0809: short[] sd = new short[size];
0810:
0811: if (!isDest) { // need to copy byte data
0812: // Only byte is smaller than short or ushort.
0813: UnpackedImageData uid = getPixelsCSM(raster, rect,
0814: sampleType, isDest);
0815: byte[][] bdata = uid.getByteData();
0816:
0817: for (int b = 0; b < numBands; b++) {
0818: byte[] bd = bdata[b]; // band data
0819: int lo = uid.getOffset(b); // line offset
0820:
0821: for (int i = b, h = 0; h < rect.height; h++) {
0822: int po = lo; // pixel offset
0823: lo += uid.lineStride;
0824:
0825: for (int w = 0; w < rect.width; w++) {
0826: sd[i] = (short) (bd[po] & 0xff);
0827:
0828: po += uid.pixelStride;
0829: i += numBands;
0830: }
0831: }
0832: }
0833: }
0834:
0835: data = repeatBand(sd, numBands);
0836: break;
0837: }
0838:
0839: pixelStride = numBands;
0840: lineStride = pixelStride * rect.width;
0841: offsets = getInterleavedOffsets(numBands);
0842: set = isDest & (raster instanceof WritableRaster);
0843: }
0844:
0845: return new UnpackedImageData(raster, rect, type, data,
0846: pixelStride, lineStride, offsets, set);
0847: }
0848:
0849: /**
0850: * Returns the pixel data in an pixel-interleaved, unpacked,
0851: * integer array.
0852: * @return The pixel data in an <code>UnpackedImageData</code> object.
0853: */
0854: private UnpackedImageData getPixelsInt(Raster raster,
0855: Rectangle rect, boolean isDest) {
0856: // The total number of data elements needed.
0857: int size = rect.width * rect.height * numBands;
0858:
0859: /*
0860: * If the Raster is destination, then the pixel data have
0861: * not been computed and stored in the buffer yet.
0862: * Just create a new array, but no need to copy anything.
0863: * Otherwise, copy the data from the Raster.
0864: */
0865: int[] d = isDest ? new int[size] : raster.getPixels(rect.x,
0866: rect.y, rect.width, rect.height, (int[]) null);
0867:
0868: return new UnpackedImageData(raster, rect, DataBuffer.TYPE_INT,
0869: repeatBand(d, numBands), numBands, numBands
0870: * rect.width, getInterleavedOffsets(numBands),
0871: isDest & (raster instanceof WritableRaster));
0872: }
0873:
0874: /**
0875: * Returns the pixel data in an pixel-interleaved, unpacked,
0876: * float array.
0877: * @return The pixel data in an <code>UnpackedImageData</code> object.
0878: */
0879: private UnpackedImageData getPixelsFloat(Raster raster,
0880: Rectangle rect, boolean isDest) {
0881: // The total number of data elements needed.
0882: int size = rect.width * rect.height * numBands;
0883:
0884: /*
0885: * If the Raster is destination, then the pixel data have
0886: * not been computed and stored in the buffer yet.
0887: * Just create a new array, but no need to copy anything.
0888: * Otherwise, copy the data from the Raster.
0889: */
0890: float[] d = isDest ? new float[size] : raster.getPixels(rect.x,
0891: rect.y, rect.width, rect.height, (float[]) null);
0892:
0893: return new UnpackedImageData(raster, rect,
0894: DataBuffer.TYPE_FLOAT, repeatBand(d, numBands),
0895: numBands, numBands * rect.width,
0896: getInterleavedOffsets(numBands), isDest
0897: & (raster instanceof WritableRaster));
0898: }
0899:
0900: /**
0901: * Returns the pixel data in an pixel-interleaved, unpacked,
0902: * double array.
0903: * @return The pixel data in an <code>UnpackedImageData</code> object.
0904: */
0905: private UnpackedImageData getPixelsDouble(Raster raster,
0906: Rectangle rect, boolean isDest) {
0907: // The total number of data elements needed.
0908: int size = rect.width * rect.height * numBands;
0909:
0910: /*
0911: * If the Raster is destination, then the pixel data have
0912: * not been computed and stored in the buffer yet.
0913: * Just create a new array, but no need to copy anything.
0914: * Otherwise, copy the data from the Raster.
0915: */
0916: double[] d = isDest ? new double[size] : raster.getPixels(
0917: rect.x, rect.y, rect.width, rect.height,
0918: (double[]) null);
0919:
0920: return new UnpackedImageData(raster, rect,
0921: DataBuffer.TYPE_DOUBLE, repeatBand(d, numBands),
0922: numBands, numBands * rect.width,
0923: getInterleavedOffsets(numBands), isDest
0924: & (raster instanceof WritableRaster));
0925: }
0926:
0927: /** Repeats a one-dimensional array into a two-dimensional array. */
0928: private byte[][] repeatBand(byte[] d, int numBands) {
0929: byte[][] data = new byte[numBands][];
0930: for (int i = 0; i < numBands; i++) {
0931: data[i] = d;
0932: }
0933: return data;
0934: }
0935:
0936: private short[][] repeatBand(short[] d, int numBands) {
0937: short[][] data = new short[numBands][];
0938: for (int i = 0; i < numBands; i++) {
0939: data[i] = d;
0940: }
0941: return data;
0942: }
0943:
0944: private int[][] repeatBand(int[] d, int numBands) {
0945: int[][] data = new int[numBands][];
0946: for (int i = 0; i < numBands; i++) {
0947: data[i] = d;
0948: }
0949: return data;
0950: }
0951:
0952: private float[][] repeatBand(float[] d, int numBands) {
0953: float[][] data = new float[numBands][];
0954: for (int i = 0; i < numBands; i++) {
0955: data[i] = d;
0956: }
0957: return data;
0958: }
0959:
0960: private double[][] repeatBand(double[] d, int numBands) {
0961: double[][] data = new double[numBands][];
0962: for (int i = 0; i < numBands; i++) {
0963: data[i] = d;
0964: }
0965: return data;
0966: }
0967:
0968: /** Returns pixel interleaved offsets for copy case. */
0969: private int[] getInterleavedOffsets(int numBands) {
0970: int[] offsets = new int[numBands];
0971: for (int i = 0; i < numBands; i++) {
0972: offsets[i] = i;
0973: }
0974: return offsets;
0975: }
0976:
0977: /**
0978: * Sets a region of the pixel data within a <code>Raster</code>
0979: * using a primitive array. This method copies data only if
0980: * the <code>set</code> flag in <code>UnpackedImageData</code> is
0981: * <code>true</code>. Performs clamping by default.
0982: *
0983: * <p> The <code>UnpackedImageData</code> should be obtained by
0984: * calling the <code>getPixels()</code> method.
0985: *
0986: * @param uid The <code>UnpackedImageData</code> object to set.
0987: * @throws IllegalArgumentException If the <code>uid</code> is
0988: * <code>null</code>.
0989: */
0990: public void setPixels(UnpackedImageData uid) {
0991:
0992: if (uid == null) {
0993: throw new IllegalArgumentException(JaiI18N
0994: .getString("Generic0"));
0995: }
0996:
0997: setPixels(uid, true);
0998: }
0999:
1000: /**
1001: * Sets a region of the pixel data within a <code>Raster</code>
1002: * using a primitive array. This method only copies data only if
1003: * the <code>set</code> flag in <code>UnpackedImageData</code> is
1004: * <code>true</code>.
1005: *
1006: * <p> The <code>UnpackedImageData</code> should be obtained by
1007: * calling the <code>getPixels()</code> method.
1008: *
1009: * @param uid The <code>UnpackedImageData</code> object to set.
1010: * @param clamp A <code>boolean</code> set to true if clamping
1011: * is to be performed.
1012: * @throws IllegalArgumentException If the <code>uid</code> is
1013: * <code>null</code>.
1014: */
1015: public void setPixels(UnpackedImageData uid, boolean clamp) {
1016:
1017: if (uid == null) {
1018: throw new IllegalArgumentException(JaiI18N
1019: .getString("Generic0"));
1020: }
1021:
1022: if (!uid.convertToDest) {
1023: return;
1024: }
1025:
1026: if (clamp) { // clamp all array elements
1027: switch (sampleType) {
1028: case DataBuffer.TYPE_BYTE:
1029: clampByte(uid.data, uid.type);
1030: break;
1031: case DataBuffer.TYPE_USHORT:
1032: clampUShort(uid.data, uid.type);
1033: break;
1034: case DataBuffer.TYPE_SHORT:
1035: clampShort(uid.data, uid.type);
1036: break;
1037: case DataBuffer.TYPE_INT:
1038: clampInt(uid.data, uid.type);
1039: break;
1040: case DataBuffer.TYPE_FLOAT:
1041: clampFloat(uid.data, uid.type);
1042: break;
1043: }
1044: }
1045:
1046: WritableRaster raster = (WritableRaster) uid.raster;
1047: Rectangle rect = uid.rect;
1048: int type = uid.type;
1049:
1050: switch (type) {
1051: case DataBuffer.TYPE_BYTE:
1052: byte[] bd = uid.getByteData(0);
1053:
1054: if (isMultiPixelPackedSM
1055: && transferType == DataBuffer.TYPE_BYTE) {
1056: raster.setDataElements(rect.x, rect.y, rect.width,
1057: rect.height, bd);
1058: } else {
1059: int size = bd.length;
1060: int[] d = new int[size];
1061: for (int i = 0; i < size; i++) {
1062: d[i] = bd[i] & 0xff;
1063: }
1064: raster.setPixels(rect.x, rect.y, rect.width,
1065: rect.height, d);
1066: }
1067: break;
1068:
1069: case DataBuffer.TYPE_USHORT:
1070: case DataBuffer.TYPE_SHORT:
1071: short[] sd = uid.getShortData(0);
1072:
1073: if (isComponentSM) {
1074: // The only time this needs to set to is a byte buffer.
1075: UnpackedImageData buid = getPixelsCSM(raster, rect,
1076: DataBuffer.TYPE_BYTE, true);
1077: byte[][] bdata = buid.getByteData();
1078:
1079: for (int b = 0; b < numBands; b++) {
1080: byte[] d = bdata[b];
1081: int lo = buid.getOffset(b);
1082:
1083: for (int i = b, h = 0; h < rect.height; h++) {
1084: int po = lo;
1085: lo += buid.lineStride;
1086:
1087: for (int w = 0; w < rect.width; w++) {
1088: d[po] = (byte) sd[i];
1089:
1090: po += buid.pixelStride;
1091: i += numBands;
1092: }
1093: }
1094: }
1095: } else if (isMultiPixelPackedSM
1096: && transferType == DataBuffer.TYPE_USHORT) {
1097: raster.setDataElements(rect.x, rect.y, rect.width,
1098: rect.height, sd);
1099: } else {
1100: int size = sd.length;
1101: int[] d = new int[size];
1102: if (type == DataBuffer.TYPE_USHORT) {
1103: for (int i = 0; i < size; i++) {
1104: d[i] = sd[i] & 0xffff;
1105: }
1106: } else {
1107: for (int i = 0; i < size; i++) {
1108: d[i] = sd[i];
1109: }
1110: }
1111: raster.setPixels(rect.x, rect.y, rect.width,
1112: rect.height, d);
1113: }
1114: break;
1115:
1116: case DataBuffer.TYPE_INT:
1117: raster.setPixels(rect.x, rect.y, rect.width, rect.height,
1118: uid.getIntData(0));
1119: break;
1120:
1121: case DataBuffer.TYPE_FLOAT:
1122: raster.setPixels(rect.x, rect.y, rect.width, rect.height,
1123: uid.getFloatData(0));
1124: break;
1125:
1126: case DataBuffer.TYPE_DOUBLE:
1127: raster.setPixels(rect.x, rect.y, rect.width, rect.height,
1128: uid.getDoubleData(0));
1129: break;
1130: }
1131: }
1132:
1133: /** Clamps the data array. */
1134: private void clampByte(Object data, int type) {
1135: int bands, size;
1136: switch (type) {
1137: case DataBuffer.TYPE_USHORT:
1138: short[][] usd = (short[][]) data;
1139: bands = usd.length;
1140:
1141: for (int j = 0; j < bands; j++) {
1142: short[] d = usd[j];
1143: size = d.length;
1144:
1145: for (int i = 0; i < size; i++) {
1146: int n = d[i] & 0xffff;
1147: d[i] = (short) (n > 0xff ? 0xff : n);
1148: }
1149: }
1150: break;
1151:
1152: case DataBuffer.TYPE_SHORT:
1153: short[][] sd = (short[][]) data;
1154: bands = sd.length;
1155:
1156: for (int j = 0; j < bands; j++) {
1157: short[] d = sd[j];
1158: size = d.length;
1159:
1160: for (int i = 0; i < size; i++) {
1161: int n = d[i];
1162: d[i] = (short) (n > 0xff ? 0xff : (n < 0 ? 0 : n));
1163: }
1164: }
1165: break;
1166:
1167: case DataBuffer.TYPE_INT:
1168: int[][] id = (int[][]) data;
1169: bands = id.length;
1170:
1171: for (int j = 0; j < bands; j++) {
1172: int[] d = id[j];
1173: size = d.length;
1174:
1175: for (int i = 0; i < size; i++) {
1176: int n = d[i];
1177: d[i] = n > 0xff ? 0xff : (n < 0 ? 0 : n);
1178: }
1179: }
1180: break;
1181:
1182: case DataBuffer.TYPE_FLOAT:
1183: float[][] fd = (float[][]) data;
1184: bands = fd.length;
1185:
1186: for (int j = 0; j < bands; j++) {
1187: float[] d = fd[j];
1188: size = d.length;
1189:
1190: for (int i = 0; i < size; i++) {
1191: float n = d[i];
1192: d[i] = n > 0xff ? 0xff : (n < 0 ? 0 : n);
1193: }
1194: }
1195: break;
1196:
1197: case DataBuffer.TYPE_DOUBLE:
1198: double[][] dd = (double[][]) data;
1199: bands = dd.length;
1200:
1201: for (int j = 0; j < bands; j++) {
1202: double[] d = dd[j];
1203: size = d.length;
1204:
1205: for (int i = 0; i < size; i++) {
1206: double n = d[i];
1207: d[i] = n > 0xff ? 0xff : (n < 0 ? 0 : n);
1208: }
1209: }
1210: break;
1211: }
1212: }
1213:
1214: private void clampUShort(Object data, int type) {
1215: int bands, size;
1216: switch (type) {
1217: case DataBuffer.TYPE_INT:
1218: int[][] id = (int[][]) data;
1219: bands = id.length;
1220:
1221: for (int j = 0; j < bands; j++) {
1222: int[] d = id[j];
1223: size = d.length;
1224:
1225: for (int i = 0; i < size; i++) {
1226: int n = d[i];
1227: d[i] = n > 0xffff ? 0xffff : (n < 0 ? 0 : n);
1228: }
1229: }
1230: break;
1231:
1232: case DataBuffer.TYPE_FLOAT:
1233: float[][] fd = (float[][]) data;
1234: bands = fd.length;
1235:
1236: for (int j = 0; j < bands; j++) {
1237: float[] d = fd[j];
1238: size = d.length;
1239:
1240: for (int i = 0; i < size; i++) {
1241: float n = d[i];
1242: d[i] = n > 0xffff ? 0xffff : (n < 0 ? 0 : n);
1243: }
1244: }
1245: break;
1246:
1247: case DataBuffer.TYPE_DOUBLE:
1248: double[][] dd = (double[][]) data;
1249: bands = dd.length;
1250:
1251: for (int j = 0; j < bands; j++) {
1252: double[] d = dd[j];
1253: size = d.length;
1254:
1255: for (int i = 0; i < size; i++) {
1256: double n = d[i];
1257: d[i] = n > 0xffff ? 0xffff : (n < 0 ? 0 : n);
1258: }
1259: }
1260: break;
1261: }
1262: }
1263:
1264: private void clampShort(Object data, int type) {
1265: int bands, size;
1266: switch (type) {
1267: case DataBuffer.TYPE_INT:
1268: int[][] id = (int[][]) data;
1269: bands = id.length;
1270:
1271: for (int j = 0; j < bands; j++) {
1272: int[] d = id[j];
1273: size = d.length;
1274:
1275: for (int i = 0; i < size; i++) {
1276: int n = d[i];
1277: d[i] = n > Short.MAX_VALUE ? Short.MAX_VALUE
1278: : (n < Short.MIN_VALUE ? Short.MIN_VALUE
1279: : n);
1280: }
1281: }
1282: break;
1283:
1284: case DataBuffer.TYPE_FLOAT:
1285: float[][] fd = (float[][]) data;
1286: bands = fd.length;
1287:
1288: for (int j = 0; j < bands; j++) {
1289: float[] d = fd[j];
1290: size = d.length;
1291:
1292: for (int i = 0; i < size; i++) {
1293: float n = d[i];
1294: d[i] = n > Short.MAX_VALUE ? Short.MAX_VALUE
1295: : (n < Short.MIN_VALUE ? Short.MIN_VALUE
1296: : n);
1297: }
1298: }
1299: break;
1300:
1301: case DataBuffer.TYPE_DOUBLE:
1302: double[][] dd = (double[][]) data;
1303: bands = dd.length;
1304:
1305: for (int j = 0; j < bands; j++) {
1306: double[] d = dd[j];
1307: size = d.length;
1308:
1309: for (int i = 0; i < size; i++) {
1310: double n = d[i];
1311: d[i] = n > Short.MAX_VALUE ? Short.MAX_VALUE
1312: : (n < Short.MIN_VALUE ? Short.MIN_VALUE
1313: : n);
1314: }
1315: }
1316: break;
1317: }
1318: }
1319:
1320: private void clampInt(Object data, int type) {
1321: int bands, size;
1322: switch (type) {
1323: case DataBuffer.TYPE_FLOAT:
1324: float[][] fd = (float[][]) data;
1325: bands = fd.length;
1326:
1327: for (int j = 0; j < bands; j++) {
1328: float[] d = fd[j];
1329: size = d.length;
1330:
1331: for (int i = 0; i < size; i++) {
1332: float n = d[i];
1333: d[i] = n > Integer.MAX_VALUE ? Integer.MAX_VALUE
1334: : (n < Integer.MIN_VALUE ? Integer.MIN_VALUE
1335: : n);
1336: }
1337: }
1338: break;
1339:
1340: case DataBuffer.TYPE_DOUBLE:
1341: double[][] dd = (double[][]) data;
1342: bands = dd.length;
1343:
1344: for (int j = 0; j < bands; j++) {
1345: double[] d = dd[j];
1346: size = d.length;
1347:
1348: for (int i = 0; i < size; i++) {
1349: double n = d[i];
1350: d[i] = n > Integer.MAX_VALUE ? Integer.MAX_VALUE
1351: : (n < Integer.MIN_VALUE ? Integer.MIN_VALUE
1352: : n);
1353: }
1354: }
1355: break;
1356: }
1357: }
1358:
1359: private void clampFloat(Object data, int type) {
1360: int bands, size;
1361: switch (type) {
1362: case DataBuffer.TYPE_DOUBLE:
1363: double[][] dd = (double[][]) data;
1364: bands = dd.length;
1365:
1366: for (int j = 0; j < bands; j++) {
1367: double[] d = dd[j];
1368: size = d.length;
1369:
1370: for (int i = 0; i < size; i++) {
1371: double n = d[i];
1372: d[i] = n > Float.MAX_VALUE ? Float.MAX_VALUE
1373: : (n < -Float.MAX_VALUE ? -Float.MAX_VALUE
1374: : n);
1375: }
1376: }
1377: break;
1378: }
1379: }
1380:
1381: /**
1382: * Returns a region of the pixel data within a <code>Raster</code>
1383: * in a packed <code>byte</code> array. The returned data are
1384: * retrieved from the <code>Raster</code>'s <code>DataBuffer</code>;
1385: * no pixel-to-color translation is performed.
1386: *
1387: * <p> This method only returns a valid result when the pixels are
1388: * single-band and single-bit. All other types of data result in
1389: * an exception. The data are packed in such a format that eight
1390: * pixels are packed into one byte, and the end of each scanline is
1391: * padded with zeros to the end of the byte.
1392: *
1393: * <p> In general, this method is called when operations are to be
1394: * performed on the bit data in a packed format directly, to save
1395: * memory usage. The static method <code>isPackedOperation</code>
1396: * should be used to determine whether the destination and/or its sources
1397: * are suitable for performing operations to a packed array.
1398: *
1399: * <p> The <code>Rectangle</code> specifies the region of interest
1400: * within which the pixel data are to be retrieved. It must be
1401: * completely inside the <code>Raster</code>'s boundary, or
1402: * this method will throw an exception.
1403: *
1404: * @param raster The <code>Raster</code> that contains the pixel data.
1405: * @param rect The region of interest within the <code>Raster</code>
1406: * where the pixels are accessed.
1407: * @param isDest Indicates whether this <code>Raster</code> is a
1408: * destination <code>Raster</code>. That is, its pixels have
1409: * not been computed.
1410: * @param coerceZeroOffset If <code>true</code> the returned
1411: * <code>PackedImageData</code> will be forced to have a
1412: * <code>bitOffset</code> and <code>offset</code> of zero
1413: * and a <code>lineStride</code> of <code>(rect.width+7)/8</code>.
1414: * The <code>coercedZeroOffset</code> field of the returned
1415: * <code>PackedImageData</code> will be set to <code>true</code>.
1416: * @return The <code>PackedImageData</code> with its data filled in.
1417: *
1418: * @throws IllegalArgumentException If data described by the
1419: * <code>Raster</code>'s <code>SampleModel</code> are not
1420: * single-band and single-bit.
1421: * @throws IllegalArgumentException If <code>rect</code> is not
1422: * within the bounds of the specified <code>Raster</code>.
1423: */
1424: public PackedImageData getPackedPixels(Raster raster,
1425: Rectangle rect, boolean isDest, boolean coerceZeroOffset) {
1426: if (!isPacked) {
1427: throw new IllegalArgumentException(JaiI18N
1428: .getString("PixelAccessor3"));
1429: }
1430:
1431: if (!raster.getBounds().contains(rect)) {
1432: throw new IllegalArgumentException(JaiI18N
1433: .getString("PixelAccessor0"));
1434: }
1435:
1436: byte[] data; // packed pixels
1437: int lineStride, offset, bitOffset; // access information
1438: boolean set; // true if need to and can set data
1439:
1440: if (isMultiPixelPackedSM) {
1441:
1442: set = isDest;
1443:
1444: if (coerceZeroOffset) {
1445:
1446: data = ImageUtil.getPackedBinaryData(raster, rect);
1447: lineStride = (rect.width + 7) / 8;
1448: offset = bitOffset = 0;
1449:
1450: } else {
1451:
1452: MultiPixelPackedSampleModel sm = (MultiPixelPackedSampleModel) sampleModel;
1453:
1454: DataBuffer db = raster.getDataBuffer();
1455: int dbOffset = db.getOffset();
1456:
1457: int x = rect.x - raster.getSampleModelTranslateX();
1458: int y = rect.y - raster.getSampleModelTranslateY();
1459:
1460: int smLineStride = sm.getScanlineStride();
1461: int minOffset = sm.getOffset(x, y) + dbOffset;
1462: int maxOffset = sm.getOffset(x + rect.width - 1, y)
1463: + dbOffset;
1464: int numElements = maxOffset - minOffset + 1; // per line
1465: int smBitOffset = sm.getBitOffset(x);
1466:
1467: switch (bufferType) { // DataBuffer type
1468: case DataBuffer.TYPE_BYTE: // no need to copy
1469: data = ((DataBufferByte) db).getData();
1470: lineStride = smLineStride;
1471: offset = minOffset;
1472: bitOffset = smBitOffset;
1473: set = false; // no need to set for destination
1474: break;
1475:
1476: // Copy even if it's destination so they can easily
1477: // be set back.
1478: case DataBuffer.TYPE_USHORT:
1479: lineStride = numElements * 2; // 2 bytes for each ushort
1480: offset = smBitOffset / 8;
1481: bitOffset = smBitOffset % 8;
1482: data = new byte[lineStride * rect.height];
1483:
1484: short[] sd = ((DataBufferUShort) db).getData();
1485: for (int i = 0, h = 0; h < rect.height; h++) {
1486: for (int w = minOffset; w <= maxOffset; w++) {
1487: short d = sd[w];
1488: data[i++] = (byte) ((d >>> 8) & 0xff);
1489: data[i++] = (byte) (d & 0xff);
1490: }
1491: minOffset += smLineStride;
1492: maxOffset += smLineStride;
1493: }
1494: break;
1495:
1496: case DataBuffer.TYPE_INT:
1497: lineStride = numElements * 4; // 4 bytes for each int
1498: offset = smBitOffset / 8;
1499: bitOffset = smBitOffset % 8;
1500: data = new byte[lineStride * rect.height];
1501:
1502: int[] id = ((DataBufferInt) db).getData();
1503: for (int i = 0, h = 0; h < rect.height; h++) {
1504: for (int w = minOffset; w <= maxOffset; w++) {
1505: int d = id[w];
1506: data[i++] = (byte) ((d >>> 24) & 0xff);
1507: data[i++] = (byte) ((d >>> 16) & 0xff);
1508: data[i++] = (byte) ((d >>> 8) & 0xff);
1509: data[i++] = (byte) (d & 0xff);
1510: }
1511: minOffset += smLineStride;
1512: maxOffset += smLineStride;
1513: }
1514: break;
1515:
1516: default:
1517: throw new RuntimeException(); // should never get here
1518: }
1519: }
1520:
1521: } else { // unknown SampleModel
1522: lineStride = (rect.width + 7) / 8;
1523: offset = 0;
1524: bitOffset = 0;
1525: set = isDest & (raster instanceof WritableRaster);
1526: data = new byte[lineStride * rect.height];
1527:
1528: if (!isDest) { // copy one line at a time to
1529: int size = lineStride * 8; // avoid using too much memory
1530: int[] p = new int[size];
1531: for (int i = 0, h = 0; h < rect.height; h++) {
1532: p = raster.getPixels(rect.x, rect.y + h,
1533: rect.width, 1, p);
1534: for (int w = 0; w < size; w += 8) {
1535: data[i++] = (byte) (p[w] << 7 | p[w + 1] << 6
1536: | p[w + 2] << 5 | p[w + 3] << 4
1537: | p[w + 4] << 3 | p[w + 5] << 2
1538: | p[w + 6] << 1 | p[w + 7]);
1539: }
1540: }
1541: }
1542: }
1543:
1544: return new PackedImageData(raster, rect, data, lineStride,
1545: offset, bitOffset, coerceZeroOffset, set);
1546: }
1547:
1548: /**
1549: * Sets a region of the pixel data within a <code>Raster</code>
1550: * using a primitive array. This method copies data only if
1551: * the <code>set</code> flag in <code>PackedImageData</code> is
1552: * <code>true</code>.
1553: *
1554: * <p> The <code>PackedImageData</code> should be obtained by
1555: * calling the <code>getPackedPixels()</code> method.
1556: *
1557: * @param pid The </code>PackedImageData</code> object whose pixels
1558: * are to be written.
1559: * @throws IllegalArgumentException If the <code>pid</code> is
1560: * <code>null</code>.
1561: */
1562: public void setPackedPixels(PackedImageData pid) {
1563:
1564: if (pid == null) {
1565: throw new IllegalArgumentException(JaiI18N
1566: .getString("Generic0"));
1567: }
1568:
1569: if (!pid.convertToDest) {
1570: return;
1571: }
1572:
1573: Raster raster = pid.raster;
1574: Rectangle rect = pid.rect;
1575: byte[] data = pid.data;
1576:
1577: if (isMultiPixelPackedSM) {
1578:
1579: if (pid.coercedZeroOffset) {
1580: ImageUtil.setPackedBinaryData(data,
1581: (WritableRaster) raster, rect);
1582: } else {
1583: MultiPixelPackedSampleModel sm = (MultiPixelPackedSampleModel) sampleModel;
1584:
1585: DataBuffer db = raster.getDataBuffer();
1586: int dbOffset = db.getOffset();
1587:
1588: int x = rect.x - raster.getSampleModelTranslateX();
1589: int y = rect.y - raster.getSampleModelTranslateY();
1590:
1591: int lineStride = sm.getScanlineStride();
1592: int minOffset = sm.getOffset(x, y) + dbOffset;
1593: int maxOffset = sm.getOffset(x + rect.width - 1, y)
1594: + dbOffset;
1595:
1596: // Only need to set for buffer types of ushort and int.
1597: switch (bufferType) {
1598: case DataBuffer.TYPE_USHORT:
1599: short[] sd = ((DataBufferUShort) db).getData();
1600: for (int i = 0, h = 0; h < rect.height; h++) {
1601: for (int w = minOffset; w <= maxOffset; w++) {
1602: sd[w] = (short) (data[i++] << 8 | data[i++]);
1603: }
1604: minOffset += lineStride;
1605: maxOffset += lineStride;
1606: }
1607: break;
1608:
1609: case DataBuffer.TYPE_INT:
1610: int[] id = ((DataBufferInt) db).getData();
1611: for (int i = 0, h = 0; h < rect.height; h++) {
1612: for (int w = minOffset; w <= maxOffset; w++) {
1613: id[w] = data[i++] << 24 | data[i++] << 16
1614: | data[i++] << 8 | data[i++];
1615: }
1616: minOffset += lineStride;
1617: maxOffset += lineStride;
1618: }
1619: break;
1620: }
1621: }
1622:
1623: } else {
1624: /*
1625: * The getPackedData() method should set "set" to false if
1626: * the Raster is not writable.
1627: * Copy one line at a time to avoid using too much memory.
1628: */
1629: WritableRaster wr = (WritableRaster) raster;
1630: int size = pid.lineStride * 8;
1631: int[] p = new int[size];
1632:
1633: for (int i = 0, h = 0; h < rect.height; h++) {
1634: for (int w = 0; w < size; w += 8) {
1635: p[w] = (data[i] >>> 7) & 0x1;
1636: p[w + 1] = (data[i] >>> 6) & 0x1;
1637: p[w + 2] = (data[i] >>> 5) & 0x1;
1638: p[w + 3] = (data[i] >>> 4) & 0x1;
1639: p[w + 4] = (data[i] >>> 3) & 0x1;
1640: p[w + 5] = (data[i] >>> 2) & 0x1;
1641: p[w + 6] = (data[i] >>> 1) & 0x1;
1642: p[w + 7] = data[i] & 0x1;
1643: i++;
1644: }
1645: wr.setPixels(rect.x, rect.y + h, rect.width, 1, p);
1646: }
1647: }
1648: }
1649:
1650: /**
1651: * Returns an array of unnormalized color/alpha components in the
1652: * <code>ColorSpace</code> defined in the image's
1653: * <code>ColorModel</code>. This method retrieves the pixel data
1654: * within the specified rectangular region from the
1655: * <code>Raster</code>, performs the pixel-to-color translation based
1656: * on the image's <code>ColorModel</code>, and returns the components
1657: * in the order specified by the <code>ColorSpace</code>.
1658: *
1659: * <p> In order for this method to return a valid result, the
1660: * image must have a valid <code>ColorModel</code> that is compatible
1661: * with the image's <code>SampleModel</code>. Further, the
1662: * <code>SampleModel</code> and <code>ColorModel</code> must have
1663: * the same <code>transferType</code>.
1664: *
1665: * <p> The component data are stored in a primitive array of the
1666: * type specified by the <code>type</code> argument. It must be one
1667: * of the valid data types defined in <code>DataBuffer</code> and
1668: * large (in bit depth) enough to hold the color/alpha components,
1669: * or an exception is thrown. This means <code>type</code> should
1670: * be greater than or equal to <code>componentType</code>. To avoid
1671: * extra array copy, it is best to use
1672: * <code>DataBuffer.TYPE_INT</code> for this argument.
1673: *
1674: * <p> The <code>Rectangle</code> specifies the region of interest
1675: * within which the pixel data are to be retrieved. It must be
1676: * completely inside the <code>Raster</code>'s boundary, or else
1677: * this method throws an exception.
1678: *
1679: * @param raster The <code>Raster</code> that contains the pixel data.
1680: * @param rect The region of interest within the <code>Raster</code>
1681: * where the pixels are accessed.
1682: * @param type The type of the primitive array used to return the
1683: * color/alpha components with.
1684: * @return The <code>UnpackedImageData</code> with its data filled in.
1685: *
1686: * @throws IllegalArgumentException If the image does not have a valid
1687: * <code>ColorModel</code> that is compatible with its
1688: * <code>SampleModel</code>.
1689: * @throws IllegalArgumentException If <code>type</code> is not a
1690: * valid data type defined in <code>DataBuffer</code>, or
1691: * is not large enough to hold the translated color/alpha
1692: * components.
1693: * @throws IllegalArgumentException If <code>rect</code> is not
1694: * contained by the bounds of the specified <code>Raster</code>.
1695: */
1696: public UnpackedImageData getComponents(Raster raster,
1697: Rectangle rect, int type) {
1698: if (!hasCompatibleCM) {
1699: throw new IllegalArgumentException(JaiI18N
1700: .getString("PixelAccessor5"));
1701: }
1702:
1703: if (!raster.getBounds().contains(rect)) {
1704: throw new IllegalArgumentException(JaiI18N
1705: .getString("PixelAccessor0"));
1706: }
1707:
1708: if (type < DataBuffer.TYPE_BYTE
1709: || type > DataBuffer.TYPE_DOUBLE) { // unknown data type
1710: throw new IllegalArgumentException(JaiI18N
1711: .getString("PixelAccessor1"));
1712: }
1713:
1714: if (type < componentType
1715: || (componentType == DataBuffer.TYPE_USHORT && type == DataBuffer.TYPE_SHORT)) { // type not large enough
1716: throw new IllegalArgumentException(JaiI18N
1717: .getString("PixelAccessor4"));
1718: }
1719:
1720: // Get color/alpha components in an integer array.
1721: int size = rect.width * rect.height * numComponents;
1722: int[] ic = new int[size];
1723: int width = rect.x + rect.width;
1724: int height = rect.y + rect.height;
1725:
1726: for (int i = 0, y = rect.y; y < height; y++) {
1727: for (int x = rect.x; x < width; x++) {
1728: Object p = raster.getDataElements(x, y, null);
1729: colorModel.getComponents(p, ic, i);
1730: i += numComponents;
1731: }
1732: }
1733:
1734: // Reformat components into the specified data type.
1735: Object data = null;
1736: switch (type) {
1737: case DataBuffer.TYPE_BYTE:
1738: byte[] bc = new byte[size];
1739: for (int i = 0; i < size; i++) {
1740: bc[i] = (byte) (ic[i] & 0xff);
1741: }
1742: data = repeatBand(bc, numComponents);
1743: break;
1744:
1745: case DataBuffer.TYPE_USHORT:
1746: short[] usc = new short[size];
1747: for (int i = 0; i < size; i++) {
1748: usc[i] = (short) (ic[i] & 0xffff);
1749: }
1750: data = repeatBand(usc, numComponents);
1751: break;
1752:
1753: case DataBuffer.TYPE_SHORT:
1754: short[] sc = new short[size];
1755: for (int i = 0; i < size; i++) {
1756: sc[i] = (short) ic[i];
1757: }
1758: data = repeatBand(sc, numComponents);
1759: break;
1760:
1761: case DataBuffer.TYPE_INT:
1762: data = repeatBand(ic, numComponents);
1763: break;
1764:
1765: case DataBuffer.TYPE_FLOAT:
1766: float[] fc = new float[size];
1767: for (int i = 0; i < size; i++) {
1768: fc[i] = ic[i];
1769: }
1770: data = repeatBand(fc, numComponents);
1771: break;
1772:
1773: case DataBuffer.TYPE_DOUBLE:
1774: double[] dc = new double[size];
1775: for (int i = 0; i < size; i++) {
1776: dc[i] = ic[i];
1777: }
1778: data = repeatBand(dc, numComponents);
1779: break;
1780: }
1781:
1782: return new UnpackedImageData(raster, rect, type, data,
1783: numComponents, numComponents * rect.width,
1784: getInterleavedOffsets(numComponents),
1785: raster instanceof WritableRaster);
1786: }
1787:
1788: /**
1789: * Given an array of unnormalized color/alpha components, this
1790: * method performs color-to-pixel translation, and sets the
1791: * translated pixel data back to the <code>Raster</code> within
1792: * a specific region. It is very important that the components
1793: * array along with access information are obtained by calling
1794: * the <code>getComponents()</code> method, or errors
1795: * will occur.
1796: *
1797: * <p> In order for this method to return a valid result, the
1798: * image must have a valid <code>ColorModel</code> that is compatible
1799: * with the image's <code>SampleModel</code>. Further, the
1800: * <code>SampleModel</code> and <code>ColorModel</code> must have
1801: * the same <code>transferType</code>.
1802: *
1803: * <p> This method sets data only if the <code>set</code> flag in
1804: * <code>UnpackedImageData</code> is <code>true</code>.
1805: *
1806: * @param uid The <code>UnpackedImageData</code> whose data is to be set.
1807: * @throws IllegalArgumentException If the <code>uid</code> is
1808: * <code>null</code>.
1809: */
1810: public void setComponents(UnpackedImageData uid) {
1811:
1812: if (uid == null) {
1813: throw new IllegalArgumentException(JaiI18N
1814: .getString("Generic0"));
1815: }
1816:
1817: if (!uid.convertToDest) {
1818: return;
1819: }
1820:
1821: WritableRaster raster = (WritableRaster) uid.raster;
1822: Rectangle rect = uid.rect;
1823: int type = uid.type;
1824:
1825: int size = rect.width * rect.height * numComponents;
1826: int[] ic = null;
1827:
1828: switch (type) {
1829: case DataBuffer.TYPE_BYTE:
1830: byte[] bc = uid.getByteData(0);
1831: ic = new int[size];
1832: for (int i = 0; i < size; i++) {
1833: ic[i] = bc[i] & 0xff;
1834: }
1835: break;
1836:
1837: case DataBuffer.TYPE_USHORT:
1838: short[] usc = uid.getShortData(0);
1839: ic = new int[size];
1840: for (int i = 0; i < size; i++) {
1841: ic[i] = usc[i] & 0xffff;
1842: }
1843: break;
1844:
1845: case DataBuffer.TYPE_SHORT:
1846: short[] sc = uid.getShortData(0);
1847: ic = new int[size];
1848: for (int i = 0; i < size; i++) {
1849: ic[i] = sc[i];
1850: }
1851: break;
1852:
1853: case DataBuffer.TYPE_INT:
1854: ic = uid.getIntData(0);
1855: break;
1856:
1857: case DataBuffer.TYPE_FLOAT:
1858: float[] fc = uid.getFloatData(0);
1859: ic = new int[size];
1860: for (int i = 0; i < size; i++) {
1861: ic[i] = (int) fc[i];
1862: ;
1863: }
1864: break;
1865:
1866: case DataBuffer.TYPE_DOUBLE:
1867: double[] dc = uid.getDoubleData(0);
1868: ic = new int[size];
1869: for (int i = 0; i < size; i++) {
1870: ic[i] = (int) dc[i];
1871: }
1872: break;
1873: }
1874:
1875: int width = rect.x + rect.width;
1876: int height = rect.y + rect.height;
1877:
1878: for (int i = 0, y = rect.y; y < height; y++) {
1879: for (int x = rect.x; x < width; x++) {
1880: Object p = colorModel.getDataElements(ic, i, null);
1881: raster.setDataElements(x, y, p);
1882: i += numComponents;
1883: }
1884: }
1885: }
1886:
1887: /**
1888: * Returns an array of color/alpha components scaled from 0 to 255
1889: * in the default sRGB <code>ColorSpace</code>. This method
1890: * retrieves the pixel data within the specified rectangular region
1891: * from the <code>Raster</code>, performs the pixel-to-color translation
1892: * based on the image's <code>ColorModel</code>, and returns the
1893: * components in the order specified by the <code>ColorSpace</code>.
1894: *
1895: * <p> In order for this method to return a valid result, the
1896: * image must have a valid <code>ColorModel</code> that is compatible
1897: * with the image's <code>SampleModel</code>. Further, the
1898: * <code>SampleModel</code> and <code>ColorModel</code> must have
1899: * the same <code>transferType</code>.
1900: *
1901: * <p> The component data are stored in a two-dimensional,
1902: * band-interleaved, <code>byte</code> array, because the components
1903: * are always scaled from 0 to 255. Red is band 0, green is band 1,
1904: * blue is band 2, and alpha is band 3.
1905: *
1906: * <p> The <code>Rectangle</code> specifies the region of interest
1907: * within which the pixel data are to be retrieved. It must be
1908: * completely inside the <code>Raster</code>'s boundary, or
1909: * this method will throw an exception.
1910: *
1911: * @param raster The <code>Raster</code> that contains the pixel data.
1912: * @param rect The region of interest within the <code>Raster</code>
1913: * where the pixels are accessed.
1914: * @return The <code>UnpackedImageData</code> with its data filled in.
1915: *
1916: * @throws IllegalArgumentException If the image does not have a valid
1917: * <code>ColorModel</code> that is compatible with its
1918: * <code>SampleModel</code>.
1919: * @throws IllegalArgumentException If <code>rect</code> is not
1920: * contained by the bounds of the specified <code>Raster</code>.
1921: */
1922: public UnpackedImageData getComponentsRGB(Raster raster,
1923: Rectangle rect) {
1924: if (!hasCompatibleCM) {
1925: throw new IllegalArgumentException(JaiI18N
1926: .getString("PixelAccessor5"));
1927: }
1928:
1929: if (!raster.getBounds().contains(rect)) {
1930: throw new IllegalArgumentException(JaiI18N
1931: .getString("PixelAccessor0"));
1932: }
1933:
1934: int size = rect.width * rect.height;
1935:
1936: byte[][] data = new byte[4][size];
1937: byte[] r = data[0]; // red
1938: byte[] g = data[1]; // green
1939: byte[] b = data[2]; // blue
1940: byte[] a = data[3]; // alpha
1941:
1942: // Get color/alpha components in an integer array.
1943: int maxX = rect.x + rect.width;
1944: int maxY = rect.y + rect.height;
1945:
1946: if (isIndexCM) {
1947: // Cast the CM and get the size of the ICM tables.
1948: IndexColorModel icm = (IndexColorModel) colorModel;
1949: int mapSize = icm.getMapSize();
1950:
1951: // Load the ICM tables.
1952: byte[] reds = new byte[mapSize];
1953: icm.getReds(reds);
1954: byte[] greens = new byte[mapSize];
1955: icm.getGreens(greens);
1956: byte[] blues = new byte[mapSize];
1957: icm.getBlues(blues);
1958: byte[] alphas = null;
1959: if (icm.hasAlpha()) {
1960: alphas = new byte[mapSize];
1961: icm.getAlphas(alphas);
1962: }
1963:
1964: // Get the index values.
1965: int[] indices = raster.getPixels(rect.x, rect.y,
1966: rect.width, rect.height, (int[]) null);
1967:
1968: // Use the ICM tables to get the [A]RGB values.
1969: if (alphas == null) {
1970: // No alpha.
1971: for (int i = 0, y = rect.y; y < maxY; y++) {
1972: for (int x = rect.x; x < maxX; x++) {
1973: int index = indices[i];
1974:
1975: r[i] = reds[index];
1976: g[i] = greens[index];
1977: b[i] = blues[index];
1978:
1979: i++;
1980: }
1981: }
1982: } else {
1983: // Alpha.
1984: for (int i = 0, y = rect.y; y < maxY; y++) {
1985: for (int x = rect.x; x < maxX; x++) {
1986: int index = indices[i];
1987:
1988: r[i] = reds[index];
1989: g[i] = greens[index];
1990: b[i] = blues[index];
1991: a[i] = alphas[index];
1992:
1993: i++;
1994: }
1995: }
1996: }
1997: } else {
1998: // XXX If ColorSpaceJAI is implemented use the
1999: // Raster-based methods here.
2000: // Not an IndexColorModel: use the "slow method".
2001: for (int i = 0, y = rect.y; y < maxY; y++) {
2002: for (int x = rect.x; x < maxX; x++) {
2003: Object p = raster.getDataElements(x, y, null);
2004:
2005: r[i] = (byte) colorModel.getRed(p);
2006: g[i] = (byte) colorModel.getGreen(p);
2007: b[i] = (byte) colorModel.getBlue(p);
2008: a[i] = (byte) colorModel.getAlpha(p);
2009: i++;
2010: }
2011: }
2012: }
2013:
2014: return new UnpackedImageData(raster, rect,
2015: DataBuffer.TYPE_BYTE, data, 1, rect.width, new int[4], // all entries automatically initialized to 0
2016: raster instanceof WritableRaster);
2017: }
2018:
2019: /**
2020: * Given an array of normalized (between 0 and 255) alpha/RGB color
2021: * components, this method performs color-to-pixel translation, and
2022: * sets the translated pixel data back to the <code>Raster</code>
2023: * within a specific region. It is very important that the components
2024: * array along with access information are obtained by calling
2025: * the <code>getComponentsRGB()</code> method, or errors
2026: * will occur.
2027: *
2028: * <p> In order for this method to return a valid result, the
2029: * image must have a valid <code>ColorModel</code> that is compatible
2030: * with the image's <code>SampleModel</code>. Furthermore, the
2031: * <code>SampleModel</code> and <code>ColorModel</code> must have
2032: * the same <code>transferType</code>.
2033: *
2034: * <p> This method sets data only if the <code>set</code> flag in
2035: * <code>UnpackedImageData</code> is <code>true</code>.
2036: *
2037: * @param uid The <code>UnpackedImageData</code> to set.
2038: * @throws IllegalArgumentException If the <code>uid</code> is
2039: * <code>null</code>.
2040: */
2041: public void setComponentsRGB(UnpackedImageData uid) {
2042:
2043: if (uid == null) {
2044: throw new IllegalArgumentException(JaiI18N
2045: .getString("Generic0"));
2046: }
2047:
2048: if (!uid.convertToDest) {
2049: return;
2050: }
2051:
2052: byte[][] data = uid.getByteData();
2053: byte[] r = data[0]; // red
2054: byte[] g = data[1]; // green
2055: byte[] b = data[2]; // blue
2056: byte[] a = data[3]; // alpha
2057:
2058: WritableRaster raster = (WritableRaster) uid.raster;
2059: Rectangle rect = uid.rect;
2060:
2061: int maxX = rect.x + rect.width;
2062: int maxY = rect.y + rect.height;
2063:
2064: for (int i = 0, y = rect.y; y < maxY; y++) {
2065: for (int x = rect.x; x < maxX; x++) {
2066: int rgb = (a[i] << 24) | (b[i] << 16) | (g[i] << 8)
2067: | r[i];
2068:
2069: Object p = colorModel.getDataElements(rgb, null);
2070: raster.setDataElements(x, y, p);
2071: i++;
2072: }
2073: }
2074: }
2075: }
|