/* * @(#)SampleModel.java 1.36 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. 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; /** * This abstract class defines an interface for extracting samples of pixels * in an image. All image data is expressed as a collection of pixels. * Each pixel consists of a number of samples. A sample is a datum * for one band of an image and a band consists of all samples of a * particular type in an image. For example, a pixel might contain * three samples representing its red, green and blue components. * There are three bands in the image containing this pixel. One band * consists of all the red samples from all pixels in the * image. The second band consists of all the green samples and * the remaining band consists of all of the blue samples. The pixel * can be stored in various formats. For example, all samples from * a particular band can be stored contiguously or all samples from a * single pixel can be stored contiguously. *
* Subclasses of SampleModel specify the types of samples they can * represent (e.g. unsigned 8-bit byte, signed 16-bit short, etc.) * and may specify how the samples are organized in memory. * In the Java 2D(tm) API, built-in image processing operators may * not operate on all possible sample types, but generally will work * for unsigned integral samples of 16 bits or less. Some operators * support a wider variety of sample types. *
* A collection of pixels is represented as a Raster, which consists of * a DataBuffer and a SampleModel. The SampleModel allows access to * samples in the DataBuffer and may provide low-level information that * a programmer can use to directly manipulate samples and pixels in the * DataBuffer. *
 *  This class is generally a fall back method for dealing with
 *  images.  More efficient code will cast the SampleModel to the
 *  appropriate subclass and extract the information needed to directly
 *  manipulate pixels in the DataBuffer.
 *
 *  @see java.awt.image.DataBuffer
 *  @see java.awt.image.Raster
 *  @see java.awt.image.ComponentSampleModel
 *  @see java.awt.image.PixelInterleavedSampleModel
 *  @see java.awt.image.BandedSampleModel
 *  @see java.awt.image.MultiPixelPackedSampleModel
 *  @see java.awt.image.SinglePixelPackedSampleModel
 */
public abstract class SampleModel
{
    /** Width in pixels of the region of image data that this SampleModel
     *  describes.
     */
    protected int width;
    /** Height in pixels of the region of image data that this SampleModel
     *  describes.
     */
    protected int height;
    /** Number of bands of the image data that this SampleModel describes. */
    protected int numBands;
    /** Data type of the DataBuffer storing the pixel data.
     *  @see java.awt.image.DataBuffer
     */
    protected int dataType; 
    static private native void initIDs();
    static {
        ColorModel.loadLibraries();
        initIDs();
    }
    /**
     * Constructs a SampleModel with the specified parameters.
     * @param dataType	The data type of the DataBuffer storing the pixel data.
     * @param w 	The width (in pixels) of the region of image data.
     * @param h         The height (in pixels) of the region of image data.
     * @param numBands  The number of bands of the image data.
     * @throws IllegalArgumentException if  
     * If obj is non-null, it should be a primitive array of type TransferType.
     * Otherwise, a ClassCastException is thrown.  An
     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
     * not in bounds, or if obj is non-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 elements for the specified pixel.
     * @see #getNumDataElements
     * @see #getTransferType
     * @see java.awt.image.DataBuffer
     * @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 output.
     */
    public abstract Object getDataElements(int x, int y,
                                           Object obj, DataBuffer data);
    /** 
     * Returns the pixel data for the specified rectangle of pixels in a
     * primitive array of type TransferType.
     * For image data supported by the Java 2D API, this
     * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
     * or DataBuffer.TYPE_DOUBLE.  Data may be returned in a packed format,
     * thus increasing efficiency for data transfers. 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 a rectangular
     * region of pixels from
     * DataBuffer  
     * If obj is non-null, it should be a primitive array of type TransferType.
     * Otherwise, a ClassCastException is thrown.  An
     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
     * not in bounds, or if obj is non-null and is not large enough to hold
     * the pixel data.
     * @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.
     * @return the data elements for the specified region of pixels.
     * @see #getNumDataElements
     * @see #getTransferType
     * @see #setDataElements(int, int, int, int, Object, DataBuffer)
     * @see java.awt.image.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 output.
     */
    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; i 
     * obj must be a primitive array of type TransferType.  Otherwise,
     * a ClassCastException is thrown.  An
     * ArrayIndexOutOfBoundsException may 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 #getNumDataElements
     * @see #getTransferType
     * @see #getDataElements(int, int, Object, DataBuffer)
     * @see java.awt.image.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 input.
     */
    public abstract void setDataElements(int x, int y,
                                         Object obj, DataBuffer data);
    /** 
     * Sets the data for a rectangle of pixels in the specified DataBuffer
     * from a primitive array of type TransferType.  For image data supported
     * by the Java 2D API, this will be one of DataBuffer.TYPE_BYTE,
     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.  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  
     * obj must be a primitive array of type TransferType.  Otherwise,
     * a ClassCastException is thrown.  An
     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
     * not in bounds, or if obj is not large enough to hold the pixel data.
     * @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.
     * @see #getNumDataElements
     * @see #getTransferType
     * @see #getDataElements(int, int, int, int, Object, DataBuffer)
     * @see java.awt.image.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 input.
     */    
    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; iw or h
     *         is not greater than 0
     * @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 SampleModel(int dataType, int w, int h, int numBands)
    {
        float size = (float)w*h;
        if (w <= 0 || h <= 0) {
            throw new IllegalArgumentException("Width ("+w+") and height ("+
                                               h+") must be > 0");
        }
        if (size >= Integer.MAX_VALUE) {
            throw new IllegalArgumentException("Dimensions (width="+w+
                                               " height="+h+") are too large");
        }
        if (dataType < DataBuffer.TYPE_BYTE ||
            (dataType > DataBuffer.TYPE_DOUBLE &&
             dataType != DataBuffer.TYPE_UNDEFINED))
        {
            throw new IllegalArgumentException("Unsupported dataType: "+
                                               dataType);
        }
        if (numBands <= 0) {
            throw new IllegalArgumentException("Number of bands must be > 0");
        }
        
	this.dataType = dataType;
	this.width = w;
	this.height = h;
	this.numBands = numBands;
    }
    /** Returns the width in pixels.
     *  @return the width in pixels of the region of image data 
     *          that this SampleModel describes.
     */
    final public int getWidth() {
	 return width;
    }
    /** Returns the height in pixels. 
     *  @return the height in pixels of the region of image data 
     *          that this SampleModel describes.
     */
    final public int getHeight() {
	 return height;
    }
    /** Returns the total number of bands of image data. 
     *  @return the number of bands of image data that this
     *          SampleModel describes.
     */
    final public int getNumBands() {
	 return numBands;
    }
    /** Returns the number of data elements needed to transfer a pixel
     *  via the getDataElements and setDataElements methods.  When pixels
     *  are transferred via these methods, they may be transferred in a
     *  packed or unpacked format, depending on the implementation of the
     *  SampleModel.  Using these methods, pixels are transferred as an
     *  array of getNumDataElements() elements of a primitive type given
     *  by getTransferType().  The TransferType may or may not be the same
     *  as the storage DataType.
     *  @return the number of data elements.
     *  @see #getDataElements(int, int, Object, DataBuffer)
     *  @see #getDataElements(int, int, int, int, Object, DataBuffer)
     *  @see #setDataElements(int, int, Object, DataBuffer)
     *  @see #setDataElements(int, int, int, int, Object, DataBuffer)
     *  @see #getTransferType
     */
    public abstract int getNumDataElements();
    
