0001: /*
0002: * $RCSfile: RasterAccessor.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:18 $
0010: * $State: Exp $
0011: */
0012: package javax.media.jai;
0013:
0014: import java.awt.image.SampleModel;
0015: import java.awt.image.ComponentSampleModel;
0016: import java.awt.image.DataBuffer;
0017: import java.awt.image.DataBufferByte;
0018: import java.awt.image.DataBufferUShort;
0019: import java.awt.image.DataBufferShort;
0020: import java.awt.image.DataBufferInt;
0021: import java.awt.image.MultiPixelPackedSampleModel;
0022: import java.awt.image.Raster;
0023: import java.awt.image.WritableRaster;
0024: import java.awt.Rectangle;
0025: import java.awt.image.RenderedImage;
0026: import java.awt.image.ColorModel;
0027: import java.awt.image.IndexColorModel;
0028: import java.awt.image.ComponentColorModel;
0029: import com.sun.media.jai.util.DataBufferUtils;
0030: import com.sun.media.jai.util.ImageUtil;
0031:
0032: /**
0033: * An adapter class for presenting non-binary image data in a
0034: * <code>ComponentSampleModel</code> format and binary image data in
0035: * a zero-offset byte array format even when the original data are not
0036: * so stored. <code>RasterAccessor</code> is meant to make the common
0037: * (<code>ComponentSampleModel</code>) case fast and other formats
0038: * possible without forcing the <code>OpImage</code> writer to cover more
0039: * than one case per non-binary data type.
0040: *
0041: * <p>When constructing a <code>RasterAccessor</code> with a source(s) that
0042: * has an IndexColorModel and a destination that has a
0043: * non-<code>IndexColorModel</code>, <code>RasterAccessor</code> will
0044: * perform expansion of the source pixels. If the source(s) and the
0045: * destination have an IndexColorModel, then <code>RasterAccessor</code>
0046: * will assume that the operation can correctly process an IndexColorModel
0047: * source and will not expand the source pixels (colormap indices) into
0048: * color components. Refer to {@link JAI#KEY_REPLACE_INDEX_COLOR_MODEL}
0049: * for a mechanism by which the destination image's <code>ColorModel</code>
0050: * is set to a non-<code>IndexColorModel</code> to cause
0051: * <code>RasterAccessor</code> to expand the source's
0052: * <code>IndexColorModel</code>.
0053: *
0054: * <p> Binary data are handled as a special case. In general image data
0055: * are considered to be binary when the image has a single-banded
0056: * <code>MultiPixelPackedSampleModel</code> with one bit per pixel. This
0057: * may be verified by invoking the <code>isBinary()</code> method. For this
0058: * case the methods <code>getBinaryDataArray()</code> and
0059: * <code>copyBinaryDataToRaster()</code> should be used to access and set,
0060: * respectively, the binary data in packed form. If the binary data are
0061: * to be accessed in expanded form, i.e., as bytes, then the usual byte
0062: * methods <code>getByteDataArray()</code>, <code>getByteDataArrays()</code>,
0063: * and <code>copyDataToRaster()</code> should be used.
0064: *
0065: */
0066: public class RasterAccessor {
0067:
0068: /**
0069: * Value indicating how far COPY_MASK info is shifted to avoid
0070: * interfering with the data type info.
0071: */
0072: private static final int COPY_MASK_SHIFT = 7;
0073:
0074: /* Value indicating how many bits the COPY_MASK is */
0075: private static final int COPY_MASK_SIZE = 2;
0076:
0077: /** The bits of a FormatTag associated with how dataArrays are obtained. */
0078: public static final int COPY_MASK = ((1 << COPY_MASK_SIZE) - 1) << COPY_MASK_SHIFT;
0079:
0080: /** Flag indicating data is raster's data. */
0081: public static final int UNCOPIED = 0x0 << COPY_MASK_SHIFT;
0082:
0083: /** Flag indicating data is a copy of the raster's data. */
0084: public static final int COPIED = 0x1 << COPY_MASK_SHIFT;
0085:
0086: /**
0087: * Value indicating how far EXPANSION_MASK info is shifted to avoid
0088: * interfering with the data type info.
0089: */
0090: private static final int EXPANSION_MASK_SHIFT = COPY_MASK_SHIFT
0091: + COPY_MASK_SIZE;
0092:
0093: /** Value indicating how many bits the EXPANSION_MASK is */
0094: private static final int EXPANSION_MASK_SIZE = 2;
0095:
0096: /** The bits of a FormatTag associated with how ColorModels are used. */
0097: public static final int EXPANSION_MASK = ((1 << EXPANSION_MASK_SIZE) - 1) << EXPANSION_MASK_SHIFT;
0098:
0099: /** Flag indicating ColorModel data should be used only in copied case */
0100: public static final int DEFAULTEXPANSION = 0x0 << EXPANSION_MASK_SHIFT;
0101:
0102: /** Flag indicating ColorModel data should be interpreted. */
0103: public static final int EXPANDED = 0x1 << EXPANSION_MASK_SHIFT;
0104:
0105: /** Flag indicating ColorModel info should be ignored */
0106: public static final int UNEXPANDED = 0x02 << EXPANSION_MASK_SHIFT;
0107:
0108: /** The bits of a FormatTagID associated with pixel datatype. */
0109: public static final int DATATYPE_MASK = (0x1 << COPY_MASK_SHIFT) - 1;
0110:
0111: /** FormatTagID indicating data in byte arrays and uncopied. */
0112: public static final int TAG_BYTE_UNCOPIED = DataBuffer.TYPE_BYTE
0113: | UNCOPIED;
0114:
0115: /** FormatTagID indicating data in unsigned short arrays and uncopied. */
0116: public static final int TAG_USHORT_UNCOPIED = DataBuffer.TYPE_USHORT
0117: | UNCOPIED;
0118:
0119: /** FormatTagID indicating data in short arrays and uncopied. */
0120: public static final int TAG_SHORT_UNCOPIED = DataBuffer.TYPE_SHORT
0121: | UNCOPIED;
0122:
0123: /** FormatTagID indicating data in int arrays and uncopied. */
0124: public static final int TAG_INT_UNCOPIED = DataBuffer.TYPE_INT
0125: | UNCOPIED;
0126:
0127: /** FormatTagID indicating data in float arrays and uncopied. */
0128: public static final int TAG_FLOAT_UNCOPIED = DataBuffer.TYPE_FLOAT
0129: | UNCOPIED;
0130:
0131: /** FormatTagID indicating data in double arrays and uncopied. */
0132: public static final int TAG_DOUBLE_UNCOPIED = DataBuffer.TYPE_DOUBLE
0133: | UNCOPIED;
0134:
0135: /** FormatTagID indicating data in int arrays and copied. */
0136: public static final int TAG_INT_COPIED = DataBuffer.TYPE_INT
0137: | COPIED;
0138:
0139: /** FormatTagID indicating data in float arrays and copied. */
0140: public static final int TAG_FLOAT_COPIED = DataBuffer.TYPE_FLOAT
0141: | COPIED;
0142:
0143: /** FormatTagID indicating data in double arrays and copied. */
0144: public static final int TAG_DOUBLE_COPIED = DataBuffer.TYPE_DOUBLE
0145: | COPIED;
0146:
0147: /** FormatTagID indicating data in byte arrays and expanded. */
0148: public static final int TAG_BYTE_EXPANDED = DataBuffer.TYPE_BYTE
0149: | EXPANDED;
0150:
0151: /**
0152: * FormatTagID corresponding to the binary case. This occurs when
0153: * the image has a <code>MultiPixelPackedSampleModel</code> with a
0154: * single band and one bit per pixel.
0155: */
0156: private static final int TAG_BINARY = DataBuffer.TYPE_BYTE | COPIED
0157: | UNEXPANDED;
0158:
0159: /** The raster that is the source of pixel data. */
0160: protected Raster raster;
0161:
0162: /** The width of the rectangle this RasterAccessor addresses. */
0163: protected int rectWidth;
0164:
0165: /** The height of the rectangle this RasterAccessor addresses. */
0166: protected int rectHeight;
0167:
0168: /** The x coordinate of upper-left corner of the rectangle this
0169: * RasterAccessor addresses.
0170: */
0171: protected int rectX;
0172:
0173: /** The y coordinate of upper-left corner of the rectangle this
0174: * RasterAccessor addresses.
0175: */
0176: protected int rectY;
0177:
0178: /** Tag indicating the data type of the data and whether it's copied */
0179: protected int formatTagID;
0180:
0181: /**
0182: * The image data for the binary case. The data will be packed as
0183: * eight bits per byte with no bit offset, i.e., the first bit in each
0184: * image line will be the left-most bit of the first byte of the line.
0185: * The line stride in bytes will be <code>(int)((rectWidth+7)/8)</code>.
0186: * The length of the array will be <code>rectHeight</code> multiplied
0187: * by the line stride.
0188: *
0189: * @since JAI 1.1
0190: */
0191: protected byte binaryDataArray[] = null;
0192:
0193: /**
0194: * The image data in a two-dimensional byte array. This
0195: * value will be non-null only if getDataType() returns
0196: * DataBuffer.TYPE_BYTE. byteDataArrays.length will equal
0197: * numBands. Note that often the numBands subArrays will all
0198: * point to the same place in memory.
0199: *
0200: * <p> For the case of binary data this variable will not be initialized
0201: * until <code>getByteDataArrays()</code> or
0202: * <code>getByteDataArray(int b)</code> is invoked.
0203: */
0204: protected byte byteDataArrays[][] = null;
0205:
0206: /**
0207: * The image data in a two-dimensional short array. This
0208: * value will be non-null only if getDataType() returns
0209: * DataBuffer.TYPE_USHORT or DataBuffer.TYPE_SHORT.
0210: * shortDataArrays.length will equal
0211: * numBands. Note that often the numBands subArrays will all
0212: * point to the same place in memory.
0213: */
0214: protected short shortDataArrays[][] = null;
0215:
0216: /**
0217: * The image data in a two-dimensional int array. This
0218: * value will be non-null only if getDataType() returns
0219: * DataBuffer.TYPE_INT. intDataArrays.length will equal
0220: * numBands. Note that often the numBands subArrays will all
0221: * point to the same place in memory.
0222: */
0223: protected int intDataArrays[][] = null;
0224:
0225: /**
0226: * The image data in a two-dimensional float array. This
0227: * value will be non-null only if getDataType() returns
0228: * DataBuffer.TYPE_FLOAT. floatDataArrays.length will equal
0229: * numBands. Note that often the numBand subArrays will all
0230: * point to the same place in memory.
0231: */
0232: protected float floatDataArrays[][] = null;
0233:
0234: /**
0235: * The image data in a two-dimensional double array. This
0236: * value will be non-null only if getDataType() returns
0237: * DataBuffer.TYPE_DOUBLE. doubleDataArrays.length will equal
0238: * numBands. Note that often the numBand subArrays will all
0239: * point to the same place in memory.
0240: */
0241: protected double doubleDataArrays[][] = null;
0242:
0243: /**
0244: * The bandOffset + subRasterOffset + DataBufferOffset into each of
0245: * the numBand data arrays
0246: */
0247: protected int bandDataOffsets[];
0248:
0249: /** Offset from a pixel's offset to a band of that pixel */
0250: protected int bandOffsets[];
0251:
0252: /** The number of bands per pixel in the data array. */
0253: protected int numBands;
0254:
0255: /** The scanline stride of the image data in each data array */
0256: protected int scanlineStride;
0257:
0258: /** The pixel stride of the image data in each data array */
0259: protected int pixelStride;
0260:
0261: /**
0262: * Finds the appropriate tags for the constructor, based on the
0263: * SampleModel and ColorModel of all the source and destination.
0264: *
0265: * @param srcs The operations sources; may be <code>null</code> which
0266: * is taken to be equivalent to zero sources.
0267: * @param dst The operation destination.
0268: * @return An array containing <code>RasterFormatTag</code>s for the
0269: * sources in the first src.length elements and a
0270: * <code>RasterFormatTag</code> for the destination in the last element.
0271: * @throws NullPointerException if <code>dst</code> is <code>null</code>.
0272: */
0273: public static RasterFormatTag[] findCompatibleTags(
0274: RenderedImage srcs[], RenderedImage dst) {
0275: int tagIDs[];
0276: if (srcs != null) {
0277: tagIDs = new int[srcs.length + 1];
0278: } else {
0279: tagIDs = new int[1];
0280: }
0281: SampleModel dstSampleModel = dst.getSampleModel();
0282: int dstDataType = dstSampleModel.getTransferType();
0283:
0284: int defaultDataType = dstDataType;
0285: boolean binaryDst = ImageUtil.isBinary(dstSampleModel);
0286: if (binaryDst) {
0287: defaultDataType = DataBuffer.TYPE_BYTE;
0288: } else if ((dstDataType == DataBuffer.TYPE_BYTE)
0289: || (dstDataType == DataBuffer.TYPE_USHORT)
0290: || (dstDataType == DataBuffer.TYPE_SHORT)) {
0291: defaultDataType = DataBuffer.TYPE_INT;
0292: }
0293:
0294: // use highest precision datatype of all srcs & dst
0295: if (srcs != null) {
0296: int numSources = srcs.length;
0297: int i;
0298: for (i = 0; i < numSources; i++) {
0299: SampleModel srcSampleModel = srcs[i].getSampleModel();
0300: int srcDataType = srcSampleModel.getTransferType();
0301: if (!(binaryDst && ImageUtil.isBinary(srcSampleModel))
0302: && srcDataType > defaultDataType) {
0303: defaultDataType = srcDataType;
0304: }
0305: }
0306: }
0307:
0308: // Set the tag. For binary data at this point this should
0309: // equal DataBuffer.TYPE_BYTE | COPIED.
0310: int tagID = defaultDataType | COPIED;
0311:
0312: if (dstSampleModel instanceof ComponentSampleModel) {
0313: if (srcs != null) {
0314: int numSources = srcs.length;
0315: int i;
0316: for (i = 0; i < numSources; i++) {
0317: SampleModel srcSampleModel = srcs[i]
0318: .getSampleModel();
0319: int srcDataType = srcSampleModel.getTransferType();
0320: if (!(srcSampleModel instanceof ComponentSampleModel)
0321: || (srcDataType != dstDataType)) {
0322: break;
0323: }
0324: }
0325: if (i == numSources) {
0326: tagID = dstDataType | UNCOPIED;
0327: }
0328: } else {
0329: tagID = dstDataType | UNCOPIED;
0330: }
0331: }
0332:
0333: // If the source has an IndexColorModel but the dest does not,
0334: // perform expansion of the source pixels. If both have an
0335: // IndexColorModel, assume the operation knows what it is doing.
0336: RasterFormatTag rft[] = new RasterFormatTag[tagIDs.length];
0337: if (srcs != null) {
0338: for (int i = 0; i < srcs.length; i++) {
0339: // dst can't be EXPANDED
0340: if ((srcs[i].getColorModel() instanceof IndexColorModel)) {
0341: if (dst.getColorModel() instanceof IndexColorModel) {
0342: tagIDs[i] = tagID | UNEXPANDED;
0343: } else {
0344: tagIDs[i] = tagID | EXPANDED;
0345: }
0346: } else if (srcs[i].getColorModel() instanceof ComponentColorModel
0347: || (binaryDst && ImageUtil.isBinary(srcs[i]
0348: .getSampleModel()))) {
0349: tagIDs[i] = tagID | UNEXPANDED;
0350: } else {
0351: tagIDs[i] = tagID | DEFAULTEXPANSION;
0352: }
0353: }
0354: tagIDs[srcs.length] = tagID | UNEXPANDED;
0355:
0356: for (int i = 0; i < srcs.length; i++) {
0357: rft[i] = new RasterFormatTag(srcs[i].getSampleModel(),
0358: tagIDs[i]);
0359: }
0360: // get the dest
0361: rft[srcs.length] = new RasterFormatTag(dstSampleModel,
0362: tagIDs[srcs.length]);
0363: } else { // no sources, dest only
0364: rft[0] = new RasterFormatTag(dstSampleModel, tagID
0365: | UNEXPANDED);
0366: }
0367:
0368: return rft;
0369: }
0370:
0371: /**
0372: * Returns the most efficient FormatTagID that is compatible with
0373: * the destination SampleModel and all source SampleModels.
0374: * Since there is no <code>ColorModel</code> associated with
0375: * a <code>SampleModel</code>, this method does not expand the data
0376: * buffer as it has no access to the Raster's ColorModel.
0377: */
0378: public static int findCompatibleTag(SampleModel[] srcSampleModels,
0379: SampleModel dstSampleModel) {
0380: int dstDataType = dstSampleModel.getTransferType();
0381:
0382: int tag = dstDataType | COPIED;
0383: if (ImageUtil.isBinary(dstSampleModel)) {
0384: tag = DataBuffer.TYPE_BYTE | COPIED;
0385: } else if (dstDataType == DataBuffer.TYPE_BYTE
0386: || dstDataType == DataBuffer.TYPE_USHORT
0387: || dstDataType == DataBuffer.TYPE_SHORT) {
0388: tag = TAG_INT_COPIED;
0389: }
0390:
0391: if (dstSampleModel instanceof ComponentSampleModel) {
0392: if (srcSampleModels != null) {
0393: int numSources = srcSampleModels.length;
0394: int i;
0395: for (i = 0; i < numSources; i++) {
0396: int srcDataType = srcSampleModels[i]
0397: .getTransferType();
0398:
0399: if (!(srcSampleModels[i] instanceof ComponentSampleModel)
0400: || srcDataType != dstDataType) {
0401: break;
0402: }
0403: }
0404: if (i == numSources) {
0405: tag = dstDataType | UNCOPIED;
0406: }
0407: } else {
0408: tag = dstDataType | UNCOPIED;
0409: }
0410: }
0411: return tag | UNEXPANDED; // only called when colormodel not around
0412: // so never expand
0413: }
0414:
0415: /**
0416: * Constructs a RasterAccessor object out of a Raster, Rectangle
0417: * and formatTagID returned from RasterFormat.findCompatibleTag().
0418: *
0419: * <p> The <code>RasterFormatTag</code> must agree with the raster's
0420: * <code>SampleModel</code> and <code>ColorModel</code>. It is best
0421: * to obtain the correct tag using the <code>findCompatibleTags</code>
0422: * static method.
0423: *
0424: * @param raster The raster to be accessed
0425: * @param rect A <code>Rectangle</code> from the raster to be accessed
0426: * @param rft The <code>RasterFormatTag</code> associated with the Raster
0427: * @param theColorModel The <code>ColorModel</code> for color components
0428: *
0429: * @throws ClassCastException if the data type of
0430: * <code>RasterFormatTag</code> does not agree with the actual
0431: * data type of the <code>Raster</code>.
0432: * @throws IllegalArgumentException if <code>raster</code>,
0433: * <code>rect</code>, or <code>rft</code> is <code>null</code>.
0434: * @throws IllegalArgumentException if the <code>Rectangle</code>
0435: * is not contained within <code>Raster</code>'s bounds.
0436: */
0437: public RasterAccessor(Raster raster, Rectangle rect,
0438: RasterFormatTag rft, ColorModel theColorModel) {
0439:
0440: if (raster == null || rect == null || rft == null) {
0441: throw new IllegalArgumentException(JaiI18N
0442: .getString("Generic0"));
0443: }
0444:
0445: // If requesting a region that lies outside the bounds,
0446: // throw an exception.
0447: if (!raster.getBounds().contains(rect)) {
0448: throw new IllegalArgumentException(JaiI18N
0449: .getString("RasterAccessor2"));
0450: }
0451:
0452: this .raster = raster;
0453: this .rectX = rect.x;
0454: this .rectY = rect.y;
0455: this .rectWidth = rect.width;
0456: this .rectHeight = rect.height;
0457: this .formatTagID = rft.getFormatTagID();
0458: if ((formatTagID & COPY_MASK) == UNCOPIED) {
0459:
0460: this .numBands = rft.getNumBands();
0461: this .pixelStride = rft.getPixelStride();
0462:
0463: ComponentSampleModel csm = (ComponentSampleModel) raster
0464: .getSampleModel();
0465: this .scanlineStride = csm.getScanlineStride();
0466:
0467: int bankIndices[] = null;
0468:
0469: // if the rft isPixelSequential we can rely on it's
0470: // version of bandOffsets and bankIndicies. If it's
0471: // not the SampleModel passed in might not completely
0472: // match the one that was passed to the the
0473: // RasterFormatTag constructor so we have to get them
0474: // from the passed in Raster/SampleModel
0475: if (rft.isPixelSequential()) {
0476: this .bandOffsets = rft.getBandOffsets();
0477: bankIndices = rft.getBankIndices();
0478: } else {
0479: this .bandOffsets = csm.getBandOffsets();
0480: bankIndices = csm.getBankIndices();
0481: }
0482:
0483: this .bandDataOffsets = new int[numBands];
0484:
0485: int dataBufferOffsets[] = raster.getDataBuffer()
0486: .getOffsets();
0487:
0488: int subRasterOffset = (rectY - raster
0489: .getSampleModelTranslateY())
0490: * scanlineStride
0491: + (rectX - raster.getSampleModelTranslateX())
0492: * pixelStride;
0493:
0494: if (dataBufferOffsets.length == 1) {
0495: int theDataBufferOffset = dataBufferOffsets[0];
0496: for (int i = 0; i < numBands; i++) {
0497: bandDataOffsets[i] = bandOffsets[i]
0498: + theDataBufferOffset + subRasterOffset;
0499: }
0500: } else if (dataBufferOffsets.length == bandDataOffsets.length) {
0501: for (int i = 0; i < numBands; i++) {
0502: bandDataOffsets[i] = bandOffsets[i]
0503: + dataBufferOffsets[i] + subRasterOffset;
0504: }
0505: } else {
0506: throw new RuntimeException(JaiI18N
0507: .getString("RasterAccessor0"));
0508: }
0509:
0510: switch (formatTagID & DATATYPE_MASK) {
0511: case DataBuffer.TYPE_BYTE:
0512: DataBufferByte dbb = (DataBufferByte) raster
0513: .getDataBuffer();
0514: byteDataArrays = new byte[numBands][];
0515: for (int i = 0; i < numBands; i++) {
0516: byteDataArrays[i] = dbb.getData(bankIndices[i]);
0517: }
0518: break;
0519:
0520: case DataBuffer.TYPE_USHORT:
0521: DataBufferUShort dbus = (DataBufferUShort) raster
0522: .getDataBuffer();
0523: shortDataArrays = new short[numBands][];
0524: for (int i = 0; i < numBands; i++) {
0525: shortDataArrays[i] = dbus.getData(bankIndices[i]);
0526: }
0527: break;
0528:
0529: case DataBuffer.TYPE_SHORT:
0530: DataBufferShort dbs = (DataBufferShort) raster
0531: .getDataBuffer();
0532: shortDataArrays = new short[numBands][];
0533: for (int i = 0; i < numBands; i++) {
0534: shortDataArrays[i] = dbs.getData(bankIndices[i]);
0535: }
0536: break;
0537:
0538: case DataBuffer.TYPE_INT:
0539: DataBufferInt dbi = (DataBufferInt) raster
0540: .getDataBuffer();
0541: intDataArrays = new int[numBands][];
0542: for (int i = 0; i < numBands; i++) {
0543: intDataArrays[i] = dbi.getData(bankIndices[i]);
0544: }
0545: break;
0546:
0547: case DataBuffer.TYPE_FLOAT:
0548: DataBuffer dbf = (DataBuffer) raster.getDataBuffer();
0549: floatDataArrays = new float[numBands][];
0550: for (int i = 0; i < numBands; i++) {
0551: floatDataArrays[i] = DataBufferUtils.getDataFloat(
0552: dbf, bankIndices[i]);
0553: }
0554: break;
0555:
0556: case DataBuffer.TYPE_DOUBLE:
0557: DataBuffer dbd = (DataBuffer) raster.getDataBuffer();
0558: doubleDataArrays = new double[numBands][];
0559: for (int i = 0; i < numBands; i++) {
0560: doubleDataArrays[i] = DataBufferUtils
0561: .getDataDouble(dbd, bankIndices[i]);
0562: }
0563: break;
0564: }
0565: // only do this if not copied and expanded
0566: if ((formatTagID & EXPANSION_MASK) == EXPANDED
0567: && theColorModel instanceof IndexColorModel) {
0568: IndexColorModel icm = (IndexColorModel) theColorModel;
0569:
0570: int newNumBands = icm.getNumComponents();
0571:
0572: int mapSize = icm.getMapSize();
0573: int newBandDataOffsets[] = new int[newNumBands];
0574: int newScanlineStride = rectWidth * newNumBands;
0575: int newPixelStride = newNumBands;
0576: byte ctable[][] = new byte[newNumBands][mapSize];
0577:
0578: icm.getReds(ctable[0]);
0579: icm.getGreens(ctable[1]);
0580: icm.getBlues(ctable[2]);
0581: byte rtable[] = ctable[0];
0582: byte gtable[] = ctable[1];
0583: byte btable[] = ctable[2];
0584:
0585: byte atable[] = null;
0586: if (newNumBands == 4) {
0587: icm.getAlphas(ctable[3]);
0588: atable = ctable[3];
0589: }
0590:
0591: for (int i = 0; i < newNumBands; i++) {
0592: newBandDataOffsets[i] = i;
0593: }
0594:
0595: switch (formatTagID & DATATYPE_MASK) {
0596: case DataBuffer.TYPE_BYTE: {
0597: byte newBArray[] = new byte[rectWidth * rectHeight
0598: * newNumBands];
0599: byte byteDataArray[] = byteDataArrays[0];
0600: int scanlineOffset = bandDataOffsets[0];
0601: int newScanlineOffset = 0;
0602: for (int j = 0; j < rectHeight; j++) {
0603: int pixelOffset = scanlineOffset;
0604: int newPixelOffset = newScanlineOffset;
0605: for (int i = 0; i < rectWidth; i++) {
0606: int index = byteDataArray[pixelOffset] & 0xff;
0607: for (int k = 0; k < newNumBands; k++) {
0608: newBArray[newPixelOffset + k] = ctable[k][index];
0609: }
0610: pixelOffset += pixelStride;
0611: newPixelOffset += newPixelStride;
0612: }
0613: scanlineOffset += scanlineStride;
0614: newScanlineOffset += newScanlineStride;
0615: }
0616: byteDataArrays = new byte[newNumBands][];
0617: for (int i = 0; i < newNumBands; i++) {
0618: byteDataArrays[i] = newBArray;
0619: }
0620: }
0621: break;
0622:
0623: case DataBuffer.TYPE_USHORT: {
0624: short newIArray[] = new short[rectWidth
0625: * rectHeight * newNumBands];
0626: short shortDataArray[] = shortDataArrays[0];
0627: int scanlineOffset = bandDataOffsets[0];
0628: int newScanlineOffset = 0;
0629: for (int j = 0; j < rectHeight; j++) {
0630: int pixelOffset = scanlineOffset;
0631: int newPixelOffset = newScanlineOffset;
0632: for (int i = 0; i < rectWidth; i++) {
0633: int index = (shortDataArray[pixelOffset] & 0xffff);
0634: for (int k = 0; k < newNumBands; k++) {
0635: newIArray[newPixelOffset + k] = (short) (ctable[k][index] & 0xff);
0636: }
0637: pixelOffset += pixelStride;
0638: newPixelOffset += newPixelStride;
0639: }
0640: scanlineOffset += scanlineStride;
0641: newScanlineOffset += newScanlineStride;
0642: }
0643:
0644: shortDataArrays = new short[newNumBands][];
0645: for (int i = 0; i < newNumBands; i++) {
0646: shortDataArrays[i] = newIArray;
0647: }
0648: }
0649: break;
0650:
0651: case DataBuffer.TYPE_SHORT: {
0652: short newIArray[] = new short[rectWidth
0653: * rectHeight * newNumBands];
0654: short shortDataArray[] = shortDataArrays[0];
0655: int scanlineOffset = bandDataOffsets[0];
0656: int newScanlineOffset = 0;
0657: for (int j = 0; j < rectHeight; j++) {
0658: int pixelOffset = scanlineOffset;
0659: int newPixelOffset = newScanlineOffset;
0660: for (int i = 0; i < rectWidth; i++) {
0661: int index = shortDataArray[pixelOffset];
0662: for (int k = 0; k < newNumBands; k++) {
0663: newIArray[newPixelOffset + k] = (short) (ctable[k][index] & 0xff);
0664: }
0665: pixelOffset += pixelStride;
0666: newPixelOffset += newPixelStride;
0667: }
0668: scanlineOffset += scanlineStride;
0669: newScanlineOffset += newScanlineStride;
0670: }
0671:
0672: shortDataArrays = new short[newNumBands][];
0673: for (int i = 0; i < newNumBands; i++) {
0674: shortDataArrays[i] = newIArray;
0675: }
0676: }
0677: break;
0678:
0679: case DataBuffer.TYPE_INT: {
0680: int newIArray[] = new int[rectWidth * rectHeight
0681: * newNumBands];
0682: int intDataArray[] = intDataArrays[0];
0683: int scanlineOffset = bandDataOffsets[0];
0684: int newScanlineOffset = 0;
0685: for (int j = 0; j < rectHeight; j++) {
0686: int pixelOffset = scanlineOffset;
0687: int newPixelOffset = newScanlineOffset;
0688: for (int i = 0; i < rectWidth; i++) {
0689: int index = intDataArray[pixelOffset];
0690: for (int k = 0; k < newNumBands; k++) {
0691: newIArray[newPixelOffset + k] = (ctable[k][index] & 0xff);
0692: }
0693: pixelOffset += pixelStride;
0694: newPixelOffset += newPixelStride;
0695: }
0696: scanlineOffset += scanlineStride;
0697: newScanlineOffset += newScanlineStride;
0698: }
0699:
0700: intDataArrays = new int[newNumBands][];
0701: for (int i = 0; i < newNumBands; i++) {
0702: intDataArrays[i] = newIArray;
0703: }
0704: }
0705: break;
0706:
0707: case DataBuffer.TYPE_FLOAT: {
0708: float newFArray[] = new float[rectWidth
0709: * rectHeight * newNumBands];
0710: float floatDataArray[] = floatDataArrays[0];
0711: int scanlineOffset = bandDataOffsets[0];
0712: int newScanlineOffset = 0;
0713: for (int j = 0; j < rectHeight; j++) {
0714: int pixelOffset = scanlineOffset;
0715: int newPixelOffset = newScanlineOffset;
0716: for (int i = 0; i < rectWidth; i++) {
0717: int index = (int) floatDataArray[pixelOffset];
0718: for (int k = 0; k < newNumBands; k++) {
0719: newFArray[newPixelOffset + k] = (ctable[k][index] & 0xff);
0720: }
0721: pixelOffset += pixelStride;
0722: newPixelOffset += newPixelStride;
0723: }
0724: scanlineOffset += scanlineStride;
0725: newScanlineOffset += newScanlineStride;
0726: }
0727: floatDataArrays = new float[newNumBands][];
0728: for (int i = 0; i < newNumBands; i++) {
0729: floatDataArrays[i] = newFArray;
0730: }
0731: }
0732: break;
0733:
0734: case DataBuffer.TYPE_DOUBLE: {
0735: double newDArray[] = new double[rectWidth
0736: * rectHeight * newNumBands];
0737: double doubleDataArray[] = doubleDataArrays[0];
0738: int scanlineOffset = bandDataOffsets[0];
0739: int newScanlineOffset = 0;
0740: for (int j = 0; j < rectHeight; j++) {
0741: int pixelOffset = scanlineOffset;
0742: int newPixelOffset = newScanlineOffset;
0743: for (int i = 0; i < rectWidth; i++) {
0744: int index = (int) doubleDataArray[pixelOffset];
0745: for (int k = 0; k < newNumBands; k++) {
0746: newDArray[newPixelOffset + k] = (ctable[k][index] & 0xff);
0747: }
0748: pixelOffset += pixelStride;
0749: newPixelOffset += newPixelStride;
0750: }
0751: scanlineOffset += scanlineStride;
0752: newScanlineOffset += newScanlineStride;
0753: }
0754: doubleDataArrays = new double[newNumBands][];
0755: for (int i = 0; i < newNumBands; i++) {
0756: doubleDataArrays[i] = newDArray;
0757: }
0758: }
0759: break;
0760: }
0761: this .numBands = newNumBands;
0762: this .pixelStride = newPixelStride;
0763: this .scanlineStride = newScanlineStride;
0764: this .bandDataOffsets = newBandDataOffsets;
0765: this .bandOffsets = newBandDataOffsets;
0766: }
0767: } else if ((formatTagID & COPY_MASK) == COPIED
0768: && (formatTagID & EXPANSION_MASK) != UNEXPANDED
0769: && theColorModel != null) {
0770: this .numBands = theColorModel instanceof IndexColorModel ? theColorModel
0771: .getNumComponents()
0772: : raster.getSampleModel().getNumBands();
0773: this .pixelStride = this .numBands;
0774: this .scanlineStride = rectWidth * numBands;
0775: this .bandOffsets = new int[numBands];
0776:
0777: for (int i = 0; i < numBands; i++) {
0778: bandOffsets[i] = i;
0779: }
0780: this .bandDataOffsets = bandOffsets;
0781:
0782: Object odata = null;
0783: int offset = 0;
0784:
0785: int[] components = new int[theColorModel.getNumComponents()];
0786:
0787: switch (formatTagID & DATATYPE_MASK) {
0788:
0789: case DataBuffer.TYPE_INT:
0790: int idata[] = new int[rectWidth * rectHeight * numBands];
0791: intDataArrays = new int[numBands][];
0792: for (int i = 0; i < numBands; i++) {
0793: intDataArrays[i] = idata;
0794: }
0795:
0796: odata = raster.getDataElements(rectX, rectY, null);
0797: offset = 0;
0798:
0799: // Workaround for bug in BytePackedRaster
0800: byte[] bdata = null;
0801: if (raster instanceof sun.awt.image.BytePackedRaster) {
0802: bdata = (byte[]) odata;
0803: }
0804:
0805: for (int j = rectY; j < rectY + rectHeight; j++) {
0806: for (int i = rectX; i < rectX + rectWidth; i++) {
0807: if (bdata != null) {
0808: bdata[0] = (byte) raster.getSample(i, j, 0);
0809: } else {
0810: raster.getDataElements(i, j, odata);
0811: }
0812:
0813: theColorModel.getComponents(odata, components,
0814: 0);
0815:
0816: idata[offset] = components[0];
0817: idata[offset + 1] = components[1];
0818: idata[offset + 2] = components[2];
0819: if (numBands > 3) {
0820: idata[offset + 3] = components[3];
0821: }
0822:
0823: offset += pixelStride;
0824: }
0825: }
0826: break;
0827:
0828: case DataBuffer.TYPE_FLOAT:
0829: float fdata[] = new float[rectWidth * rectHeight
0830: * numBands];
0831: floatDataArrays = new float[numBands][];
0832: for (int i = 0; i < numBands; i++) {
0833: floatDataArrays[i] = fdata;
0834: }
0835: odata = null;
0836: offset = 0;
0837: for (int j = rectY; j < rectY + rectHeight; j++) {
0838: for (int i = rectX; i < rectX + rectWidth; i++) {
0839: odata = raster.getDataElements(i, j, odata);
0840:
0841: theColorModel.getComponents(odata, components,
0842: 0);
0843:
0844: fdata[offset] = components[0];
0845: fdata[offset + 1] = components[1];
0846: fdata[offset + 2] = components[2];
0847: if (numBands > 3) {
0848: fdata[offset + 3] = components[3];
0849: }
0850: offset += pixelStride;
0851: }
0852: }
0853: break;
0854:
0855: case DataBuffer.TYPE_DOUBLE:
0856: double ddata[] = new double[rectWidth * rectHeight
0857: * numBands];
0858: doubleDataArrays = new double[numBands][];
0859: for (int i = 0; i < numBands; i++) {
0860: doubleDataArrays[i] = ddata;
0861: }
0862: odata = null;
0863: offset = 0;
0864: for (int j = rectY; j < rectY + rectHeight; j++) {
0865: for (int i = rectX; i < rectX + rectWidth; i++) {
0866: odata = raster.getDataElements(i, j, odata);
0867:
0868: theColorModel.getComponents(odata, components,
0869: 0);
0870:
0871: ddata[offset] = components[0];
0872: ddata[offset + 1] = components[1];
0873: ddata[offset + 2] = components[2];
0874: if (numBands > 3) {
0875: ddata[offset + 3] = components[3];
0876: }
0877: offset += pixelStride;
0878: }
0879: }
0880: break;
0881: }
0882: } else {
0883: // if ((formatTagID & COPY_MASK) == COPIED &&
0884: // (formatTagID & EXPANSION_MASK) == UNEXPANDED) {
0885: // this has become a catchall case. Specifically for
0886: // Rasters with null colormodels. So we take out the
0887: // if as the boolean clause will get way complicated
0888: // otherwise.
0889: this .numBands = rft.getNumBands();
0890: this .pixelStride = this .numBands;
0891: this .scanlineStride = rectWidth * numBands;
0892: this .bandDataOffsets = rft.getBandOffsets();
0893: this .bandOffsets = this .bandDataOffsets;
0894:
0895: switch (formatTagID & DATATYPE_MASK) {
0896: case DataBuffer.TYPE_INT:
0897: int idata[] = raster.getPixels(rectX, rectY, rectWidth,
0898: rectHeight, (int[]) null);
0899: intDataArrays = new int[numBands][];
0900: for (int i = 0; i < numBands; i++) {
0901: intDataArrays[i] = idata;
0902: }
0903: break;
0904:
0905: case DataBuffer.TYPE_FLOAT:
0906: float fdata[] = raster.getPixels(rectX, rectY,
0907: rectWidth, rectHeight, (float[]) null);
0908: floatDataArrays = new float[numBands][];
0909: for (int i = 0; i < numBands; i++) {
0910: floatDataArrays[i] = fdata;
0911: }
0912: break;
0913:
0914: case DataBuffer.TYPE_DOUBLE:
0915: double ddata[] = raster.getPixels(rectX, rectY,
0916: rectWidth, rectHeight, (double[]) null);
0917: doubleDataArrays = new double[numBands][];
0918: for (int i = 0; i < numBands; i++) {
0919: doubleDataArrays[i] = ddata;
0920: }
0921: break;
0922: }
0923: }
0924: }
0925:
0926: /**
0927: * Returns the x coordinate of the upper-left corner of the
0928: * RasterAccessor's accessible area.
0929: */
0930: public int getX() {
0931: return rectX;
0932: }
0933:
0934: /**
0935: * Returns the y coordinate of the upper-left corner of the
0936: * RasterAccessor's accessible area.
0937: */
0938: public int getY() {
0939: return rectY;
0940: }
0941:
0942: /** Returns the width of the
0943: * RasterAccessor's accessible area.
0944: */
0945: public int getWidth() {
0946: return rectWidth;
0947: }
0948:
0949: /** Returns the height of the
0950: * RasterAccessor's accessible area.
0951: */
0952: public int getHeight() {
0953: return rectHeight;
0954: }
0955:
0956: /** Returns the numBands of the presented area. */
0957: public int getNumBands() {
0958: return numBands;
0959: }
0960:
0961: /**
0962: * Whether the <code>RasterAccessor</code> represents binary data.
0963: * This occurs when the <code>Raster</code> has a
0964: * <code>MultiPixelPackedSampleModel</code> with a single band and
0965: * one bit per pixel.
0966: *
0967: * @since JAI 1.1
0968: */
0969: public boolean isBinary() {
0970: return (formatTagID & TAG_BINARY) == TAG_BINARY
0971: && ImageUtil.isBinary(raster.getSampleModel());
0972: }
0973:
0974: /**
0975: * For the case of binary data (<code>isBinary()</code> returns
0976: * <code>true</code>), return the binary data as a packed byte array.
0977: * The data will be packed as eight bits per byte with no bit offset,
0978: * i.e., the first bit in each image line will be the left-most of the
0979: * first byte of the line. The line stride in bytes will be
0980: * <code>(int)((getWidth()+7)/8)</code>. The length of the returned
0981: * array will be the line stride multiplied by <code>getHeight()</code>
0982: *
0983: * @return the binary data as a packed array of bytes with zero offset
0984: * of <code>null</code> if the data are not binary.
0985: *
0986: * @since JAI 1.1
0987: */
0988: public byte[] getBinaryDataArray() {
0989: if (binaryDataArray == null && isBinary()) {
0990: binaryDataArray = ImageUtil.getPackedBinaryData(raster,
0991: new Rectangle(rectX, rectY, rectWidth, rectHeight));
0992: }
0993: return binaryDataArray;
0994: }
0995:
0996: /**
0997: * Returns the image data as a byte array. Non-null only if
0998: * getDataType = DataBuffer.TYPE_BYTE.
0999: *
1000: * <p> For the case of binary data the corresponding instance variable
1001: * <code>byteDataArrays</code> will not be initialized until this
1002: * method or <code>getByteDataArray(int b)</code> is invoked. The
1003: * binary data will be returned as bytes with value 0 or 1.
1004: */
1005: public byte[][] getByteDataArrays() {
1006: if (byteDataArrays == null && isBinary()) {
1007: byte[] bdata = ImageUtil.getUnpackedBinaryData(raster,
1008: new Rectangle(rectX, rectY, rectWidth, rectHeight));
1009: byteDataArrays = new byte[][] { bdata };
1010: }
1011: return byteDataArrays;
1012: }
1013:
1014: /**
1015: * Returns the image data as a byte array for a specific band.
1016: * Non-null only if getDataType = DataBuffer.TYPE_BYTE.
1017: */
1018: public byte[] getByteDataArray(int b) {
1019: byte[][] bda = getByteDataArrays();
1020: return (bda == null ? null : bda[b]);
1021: }
1022:
1023: /**
1024: * Returns the image data as a short array. Non-null only if
1025: * getDataType = DataBuffer.TYPE_USHORT or DataBuffer.TYPE_SHORT.
1026: */
1027: public short[][] getShortDataArrays() {
1028: return shortDataArrays;
1029: }
1030:
1031: /**
1032: * Returns the image data as a short array for a specific band.
1033: * Non-null only if getDataType = DataBuffer.TYPE_USHORT or
1034: * DataBuffer.TYPE_SHORT.
1035: */
1036: public short[] getShortDataArray(int b) {
1037: return (shortDataArrays == null ? null : shortDataArrays[b]);
1038: }
1039:
1040: /**
1041: * Returns the image data as an int array. Non-null only if
1042: * getDataType = DataBuffer.TYPE_INT.
1043: */
1044: public int[][] getIntDataArrays() {
1045: return intDataArrays;
1046: }
1047:
1048: /**
1049: * Returns the image data as an int array for a specific band.
1050: * Non-null only if getDataType = DataBuffer.TYPE_INT.
1051: */
1052: public int[] getIntDataArray(int b) {
1053: return (intDataArrays == null ? null : intDataArrays[b]);
1054: }
1055:
1056: /**
1057: * Returns the image data as a float array. Non-null only if
1058: * getDataType = DataBuffer.TYPE_FLOAT.
1059: */
1060: public float[][] getFloatDataArrays() {
1061: return floatDataArrays;
1062: }
1063:
1064: /**
1065: * Returns the image data as a float array for a specific band.
1066: * Non-null only if getDataType = DataBuffer.TYPE_FLOAT.
1067: */
1068: public float[] getFloatDataArray(int b) {
1069: return (floatDataArrays == null ? null : floatDataArrays[b]);
1070: }
1071:
1072: /**
1073: * Returns the image data as a double array. Non-null only if
1074: * getDataType = DataBuffer.TYPE_DOUBLE
1075: */
1076: public double[][] getDoubleDataArrays() {
1077: return doubleDataArrays;
1078: }
1079:
1080: /**
1081: * Returns the image data as a double array for a specific band.
1082: * Non-null only if getDataType = DataBuffer.TYPE_DOUBLE
1083: */
1084: public double[] getDoubleDataArray(int b) {
1085: return (doubleDataArrays == null ? null : doubleDataArrays[b]);
1086: }
1087:
1088: /**
1089: * Returns the image data as an Object for a specific band.
1090: *
1091: * @param b The index of the image band of interest.
1092: */
1093: public Object getDataArray(int b) {
1094: Object dataArray = null;
1095: switch (getDataType()) {
1096: case DataBuffer.TYPE_BYTE:
1097: dataArray = getByteDataArray(b);
1098: break;
1099:
1100: case DataBuffer.TYPE_SHORT:
1101: case DataBuffer.TYPE_USHORT:
1102: dataArray = getShortDataArray(b);
1103: break;
1104:
1105: case DataBuffer.TYPE_INT:
1106: dataArray = getIntDataArray(b);
1107: break;
1108:
1109: case DataBuffer.TYPE_FLOAT:
1110: dataArray = getFloatDataArray(b);
1111: break;
1112:
1113: case DataBuffer.TYPE_DOUBLE:
1114: dataArray = getDoubleDataArray(b);
1115: break;
1116:
1117: default:
1118: dataArray = null;
1119: }
1120:
1121: return dataArray;
1122: }
1123:
1124: /** Returns the bandDataOffsets into the dataArrays. */
1125: public int[] getBandOffsets() {
1126: return bandDataOffsets;
1127: }
1128:
1129: /**
1130: * Returns the offset of all band's samples from any
1131: * pixel offset.
1132: */
1133: public int[] getOffsetsForBands() {
1134: return bandOffsets;
1135: }
1136:
1137: /**
1138: * Returns the offset of a specific band's first sample into the
1139: * DataBuffer including the DataBuffer's offset.
1140: */
1141: public int getBandOffset(int b) {
1142: return bandDataOffsets[b];
1143: }
1144:
1145: /**
1146: * Returns the offset of a specified band's sample from any
1147: * pixel offset.
1148: */
1149: public int getOffsetForBand(int b) {
1150: return bandOffsets[b];
1151: }
1152:
1153: /**
1154: * Returns the scanlineStride for the image data.
1155: *
1156: * <p> For binary data this stride is applies to the arrays returned by
1157: * <code>getByteDataArray()</code> and <code>getByteDataArrays()</code>
1158: * if the data are accessed as bytes; it does not apply to the array
1159: * returned by <code>getBinaryDataArray()</code> when the data are
1160: * accessed as bits packed into bytes.
1161: */
1162: public int getScanlineStride() {
1163: return scanlineStride;
1164: }
1165:
1166: /** Returns the pixelStride for the image data. */
1167: public int getPixelStride() {
1168: return pixelStride;
1169: }
1170:
1171: /**
1172: * Returns the data type of the RasterAccessor object. Note that
1173: * this datatype is not necessarily the same data type as the
1174: * underlying raster.
1175: */
1176: public int getDataType() {
1177: return formatTagID & DATATYPE_MASK;
1178: }
1179:
1180: /**
1181: * Returns true if the RasterAccessors's data is copied from it's
1182: * raster.
1183: */
1184: public boolean isDataCopy() {
1185: return ((formatTagID & COPY_MASK) == COPIED);
1186: }
1187:
1188: /**
1189: * For the case of binary data (<code>isBinary()</code> returns
1190: * <code>true</code>), copy the binary data back into the
1191: * <code>Raster</code> of the <code>RasterAccessor</code>. If
1192: * this method is invoked in the non-binary case it does nothing.
1193: * Any bit offset in the original <code>SampleModel</code> will be
1194: * accounted for.
1195: *
1196: * @since JAI 1.1
1197: */
1198: // Note: ALL branches of this method have been tested. (bpb 10 May 2000)
1199: public void copyBinaryDataToRaster() {
1200: if (binaryDataArray == null || !isBinary()) {
1201: return;
1202: }
1203:
1204: ImageUtil.setPackedBinaryData(binaryDataArray,
1205: (WritableRaster) raster, new Rectangle(rectX, rectY,
1206: rectWidth, rectHeight));
1207: }
1208:
1209: /**
1210: * Copies data back into the RasterAccessor's raster. Note that
1211: * the data is cast from the intermediate data format to
1212: * the raster's format. If clamping is needed, the call
1213: * clampDataArrays() method needs to be called before
1214: * calling the copyDataToRaster() method.
1215: * Note: the raster is expected to be writable - typically a
1216: * destination raster - otherwise, a run-time exception will occur.
1217: *
1218: * <p> If the data are binary, then the target bit will be set if
1219: * and only if the corresponding byte is non-zero.
1220: */
1221: public void copyDataToRaster() {
1222: if (isDataCopy()) {
1223:
1224: // Writeback should only be necessary on destRasters which
1225: // should be writable so this cast should succeed.
1226: WritableRaster wr = (WritableRaster) raster;
1227: switch (getDataType()) {
1228: case DataBuffer.TYPE_BYTE:
1229: // Note: ALL branches of this case have been tested.
1230: // (bpb 10 May 2000)
1231: if (!isBinary()) {
1232: // If this exception occurs then there is a logic
1233: // error within this accessor since the only case
1234: // wherein byte data should be COPIED is when the
1235: // data set is binary.
1236: throw new RuntimeException(JaiI18N
1237: .getString("RasterAccessor1"));
1238: }
1239:
1240: // This case only occurs for binary src and dst.
1241:
1242: ImageUtil.setUnpackedBinaryData(byteDataArrays[0], wr,
1243: new Rectangle(rectX, rectY, rectWidth,
1244: rectHeight));
1245: break;
1246: case DataBuffer.TYPE_INT:
1247: wr.setPixels(rectX, rectY, rectWidth, rectHeight,
1248: intDataArrays[0]);
1249: break;
1250:
1251: case DataBuffer.TYPE_FLOAT:
1252: wr.setPixels(rectX, rectY, rectWidth, rectHeight,
1253: floatDataArrays[0]);
1254: break;
1255:
1256: case DataBuffer.TYPE_DOUBLE:
1257: wr.setPixels(rectX, rectY, rectWidth, rectHeight,
1258: doubleDataArrays[0]);
1259: break;
1260: }
1261: }
1262: }
1263:
1264: /**
1265: * Indicates if the RasterAccessor has a larger dynamic range than
1266: * the underlying Raster. Except in special cases, where the op
1267: * knows something special, this call will determine whether or
1268: * not clampDataArrays() needs to be called.
1269: */
1270: public boolean needsClamping() {
1271: int bits[] = raster.getSampleModel().getSampleSize();
1272:
1273: // Do we even need a clamp? We do if there's any band
1274: // of the source image stored in that's less than 32 bits
1275: // and is stored in a byte, short or int format. (The automatic
1276: // casts between floats/doubles and 32-bit ints in setPixel()
1277: // do what we want.)
1278:
1279: for (int i = 0; i < bits.length; i++) {
1280: if (bits[i] < 32) {
1281: return true;
1282: }
1283: }
1284: return false;
1285: }
1286:
1287: /**
1288: * Clamps data array values to a range that the underlying raster
1289: * can deal with. For example, if the underlying raster stores
1290: * data as bytes, but the samples are unpacked into integer arrays by
1291: * the RasterAccessor for an operation, the operation will
1292: * need to call clampDataArrays() so that the data in the int
1293: * arrays is restricted to the range 0..255 before a setPixels()
1294: * call is made on the underlying raster. Note that some
1295: * operations (for example, lookup) can guarantee that their
1296: * results don't need clamping so they can call
1297: * RasterAccessor.copyDataToRaster() without first calling this
1298: * function.
1299: */
1300: public void clampDataArrays() {
1301: int bits[] = raster.getSampleModel().getSampleSize();
1302:
1303: // Do we even need a clamp? We do if there's any band
1304: // of the source image stored in that's less than 32 bits
1305: // and is stored in a byte, short or int format. (The automatic
1306: // casts between floats/doubles and 32-bit ints in setPixel()
1307: // do what we want.)
1308:
1309: boolean needClamp = false;
1310: boolean uniformBitSize = true;
1311: int bitSize = bits[0];
1312: for (int i = 0; i < bits.length; i++) {
1313: if (bits[i] < 32) {
1314: needClamp = true;
1315: }
1316: if (bits[i] != bitSize) {
1317: uniformBitSize = false;
1318: }
1319: }
1320: if (!needClamp) {
1321: return;
1322: }
1323:
1324: int dataType = raster.getDataBuffer().getDataType();
1325: double hiVals[] = new double[bits.length];
1326: double loVals[] = new double[bits.length];
1327:
1328: if (dataType == DataBuffer.TYPE_USHORT && uniformBitSize
1329: && bits[0] == 16) {
1330: for (int i = 0; i < bits.length; i++) {
1331: hiVals[i] = (double) 0xFFFF;
1332: loVals[i] = (double) 0;
1333: }
1334: } else if (dataType == DataBuffer.TYPE_SHORT && uniformBitSize
1335: && bits[0] == 16) {
1336: for (int i = 0; i < bits.length; i++) {
1337: hiVals[i] = (double) Short.MAX_VALUE;
1338: loVals[i] = (double) Short.MIN_VALUE;
1339: }
1340: } else if (dataType == DataBuffer.TYPE_INT && uniformBitSize
1341: && bits[0] == 32) {
1342: for (int i = 0; i < bits.length; i++) {
1343: hiVals[i] = (double) Integer.MAX_VALUE;
1344: loVals[i] = (double) Integer.MIN_VALUE;
1345: }
1346: } else {
1347: for (int i = 0; i < bits.length; i++) {
1348: hiVals[i] = (double) ((1 << bits[i]) - 1);
1349: loVals[i] = (double) 0;
1350: }
1351: }
1352: clampDataArray(hiVals, loVals);
1353: }
1354:
1355: private void clampDataArray(double hiVals[], double loVals[]) {
1356: switch (getDataType()) {
1357: case DataBuffer.TYPE_INT:
1358: clampIntArrays(toIntArray(hiVals), toIntArray(loVals));
1359: break;
1360:
1361: case DataBuffer.TYPE_FLOAT:
1362: clampFloatArrays(toFloatArray(hiVals), toFloatArray(loVals));
1363: break;
1364:
1365: case DataBuffer.TYPE_DOUBLE:
1366: clampDoubleArrays(hiVals, loVals);
1367: break;
1368: }
1369: }
1370:
1371: private int[] toIntArray(double vals[]) {
1372: int returnVals[] = new int[vals.length];
1373: for (int i = 0; i < vals.length; i++) {
1374: returnVals[i] = (int) vals[i];
1375: }
1376: return returnVals;
1377: }
1378:
1379: private float[] toFloatArray(double vals[]) {
1380: float returnVals[] = new float[vals.length];
1381: for (int i = 0; i < vals.length; i++) {
1382: returnVals[i] = (float) vals[i];
1383: }
1384: return returnVals;
1385: }
1386:
1387: private void clampIntArrays(int hiVals[], int loVals[]) {
1388: int width = rectWidth;
1389: int height = rectHeight;
1390: for (int k = 0; k < numBands; k++) {
1391: int data[] = intDataArrays[k];
1392: int scanlineOffset = bandDataOffsets[k];
1393: int hiVal = hiVals[k];
1394: int loVal = loVals[k];
1395: for (int j = 0; j < height; j++) {
1396: int pixelOffset = scanlineOffset;
1397: for (int i = 0; i < width; i++) {
1398: int tmp = data[pixelOffset];
1399: if (tmp < loVal) {
1400: data[pixelOffset] = loVal;
1401: } else if (tmp > hiVal) {
1402: data[pixelOffset] = hiVal;
1403: }
1404: pixelOffset += pixelStride;
1405: }
1406: scanlineOffset += scanlineStride;
1407: }
1408: }
1409: }
1410:
1411: private void clampFloatArrays(float hiVals[], float loVals[]) {
1412: int width = rectWidth;
1413: int height = rectHeight;
1414: for (int k = 0; k < numBands; k++) {
1415: float data[] = floatDataArrays[k];
1416: int scanlineOffset = bandDataOffsets[k];
1417: float hiVal = hiVals[k];
1418: float loVal = loVals[k];
1419: for (int j = 0; j < height; j++) {
1420: int pixelOffset = scanlineOffset;
1421: for (int i = 0; i < width; i++) {
1422: float tmp = data[pixelOffset];
1423: if (tmp < loVal) {
1424: data[pixelOffset] = loVal;
1425: } else if (tmp > hiVal) {
1426: data[pixelOffset] = hiVal;
1427: }
1428: pixelOffset += pixelStride;
1429: }
1430: scanlineOffset += scanlineStride;
1431: }
1432: }
1433: }
1434:
1435: private void clampDoubleArrays(double hiVals[], double loVals[]) {
1436: int width = rectWidth;
1437: int height = rectHeight;
1438: for (int k = 0; k < numBands; k++) {
1439: double data[] = doubleDataArrays[k];
1440: int scanlineOffset = bandDataOffsets[k];
1441: double hiVal = hiVals[k];
1442: double loVal = loVals[k];
1443: for (int j = 0; j < height; j++) {
1444: int pixelOffset = scanlineOffset;
1445: for (int i = 0; i < width; i++) {
1446: double tmp = data[pixelOffset];
1447: if (tmp < loVal) {
1448: data[pixelOffset] = loVal;
1449: } else if (tmp > hiVal) {
1450: data[pixelOffset] = hiVal;
1451: }
1452: pixelOffset += pixelStride;
1453: }
1454: scanlineOffset += scanlineStride;
1455: }
1456: }
1457: }
1458: }
|