- /*
- * @(#)MultiPixelPackedSampleModel.java 1.28 00/02/02
- *
- * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the proprietary information of Sun Microsystems, Inc.
- * Use is subject to license terms.
- *
- */
-
- /* ****************************************************************
- ******************************************************************
- ******************************************************************
- *** COPYRIGHT (c) Eastman Kodak Company, 1997
- *** As an unpublished work pursuant to Title 17 of the United
- *** States Code. All rights reserved.
- ******************************************************************
- ******************************************************************
- ******************************************************************/
-
- package java.awt.image;
-
- /**
- * The <code>MultiPixelPackedSampleModel</code> class represents
- * one-banded images and can pack multiple one-sample
- * pixels into one data element. Pixels are not allowed to span data elements.
- * The data type can be DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
- * or DataBuffer.TYPE_INT. Each pixel must be a power of 2 number of bits
- * and a power of 2 number of pixels must fit exactly in one data element.
- * Pixel bit stride is equal to the number of bits per pixel. Scanline
- * stride is in data elements and the last several data elements might be
- * padded with unused pixels. Data bit offset is the offset in bits from
- * the beginning of the {@link DataBuffer} to the first pixel and must be
- * a multiple of pixel bit stride.
- * <p>
- * The following code illustrates extracting the bits for pixel
- * <code>x, y</code> from <code>DataBuffer</code> <code>data</code>
- * and storing the pixel data in data elements of type
- * <code>dataType</code>:
- * <pre>
- * int dataElementSize = DataBuffer.getDataTypeSize(dataType);
- * int bitnum = dataBitOffset + x*pixelBitStride;
- * int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
- * int shift = dataElementSize - (bitnum & (dataElementSize-1))
- * - pixelBitStride;
- * int pixel = (element >> shift) & ((1 << pixelBitStride) - 1);
- * </pre>
- */
-
- public class MultiPixelPackedSampleModel extends SampleModel
- {
- /** The number of bits from one pixel to the next. */
- int pixelBitStride;
-
- /** Bitmask that extracts the rightmost pixel of a data element. */
- int bitMask;
-
- /**
- * The number of pixels that fit in a data element. Also used
- * as the number of bits per pixel.
- */
- int pixelsPerDataElement;
-
- /** The size of a data element in bits. */
- int dataElementSize;
-
- /** The bit offset into the data array where the first pixel begins.
- */
- int dataBitOffset;
-
- /** ScanlineStride of the data buffer described in data array elements. */
- int scanlineStride;
-
- /**
- * Constructs a <code>MultiPixelPackedSampleModel</code> with the
- * specified data type, width, height and number of bits per pixel.
- * @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 numberOfBits the number of bits per pixel
- * @throws IllegalArgumentException if <code>dataType</code> is not
- * either <code>DataBuffer.TYPE_BYTE</code>,
- * <code>DataBuffer.TYPE_USHORT</code>, or
- * <code>DataBuffer.TYPE_INT</code>
- */
- public MultiPixelPackedSampleModel(int dataType,
- int w,
- int h,
- int numberOfBits) {
- this(dataType,w,h,
- numberOfBits,
- (w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
- DataBuffer.getDataTypeSize(dataType),
- 0);
- if (dataType != DataBuffer.TYPE_BYTE &&
- dataType != DataBuffer.TYPE_USHORT &&
- dataType != DataBuffer.TYPE_INT) {
- throw new IllegalArgumentException("Unsupported data type "+
- dataType);
- }
- }
-
- /**
- * Constructs a <code>MultiPixelPackedSampleModel</code> with
- * specified data type, width, height, number of bits per pixel,
- * scanline stride and data bit offset.
- * @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 numberOfBits the number of bits per pixel
- * @param scanlineStride the line stride of the image data
- * @param dataBitOffset the data bit offset for the region of image
- * data described
- * @exception RasterFormatException if the number of bits per pixel
- * is not a power of 2 or if a power of 2 number of
- * pixels do not fit in one data element.
- * @throws IllegalArgumentException if <code>w</code> or
- * <code>h</code> is not greater than 0
- * @throws IllegalArgumentException if <code>dataType</code> is not
- * either <code>DataBuffer.TYPE_BYTE</code>,
- * <code>DataBuffer.TYPE_USHORT</code>, or
- * <code>DataBuffer.TYPE_INT</code>
- */
- public MultiPixelPackedSampleModel(int dataType, int w, int h,
- int numberOfBits,
- int scanlineStride,
- int dataBitOffset) {
- super(dataType, w, h, 1);
- if (dataType != DataBuffer.TYPE_BYTE &&
- dataType != DataBuffer.TYPE_USHORT &&
- dataType != DataBuffer.TYPE_INT) {
- throw new IllegalArgumentException("Unsupported data type "+
- dataType);
- }
- this.dataType = dataType;
- this.pixelBitStride = numberOfBits;
- this.scanlineStride = scanlineStride;
- this.dataBitOffset = dataBitOffset;
- this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
- this.pixelsPerDataElement = dataElementSizenumberOfBits;
- if (pixelsPerDataElement*numberOfBits != dataElementSize) {
- throw new RasterFormatException("MultiPixelPackedSampleModel " +
- "does not allow pixels to " +
- "span data element boundaries");
- }
- this.bitMask = (1 << numberOfBits) - 1;
- }
-
-
- /**
- * Creates a new <code>MultiPixelPackedSampleModel</code> with the
- * specified width and height. The new
- * <code>MultiPixelPackedSampleModel</code> has the
- * same storage data type and number of bits per pixel as this
- * <code>MultiPixelPackedSampleModel</code>.
- * @param w the specified width
- * @param h the specified height
- * @return a {@link SampleModel} with the specified width and height
- * and with the same storage data type and number of bits per pixel
- * as this <code>MultiPixelPackedSampleModel</code>.
- * @throws IllegalArgumentException if <code>w</code> or
- * <code>h</code> is not greater than 0
- */
- public SampleModel createCompatibleSampleModel(int w, int h) {
- SampleModel sampleModel =
- new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
- return sampleModel;
- }
-
- /**
- * Creates a <code>DataBuffer</code> that corresponds to this
- * <code>MultiPixelPackedSampleModel</code>. The
- * <code>DataBuffer</code> object's data type and size
- * is consistent with this <code>MultiPixelPackedSampleModel</code>.
- * The <code>DataBuffer</code> has a single bank.
- * @return a <code>DataBuffer</code> with the same data type and
- * size as this <code>MultiPixelPackedSampleModel</code>.
- */
- public DataBuffer createDataBuffer() {
- DataBuffer dataBuffer = null;
-
- int size = (int)scanlineStride*height;
- switch (dataType) {
- case DataBuffer.TYPE_BYTE:
- dataBuffer = new DataBufferByte(size+(dataBitOffset+7)/8);
- break;
- case DataBuffer.TYPE_USHORT:
- dataBuffer = new DataBufferUShort(size+(dataBitOffset+15)/16);
- break;
- case DataBuffer.TYPE_INT:
- dataBuffer = new DataBufferInt(size+(dataBitOffset+31)/32);
- break;
- }
- return dataBuffer;
- }
-
- /**
- * Returns the number of data elements needed to transfer one pixel
- * via the {@link #getDataElements} and {@link #setDataElements}
- * methods. For a <code>MultiPixelPackedSampleModel</code>, this is
- * one.
- * @return the number of data elements.
- */
- public int getNumDataElements() {
- return 1;
- }
-
- /**
- * Returns the number of bits per sample for all bands.
- * @return the number of bits per sample.
- */
- public int[] getSampleSize() {
- int sampleSize[] = {pixelBitStride};
- return sampleSize;
- }
-
- /**
- * Returns the number of bits per sample for the specified band.
- * @param band the specified band
- * @return the number of bits per sample for the specified band.
- */
- public int getSampleSize(int band) {
- return pixelBitStride;
- }
-
- /**
- * Returns the offset of pixel (x, y) in data array elements.
- * @param x, y the specified pixel
- * @return the offset of the specified pixel.
- */
- public int getOffset(int x, int y) {
- int offset = y * scanlineStride;
- offset += (x*pixelBitStride+dataBitOffset)/dataElementSize;
- return offset;
- }
-
- /**
- * Returns the offset, in bits, into the data element in which it is
- * stored for the <code>x</code>th pixel of a scanline.
- * This offset is the same for all scanlines.
- * @param x the specified pixel
- * @return the bit offset of the specified pixel.
- */
- public int getBitOffset(int x){
- return (x*pixelBitStride+dataBitOffset)%dataElementSize;
- }
-
- /**
- * Returns the scanline stride.
- * @return the scanline stride of this
- * <code>MultiPixelPackedSampleModel</code>.
- */
- public int getScanlineStride() {
- return scanlineStride;
- }
-
- /**
- * Returns the pixel bit stride in bits. This value is the same as
- * the number of bits per pixel.
- * @return the <code>pixelBitStride</code> of this
- * <code>MultiPixelPackedSampleModel</code>.
- */
- public int getPixelBitStride() {
- return pixelBitStride;
- }
-
- /**
- * Returns the data bit offset in bits.
- * @return the <code>dataBitOffset</code> of this
- * <code>MultiPixelPackedSampleModel</code>.
- */
- public int getDataBitOffset() {
- return dataBitOffset;
- }
-
- /**
- * Returns the TransferType used to transfer pixels by way of the
- * <code>getDataElements</code> and <code>setDataElements</code>
- * methods. The TransferType might or might not be the same as the
- * storage DataType. The TransferType is one of
- * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
- * or DataBuffer.TYPE_INT.
- * @return the transfertype.
- */
- public int getTransferType() {
- if (pixelBitStride > 16)
- return DataBuffer.TYPE_INT;
- else if (pixelBitStride > 8)
- return DataBuffer.TYPE_USHORT;
- else
- return DataBuffer.TYPE_BYTE;
- }
-
- /**
- * Creates a new <code>MultiPixelPackedSampleModel</code> with a
- * subset of the bands of this
- * <code>MultiPixelPackedSampleModel</code>. Since a
- * <code>MultiPixelPackedSampleModel</code> only has one band, the
- * bands argument must have a length of one and indicate the zeroth
- * band.
- * @param bands the specified bands
- * @return a new <code>SampleModel</code> with a subset of bands of
- * this <code>MultiPixelPackedSampleModel</code>.
- * @exception RasterFormatException if the number of bands requested
- * is not one.
- * @throws IllegalArgumentException if <code>w</code> or
- * <code>h</code> is not greater than 0
- */
- public SampleModel createSubsetSampleModel(int bands[]) {
- if (bands != null) {
- if (bands.length != 1)
- throw new RasterFormatException("MultiPixelPackedSampleModel has "
- + "only one band.");
- }
- SampleModel sm = createCompatibleSampleModel(width, height);
- return sm;
- }
-
- /**
- * Returns as <code>int</code> the sample in a specified band for the
- * pixel located at (x, y). An
- * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * coordinates are not in bounds.
- * @param x, y the coordinates of the specified pixel
- * @param b the band to return, which is assumed to be 0
- * @param data the <code>DataBuffer</code> containing the image
- * data
- * @return the specified band containing the sample of the specified
- * pixel.
- * @exception ArrayIndexOutOfBoundException if the specified
- * coordinates are not in bounds.
- */
- public int getSample(int x, int y, int b, DataBuffer data) {
- int bitnum = dataBitOffset + x*pixelBitStride;
- int element = data.getElem(y*scanlineStride + bitnumdataElementSize);
- int shift = dataElementSize - (bitnum & (dataElementSize-1))
- - pixelBitStride;
- return (element >> shift) & bitMask;
- }
-
- /**
- * Sets a sample in the specified band for the pixel located at
- * (x, y) in the <code>DataBuffer</code> using an
- * <code>int</code> for input.
- * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * coordinates are not in bounds.
- * @param x, y the coordinates of the specified pixel
- * @param b the band to return, which is assumed to be 0
- * @param s the input sample as an <code>int</code>
- * @param data the <code>DataBuffer</code> where image data is stored
- * @exception ArrayIndexOutOfBoundsException if the coordinates are
- * not in bounds.
- */
- public void setSample(int x, int y, int b, int s,
- DataBuffer data) {
- int bitnum = dataBitOffset + x * pixelBitStride;
- int index = y * scanlineStride + (bitnum / dataElementSize);
- int shift = dataElementSize - (bitnum & (dataElementSize-1))
- - pixelBitStride;
- int element = data.getElem(index);
- element &= ~(bitMask << shift);
- element |= (s & bitMask) << shift;
- data.setElem(index,element);
- }
-
- /**
- * Returns data for a single pixel in a primitive array of type
- * TransferType. For a <code>MultiPixelPackedSampleModel</code>,
- * the array has one element, and the type is the smallest of
- * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
- * that can hold a single pixel. Generally, <code>obj</code>
- * should be passed in as <code>null</code>, so that the
- * <code>Object</code> is created automatically and is the
- * correct primitive data type.
- * <p>
- * The following code illustrates transferring data for one pixel from
- * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
- * described by <code>MultiPixelPackedSampleModel</code>
- * <code>mppsm1</code>, to <code>DataBuffer</code> <code>db2</code>,
- * whose storage layout is described by
- * <code>MultiPixelPackedSampleModel</code> <code>mppsm2</code>.
- * The transfer is generally more efficient than using
- * <code>getPixel</code> or <code>setPixel</code>.
- * <pre>
- * MultiPixelPackedSampleModel mppsm1, mppsm2;
- * DataBufferInt db1, db2;
- * mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
- * db1), db2);
- * </pre>
- * Using <code>getDataElements</code> or <code>setDataElements</code>
- * to transfer between two <code>DataBuffer/SampleModel</code> pairs
- * is legitimate if the <code>SampleModels</code> have the same number
- * of bands, corresponding bands have the same number of
- * bits per sample, and the TransferTypes are the same.
- * <p>
- * If <code>obj</code> is not <code>null</code>, it should be a
- * primitive array of type TransferType. Otherwise, a
- * <code>ClassCastException</code> is thrown. An
- * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * coordinates are not in bounds, or if <code>obj</code> is not
- * <code>null</code> and is not large enough to hold the pixel data.
- * @param x, y coordinates of the pixel location.
- * @param obj a primitive array in which to return the pixel data or
- * <code>null</code>.
- * @param data the <code>DataBuffer</code> containing the image data.
- * @return an <code>Object</code> containing data for the specified
- * pixel.
- * @exception ClassCastException if <code>obj</code> is not a
- * primitive array of type TransferType or is not <code>null</code>
- * @exception ArrayIndexOutOfBoundsException if the coordinates are
- * not in bounds, or if <code>obj</code> is not <code>null</code> or
- * not large enough to hold the pixel data
- */
- public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
-
- int type = getTransferType();
- int bitnum = dataBitOffset + x*pixelBitStride;
- int shift = dataElementSize - (bitnum & (dataElementSize-1))
- - pixelBitStride;
- int element = 0;
-
- switch(type) {
-
- case DataBuffer.TYPE_BYTE:
-
- byte[] bdata;
-
- if (obj == null)
- bdata = new byte[1];
- else
- bdata = (byte[])obj;
-
- element = data.getElem(y*scanlineStride +
- bitnumdataElementSize);
- bdata[0] = (byte)((element >> shift) & bitMask);
-
- obj = (Object)bdata;
- break;
-
- case DataBuffer.TYPE_USHORT:
-
- short[] sdata;
-
- if (obj == null)
- sdata = new short[1];
- else
- sdata = (short[])obj;
-
- element = data.getElem(y*scanlineStride +
- bitnumdataElementSize);
- sdata[0] = (short)((element >> shift) & bitMask);
-
- obj = (Object)sdata;
- break;
-
- case DataBuffer.TYPE_INT:
-
- int[] idata;
-
- if (obj == null)
- idata = new int[1];
- else
- idata = (int[])obj;
-
- element = data.getElem(y*scanlineStride +
- bitnumdataElementSize);
- idata[0] = (element >> shift) & bitMask;
-
- obj = (Object)idata;
- break;
- }
-
- return obj;
- }
-
- /**
- * Returns the specified single band pixel in the first element
- * of an <code>int</code> array.
- * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * coordinates are not in bounds.
- * @param x, y the coordinates of the pixel location
- * @param iArray the array containing the pixel to be returned or
- * <code>null</code>
- * @param data the <code>DataBuffer</code> where image data is stored
- * @return an array containing the specified pixel.
- * @exception ArrayIndexOutOfBoundsException if the coordinates
- * are not in bounds
- */
- public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
- int pixels[];
- if (iArray != null) {
- pixels = iArray;
- } else {
- pixels = new int [numBands];
- }
- int bitnum = dataBitOffset + x*pixelBitStride;
- int element = data.getElem(y*scanlineStride + bitnumdataElementSize);
- int shift = dataElementSize - (bitnum & (dataElementSize-1))
- - pixelBitStride;
- pixels[0] = (element >> shift) & bitMask;
- return pixels;
- }
-
- /**
- * Sets the data for a single pixel in the specified
- * <code>DataBuffer</code> from a primitive array of type
- * TransferType. For a <code>MultiPixelPackedSampleModel</code>,
- * only the first element of the array holds valid data,
- * and the type must be the smallest of
- * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
- * that can hold a single pixel.
- * <p>
- * The following code illustrates transferring data for one pixel from
- * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
- * described by <code>MultiPixelPackedSampleModel</code>
- * <code>mppsm1</code>, to <code>DataBuffer</code> <code>db2</code>,
- * whose storage layout is described by
- * <code>MultiPixelPackedSampleModel</code> <code>mppsm2</code>.
- * The transfer is generally more efficient than using
- * <code>getPixel</code> or <code>setPixel</code>.
- * <pre>
- * MultiPixelPackedSampleModel mppsm1, mppsm2;
- * DataBufferInt db1, db2;
- * mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
- * db1), db2);
- * </pre>
- * Using <code>getDataElements</code> or <code>setDataElements</code> to
- * transfer between two <code>DataBuffer/SampleModel</code> pairs is
- * legitimate if the <code>SampleModel</code> objects have
- * the same number of bands, corresponding bands have the same number of
- * bits per sample, and the TransferTypes are the same.
- * <p>
- * <code>obj</code> must be a primitive array of type TransferType.
- * Otherwise, a <code>ClassCastException</code> is thrown. An
- * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * coordinates are not in bounds, or if <code>obj</code> is not large
- * enough to hold the pixel data.
- * @param x, y the coordinates of the pixel location
- * @param obj a primitive array containing pixel data
- * @param data the <code>DataBuffer</code> containing the image data
- */
- public void setDataElements(int x, int y, Object obj, DataBuffer data) {
-
- int type = getTransferType();
- int bitnum = dataBitOffset + x * pixelBitStride;
- int index = y * scanlineStride + (bitnum / dataElementSize);
- int shift = dataElementSize - (bitnum & (dataElementSize-1))
- - pixelBitStride;
- int element = data.getElem(index);
- element &= ~(bitMask << shift);
-
- switch(type) {
-
- case DataBuffer.TYPE_BYTE:
-
- byte[] barray = (byte[])obj;
- element |= ( ((int)(barray[0])&0xff) & bitMask) << shift;
- data.setElem(index, element);
- break;
-
- case DataBuffer.TYPE_USHORT:
-
- short[] sarray = (short[])obj;
- element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift;
- data.setElem(index, element);
- break;
-
- case DataBuffer.TYPE_INT:
-
- int[] iarray = (int[])obj;
- element |= (iarray[0] & bitMask) << shift;
- data.setElem(index, element);
- break;
- }
- }
-
- /**
- * Sets a pixel in the <code>DataBuffer</code> using an
- * <code>int</code> array for input.
- * <code>ArrayIndexOutOfBoundsException</code> is thrown if
- * the coordinates are not in bounds.
- * @param x, y the coordinates of the pixel location
- * @param iArray the input pixel in an <code>int</code> array
- * @param data the <code>DataBuffer</code> containing the image data
- */
- public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
- int bitnum = dataBitOffset + x * pixelBitStride;
- int index = y * scanlineStride + (bitnum / dataElementSize);
- int shift = dataElementSize - (bitnum & (dataElementSize-1))
- - pixelBitStride;
- int element = data.getElem(index);
- element &= ~(bitMask << shift);
- element |= (iArray[0] & bitMask) << shift;
- data.setElem(index,element);
- }
-
-
- }
-
-