    /** Returns the data type of the DataBuffer storing the pixel data. 
     *  @return the data type.
     */
    final public int getDataType() {
	return dataType;
    }
    /** Returns the TransferType used to transfer pixels via the
     *  getDataElements and setDataElements methods.  When pixels
     *  are transferred via these methods, they may be transferred in a
     *  packed or unpacked format, depending on the implementation of the
     *  SampleModel.  Using these methods, pixels are transferred as an
     *  array of getNumDataElements() elements of a primitive type given
     *  by getTransferType().  The TransferType may or may not be the same
     *  as the storage DataType.  The TransferType will be one of the types
     *  defined in DataBuffer.
     *  @return the transfer type.
     *  @see #getDataElements(int, int, Object, DataBuffer)
     *  @see #getDataElements(int, int, int, int, Object, DataBuffer)
     *  @see #setDataElements(int, int, Object, DataBuffer)
     *  @see #setDataElements(int, int, int, int, Object, DataBuffer)
     *  @see #getNumDataElements
     *  @see java.awt.image.DataBuffer
     */
    public int getTransferType() {
        return dataType;
    }
    /** 
     * Returns the samples for a specified pixel in an int array,
     * one sample per array element.
     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
     * not in bounds.
     * @param x, y The coordinates of the pixel location
     * @param iArray    If non-null, returns the samples in this array
     * @param data      The DataBuffer containing the image data
     * @return the samples for the specified pixel.
     * @see #setPixel(int, int, int[], DataBuffer)
     *
     * @throws NullPointerException if data is null.
     * @throws ArrayIndexOutOfBoundsException if the coordinates are
     * not in bounds, or if iArray is too small to hold the output.
     */
    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
	int pixels[];
	if (iArray != null)
	    pixels = iArray;
	else
	    pixels = new int[numBands];
	for (int i=0; idb1, 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
     * getPixel/setPixel.
     * 
     * 	     SampleModel sm1, sm2;
     *	     DataBuffer db1, db2;
     * 	     sm2.setDataElements(x, y, sm1.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.
     * 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.
     * 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
     * getPixel/setPixel.
     * 
     * 	     SampleModel sm1, sm2;
     *	     DataBuffer db1, db2;
     * 	     sm2.setDataElements(x, y, sm1.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.
     * 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.
     * SampleModel, but with a 
     *          different size.
     */
    public abstract SampleModel createCompatibleSampleModel(int w, int h);
    /**
     * Creates a new SampleModel 
     * with a subset of the bands of this
     * SampleModel.
     * @param bands the subset of bands of this SampleModel
     * @return a SampleModel with a subset of bands of this
     *         SampleModel.
     */
    public abstract SampleModel createSubsetSampleModel(int bands[]);
    /**
     * Creates a DataBuffer that corresponds to this SampleModel.
     * The DataBuffer's width and height will match this SampleModel's.
     * @return a DataBuffer corresponding to this
     *         SampleModel.
     */
    public abstract DataBuffer createDataBuffer();
    /** Returns the size in bits of samples for all bands. 
     *  @return the size of samples for all bands.
     */
    public abstract int[] getSampleSize();
    /** Returns the size in bits of samples for the specified band. 
     *  @param band the specified band
     *  @return the size of the samples of the specified band.    
     */
    public abstract int getSampleSize(int band);
}