DataBuffer.TYPE_BYTE
,
* DataBuffer.TYPE_USHORT
, or DataBuffer.TYPE_INT
,
* respectively), data for which each sample is a signed integral number
* which can be stored in 16 bits (using DataBuffer.TYPE_SHORT
),
* or data for which each sample is a signed float or double quantity
* (using DataBuffer.TYPE_FLOAT
or
* DataBuffer.TYPE_DOUBLE
, respectively).
* All samples of a given ComponentSampleModel
* are stored with the same precision. All strides and offsets must be
* non-negative. This class supports
* {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
* {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
* {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
* {@link DataBuffer#TYPE_INT TYPE_INT},
* {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT},
* {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE},
* @see java.awt.image.PixelInterleavedSampleModel
* @see java.awt.image.BandedSampleModel
*/
public class ComponentSampleModel extends SampleModel
{
/** Offsets for all bands in data array elements. */
protected int bandOffsets[];
/** Index for each bank storing a band of image data. */
protected int[] bankIndices;
/**
* The number of bands in this
* ComponentSampleModel
.
*/
protected int numBands = 1;
/**
* The number of banks in this
* ComponentSampleModel
.
*/
protected int numBanks = 1;
/**
* Line stride (in data array elements) of the region of image
* data described by this ComponentSampleModel.
*/
protected int scanlineStride;
/** Pixel stride (in data array elements) of the region of image
* data described by this ComponentSampleModel.
*/
protected int pixelStride;
static private native void initIDs();
static {
ColorModel.loadLibraries();
initIDs();
}
/**
* 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
* @throws IllegalArgumentException if w
or
* h
is not greater than 0
* @throws IllegalArgumentException if pixelStride
* is less than 0
* @throws IllegalArgumentException if scanlineStride
* is less than 0
* @throws IllegalArgumentException if numBands
* is less than 1
* @throws IllegalArgumentException if the product of w
* and h
is greater than
* Integer.MAX_VALUE
* @throws IllegalArgumentException if dataType
is not
* one of the supported data types
*/
public ComponentSampleModel(int dataType,
int w, int h,
int pixelStride,
int scanlineStride,
int bandOffsets[]) {
super(dataType, w, h, bandOffsets.length);
this.dataType = dataType;
this.pixelStride = pixelStride;
this.scanlineStride = scanlineStride;
this.bandOffsets = (int[])bandOffsets.clone();
numBands = this.bandOffsets.length;
if (pixelStride < 0) {
throw new IllegalArgumentException("Pixel stride must be >= 0");
}
// TODO - bug 4296691 - remove this check
if (scanlineStride < 0) {
throw new IllegalArgumentException("Scanline stride must be >= 0");
}
if (numBands < 1) {
throw new IllegalArgumentException("Must have at least one band.");
}
if ((dataType < DataBuffer.TYPE_BYTE) ||
(dataType > DataBuffer.TYPE_DOUBLE)) {
throw new IllegalArgumentException("Unsupported dataType.");
}
bankIndices = new int[numBands];
for (int i=0; ih
is not greater than 0
* @throws IllegalArgumentException if pixelStride
* is less than 0
* @throws IllegalArgumentException if scanlineStride
* is less than 0
* @throws IllegalArgumentException if the length of
* bankIndices
does not equal the length of
* bankOffsets
* @throws IllegalArgumentException if any of the bank indices
* of bandIndices
is less than 0
* @throws IllegalArgumentException if dataType
is not
* one of the supported data types
*/
public ComponentSampleModel(int dataType,
int w, int h,
int pixelStride,
int scanlineStride,
int bankIndices[],
int bandOffsets[]) {
super(dataType, w, h, bandOffsets.length);
this.dataType = dataType;
this.pixelStride = pixelStride;
this.scanlineStride = scanlineStride;
this.bandOffsets = (int[])bandOffsets.clone();
this.bankIndices = (int[]) bankIndices.clone();
if (pixelStride < 0) {
throw new IllegalArgumentException("Pixel stride must be >= 0");
}
// TODO - bug 4296691 - remove this check
if (scanlineStride < 0) {
throw new IllegalArgumentException("Scanline stride must be >= 0");
}
if ((dataType < DataBuffer.TYPE_BYTE) ||
(dataType > DataBuffer.TYPE_DOUBLE)) {
throw new IllegalArgumentException("Unsupported dataType.");
}
int maxBank = this.bankIndices[0];
if (maxBank < 0) {
throw new IllegalArgumentException("Index of bank 0 is less than "+
"0 ("+maxBank+")");
}
for (int i=1; i < this.bankIndices.length; i++) {
if (this.bankIndices[i] > maxBank) {
maxBank = this.bankIndices[i];
}
else if (this.bankIndices[i] < 0) {
throw new IllegalArgumentException("Index of bank "+i+
" is less than 0 ("+
maxBank+")");
}
}
numBanks = maxBank+1;
numBands = this.bandOffsets.length;
if (this.bandOffsets.length != this.bankIndices.length) {
throw new IllegalArgumentException("Length of bandOffsets must "+
"equal length of bankIndices.");
}
}
/**
* 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; iComponentSampleModel
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 of the resulting SampleModel
* @param h the height of the resulting SampleModel
* @return a new ComponentSampleModel
with the specified size
* @throws IllegalArgumentException if w
or
* h
is not greater than 0
*/
public SampleModel createCompatibleSampleModel(int w, int h) {
SampleModel ret=null;
long size;
int minBandOff=bandOffsets[0];
int maxBandOff=bandOffsets[0];
for (int i=1; iComponentSampleModel
created with a subset
* of bands from this ComponentSampleModel
.
*/
public SampleModel createSubsetSampleModel(int bands[]) {
if (bands.length > bankIndices.length)
throw new RasterFormatException("There are only " +
bankIndices.length +
" bands");
int newBankIndices[] = new int[bands.length];
int newBandOffsets[] = new int[bands.length];
for (int i=0; iComponentSampleModel
.
* The DataBuffer
object's data type, number of banks,
* and size are be consistent with this ComponentSampleModel
.
* @return a DataBuffer
whose data type, number of banks
* and size are 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_SHORT:
dataBuffer = new DataBufferShort(size, numBanks);
break;
case DataBuffer.TYPE_INT:
dataBuffer = new DataBufferInt(size, numBanks);
break;
case DataBuffer.TYPE_FLOAT:
dataBuffer = new DataBufferFloat(size, numBanks);
break;
case DataBuffer.TYPE_DOUBLE:
dataBuffer = new DataBufferDouble(size, numBanks);
break;
}
return dataBuffer;
}
/** Gets the offset for the first band of pixel (x,y).
* A sample of the first band can be retrieved from a
* DataBuffer
* data
with a ComponentSampleModel
* csm
as
* * data.getElem(csm.getOffset(x, y)); ** @param x the X location of the pixel * @param y the Y location of the pixel * @return the offset for the first band of the specified pixel. */ public int getOffset(int x, int y) { int offset = y*scanlineStride + x*pixelStride + bandOffsets[0]; return offset; } /** Gets the offset for band b of pixel (x,y). * A sample of band
b
can be retrieved from a
* DataBuffer
data
* with a ComponentSampleModel
csm
as
* * data.getElem(csm.getOffset(x, y, b)); ** @param x the X location of the specified pixel * @param y the Y location of the specified pixel * @param b the specified band * @return the offset for the specified band of the specified pixel. */ public int getOffset(int x, int y, int b) { int offset = y*scanlineStride + x*pixelStride + bandOffsets[b]; return offset; } /** Returns the number of bits per sample for all bands. * @return an array containing the number of bits per sample * for all bands, where each element in the array * represents a band. */ public final int[] getSampleSize() { int sampleSize[] = new int [numBands]; int sizeInBits = getSampleSize(0); for (int i=0; i
ComponentSampleModel
.
*/
public final int getPixelStride() {
return pixelStride;
}
/**
* Returns the number of data elements needed to transfer a pixel
* with the
* {@link #getDataElements(int, int, Object, DataBuffer) } and
* {@link #setDataElements(int, int, Object, DataBuffer) }
* methods.
* For a ComponentSampleModel
, this is identical to the
* number of bands.
* @return the number of data elements needed to transfer a pixel with
* the getDataElements
and
* setDataElements
methods.
* @see java.awt.image.SampleModel#getNumDataElements
* @see #getNumBands
*/
public final int getNumDataElements() {
return getNumBands();
}
/**
* Returns data for a single pixel in a primitive array of type
* TransferType
. For a ComponentSampleModel
,
* this is the same as the data type, and samples are returned
* one per array element. Generally, obj
should
* be passed in as null
, so that the Object
* is created automatically and is 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 is usually more efficient than using
* getPixel
and setPixel
.
*
* ComponentSampleModel csm1, csm2; * DataBufferInt db1, db2; * csm2.setDataElements(x, y, * csm1.getDataElements(x, y, null, db1), db2); ** * Using
getDataElements
and setDataElements
* to transfer between two DataBuffer/SampleModel
* pairs is legitimate if the SampleModel
objects have
* the same number of bands, corresponding bands have the same number of
* bits per sample, and the TransferType
s are the same.
*
* If
* The following code illustrates transferring data for one pixel from
*
* A obj
is not null
, it should be a
* primitive array of type TransferType
.
* Otherwise, a ClassCastException
is thrown. An
* ArrayIndexOutOfBoundsException
might be thrown if the
* coordinates are not in bounds, or if obj
is not
* null
and is not large enough to hold
* the pixel data.
*
* @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
* @return the data of the specified pixel
* @see #setDataElements(int, int, Object, DataBuffer)
*
* @throws NullPointerException if data is null.
* @throws ArrayIndexOutOfBoundsException if the coordinates are
* not in bounds, or if obj is too small to hold the ouput.
*/
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
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; iArrayIndexOutOfBoundsException
might 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 the sample in a specified band for the specified pixel
* @see #setSample(int, int, int, int, DataBuffer)
*/
public int getSample(int x, int y, int b, DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
int sample = data.getElem(bankIndices[b],
y*scanlineStride + x*pixelStride +
bandOffsets[b]);
return sample;
}
/**
* Returns the sample in a specified band
* for the pixel located at (x,y) as a float.
* An ArrayIndexOutOfBoundsException
might 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 a float value representing the sample in the specified
* band for the specified pixel.
*/
public float getSampleFloat(int x, int y, int b, DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
float sample = data.getElemFloat(bankIndices[b],
y*scanlineStride + x*pixelStride +
bandOffsets[b]);
return sample;
}
/**
* Returns the sample in a specified band
* for a pixel located at (x,y) as a double.
* An ArrayIndexOutOfBoundsException
might 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 a double value representing the sample in the specified
* band for the specified pixel.
*/
public double getSampleDouble(int x, int y, int b, DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
double sample = data.getElemDouble(bankIndices[b],
y*scanlineStride + x*pixelStride +
bandOffsets[b]);
return sample;
}
/**
* Returns the samples in a specified band for the specified rectangle
* of pixels in an int array, one sample per data array element.
* An ArrayIndexOutOfBoundsException
might 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 b the band to return
* @param iArray if non-null
, returns the samples
* in this array
* @param data the DataBuffer
containing the image data
* @return the samples in the specified band of the specified pixel
* @see #setSamples(int, int, int, int, int, int[], DataBuffer)
*/
public int[] getSamples(int x, int y, int w, int h, int b,
int iArray[], DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
int samples[];
if (iArray != null) {
samples = iArray;
} else {
samples = new int [w*h];
}
int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b];
int srcOffset = 0;
for (int i = 0; i < h; i++) {
int sampleOffset = lineOffset;
for (int j = 0; j < w; j++) {
samples[srcOffset++] = data.getElem(bankIndices[b],
sampleOffset);
sampleOffset += pixelStride;
}
lineOffset += scanlineStride;
}
return samples;
}
/**
* Sets the data for a single pixel in the specified
* DataBuffer
from a primitive array of type
* TransferType
. For a ComponentSampleModel
,
* this is the same as the data type, and samples are transferred
* one per array element.
* DataBuffer
db1
, whose storage layout is
* described by ComponentSampleModel
csm1
,
* to DataBuffer
db2
, whose storage layout
* is described by ComponentSampleModel
csm2
.
* The transfer is usually more efficient than using
* getPixel
and setPixel
.
*
* ComponentSampleModel csm1, csm2;
* DataBufferInt db1, db2;
* csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
* db2);
*
* Using getDataElements
and setDataElements
* to transfer between two DataBuffer/SampleModel
pairs
* is legitimate if the SampleModel
objects have
* the same number of bands, corresponding bands have the same number of
* bits per sample, and the TransferType
s are the same.
* ClassCastException
is thrown if obj
is not
* a primitive array of type TransferType
.
* An ArrayIndexOutOfBoundsException
might be thrown if
* the coordinates are not in bounds, or if obj
is not large
* enough to hold the pixel data.
* @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
* @see #getDataElements(int, int, Object, DataBuffer)
*/
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
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; iArrayIndexOutOfBoundsException
* might 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 iArray The input samples in an int array
* @param data The DataBuffer containing the image data
* @see #getPixel(int, int, int[], DataBuffer)
*/
public void setPixel(int x, int y, int iArray[], DataBuffer data) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
int pixelOffset = y*scanlineStride + x*pixelStride;
for (int i=0; iDataBuffer
using an int for input.
* An ArrayIndexOutOfBoundsException
might 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 an int
* @param data the DataBuffer containing the image data
* @see #getSample(int, int, int, DataBuffer)
*/
public void setSample(int x, int y, int b, int s,
DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
data.setElem(bankIndices[b],
y*scanlineStride + x*pixelStride + bandOffsets[b], s);
}
/**
* Sets a sample in the specified band for the pixel located at (x,y)
* in the DataBuffer
using a float for input.
* An ArrayIndexOutOfBoundsException
might 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
* @see #getSample(int, int, int, DataBuffer)
*/
public void setSample(int x, int y, int b,
float s ,
DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
data.setElemFloat(bankIndices[b],
y*scanlineStride + x*pixelStride + bandOffsets[b],
s);
}
/**
* Sets a sample in the specified band for the pixel located at (x,y)
* in the DataBuffer
using a double for input.
* An ArrayIndexOutOfBoundsException
might 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
* @see #getSample(int, int, int, DataBuffer)
*/
public void setSample(int x, int y, int b,
double s,
DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
data.setElemDouble(bankIndices[b],
y*scanlineStride + x*pixelStride + bandOffsets[b],
s);
}
/**
* Sets the samples in the specified band for the specified rectangle
* of pixels from an int array containing one sample per data array element.
* An ArrayIndexOutOfBoundsException
might 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 b The band to set
* @param iArray The input samples in an int array
* @param data The DataBuffer containing the image data
* @see #getSamples(int, int, int, int, int, int[], DataBuffer)
*/
public void setSamples(int x, int y, int w, int h, int b,
int iArray[], DataBuffer data) {
// Bounds check for 'b' will be performed automatically
if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
throw new ArrayIndexOutOfBoundsException
("Coordinate out of bounds!");
}
int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b];
int srcOffset = 0;
for (int i = 0; i < h; i++) {
int sampleOffset = lineOffset;
for (int j = 0; j < w; j++) {
data.setElem(bankIndices[b], sampleOffset, iArray[srcOffset++]);
sampleOffset += pixelStride;
}
lineOffset += scanlineStride;
}
}
public boolean equals(Object o) {
if ((o == null) || !(o instanceof ComponentSampleModel)) {
return false;
}
ComponentSampleModel that = (ComponentSampleModel)o;
return this.width == that.width &&
this.height == that.height &&
this.numBands == that.numBands &&
this.dataType == that.dataType &&
Arrays.equals(this.bandOffsets, that.bandOffsets) &&
Arrays.equals(this.bankIndices, that.bankIndices) &&
this.numBands == that.numBands &&
this.numBanks == that.numBanks &&
this.scanlineStride == that.scanlineStride &&
this.pixelStride == that.pixelStride;
}
// If we implement equals() we must also implement hashCode
public int hashCode() {
int hash = 0;
hash = width;
hash <<= 8;
hash ^= height;
hash <<= 8;
hash ^= numBands;
hash <<= 8;
hash ^= dataType;
hash <<= 8;
for (int i = 0; i < bandOffsets.length; i++) {
hash ^= bandOffsets[i];
hash <<= 8;
}
for (int i = 0; i < bankIndices.length; i++) {
hash ^= bankIndices[i];
hash <<= 8;
}
hash ^= numBands;
hash <<= 8;
hash ^= numBanks;
hash <<= 8;
hash ^= scanlineStride;
hash <<= 8;
hash ^= pixelStride;
return hash;
}
}