src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java
changeset 47216 71c04702a3d5
parent 35667 ed476aba94de
child 52248 2e330da7cbf4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** 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;
+
+import java.util.Arrays;
+
+/**
+ *  This class represents pixel data packed such that the N samples which make
+ *  up a single pixel are stored in a single data array element, and each data
+ *  data array element holds samples for only one pixel.
+ *  This class supports
+ *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
+ *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
+ *  {@link DataBuffer#TYPE_INT TYPE_INT} data types.
+ *  All data array elements reside
+ *  in the first bank of a DataBuffer.  Accessor methods are provided so
+ *  that the image data can be manipulated directly. 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. Bit masks are the masks
+ *  required to extract the samples representing the bands of the pixel.
+ *  Bit offsets are the offsets in bits into the data array
+ *  element of the samples representing the bands of the pixel.
+ * <p>
+ * The following code illustrates extracting the bits of the sample
+ * representing band {@code b} for pixel {@code x,y}
+ * from DataBuffer {@code data}:
+ * <pre>{@code
+ *      int sample = data.getElem(y * scanlineStride + x);
+ *      sample = (sample & bitMasks[b]) >>> bitOffsets[b];
+ * }</pre>
+ */
+
+public class SinglePixelPackedSampleModel extends SampleModel
+{
+    /** Bit masks for all bands of the image data. */
+    private int bitMasks[];
+
+    /** Bit Offsets for all bands of the image data. */
+    private int bitOffsets[];
+
+    /** Bit sizes for all the bands of the image data. */
+    private int bitSizes[];
+
+    /** Maximum bit size. */
+    private int maxBitSize;
+
+    /** Line stride of the region of image data described by this
+     *  SinglePixelPackedSampleModel.
+     */
+    private int scanlineStride;
+
+    private static native void initIDs();
+    static {
+        ColorModel.loadLibraries();
+        initIDs();
+    }
+
+    /**
+     * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands.
+     * Each sample is stored in a data array element in the position of
+     * its corresponding bit mask.  Each bit mask must be contiguous and
+     * masks must not overlap. Bit masks exceeding data type capacity are
+     * truncated.
+     * @param dataType  The data type for storing samples.
+     * @param w         The width (in pixels) of the region of the
+     *                  image data described.
+     * @param h         The height (in pixels) of the region of the
+     *                  image data described.
+     * @param bitMasks  The bit masks for all bands.
+     * @throws IllegalArgumentException if {@code dataType} is not
+     *         either {@code DataBuffer.TYPE_BYTE},
+     *         {@code DataBuffer.TYPE_USHORT}, or
+     *         {@code DataBuffer.TYPE_INT}
+     */
+    public SinglePixelPackedSampleModel(int dataType, int w, int h,
+                                   int bitMasks[]) {
+        this(dataType, w, h, w, bitMasks);
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type "+
+                                               dataType);
+        }
+    }
+
+    /**
+     * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands
+     * and a scanline stride equal to scanlineStride data array elements.
+     * Each sample is stored in a data array element in the position of
+     * its corresponding bit mask.  Each bit mask must be contiguous and
+     * masks must not overlap. Bit masks exceeding data type capacity are
+     * truncated.
+     * @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 scanlineStride The line stride of the image data.
+     * @param bitMasks The bit masks for all bands.
+     * @throws IllegalArgumentException if {@code w} or
+     *         {@code h} is not greater than 0
+     * @throws IllegalArgumentException if any mask in
+     *         {@code bitMask} is not contiguous
+     * @throws IllegalArgumentException if {@code dataType} is not
+     *         either {@code DataBuffer.TYPE_BYTE},
+     *         {@code DataBuffer.TYPE_USHORT}, or
+     *         {@code DataBuffer.TYPE_INT}
+     */
+    public SinglePixelPackedSampleModel(int dataType, int w, int h,
+                                   int scanlineStride, int bitMasks[]) {
+        super(dataType, w, h, bitMasks.length);
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type "+
+                                               dataType);
+        }
+        this.dataType = dataType;
+        this.bitMasks = bitMasks.clone();
+        this.scanlineStride = scanlineStride;
+
+        this.bitOffsets = new int[numBands];
+        this.bitSizes = new int[numBands];
+
+        int maxMask = (int)((1L << DataBuffer.getDataTypeSize(dataType)) - 1);
+
+        this.maxBitSize = 0;
+        for (int i=0; i<numBands; i++) {
+            int bitOffset = 0, bitSize = 0, mask;
+            this.bitMasks[i] &= maxMask;
+            mask = this.bitMasks[i];
+            if (mask != 0) {
+                while ((mask & 1) == 0) {
+                    mask = mask >>> 1;
+                    bitOffset++;
+                }
+                while ((mask & 1) == 1) {
+                    mask = mask >>> 1;
+                    bitSize++;
+                }
+                if (mask != 0) {
+                    throw new IllegalArgumentException("Mask "+bitMasks[i]+
+                                                       " must be contiguous");
+                }
+            }
+            bitOffsets[i] = bitOffset;
+            bitSizes[i] = bitSize;
+            if (bitSize > maxBitSize) {
+                maxBitSize = bitSize;
+            }
+        }
+    }
+
+    /**
+     * Returns the number of data elements needed to transfer one pixel
+     * via the getDataElements and setDataElements methods.
+     * For a SinglePixelPackedSampleModel, this is one.
+     */
+    public int getNumDataElements() {
+        return 1;
+    }
+
+    /**
+     * Returns the size of the buffer (in data array elements)
+     * needed for a data buffer that matches this
+     * SinglePixelPackedSampleModel.
+     */
+    private long getBufferSize() {
+      long size = scanlineStride * (height-1) + width;
+      return size;
+    }
+
+    /**
+     * Creates a new SinglePixelPackedSampleModel with the specified
+     * width and height.  The new SinglePixelPackedSampleModel will have the
+     * same storage data type and bit masks as this
+     * SinglePixelPackedSampleModel.
+     * @param w the width of the resulting {@code SampleModel}
+     * @param h the height of the resulting {@code SampleModel}
+     * @return a {@code SinglePixelPackedSampleModel} with the
+     *         specified width and height.
+     * @throws IllegalArgumentException if {@code w} or
+     *         {@code h} is not greater than 0
+     */
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+      SampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h,
+                                                              bitMasks);
+      return sampleModel;
+    }
+
+    /**
+     * Creates a DataBuffer that corresponds to this
+     * SinglePixelPackedSampleModel.  The DataBuffer's data type and size
+     * will be consistent with this SinglePixelPackedSampleModel.  The
+     * DataBuffer will have a single bank.
+     */
+    public DataBuffer createDataBuffer() {
+        DataBuffer dataBuffer = null;
+
+        int size = (int)getBufferSize();
+        switch (dataType) {
+        case DataBuffer.TYPE_BYTE:
+            dataBuffer = new DataBufferByte(size);
+            break;
+        case DataBuffer.TYPE_USHORT:
+            dataBuffer = new DataBufferUShort(size);
+            break;
+        case DataBuffer.TYPE_INT:
+            dataBuffer = new DataBufferInt(size);
+            break;
+        }
+        return dataBuffer;
+    }
+
+    /** Returns the number of bits per sample for all bands. */
+    public int[] getSampleSize() {
+        return bitSizes.clone();
+    }
+
+    /** Returns the number of bits per sample for the specified band. */
+    public int getSampleSize(int band) {
+        return bitSizes[band];
+    }
+
+    /** Returns the offset (in data array elements) of pixel (x,y).
+     *  The data element containing pixel {@code x,y}
+     *  can be retrieved from a DataBuffer {@code data} with a
+     *  SinglePixelPackedSampleModel {@code sppsm} as:
+     * <pre>
+     *        data.getElem(sppsm.getOffset(x, y));
+     * </pre>
+     * @param x the X coordinate of the specified pixel
+     * @param y the Y coordinate of the specified pixel
+     * @return the offset of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        int offset = y * scanlineStride + x;
+        return offset;
+    }
+
+    /** Returns the bit offsets into the data array element representing
+     *  a pixel for all bands.
+     *  @return the bit offsets representing a pixel for all bands.
+     */
+    public int [] getBitOffsets() {
+      return bitOffsets.clone();
+    }
+
+    /** Returns the bit masks for all bands.
+     *  @return the bit masks for all bands.
+     */
+    public int [] getBitMasks() {
+      return bitMasks.clone();
+    }
+
+    /** Returns the scanline stride of this SinglePixelPackedSampleModel.
+     *  @return the scanline stride of this
+     *          {@code SinglePixelPackedSampleModel}.
+     */
+    public int getScanlineStride() {
+      return scanlineStride;
+    }
+
+    /**
+     * This creates a new SinglePixelPackedSampleModel with a subset of the
+     * bands of this SinglePixelPackedSampleModel.  The new
+     * SinglePixelPackedSampleModel can be used with any DataBuffer that the
+     * existing SinglePixelPackedSampleModel can be used with.  The new
+     * SinglePixelPackedSampleModel/DataBuffer combination will represent
+     * an image with a subset of the bands of the original
+     * SinglePixelPackedSampleModel/DataBuffer combination.
+     * @exception RasterFormatException if the length of the bands argument is
+     *                                  greater than the number of bands in
+     *                                  the sample model.
+     */
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands.length > numBands)
+            throw new RasterFormatException("There are only " +
+                                            numBands +
+                                            " bands");
+        int newBitMasks[] = new int[bands.length];
+        for (int i=0; i<bands.length; i++)
+            newBitMasks[i] = bitMasks[bands[i]];
+
+        return new SinglePixelPackedSampleModel(this.dataType, width, height,
+                                           this.scanlineStride, newBitMasks);
+    }
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * TransferType.  For a SinglePixelPackedSampleModel, the array will
+     * have one element, and the type will be the same as the storage
+     * data type.  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.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer {@code db1}, whose storage layout is described by
+     * SinglePixelPackedSampleModel {@code sppsm1}, to
+     * DataBuffer {@code db2}, whose storage layout is described by
+     * SinglePixelPackedSampleModel {@code sppsm2}.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       SinglePixelPackedSampleModel sppsm1, sppsm2;
+     *       DataBufferInt db1, db2;
+     *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * </pre>
+     * 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.
+     * <p>
+     * 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 for the specified pixel.
+     * @see #setDataElements(int, int, Object, DataBuffer)
+     */
+    public Object getDataElements(int x, int y, Object obj, 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 type = getTransferType();
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] bdata;
+
+            if (obj == null)
+                bdata = new byte[1];
+            else
+                bdata = (byte[])obj;
+
+            bdata[0] = (byte)data.getElem(y * scanlineStride + x);
+
+            obj = (Object)bdata;
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+
+            short[] sdata;
+
+            if (obj == null)
+                sdata = new short[1];
+            else
+                sdata = (short[])obj;
+
+            sdata[0] = (short)data.getElem(y * scanlineStride + x);
+
+            obj = (Object)sdata;
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] idata;
+
+            if (obj == null)
+                idata = new int[1];
+            else
+                idata = (int[])obj;
+
+            idata[0] = data.getElem(y * scanlineStride + x);
+
+            obj = (Object)idata;
+            break;
+        }
+
+        return obj;
+    }
+
+    /**
+     * Returns all samples in for the specified pixel in an int array.
+     * 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 iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data.
+     * @return all samples for the specified pixel.
+     * @see #setPixel(int, int, int[], DataBuffer)
+     */
+    public int [] getPixel(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 pixels[];
+        if (iArray == null) {
+            pixels = new int [numBands];
+        } else {
+            pixels = iArray;
+        }
+
+        int value = data.getElem(y * scanlineStride + x);
+        for (int i=0; i<numBands; i++) {
+            pixels[i] = (value & bitMasks[i]) >>> bitOffsets[i];
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for the specified rectangle of pixels in
+     * an int 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 iArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return all samples for the specified region of pixels.
+     * @see #setPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getPixels(int x, int y, int w, int h,
+                           int iArray[], DataBuffer data) {
+        int x1 = x + w;
+        int y1 = y + h;
+
+        if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
+            y < 0 || y >= height || h > height || y1 < 0 || y1 >  height)
+        {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int pixels[];
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int [w*h*numBands];
+        }
+        int lineOffset = y*scanlineStride + x;
+        int dstOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+              int value = data.getElem(lineOffset+j);
+              for (int k=0; k < numBands; k++) {
+                  pixels[dstOffset++] =
+                     ((value & bitMasks[k]) >>> bitOffsets[k]);
+              }
+           }
+           lineOffset += scanlineStride;
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns as int the sample in a specified band for the pixel
+     * located at (x,y).
+     * 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 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(y * scanlineStride + x);
+        return ((sample & bitMasks[b]) >>> bitOffsets[b]);
+    }
+
+    /**
+     * Returns the samples for a specified band for the specified rectangle
+     * of pixels in an int 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 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 for the specified band for the specified
+     *         region of pixels.
+     * @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;
+        int dstOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+              int value = data.getElem(lineOffset+j);
+              samples[dstOffset++] =
+                 ((value & bitMasks[b]) >>> bitOffsets[b]);
+           }
+           lineOffset += scanlineStride;
+        }
+        return samples;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified DataBuffer from a
+     * primitive array of type TransferType.  For a
+     * SinglePixelPackedSampleModel, only the first element of the array
+     * will hold valid data, and the type of the array must be the same as
+     * the storage data type of the SinglePixelPackedSampleModel.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer {@code db1}, whose storage layout is described by
+     * SinglePixelPackedSampleModel {@code sppsm1},
+     * to DataBuffer {@code db2}, whose storage layout is described by
+     * SinglePixelPackedSampleModel {@code sppsm2}.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       SinglePixelPackedSampleModel sppsm1, sppsm2;
+     *       DataBufferInt db1, db2;
+     *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * </pre>
+     * 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.
+     * <p>
+     * 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 #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();
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] barray = (byte[])obj;
+            data.setElem(y*scanlineStride+x, ((int)barray[0])&0xff);
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+
+            short[] sarray = (short[])obj;
+            data.setElem(y*scanlineStride+x, ((int)sarray[0])&0xffff);
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] iarray = (int[])obj;
+            data.setElem(y*scanlineStride+x, iarray[0]);
+            break;
+        }
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using an int array of samples 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 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 lineOffset = y * scanlineStride + x;
+        int value = data.getElem(lineOffset);
+        for (int i=0; i < numBands; i++) {
+            value &= ~bitMasks[i];
+            value |= ((iArray[i] << bitOffsets[i]) & bitMasks[i]);
+        }
+        data.setElem(lineOffset, value);
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from an int array containing
+     * 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 iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          int iArray[], DataBuffer data) {
+        int x1 = x + w;
+        int y1 = y + h;
+
+        if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
+            y < 0 || y >= height || h > height || y1 < 0 || y1 >  height)
+        {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int lineOffset = y*scanlineStride + x;
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+               int value = data.getElem(lineOffset+j);
+               for (int k=0; k < numBands; k++) {
+                   value &= ~bitMasks[k];
+                   int srcValue = iArray[srcOffset++];
+                   value |= ((srcValue << bitOffsets[k])
+                             & bitMasks[k]);
+               }
+               data.setElem(lineOffset+j, value);
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using an int 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 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!");
+        }
+        int value = data.getElem(y*scanlineStride + x);
+        value &= ~bitMasks[b];
+        value |= (s << bitOffsets[b]) & bitMasks[b];
+        data.setElem(y*scanlineStride + x,value);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from an int array containing 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 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;
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+              int value = data.getElem(lineOffset+j);
+              value &= ~bitMasks[b];
+              int sample = iArray[srcOffset++];
+              value |= (sample << bitOffsets[b]) & bitMasks[b];
+              data.setElem(lineOffset+j,value);
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
+            return false;
+        }
+
+        SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel)o;
+        return this.width == that.width &&
+            this.height == that.height &&
+            this.numBands == that.numBands &&
+            this.dataType == that.dataType &&
+            Arrays.equals(this.bitMasks, that.bitMasks) &&
+            Arrays.equals(this.bitOffsets, that.bitOffsets) &&
+            Arrays.equals(this.bitSizes, that.bitSizes) &&
+            this.maxBitSize == that.maxBitSize &&
+            this.scanlineStride == that.scanlineStride;
+    }
+
+    // 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 < bitMasks.length; i++) {
+            hash ^= bitMasks[i];
+            hash <<= 8;
+        }
+        for (int i = 0; i < bitOffsets.length; i++) {
+            hash ^= bitOffsets[i];
+            hash <<= 8;
+        }
+        for (int i = 0; i < bitSizes.length; i++) {
+            hash ^= bitSizes[i];
+            hash <<= 8;
+        }
+        hash ^= maxBitSize;
+        hash <<= 8;
+        hash ^= scanlineStride;
+        return hash;
+    }
+}