/* * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduct the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that Software is not designed,licensed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ package com.fr.third.JAI; import java.awt.image.ComponentSampleModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferShort; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferUShort; import java.awt.image.SampleModel; /** * This class represents image data which is stored such that each sample * of a pixel occupies one data element of the DataBuffer. It stores the * N samples which make up a pixel in N separate data array elements. * Different bands may be in different banks of the DataBuffer. * Accessor methods are provided so that image data can be manipulated * directly. This class can support different kinds of interleaving, e.g. * band interleaving, scanline interleaving, and pixel interleaving. * Pixel stride is the number of data array elements between two samples * for the same band on the same scanline. Scanline stride is the number * of data array elements between a given sample and the corresponding sample * in the same column of the next scanline. Band offsets denote the number * of data array elements from the first data array element of the bank * of the DataBuffer holding each band to the first sample of the band. * The bands are numbered from 0 to N-1. This class can represent image * data for the dataTypes enumerated in java.awt.image.DataBuffer (all * samples of a given ComponentSampleModel are stored with the same precision) * . This class adds support for Double and Float data types in addition * to those supported by the ComponentSampleModel class in Java 2D. * All strides and offsets must be non-negative. * @see java.awt.image.ComponentSampleModel */ public class ComponentSampleModelJAI extends ComponentSampleModel { /** * Constructs a ComponentSampleModel with the specified * parameters. The number of bands will be given by the length of * the bandOffsets array. All bands will be stored in the first * bank of the DataBuffer. * * @param dataType The data type for storing samples. * @param w The width (in pixels) of the region of * image data described. * @param h The height (in pixels) of the region of * image data described. * @param pixelStride The pixel stride of the region of image * data described. * @param scanlineStride The line stride of the region of image * data described. * @param bandOffsets The offsets of all bands. */ public ComponentSampleModelJAI(int dataType, int w, int h, int pixelStride, int scanlineStride, int bandOffsets[]) { super(dataType, w, h, pixelStride, scanlineStride, bandOffsets); } /** * Constructs a ComponentSampleModel with the specified * parameters. The number of bands will be given by the length of * the bandOffsets array. Different bands may be stored in * different banks of the DataBuffer. * * @param dataType The data type for storing samples. * @param w The width (in pixels) of the region of * image data described. * @param h The height (in pixels) of the region of * image data described. * @param pixelStride The pixel stride of the region of image * data described. * @param scanlineStride The line stride of the region of image * data described. * @param bankIndices The bank indices of all bands. * @param bandOffsets The band offsets of all bands. */ public ComponentSampleModelJAI(int dataType, int w, int h, int pixelStride, int scanlineStride, int bankIndices[], int bandOffsets[]) { super(dataType, w, h, pixelStride, scanlineStride, bankIndices, bandOffsets); } /** * Returns the size of the data buffer (in data elements) needed * for a data buffer that matches this ComponentSampleModel. */ private long getBufferSize() { int maxBandOff=bandOffsets[0]; for (int i=1; i= 0) size += maxBandOff+1; if (pixelStride > 0) size += pixelStride * (width-1); if (scanlineStride > 0) size += scanlineStride*(height-1); return size; } /** * Preserves band ordering with new step factor... */ private int[] JAIorderBands(int orig[], int step) { int map[] = new int[orig.length]; int ret[] = new int[orig.length]; for (int i=0; i orig[map[j]]) { index = j; } } ret[map[index]] = i*step; map[index] = map[i]; } return ret; } /** * Creates a new ComponentSampleModel with the specified * width and height. The new SampleModel will have the same * number of bands, storage data type, interleaving scheme, and * pixel stride as this SampleModel. * * @param w The width in pixels. * @param h The height in pixels */ public SampleModel createCompatibleSampleModel(int w, int h) { SampleModel ret=null; long size; int minBandOff=bandOffsets[0]; int maxBandOff=bandOffsets[0]; for (int i=1; i lStride) { if (pStride > bStride) { if (lStride > bStride) { // pix > line > band bandOff = new int[bandOffsets.length]; for (int i=0; i band > line bandOff = JAIorderBands(bandOffsets,lStride*h); pStride = bands*lStride*h; } } else { // band > pix > line pStride = lStride*h; bandOff = JAIorderBands(bandOffsets,pStride*w); } } else { if (pStride > bStride) { // line > pix > band bandOff = new int[bandOffsets.length]; for (int i=0; i bStride) { // line > band > pix bandOff = JAIorderBands(bandOffsets,pStride*w); lStride = bands*pStride*w; } else { // band > line > pix lStride = pStride*w; bandOff = JAIorderBands(bandOffsets,lStride*h); } } } // make sure we make room for negative offsets... int base = 0; if (scanlineStride < 0) { base += lStride*h; lStride *= -1; } if (pixelStride < 0) { base += pStride*w; pStride *= -1; } for (int i=0; iComponentSampleModel with a subset of the bands * of this ComponentSampleModel. The new ComponentSampleModel can be * used with any DataBuffer that the existing ComponentSampleModel * can be used with. The new ComponentSampleModel/DataBuffer * combination will represent an image with a subset of the bands * of the original ComponentSampleModel/DataBuffer combination. * * @param bands subset of bands of this ComponentSampleModel */ public SampleModel createSubsetSampleModel(int bands[]) { int newBankIndices[] = new int[bands.length]; int newBandOffsets[] = new int[bands.length]; for (int i=0; iDataBuffer that corresponds to this ComponentSampleModel. * The DataBuffer's data type, number of banks, and size * will be consistent with this ComponentSampleModel. */ public DataBuffer createDataBuffer() { DataBuffer dataBuffer = null; int size = (int)getBufferSize(); switch (dataType) { case DataBuffer.TYPE_BYTE: dataBuffer = new DataBufferByte(size, numBanks); break; case DataBuffer.TYPE_USHORT: dataBuffer = new DataBufferUShort(size, numBanks); break; case DataBuffer.TYPE_INT: dataBuffer = new DataBufferInt(size, numBanks); break; case DataBuffer.TYPE_SHORT: dataBuffer = new DataBufferShort(size, numBanks); break; case DataBuffer.TYPE_FLOAT: dataBuffer = new DataBufferFloat(size, numBanks); break; case DataBuffer.TYPE_DOUBLE: dataBuffer = new DataBufferDouble(size, numBanks); break; default: throw new RuntimeException(JaiI18N.getString("RasterFactory3")); } return dataBuffer; } /** * Returns data for a single pixel in a primitive array of type * TransferType. For a ComponentSampleModel, this will be the same * as the data type, and samples will be returned one per array * element. Generally, obj * should be passed in as null, so that the Object will be created * automatically and will be of the right primitive data type. *

* The following code illustrates transferring data for one pixel from * DataBuffer db1, whose storage layout is described by * ComponentSampleModel csm1, to DataBuffer db2, * whose storage layout is described by * ComponentSampleModel csm2. * The transfer will generally be more efficient than using * getPixel/setPixel. *

     * 	     ComponentSampleModel csm1, csm2;
     *	     DataBufferInt db1, db2;
     * 	     csm2.setDataElements(x, y,
     *                            csm1.getDataElements(x, y, null, db1), db2);
     * 
* Using getDataElements/setDataElements to transfer between two * DataBuffer/SampleModel pairs is legitimate if the SampleModels have * the same number of bands, corresponding bands have the same number of * bits per sample, and the TransferTypes are the same. *

* @param x The X coordinate of the pixel location. * @param y The Y coordinate of the pixel location. * @param obj If non-null, a primitive array in which to return * the pixel data. * @param data The DataBuffer containing the image data. * @throws ClassCastException if obj is non-null and is not * a primitive array of type TransferType. * @throws ArrayIndexOutOfBoundsException if the coordinates * are not in bounds, or if obj is non-null and is not large * enough to hold the pixel data. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { int type = getTransferType(); int numDataElems = getNumDataElements(); int pixelOffset = y*scanlineStride + x*pixelStride; switch(type) { case DataBuffer.TYPE_BYTE: byte[] bdata; if (obj == null) bdata = new byte[numDataElems]; else bdata = (byte[])obj; for (int i=0; iObject will be created automatically and will be of the right * primitive data type. *

* The following code illustrates transferring data for a rectangular * region of pixels from * DataBuffer db1, whose storage layout is described by * SampleModel sm1, to DataBuffer db2, whose * storage layout is described by SampleModel sm2. * The transfer will generally be more efficient than using * getPixels/setPixels. *

     *       SampleModel sm1, sm2;
     *       DataBuffer db1, db2;
     *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w,
     *                           h, null, db1), db2);
     * 
* Using getDataElements/setDataElements to transfer between two * DataBuffer/SampleModel pairs is legitimate if the SampleModels have * the same number of bands, corresponding bands have the same number of * bits per sample, and the TransferTypes are the same. *

* @param x The minimum X coordinate of the pixel rectangle. * @param y The minimum Y coordinate of the pixel rectangle. * @param w The width of the pixel rectangle. * @param h The height of the pixel rectangle. * @param obj If non-null, a primitive array in which to return * the pixel data. * @param data The DataBuffer containing the image data. * @see #getNumDataElements * @see #getTransferType * @see java.awt.image.DataBuffer * @throws ClassCastException if obj is non-null and is not * a primitive array of type TransferType. * @throws ArrayIndexOutOfBoundsException if the coordinates * are not in bounds, or if obj is non-null and is not large * enough to hold the pixel data. */ public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { int type = getTransferType(); int numDataElems = getNumDataElements(); int cnt = 0; Object o = null; switch(type) { case DataBuffer.TYPE_BYTE: { byte[] btemp; byte[] bdata; if (obj == null) bdata = new byte[numDataElems*w*h]; else bdata = (byte[])obj; for (int i=y; iDataBuffer from a * primitive array of type TransferType. For a ComponentSampleModel, * this will be the same as the data type, and samples are transferred * one per array element. *

* The following code illustrates transferring data for one pixel from * DataBuffer db1, whose storage layout is described by * ComponentSampleModel csm1, to DataBuffer db2, * whose storage layout is described by * ComponentSampleModel csm2. * The transfer will generally be more efficient than using * getPixel/setPixel. *

     * 	     ComponentSampleModel csm1, csm2;
     *	     DataBufferInt db1, db2;
     * 	     csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
     *                            db2);
     * 
* Using getDataElements/setDataElements to transfer between two * DataBuffer/SampleModel pairs is legitimate if the SampleModels have * the same number of bands, corresponding bands have the same number of * bits per sample, and the TransferTypes are the same. *

* @param x The X coordinate of the pixel location. * @param y The Y coordinate of the pixel location. * @param obj A primitive array containing pixel data. * @param data The DataBuffer containing the image data. * @throws ClassCastException if obj is non-null and is not * a primitive array of type TransferType. * @throws ArrayIndexOutOfBoundsException if the coordinates * are not in bounds, or if obj is non-null and is not large * enough to hold the pixel data. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { int type = getTransferType(); int numDataElems = getNumDataElements(); int pixelOffset = y*scanlineStride + x*pixelStride; switch(type) { case DataBuffer.TYPE_BYTE: byte[] barray = (byte[])obj; for (int i=0; iDataBuffer * from a primitive array of type TransferType. For image data supported * by the Java 2D API, this will be one of the dataTypes supported by * java.awt.image.DataBuffer. Data in the array may be in a packed * format, thus increasing efficiency for data transfers. *

* The following code illustrates transferring data for a rectangular * region of pixels from * DataBuffer db1, whose storage layout is described by * SampleModel sm1, to DataBuffer db2, whose * storage layout is described by SampleModel sm2. * The transfer will generally be more efficient than using * getPixels/setPixels. *

     *       SampleModel sm1, sm2;
     *       DataBuffer db1, db2;
     *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w, h,
     *                           null, db1), db2);
     * 
* Using getDataElements/setDataElements to transfer between two * DataBuffer/SampleModel pairs is legitimate if the SampleModels have * the same number of bands, corresponding bands have the same number of * bits per sample, and the TransferTypes are the same. *

* @param x The minimum X coordinate of the pixel rectangle. * @param y The minimum Y coordinate of the pixel rectangle. * @param w The width of the pixel rectangle. * @param h The height of the pixel rectangle. * @param obj A primitive array containing pixel data. * @param data The DataBuffer containing the image data. * @throws ClassCastException if obj is non-null and is not * a primitive array of type TransferType. * @throws ArrayIndexOutOfBoundsException if the coordinates * are not in bounds, or if obj is non-null and is not large * enough to hold the pixel data. * @see #getNumDataElements * @see #getTransferType * @see java.awt.image.DataBuffer */ public void setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { int cnt = 0; Object o = null; int type = getTransferType(); int numDataElems = getNumDataElements(); switch(type) { case DataBuffer.TYPE_BYTE: { byte[] barray = (byte[])obj; byte[] btemp = new byte[numDataElems]; for (int i=y; iDataBuffer using a float for input. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are * not in bounds. * @param x The X coordinate of the pixel location. * @param y The Y coordinate of the pixel location. * @param b The band to set. * @param s The input sample as a float. * @param data The DataBuffer containing the image data. * * @throws ArrayIndexOutOfBoundsException if coordinates are not in bounds */ public void setSample(int x, int y, int b, float s, DataBuffer data) { data.setElemFloat(bankIndices[b], y*scanlineStride + x*pixelStride + bandOffsets[b], s); } /** * Returns the sample in a specified band * for the pixel located at (x,y) as a float. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are * not in bounds. * @param x The X coordinate of the pixel location. * @param y The Y coordinate of the pixel location. * @param b The band to return. * @param data The DataBuffer containing the image data. * @return sample The floating point sample value * @throws ArrayIndexOutOfBoundsException if coordinates are not in bounds */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { float sample = data.getElemFloat(bankIndices[b], y*scanlineStride + x*pixelStride + bandOffsets[b]); return sample; } /** * Sets a sample in the specified band for the pixel located at (x,y) * in the DataBuffer using a double for input. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are * not in bounds. * @param x The X coordinate of the pixel location. * @param y The Y coordinate of the pixel location. * @param b The band to set. * @param s The input sample as a double. * @param data The DataBuffer containing the image data. * * @throws ArrayIndexOutOfBoundsException if coordinates are not in bounds */ public void setSample(int x, int y, int b, double s, DataBuffer data) { data.setElemDouble(bankIndices[b], y*scanlineStride + x*pixelStride + bandOffsets[b], s); } /** * Returns the sample in a specified band * for a pixel located at (x,y) as a double. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are * not in bounds. * @param x The X coordinate of the pixel location. * @param y The Y coordinate of the pixel location. * @param b The band to return. * @param data The DataBuffer containing the image data. * @return sample The double sample value * @throws ArrayIndexOutOfBoundsException if coordinates are not in bounds */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { double sample = data.getElemDouble(bankIndices[b], y*scanlineStride + x*pixelStride + bandOffsets[b]); return sample; } /** * Returns all samples for a rectangle of pixels in a double * array, one sample per array element. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are * not in bounds. * @param x The X coordinate of the upper left pixel location. * @param y The Y coordinate of the upper left pixel location. * @param w The width of the pixel rectangle. * @param h The height of the pixel rectangle. * @param dArray If non-null, returns the samples in this array. * @param data The DataBuffer containing the image data. * @throws ArrayIndexOutOfBoundsException if coordinates are not in bounds */ public double[] getPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { double pixels[]; int Offset = 0; if (dArray != null) pixels = dArray; else pixels = new double[numBands * w * h]; for (int i=y; i<(h+y); i++) { for (int j=x; j<(w+x); j++) { for (int k=0; kString containing the values of all valid fields. */ public String toString() { String ret = "ComponentSampleModelJAI: " + " dataType=" + this.getDataType() + " numBands=" + this.getNumBands() + " width=" +this.getWidth() + " height=" +this.getHeight() + " bandOffsets=[ "; for (int i = 0; i < numBands; i++) { ret += this.getBandOffsets()[i] + " "; } ret += "]"; return ret; } }