0001: /*
0002: * $RCSfile: MediaLibAccessor.java,v $
0003: *
0004: *
0005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * - Redistribution of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * - Redistribution in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * Neither the name of Sun Microsystems, Inc. or the names of
0020: * contributors may be used to endorse or promote products derived
0021: * from this software without specific prior written permission.
0022: *
0023: * This software is provided "AS IS," without a warranty of any
0024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0035: * POSSIBILITY OF SUCH DAMAGES.
0036: *
0037: * You acknowledge that this software is not designed or intended for
0038: * use in the design, construction, operation or maintenance of any
0039: * nuclear facility.
0040: *
0041: * $Revision: 1.1 $
0042: * $Date: 2005/02/11 05:01:36 $
0043: * $State: Exp $
0044: */
0045: package com.sun.media.imageioimpl.plugins.jpeg2000;
0046:
0047: import java.awt.Rectangle;
0048: import java.awt.image.ColorModel;
0049: import java.awt.image.ComponentSampleModel;
0050: import java.awt.image.ComponentColorModel;
0051: import java.awt.image.DataBuffer;
0052: import java.awt.image.DataBufferByte;
0053: import java.awt.image.DataBufferDouble;
0054: import java.awt.image.DataBufferFloat;
0055: import java.awt.image.DataBufferInt;
0056: import java.awt.image.DataBufferShort;
0057: import java.awt.image.DataBufferUShort;
0058: import java.awt.image.MultiPixelPackedSampleModel;
0059: import java.awt.image.Raster;
0060: import java.awt.image.SampleModel;
0061: import java.awt.image.WritableRaster;
0062: import java.awt.image.RenderedImage;
0063: import java.awt.image.renderable.ParameterBlock;
0064: import java.io.FileNotFoundException;
0065: import java.io.FilePermission;
0066: import java.io.InputStream;
0067: import java.io.IOException;
0068: import java.lang.NoClassDefFoundError;
0069: import java.security.AccessControlException;
0070: import java.security.AccessController;
0071: import java.security.PrivilegedAction;
0072:
0073: import com.sun.media.imageioimpl.common.ImageUtil;
0074: import com.sun.medialib.codec.jiio.Util;
0075: import com.sun.medialib.codec.jiio.Constants;
0076: import com.sun.medialib.codec.jiio.mediaLibImage;
0077:
0078: /**
0079: * An adapter class for presenting image data in a mediaLibImage
0080: * format, even if the data isn't stored that way. MediaLibAccessor
0081: * is meant to make the common case (ComponentRasters) and allow
0082: * them to be accelerated via medialib. Note that unlike RasterAccessor,
0083: * MediaLibAccessor does not work with all cases. In the event that
0084: * MediaLibAccessor can not deal with a give collection of Rasters,
0085: * findCompatibleTag will return the value MediaLibAccessor.TAG_INCOMPATIBLE.
0086: * OpImages that use MediaLibAccessor should be paired with RIF's
0087: * which check that findCompatibleTag returns a valid tag before
0088: * actually constructing the Mlib OpImage.
0089: */
0090:
0091: public class MediaLibAccessor {
0092: /**
0093: * Value indicating how far COPY_MASK info is shifted to avoid
0094: * interfering with the data type info
0095: */
0096: private static final int COPY_MASK_SHIFT = 7;
0097:
0098: /* Value indicating how many bits the COPY_MASK is */
0099: private static final int COPY_MASK_SIZE = 1;
0100:
0101: /** The bits of a FormatTag associated with how dataArrays are obtained. */
0102: public static final int COPY_MASK = 0x1 << COPY_MASK_SHIFT;
0103:
0104: /** Flag indicating data is raster's data. */
0105: public static final int UNCOPIED = 0x0 << COPY_MASK_SHIFT;
0106:
0107: /** Flag indicating data is a copy of the raster's data. */
0108: public static final int COPIED = 0x01 << COPY_MASK_SHIFT;
0109:
0110: /** The bits of a FormatTag associated with pixel datatype. */
0111: public static final int DATATYPE_MASK = (0x1 << COPY_MASK_SHIFT) - 1;
0112:
0113: /**
0114: * Value indicating how far BINARY_MASK info is shifted to avoid
0115: * interfering with the data type and copying info.
0116: */
0117: private static final int BINARY_MASK_SHIFT = COPY_MASK_SHIFT
0118: + COPY_MASK_SIZE;
0119:
0120: /** Value indicating how many bits the BINARY_MASK is */
0121: private static final int BINARY_MASK_SIZE = 1;
0122:
0123: /** The bits of a FormatTag associated with binary data. */
0124: public static final int BINARY_MASK = ((1 << BINARY_MASK_SIZE) - 1) << BINARY_MASK_SHIFT;
0125:
0126: /** Flag indicating data are not binary. */
0127: public static final int NONBINARY = 0x0 << BINARY_MASK_SHIFT;
0128:
0129: /** Flag indicating data are binary. */
0130: public static final int BINARY = 0x1 << BINARY_MASK_SHIFT;
0131:
0132: /** FormatTag indicating data in byte arrays and uncopied. */
0133: public static final int TAG_BYTE_UNCOPIED = DataBuffer.TYPE_BYTE
0134: | UNCOPIED;
0135:
0136: /** FormatTag indicating data in unsigned short arrays and uncopied. */
0137: public static final int TAG_USHORT_UNCOPIED = DataBuffer.TYPE_USHORT
0138: | UNCOPIED;
0139:
0140: /** FormatTag indicating data in short arrays and uncopied. */
0141: public static final int TAG_SHORT_UNCOPIED = DataBuffer.TYPE_SHORT
0142: | UNCOPIED;
0143:
0144: /** FormatTag indicating data in integer arrays and uncopied. */
0145: public static final int TAG_INT_UNCOPIED = DataBuffer.TYPE_INT
0146: | UNCOPIED;
0147:
0148: /** FormatTag indicating data in float arrays and uncopied. */
0149: public static final int TAG_FLOAT_UNCOPIED = DataBuffer.TYPE_FLOAT
0150: | UNCOPIED;
0151:
0152: /** FormatTag indicating data in double arrays and uncopied. */
0153: public static final int TAG_DOUBLE_UNCOPIED = DataBuffer.TYPE_DOUBLE
0154: | UNCOPIED;
0155:
0156: /** FormatTag indicating data in byte arrays and uncopied. */
0157: public static final int TAG_BYTE_COPIED = DataBuffer.TYPE_BYTE
0158: | COPIED;
0159:
0160: /** FormatTag indicating data in unsigned short arrays and copied. */
0161: public static final int TAG_USHORT_COPIED = DataBuffer.TYPE_USHORT
0162: | COPIED;
0163:
0164: /** FormatTag indicating data in short arrays and copied. */
0165: public static final int TAG_SHORT_COPIED = DataBuffer.TYPE_SHORT
0166: | COPIED;
0167:
0168: /** FormatTag indicating data in short arrays and copied. */
0169: public static final int TAG_INT_COPIED = DataBuffer.TYPE_INT
0170: | COPIED;
0171:
0172: /** FormatTag indicating data in float arrays and copied. */
0173: public static final int TAG_FLOAT_COPIED = DataBuffer.TYPE_FLOAT
0174: | COPIED;
0175:
0176: /** FormatTag indicating data in double arrays and copied. */
0177: public static final int TAG_DOUBLE_COPIED = DataBuffer.TYPE_DOUBLE
0178: | COPIED;
0179:
0180: /** The raster that is the source of pixel data. */
0181: protected Raster raster;
0182:
0183: /** The rectangle of the raster that MediaLibAccessor addresses. */
0184: protected Rectangle rect;
0185:
0186: /** The number of bands per pixel in the data array. */
0187: protected int numBands;
0188:
0189: /** The offsets of each band in the src image */
0190: protected int bandOffsets[];
0191:
0192: /** Tag indicating the data type of the data and whether its copied */
0193: protected int formatTag;
0194:
0195: /** Area of mediaLib images that represent image data */
0196: protected mediaLibImage mlimages[] = null;
0197:
0198: /**
0199: * Whether packed data are preferred when processing binary images.
0200: * This tag is ignored if the data are not binary.
0201: */
0202: private boolean areBinaryDataPacked = false;
0203:
0204: /**
0205: * Returns the most efficient FormatTag that is compatible with
0206: * the destination raster and all source rasters.
0207: *
0208: * @param srcs the source <code>Raster</code>; may be <code>null</code>.
0209: * @param dst the destination <code>Raster</code>.
0210: */
0211: public static int findCompatibleTag(Raster src) {
0212: SampleModel dstSM = src.getSampleModel();
0213: int dstDT = dstSM.getDataType();
0214:
0215: int defaultDataType = dstSM.getDataType();
0216:
0217: boolean allComponentSampleModel = dstSM instanceof ComponentSampleModel;
0218: boolean allBinary = ImageUtil.isBinary(dstSM);
0219:
0220: if (allBinary) {
0221: // The copy flag is not set until the mediaLibImage is
0222: // created as knowing this information requires too much
0223: // processing to determine here.
0224: return DataBuffer.TYPE_BYTE | BINARY;
0225: }
0226:
0227: if (!allComponentSampleModel) {
0228: if ((defaultDataType == DataBuffer.TYPE_BYTE)
0229: || (defaultDataType == DataBuffer.TYPE_USHORT)
0230: || (defaultDataType == DataBuffer.TYPE_SHORT)) {
0231: defaultDataType = DataBuffer.TYPE_INT;
0232: }
0233: }
0234:
0235: int tag = defaultDataType | COPIED;
0236:
0237: if (!allComponentSampleModel) {
0238: return tag;
0239: }
0240:
0241: if (isPixelSequential(dstSM))
0242: return dstDT | UNCOPIED;
0243: return tag;
0244: }
0245:
0246: /**
0247: * Determines if the SampleModel stores data in a way that can
0248: * be represented by a mediaLibImage without copying
0249: */
0250: public static boolean isPixelSequential(SampleModel sm) {
0251: ComponentSampleModel csm = null;
0252: if (sm instanceof ComponentSampleModel) {
0253: csm = (ComponentSampleModel) sm;
0254: } else {
0255: return false;
0256: }
0257: int pixelStride = csm.getPixelStride();
0258: int bandOffsets[] = csm.getBandOffsets();
0259: int bankIndices[] = csm.getBankIndices();
0260: if (pixelStride != bandOffsets.length) {
0261: return false;
0262: }
0263:
0264: //XXX: for band-selection result
0265: if (pixelStride != sm.getNumBands())
0266: return false;
0267:
0268: for (int i = 0; i < bandOffsets.length; i++) {
0269: if (bandOffsets[i] >= pixelStride
0270: || bankIndices[i] != bankIndices[0]) {
0271: return false;
0272: }
0273: for (int j = i + 1; j < bandOffsets.length; j++) {
0274: if (bandOffsets[i] == bandOffsets[j]) {
0275: return false;
0276: }
0277:
0278: //XXX: for BGR images
0279: if (bandOffsets[i] != i)
0280: return false;
0281: }
0282: }
0283: return true;
0284: }
0285:
0286: public static int getMediaLibDataType(int formatTag) {
0287: int dataType = formatTag & DATATYPE_MASK;
0288: switch (dataType) {
0289: case DataBuffer.TYPE_BYTE:
0290: return Constants.MLIB_BYTE;
0291: case DataBuffer.TYPE_USHORT:
0292: return Constants.MLIB_USHORT;
0293: case DataBuffer.TYPE_SHORT:
0294: return Constants.MLIB_SHORT;
0295: case DataBuffer.TYPE_INT:
0296: return Constants.MLIB_INT;
0297: case DataBuffer.TYPE_DOUBLE:
0298: return Constants.MLIB_DOUBLE;
0299: case DataBuffer.TYPE_FLOAT:
0300: return Constants.MLIB_FLOAT;
0301: }
0302: return -1;
0303: }
0304:
0305: /**
0306: * Constructs a MediaLibAccessor object out of a Raster, Rectangle
0307: * and formatTag returned from MediaLibAccessor.findCompatibleTag().
0308: *
0309: * In the case of binary data the copy mask bits of the formatTag
0310: * will be reset within the constructor according to whether the
0311: * data are in fact copied. This cannot be easily determined before
0312: * the data are actually copied.
0313: */
0314: public MediaLibAccessor(Raster raster, Rectangle rect,
0315: int formatTag, boolean preferPacked) {
0316: areBinaryDataPacked = preferPacked;
0317:
0318: this .raster = raster;
0319: this .rect = new Rectangle(rect);
0320: this .formatTag = formatTag;
0321:
0322: if (isBinary()) {
0323: // Set binary-specific fields and return.
0324: numBands = 1;
0325: bandOffsets = new int[] { 0 };
0326:
0327: int mlibType;
0328: int scanlineStride;
0329: byte[] bdata;
0330: mlimages = new mediaLibImage[1];
0331:
0332: if (areBinaryDataPacked) {
0333: mlibType = Constants.MLIB_BIT;
0334: scanlineStride = (rect.width + 7) / 8;
0335: bdata = ImageUtil.getPackedBinaryData(raster, rect);
0336:
0337: // Update format tag depending on whether the data were copied.
0338: if (bdata == ((DataBufferByte) raster.getDataBuffer())
0339: .getData()) {
0340: this .formatTag |= UNCOPIED;
0341: } else {
0342: this .formatTag |= COPIED;
0343: }
0344: } else { // unpacked
0345: mlibType = Constants.MLIB_BYTE;
0346: scanlineStride = rect.width;
0347: bdata = ImageUtil.getUnpackedBinaryData(raster, rect);
0348: this .formatTag |= COPIED;
0349: }
0350:
0351: mlimages[0] = new mediaLibImage(mlibType, 1, rect.width,
0352: rect.height, scanlineStride, 0, bdata);
0353:
0354: return;
0355: }
0356:
0357: if ((formatTag & COPY_MASK) == UNCOPIED) {
0358: ComponentSampleModel csm = (ComponentSampleModel) raster
0359: .getSampleModel();
0360:
0361: numBands = csm.getNumBands();
0362: bandOffsets = csm.getBandOffsets();
0363: int dataOffset = raster.getDataBuffer().getOffset();
0364: dataOffset += (rect.y - raster.getSampleModelTranslateY())
0365: * csm.getScanlineStride()
0366: + (rect.x - raster.getSampleModelTranslateX())
0367: * csm.getPixelStride();
0368:
0369: // dataoffset should and is in terms of dataElements
0370:
0371: // scanline stride should be in terms of dataElements
0372: int scanlineStride = csm.getScanlineStride();
0373:
0374: switch (formatTag & DATATYPE_MASK) {
0375: case DataBuffer.TYPE_BYTE:
0376: DataBufferByte dbb = (DataBufferByte) raster
0377: .getDataBuffer();
0378: mlimages = new mediaLibImage[1];
0379: mlimages[0] = new mediaLibImage(Constants.MLIB_BYTE,
0380: numBands, rect.width, rect.height,
0381: scanlineStride, dataOffset, dbb.getData());
0382: break;
0383:
0384: case DataBuffer.TYPE_USHORT:
0385: DataBufferUShort dbus = (DataBufferUShort) raster
0386: .getDataBuffer();
0387: mlimages = new mediaLibImage[1];
0388: mlimages[0] = new mediaLibImage(Constants.MLIB_USHORT,
0389: numBands, rect.width, rect.height,
0390: scanlineStride, dataOffset, dbus.getData());
0391: break;
0392: case DataBuffer.TYPE_SHORT:
0393: DataBufferShort dbs = (DataBufferShort) raster
0394: .getDataBuffer();
0395: mlimages = new mediaLibImage[1];
0396: mlimages[0] = new mediaLibImage(Constants.MLIB_SHORT,
0397: numBands, rect.width, rect.height,
0398: scanlineStride, dataOffset, dbs.getData());
0399: break;
0400: case DataBuffer.TYPE_INT:
0401: DataBufferInt dbi = (DataBufferInt) raster
0402: .getDataBuffer();
0403: mlimages = new mediaLibImage[1];
0404: mlimages[0] = new mediaLibImage(Constants.MLIB_INT,
0405: numBands, rect.width, rect.height,
0406: scanlineStride, dataOffset, dbi.getData());
0407: break;
0408: case DataBuffer.TYPE_FLOAT:
0409: DataBufferFloat dbf = (DataBufferFloat) raster
0410: .getDataBuffer();
0411: mlimages = new mediaLibImage[1];
0412: mlimages[0] = new mediaLibImage(Constants.MLIB_FLOAT,
0413: numBands, rect.width, rect.height,
0414: scanlineStride, dataOffset, dbf.getData());
0415: break;
0416: case DataBuffer.TYPE_DOUBLE:
0417: DataBufferDouble dbd = (DataBufferDouble) raster
0418: .getDataBuffer();
0419: mlimages = new mediaLibImage[1];
0420: mlimages[0] = new mediaLibImage(Constants.MLIB_DOUBLE,
0421: numBands, rect.width, rect.height,
0422: scanlineStride, dataOffset, dbd.getData());
0423: break;
0424: default:
0425: throw new IllegalArgumentException(
0426: (formatTag & DATATYPE_MASK)
0427: + "MediaLibAccessor does not recognize this datatype.");
0428: }
0429: } else {
0430: // Copying the data because we can't deal with it
0431: numBands = raster.getNumBands();
0432: bandOffsets = new int[numBands];
0433: for (int i = 0; i < numBands; i++) {
0434: bandOffsets[i] = i;
0435: }
0436: int scanlineStride = rect.width * numBands;
0437:
0438: switch (formatTag & DATATYPE_MASK) {
0439: case DataBuffer.TYPE_BYTE:
0440: byte bdata[] = new byte[rect.width * rect.height
0441: * numBands];
0442: mlimages = new mediaLibImage[1];
0443: mlimages[0] = new mediaLibImage(Constants.MLIB_BYTE,
0444: numBands, rect.width, rect.height,
0445: scanlineStride, 0, bdata);
0446: break;
0447: case DataBuffer.TYPE_USHORT:
0448: short usdata[] = new short[rect.width * rect.height
0449: * numBands];
0450: mlimages = new mediaLibImage[1];
0451: mlimages[0] = new mediaLibImage(Constants.MLIB_USHORT,
0452: numBands, rect.width, rect.height,
0453: scanlineStride, 0, usdata);
0454: break;
0455: case DataBuffer.TYPE_SHORT:
0456: short sdata[] = new short[rect.width * rect.height
0457: * numBands];
0458: mlimages = new mediaLibImage[1];
0459: mlimages[0] = new mediaLibImage(Constants.MLIB_SHORT,
0460: numBands, rect.width, rect.height,
0461: scanlineStride, 0, sdata);
0462: break;
0463: case DataBuffer.TYPE_INT:
0464: int idata[] = new int[rect.width * rect.height
0465: * numBands];
0466: mlimages = new mediaLibImage[1];
0467: mlimages[0] = new mediaLibImage(Constants.MLIB_INT,
0468: numBands, rect.width, rect.height,
0469: scanlineStride, 0, idata);
0470: break;
0471: case DataBuffer.TYPE_FLOAT:
0472: float fdata[] = new float[rect.width * rect.height
0473: * numBands];
0474: mlimages = new mediaLibImage[1];
0475: mlimages[0] = new mediaLibImage(Constants.MLIB_FLOAT,
0476: numBands, rect.width, rect.height,
0477: scanlineStride, 0, fdata);
0478: break;
0479: case DataBuffer.TYPE_DOUBLE:
0480: double ddata[] = new double[rect.width * rect.height
0481: * numBands];
0482: mlimages = new mediaLibImage[1];
0483: mlimages[0] = new mediaLibImage(Constants.MLIB_DOUBLE,
0484: numBands, rect.width, rect.height,
0485: scanlineStride, 0, ddata);
0486: break;
0487: default:
0488: throw new IllegalArgumentException(
0489: (formatTag & DATATYPE_MASK)
0490: + "MediaLibAccessor does not recognize this datatype.");
0491: }
0492: copyDataFromRaster();
0493: }
0494: }
0495:
0496: /**
0497: * Returns <code>true</code> if the <code>MediaLibAccessor</code>
0498: * represents binary data.
0499: */
0500: public boolean isBinary() {
0501: return ((formatTag & BINARY_MASK) == BINARY);
0502: }
0503:
0504: /**
0505: * Returns an array of mediaLibImages which represents the input raster.
0506: * An array is returned instead of a single mediaLibImage because
0507: * in some cases, an input Raster can't be represented by one
0508: * mediaLibImage (unless copying is done) but can be represented
0509: * by several mediaLibImages without copying.
0510: */
0511: public mediaLibImage[] getMediaLibImages() {
0512: return mlimages;
0513: }
0514:
0515: /**
0516: * Returns the data type of the RasterAccessor object. Note that
0517: * this datatype is not necessarily the same data type as the
0518: * underlying raster.
0519: */
0520: public int getDataType() {
0521: return formatTag & DATATYPE_MASK;
0522: }
0523:
0524: /**
0525: * Returns true if the MediaLibAccessors's data is copied from it's
0526: * raster.
0527: */
0528: public boolean isDataCopy() {
0529: return ((formatTag & COPY_MASK) == COPIED);
0530: }
0531:
0532: /** Returns the bandOffsets. */
0533: public int[] getBandOffsets() {
0534: return bandOffsets;
0535: }
0536:
0537: /**
0538: * Returns parameters in the appropriate order if MediaLibAccessor
0539: * has reordered the bands or is attempting to make a
0540: * BandSequential image look like multiple PixelSequentialImages
0541: */
0542: public int[] getIntParameters(int band, int params[]) {
0543: int returnParams[] = new int[numBands];
0544: for (int i = 0; i < numBands; i++) {
0545: returnParams[i] = params[bandOffsets[i + band]];
0546: }
0547: return returnParams;
0548: }
0549:
0550: /**
0551: * Returns parameters in the appropriate order if MediaLibAccessor
0552: * has reordered the bands or is attempting to make a
0553: * BandSequential image look like multiple PixelSequentialImages
0554: */
0555: public int[][] getIntArrayParameters(int band, int[][] params) {
0556: int returnParams[][] = new int[numBands][];
0557: for (int i = 0; i < numBands; i++) {
0558: returnParams[i] = params[bandOffsets[i + band]];
0559: }
0560: return returnParams;
0561: }
0562:
0563: /**
0564: * Returns parameters in the appropriate order if MediaLibAccessor
0565: * has reordered the bands or is attempting to make a
0566: * BandSequential image look like multiple PixelSequentialImages
0567: */
0568: public double[] getDoubleParameters(int band, double params[]) {
0569: double returnParams[] = new double[numBands];
0570: for (int i = 0; i < numBands; i++) {
0571: returnParams[i] = params[bandOffsets[i + band]];
0572: }
0573: return returnParams;
0574: }
0575:
0576: /**
0577: * Copy data from Raster to MediaLib image
0578: */
0579: private void copyDataFromRaster() {
0580: // Writeback should only be necessary on destRasters which
0581: // should be writable so this cast should succeed.
0582:
0583: if (raster.getSampleModel() instanceof ComponentSampleModel) {
0584: ComponentSampleModel csm = (ComponentSampleModel) raster
0585: .getSampleModel();
0586: int rasScanlineStride = csm.getScanlineStride();
0587: int rasPixelStride = csm.getPixelStride();
0588:
0589: int subRasterOffset = (rect.y - raster
0590: .getSampleModelTranslateY())
0591: * rasScanlineStride
0592: + (rect.x - raster.getSampleModelTranslateX())
0593: * rasPixelStride;
0594:
0595: int rasBankIndices[] = csm.getBankIndices();
0596: int rasBandOffsets[] = csm.getBandOffsets();
0597: int rasDataOffsets[] = raster.getDataBuffer().getOffsets();
0598:
0599: if (rasDataOffsets.length == 1) {
0600: for (int i = 0; i < numBands; i++) {
0601: rasBandOffsets[i] += rasDataOffsets[0]
0602: + subRasterOffset;
0603: }
0604: } else if (rasDataOffsets.length == rasBandOffsets.length) {
0605: for (int i = 0; i < numBands; i++) {
0606: rasBandOffsets[i] += rasDataOffsets[i]
0607: + subRasterOffset;
0608: }
0609: }
0610:
0611: Object mlibDataArray = null;
0612: switch (getDataType()) {
0613: case DataBuffer.TYPE_BYTE:
0614: byte bArray[][] = new byte[numBands][];
0615: for (int i = 0; i < numBands; i++) {
0616: bArray[i] = mlimages[0].getByteData();
0617: }
0618: mlibDataArray = bArray;
0619: break;
0620: case DataBuffer.TYPE_USHORT:
0621: short usArray[][] = new short[numBands][];
0622: for (int i = 0; i < numBands; i++) {
0623: usArray[i] = mlimages[0].getUShortData();
0624: }
0625: mlibDataArray = usArray;
0626: break;
0627: case DataBuffer.TYPE_SHORT:
0628: short sArray[][] = new short[numBands][];
0629: for (int i = 0; i < numBands; i++) {
0630: sArray[i] = mlimages[0].getShortData();
0631: }
0632: mlibDataArray = sArray;
0633: break;
0634: case DataBuffer.TYPE_INT:
0635: int iArray[][] = new int[numBands][];
0636: for (int i = 0; i < numBands; i++) {
0637: iArray[i] = mlimages[0].getIntData();
0638: }
0639: mlibDataArray = iArray;
0640: break;
0641: case DataBuffer.TYPE_FLOAT:
0642: float fArray[][] = new float[numBands][];
0643: for (int i = 0; i < numBands; i++) {
0644: fArray[i] = mlimages[0].getFloatData();
0645: }
0646: mlibDataArray = fArray;
0647: break;
0648: case DataBuffer.TYPE_DOUBLE:
0649: double dArray[][] = new double[numBands][];
0650: for (int i = 0; i < numBands; i++) {
0651: dArray[i] = mlimages[0].getDoubleData();
0652: }
0653: mlibDataArray = dArray;
0654: break;
0655: }
0656:
0657: Object rasDataArray = null;
0658: switch (csm.getDataType()) {
0659: case DataBuffer.TYPE_BYTE: {
0660: DataBufferByte dbb = (DataBufferByte) raster
0661: .getDataBuffer();
0662: byte rasByteDataArray[][] = new byte[numBands][];
0663: for (int i = 0; i < numBands; i++) {
0664: rasByteDataArray[i] = dbb
0665: .getData(rasBankIndices[i]);
0666: }
0667: rasDataArray = rasByteDataArray;
0668: }
0669: break;
0670: case DataBuffer.TYPE_USHORT: {
0671: DataBufferUShort dbus = (DataBufferUShort) raster
0672: .getDataBuffer();
0673: short rasUShortDataArray[][] = new short[numBands][];
0674: for (int i = 0; i < numBands; i++) {
0675: rasUShortDataArray[i] = dbus
0676: .getData(rasBankIndices[i]);
0677: }
0678: rasDataArray = rasUShortDataArray;
0679: }
0680: break;
0681: case DataBuffer.TYPE_SHORT: {
0682: DataBufferShort dbs = (DataBufferShort) raster
0683: .getDataBuffer();
0684: short rasShortDataArray[][] = new short[numBands][];
0685: for (int i = 0; i < numBands; i++) {
0686: rasShortDataArray[i] = dbs
0687: .getData(rasBankIndices[i]);
0688: }
0689: rasDataArray = rasShortDataArray;
0690: }
0691: break;
0692: case DataBuffer.TYPE_INT: {
0693: DataBufferInt dbi = (DataBufferInt) raster
0694: .getDataBuffer();
0695: int rasIntDataArray[][] = new int[numBands][];
0696: for (int i = 0; i < numBands; i++) {
0697: rasIntDataArray[i] = dbi.getData(rasBankIndices[i]);
0698: }
0699: rasDataArray = rasIntDataArray;
0700: }
0701: break;
0702: case DataBuffer.TYPE_FLOAT: {
0703: DataBufferFloat dbf = (DataBufferFloat) raster
0704: .getDataBuffer();
0705: float rasFloatDataArray[][] = new float[numBands][];
0706: for (int i = 0; i < numBands; i++) {
0707: rasFloatDataArray[i] = dbf
0708: .getData(rasBankIndices[i]);
0709: }
0710: rasDataArray = rasFloatDataArray;
0711: }
0712: break;
0713: case DataBuffer.TYPE_DOUBLE: {
0714: DataBufferDouble dbd = (DataBufferDouble) raster
0715: .getDataBuffer();
0716: double rasDoubleDataArray[][] = new double[numBands][];
0717: for (int i = 0; i < numBands; i++) {
0718: rasDoubleDataArray[i] = dbd
0719: .getData(rasBankIndices[i]);
0720: }
0721: rasDataArray = rasDoubleDataArray;
0722: }
0723: break;
0724: }
0725:
0726: // dst = mlib && src = ras
0727: Util.Reformat(mlibDataArray, rasDataArray, numBands,
0728: rect.width, rect.height, getMediaLibDataType(this
0729: .getDataType()), bandOffsets, rect.width
0730: * numBands, numBands,
0731: getMediaLibDataType(csm.getDataType()),
0732: rasBandOffsets, rasScanlineStride, rasPixelStride);
0733: } else {
0734: // If COPIED and the raster doesn't have ComponentSampleModel
0735: // data is moved with getPixel/setPixel (even byte/short)
0736: switch (getDataType()) {
0737: case DataBuffer.TYPE_INT:
0738: raster.getPixels(rect.x, rect.y, rect.width,
0739: rect.height, mlimages[0].getIntData());
0740: break;
0741: case DataBuffer.TYPE_FLOAT:
0742: raster.getPixels(rect.x, rect.y, rect.width,
0743: rect.height, mlimages[0].getFloatData());
0744: break;
0745: case DataBuffer.TYPE_DOUBLE:
0746: raster.getPixels(rect.x, rect.y, rect.width,
0747: rect.height, mlimages[0].getDoubleData());
0748: break;
0749: }
0750: }
0751: }
0752:
0753: /**
0754: * Copies data back into the MediaLibAccessor's raster. Note that
0755: * the data is casted from the intermediate data format to
0756: * the raster's format. If clamping is needed, the call
0757: * clampDataArrays() method needs to be called before
0758: * calling the copyDataToRaster() method.
0759: */
0760: public void copyDataToRaster(int[] channelMap) {
0761: if (isDataCopy()) {
0762:
0763: if (isBinary()) {
0764: if (areBinaryDataPacked) {
0765: ImageUtil.setPackedBinaryData(mlimages[0]
0766: .getBitData(), (WritableRaster) raster,
0767: rect);
0768: } else { // unpacked
0769: ImageUtil.setUnpackedBinaryData(mlimages[0]
0770: .getByteData(), (WritableRaster) raster,
0771: rect);
0772: }
0773: return;
0774: }
0775:
0776: // Writeback should only be necessary on destRasters which
0777: // should be writable so this cast should succeed.
0778: WritableRaster wr = (WritableRaster) raster;
0779:
0780: if (wr.getSampleModel() instanceof ComponentSampleModel) {
0781: ComponentSampleModel csm = (ComponentSampleModel) wr
0782: .getSampleModel();
0783: int rasScanlineStride = csm.getScanlineStride();
0784: int rasPixelStride = csm.getPixelStride();
0785:
0786: int subRasterOffset = (rect.y - raster
0787: .getSampleModelTranslateY())
0788: * rasScanlineStride
0789: + (rect.x - raster.getSampleModelTranslateX())
0790: * rasPixelStride;
0791:
0792: int rasBankIndices[] = csm.getBankIndices();
0793: int rasBandOffsets[] = csm.getBandOffsets();
0794: int rasDataOffsets[] = raster.getDataBuffer()
0795: .getOffsets();
0796:
0797: if (rasDataOffsets.length == 1) {
0798: for (int i = 0; i < numBands; i++) {
0799: rasBandOffsets[i] += rasDataOffsets[0]
0800: + subRasterOffset;
0801: }
0802: } else if (rasDataOffsets.length == rasBandOffsets.length) {
0803: for (int i = 0; i < numBands; i++) {
0804: rasBandOffsets[i] += rasDataOffsets[i]
0805: + subRasterOffset;
0806: }
0807: }
0808:
0809: Object mlibDataArray = null;
0810: switch (getDataType()) {
0811: case DataBuffer.TYPE_BYTE:
0812: byte bArray[][] = new byte[numBands][];
0813: for (int i = 0; i < numBands; i++) {
0814: bArray[i] = mlimages[0].getByteData();
0815: }
0816: mlibDataArray = bArray;
0817: break;
0818: case DataBuffer.TYPE_USHORT:
0819: short usArray[][] = new short[numBands][];
0820: for (int i = 0; i < numBands; i++) {
0821: usArray[i] = mlimages[0].getUShortData();
0822: }
0823: mlibDataArray = usArray;
0824: break;
0825: case DataBuffer.TYPE_SHORT:
0826: short sArray[][] = new short[numBands][];
0827: for (int i = 0; i < numBands; i++) {
0828: sArray[i] = mlimages[0].getShortData();
0829: }
0830: mlibDataArray = sArray;
0831: break;
0832: case DataBuffer.TYPE_INT:
0833: int iArray[][] = new int[numBands][];
0834: for (int i = 0; i < numBands; i++) {
0835: iArray[i] = mlimages[0].getIntData();
0836: }
0837: mlibDataArray = iArray;
0838: break;
0839: case DataBuffer.TYPE_FLOAT:
0840: float fArray[][] = new float[numBands][];
0841: for (int i = 0; i < numBands; i++) {
0842: fArray[i] = mlimages[0].getFloatData();
0843: }
0844: mlibDataArray = fArray;
0845: break;
0846: case DataBuffer.TYPE_DOUBLE:
0847: double dArray[][] = new double[numBands][];
0848: for (int i = 0; i < numBands; i++) {
0849: dArray[i] = mlimages[0].getDoubleData();
0850: }
0851: mlibDataArray = dArray;
0852: break;
0853: }
0854:
0855: byte tmpDataArray[] = null;
0856: Object rasDataArray = null;
0857: switch (csm.getDataType()) {
0858: case DataBuffer.TYPE_BYTE: {
0859: DataBufferByte dbb = (DataBufferByte) raster
0860: .getDataBuffer();
0861: byte rasByteDataArray[][] = new byte[numBands][];
0862: for (int i = 0; i < numBands; i++) {
0863: rasByteDataArray[i] = dbb
0864: .getData(rasBankIndices[i]);
0865: }
0866: tmpDataArray = rasByteDataArray[0];
0867: rasDataArray = rasByteDataArray;
0868: }
0869: break;
0870: case DataBuffer.TYPE_USHORT: {
0871: DataBufferUShort dbus = (DataBufferUShort) raster
0872: .getDataBuffer();
0873: short rasUShortDataArray[][] = new short[numBands][];
0874: for (int i = 0; i < numBands; i++) {
0875: rasUShortDataArray[i] = dbus
0876: .getData(rasBankIndices[i]);
0877: }
0878: rasDataArray = rasUShortDataArray;
0879: }
0880: break;
0881: case DataBuffer.TYPE_SHORT: {
0882: DataBufferShort dbs = (DataBufferShort) raster
0883: .getDataBuffer();
0884: short rasShortDataArray[][] = new short[numBands][];
0885: for (int i = 0; i < numBands; i++) {
0886: rasShortDataArray[i] = dbs
0887: .getData(rasBankIndices[i]);
0888: }
0889: rasDataArray = rasShortDataArray;
0890: }
0891: break;
0892: case DataBuffer.TYPE_INT: {
0893: DataBufferInt dbi = (DataBufferInt) raster
0894: .getDataBuffer();
0895: int rasIntDataArray[][] = new int[numBands][];
0896: for (int i = 0; i < numBands; i++) {
0897: rasIntDataArray[i] = dbi
0898: .getData(rasBankIndices[i]);
0899: }
0900: rasDataArray = rasIntDataArray;
0901: }
0902: break;
0903: case DataBuffer.TYPE_FLOAT: {
0904: DataBufferFloat dbf = (DataBufferFloat) raster
0905: .getDataBuffer();
0906: float rasFloatDataArray[][] = new float[numBands][];
0907: for (int i = 0; i < numBands; i++) {
0908: rasFloatDataArray[i] = dbf
0909: .getData(rasBankIndices[i]);
0910: }
0911: rasDataArray = rasFloatDataArray;
0912: }
0913: break;
0914: case DataBuffer.TYPE_DOUBLE: {
0915: DataBufferDouble dbd = (DataBufferDouble) raster
0916: .getDataBuffer();
0917: double rasDoubleDataArray[][] = new double[numBands][];
0918: for (int i = 0; i < numBands; i++) {
0919: rasDoubleDataArray[i] = dbd
0920: .getData(rasBankIndices[i]);
0921: }
0922: rasDataArray = rasDoubleDataArray;
0923: }
0924: break;
0925: }
0926:
0927: int[] bandOffsetCopy = (int[]) bandOffsets.clone();
0928: if (channelMap != null) {
0929: for (int i = 0; i < bandOffsetCopy.length; i++)
0930: bandOffsetCopy[i] = channelMap[bandOffsetCopy[i]];
0931: }
0932:
0933: // src = mlib && dst = ras
0934: Util.Reformat(rasDataArray, mlibDataArray, numBands,
0935: rect.width, rect.height,
0936: getMediaLibDataType(csm.getDataType()),
0937: rasBandOffsets, rasScanlineStride,
0938: rasPixelStride, getMediaLibDataType(this
0939: .getDataType()), bandOffsetCopy,
0940: rect.width * numBands, numBands);
0941: } else {
0942: // If COPIED and the raster doesn't have ComponentSampleModel
0943: // data is moved with getPixel/setPixel (even byte/short)
0944: switch (getDataType()) {
0945: case DataBuffer.TYPE_INT:
0946: wr.setPixels(rect.x, rect.y, rect.width,
0947: rect.height, mlimages[0].getIntData());
0948: break;
0949: case DataBuffer.TYPE_FLOAT:
0950: wr.setPixels(rect.x, rect.y, rect.width,
0951: rect.height, mlimages[0].getFloatData());
0952: break;
0953: case DataBuffer.TYPE_DOUBLE:
0954: wr.setPixels(rect.x, rect.y, rect.width,
0955: rect.height, mlimages[0].getDoubleData());
0956: break;
0957: }
0958: }
0959: }
0960: }
0961:
0962: /**
0963: * Clamps data array values to a range that the underlying raster
0964: * can deal with. For example, if the underlying raster stores
0965: * data as bytes, but the samples ares unpacked into integer arrays by
0966: * the RasterAccessor object for an operation, the operation will
0967: * need to call clampDataArrays() so that the data in the int
0968: * arrays is restricted to the range 0..255 before a setPixels()
0969: * call is made on the underlying raster. Note that some
0970: * operations (for example, lookup) can guarantee that their
0971: * results don't need clamping so they can call
0972: * RasterAccessor.copyDataToRaster() without first calling this
0973: * function.
0974: */
0975: public void clampDataArrays() {
0976: if (!isDataCopy()) {
0977: return;
0978: }
0979:
0980: // additonal medialib check: If it's a componentSampleModel
0981: // we get a free cast when we call medialibWrapper.Reformat
0982: // to copy the data to the source. So we don't need to cast
0983: // here.
0984: if (raster.getSampleModel() instanceof ComponentSampleModel) {
0985: return;
0986: }
0987:
0988: int bits[] = raster.getSampleModel().getSampleSize();
0989:
0990: // Do we even need a clamp? We do if there's any band
0991: // of the source image stored in that's less than 32 bits
0992: // and is stored in a byte, short or int format. (The automatic
0993: // cast's between floats/doubles and 32-bit ints in setPixel()
0994: // generall do what we want.)
0995:
0996: boolean needClamp = false;
0997: boolean uniformBitSize = true;
0998: for (int i = 0; i < bits.length; i++) {
0999: int bitSize = bits[0];
1000: if (bits[i] < 32) {
1001: needClamp = true;
1002: }
1003: if (bits[i] != bitSize) {
1004: uniformBitSize = false;
1005: }
1006: }
1007:
1008: if (!needClamp) {
1009: return;
1010: }
1011:
1012: int dataType = raster.getDataBuffer().getDataType();
1013: double hiVals[] = new double[bits.length];
1014: double loVals[] = new double[bits.length];
1015:
1016: if (dataType == DataBuffer.TYPE_USHORT && uniformBitSize
1017: && bits[0] == 16) {
1018: for (int i = 0; i < bits.length; i++) {
1019: hiVals[i] = (double) 0xFFFF;
1020: loVals[i] = (double) 0;
1021: }
1022: } else if (dataType == DataBuffer.TYPE_SHORT && uniformBitSize
1023: && bits[0] == 16) {
1024: for (int i = 0; i < bits.length; i++) {
1025: hiVals[i] = (double) Short.MAX_VALUE;
1026: loVals[i] = (double) Short.MIN_VALUE;
1027: }
1028: } else if (dataType == DataBuffer.TYPE_INT && uniformBitSize
1029: && bits[0] == 32) {
1030: for (int i = 0; i < bits.length; i++) {
1031: hiVals[i] = (double) Integer.MAX_VALUE;
1032: loVals[i] = (double) Integer.MIN_VALUE;
1033: }
1034: } else {
1035: for (int i = 0; i < bits.length; i++) {
1036: hiVals[i] = (double) ((1 << bits[i]) - 1);
1037: loVals[i] = (double) 0;
1038: }
1039: }
1040: clampDataArray(hiVals, loVals);
1041: }
1042:
1043: private void clampDataArray(double hiVals[], double loVals[]) {
1044: switch (getDataType()) {
1045: case DataBuffer.TYPE_INT:
1046: clampIntArrays(toIntArray(hiVals), toIntArray(loVals));
1047: break;
1048: case DataBuffer.TYPE_FLOAT:
1049: clampFloatArrays(toFloatArray(hiVals), toFloatArray(loVals));
1050: break;
1051: case DataBuffer.TYPE_DOUBLE:
1052: clampDoubleArrays(hiVals, loVals);
1053: break;
1054: }
1055: }
1056:
1057: private int[] toIntArray(double vals[]) {
1058: int returnVals[] = new int[vals.length];
1059: for (int i = 0; i < vals.length; i++) {
1060: returnVals[i] = (int) vals[i];
1061: }
1062: return returnVals;
1063: }
1064:
1065: private float[] toFloatArray(double vals[]) {
1066: float returnVals[] = new float[vals.length];
1067: for (int i = 0; i < vals.length; i++) {
1068: returnVals[i] = (float) vals[i];
1069: }
1070: return returnVals;
1071: }
1072:
1073: private void clampIntArrays(int hiVals[], int loVals[]) {
1074: int width = rect.width;
1075: int height = rect.height;
1076: int scanlineStride = numBands * width;
1077: for (int k = 0; k < numBands; k++) {
1078: int data[] = mlimages[0].getIntData();
1079: int scanlineOffset = k;
1080: int hiVal = hiVals[k];
1081: int loVal = loVals[k];
1082: for (int j = 0; j < height; j++) {
1083: int pixelOffset = scanlineOffset;
1084: for (int i = 0; i < width; i++) {
1085: int tmp = data[pixelOffset];
1086: if (tmp < loVal) {
1087: data[pixelOffset] = loVal;
1088: } else if (tmp > hiVal) {
1089: data[pixelOffset] = hiVal;
1090: }
1091: pixelOffset += numBands;
1092: }
1093: scanlineOffset += scanlineStride;
1094: }
1095: }
1096: }
1097:
1098: private void clampFloatArrays(float hiVals[], float loVals[]) {
1099: int width = rect.width;
1100: int height = rect.height;
1101: int scanlineStride = numBands * width;
1102: for (int k = 0; k < numBands; k++) {
1103: float data[] = mlimages[0].getFloatData();
1104: int scanlineOffset = k;
1105: float hiVal = hiVals[k];
1106: float loVal = loVals[k];
1107: for (int j = 0; j < height; j++) {
1108: int pixelOffset = scanlineOffset;
1109: for (int i = 0; i < width; i++) {
1110: float tmp = data[pixelOffset];
1111: if (tmp < loVal) {
1112: data[pixelOffset] = loVal;
1113: } else if (tmp > hiVal) {
1114: data[pixelOffset] = hiVal;
1115: }
1116: pixelOffset += numBands;
1117: }
1118: scanlineOffset += scanlineStride;
1119: }
1120: }
1121: }
1122:
1123: private void clampDoubleArrays(double hiVals[], double loVals[]) {
1124: int width = rect.width;
1125: int height = rect.height;
1126: int scanlineStride = numBands * width;
1127: for (int k = 0; k < numBands; k++) {
1128: double data[] = mlimages[0].getDoubleData();
1129: int scanlineOffset = k;
1130: double hiVal = hiVals[k];
1131: double loVal = loVals[k];
1132: for (int j = 0; j < height; j++) {
1133: int pixelOffset = scanlineOffset;
1134: for (int i = 0; i < width; i++) {
1135: double tmp = data[pixelOffset];
1136: if (tmp < loVal) {
1137: data[pixelOffset] = loVal;
1138: } else if (tmp > hiVal) {
1139: data[pixelOffset] = hiVal;
1140: }
1141: pixelOffset += numBands;
1142: }
1143: scanlineOffset += scanlineStride;
1144: }
1145: }
1146: }
1147:
1148: }
|