jdk/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java
changeset 539 7952521a4ad3
child 715 f16baef3a20e
equal deleted inserted replaced
538:d95bc71a5732 539:7952521a4ad3
       
     1 /*
       
     2  * Portions Copyright 1997-2001 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 /* ****************************************************************
       
    27  ******************************************************************
       
    28  ******************************************************************
       
    29  *** COPYRIGHT (c) Eastman Kodak Company, 1997
       
    30  *** As  an unpublished  work pursuant to Title 17 of the United
       
    31  *** States Code.  All rights reserved.
       
    32  ******************************************************************
       
    33  ******************************************************************
       
    34  ******************************************************************/
       
    35 
       
    36 package java.awt.image;
       
    37 
       
    38 import java.util.Arrays;
       
    39 
       
    40 /**
       
    41  *  This class represents pixel data packed such that the N samples which make
       
    42  *  up a single pixel are stored in a single data array element, and each data
       
    43  *  data array element holds samples for only one pixel.
       
    44  *  This class supports
       
    45  *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
       
    46  *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
       
    47  *  {@link DataBuffer#TYPE_INT TYPE_INT} data types.
       
    48  *  All data array elements reside
       
    49  *  in the first bank of a DataBuffer.  Accessor methods are provided so
       
    50  *  that the image data can be manipulated directly. Scanline stride is the
       
    51  *  number of data array elements between a given sample and the corresponding
       
    52  *  sample in the same column of the next scanline. Bit masks are the masks
       
    53  *  required to extract the samples representing the bands of the pixel.
       
    54  *  Bit offsets are the offsets in bits into the data array
       
    55  *  element of the samples representing the bands of the pixel.
       
    56  * <p>
       
    57  * The following code illustrates extracting the bits of the sample
       
    58  * representing band <code>b</code> for pixel <code>x,y</code>
       
    59  * from DataBuffer <code>data</code>:
       
    60  * <pre>
       
    61  *      int sample = data.getElem(y * scanlineStride + x);
       
    62  *      sample = (sample & bitMasks[b]) >>> bitOffsets[b];
       
    63  * </pre>
       
    64  */
       
    65 
       
    66 public class SinglePixelPackedSampleModel extends SampleModel
       
    67 {
       
    68     /** Bit masks for all bands of the image data. */
       
    69     private int bitMasks[];
       
    70 
       
    71     /** Bit Offsets for all bands of the image data. */
       
    72     private int bitOffsets[];
       
    73 
       
    74     /** Bit sizes for all the bands of the image data. */
       
    75     private int bitSizes[];
       
    76 
       
    77     /** Maximum bit size. */
       
    78     private int maxBitSize;
       
    79 
       
    80     /** Line stride of the region of image data described by this
       
    81      *  SinglePixelPackedSampleModel.
       
    82      */
       
    83     private int scanlineStride;
       
    84 
       
    85     private static native void initIDs();
       
    86     static {
       
    87         ColorModel.loadLibraries();
       
    88         initIDs();
       
    89     }
       
    90 
       
    91     /**
       
    92      * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands.
       
    93      * Each sample is stored in a data array element in the position of
       
    94      * its corresponding bit mask.  Each bit mask must be contiguous and
       
    95      * masks must not overlap.
       
    96      * @param dataType  The data type for storing samples.
       
    97      * @param w         The width (in pixels) of the region of the
       
    98      *                  image data described.
       
    99      * @param h         The height (in pixels) of the region of the
       
   100      *                  image data described.
       
   101      * @param bitMasks  The bit masks for all bands.
       
   102      * @throws IllegalArgumentException if <code>dataType</code> is not
       
   103      *         either <code>DataBuffer.TYPE_BYTE</code>,
       
   104      *         <code>DataBuffer.TYPE_USHORT</code>, or
       
   105      *         <code>DataBuffer.TYPE_INT</code>
       
   106      */
       
   107     public SinglePixelPackedSampleModel(int dataType, int w, int h,
       
   108                                    int bitMasks[]) {
       
   109         this(dataType, w, h, w, bitMasks);
       
   110         if (dataType != DataBuffer.TYPE_BYTE &&
       
   111             dataType != DataBuffer.TYPE_USHORT &&
       
   112             dataType != DataBuffer.TYPE_INT) {
       
   113             throw new IllegalArgumentException("Unsupported data type "+
       
   114                                                dataType);
       
   115         }
       
   116     }
       
   117 
       
   118     /**
       
   119      * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands
       
   120      * and a scanline stride equal to scanlineStride data array elements.
       
   121      * Each sample is stored in a data array element in the position of
       
   122      * its corresponding bit mask.  Each bit mask must be contiguous and
       
   123      * masks must not overlap.
       
   124      * @param dataType  The data type for storing samples.
       
   125      * @param w         The width (in pixels) of the region of
       
   126      *                  image data described.
       
   127      * @param h         The height (in pixels) of the region of
       
   128      *                  image data described.
       
   129      * @param scanlineStride The line stride of the image data.
       
   130      * @param bitMasks The bit masks for all bands.
       
   131      * @throws IllegalArgumentException if <code>w</code> or
       
   132      *         <code>h</code> is not greater than 0
       
   133      * @throws IllegalArgumentException if any mask in
       
   134      *         <code>bitMask</code> is not contiguous
       
   135      * @throws IllegalArgumentException if <code>dataType</code> is not
       
   136      *         either <code>DataBuffer.TYPE_BYTE</code>,
       
   137      *         <code>DataBuffer.TYPE_USHORT</code>, or
       
   138      *         <code>DataBuffer.TYPE_INT</code>
       
   139      */
       
   140     public SinglePixelPackedSampleModel(int dataType, int w, int h,
       
   141                                    int scanlineStride, int bitMasks[]) {
       
   142         super(dataType, w, h, bitMasks.length);
       
   143         if (dataType != DataBuffer.TYPE_BYTE &&
       
   144             dataType != DataBuffer.TYPE_USHORT &&
       
   145             dataType != DataBuffer.TYPE_INT) {
       
   146             throw new IllegalArgumentException("Unsupported data type "+
       
   147                                                dataType);
       
   148         }
       
   149         this.dataType = dataType;
       
   150         this.bitMasks = (int[]) bitMasks.clone();
       
   151         this.scanlineStride = scanlineStride;
       
   152 
       
   153         this.bitOffsets = new int[numBands];
       
   154         this.bitSizes = new int[numBands];
       
   155 
       
   156         this.maxBitSize = 0;
       
   157         for (int i=0; i<numBands; i++) {
       
   158             int bitOffset = 0, bitSize = 0, mask;
       
   159             mask = bitMasks[i];
       
   160 
       
   161             if (mask != 0) {
       
   162                 while ((mask & 1) == 0) {
       
   163                     mask = mask >>> 1;
       
   164                     bitOffset++;
       
   165                 }
       
   166                 while ((mask & 1) == 1) {
       
   167                     mask = mask >>> 1;
       
   168                     bitSize++;
       
   169                 }
       
   170                 if (mask != 0) {
       
   171                     throw new IllegalArgumentException("Mask "+bitMasks[i]+
       
   172                                                        " must be contiguous");
       
   173                 }
       
   174             }
       
   175             bitOffsets[i] = bitOffset;
       
   176             bitSizes[i] = bitSize;
       
   177             if (bitSize > maxBitSize) {
       
   178                 maxBitSize = bitSize;
       
   179             }
       
   180         }
       
   181     }
       
   182 
       
   183     /**
       
   184      * Returns the number of data elements needed to transfer one pixel
       
   185      * via the getDataElements and setDataElements methods.
       
   186      * For a SinglePixelPackedSampleModel, this is one.
       
   187      */
       
   188     public int getNumDataElements() {
       
   189         return 1;
       
   190     }
       
   191 
       
   192     /**
       
   193      * Returns the size of the buffer (in data array elements)
       
   194      * needed for a data buffer that matches this
       
   195      * SinglePixelPackedSampleModel.
       
   196      */
       
   197     private long getBufferSize() {
       
   198       long size = scanlineStride * (height-1) + width;
       
   199       return size;
       
   200     }
       
   201 
       
   202     /**
       
   203      * Creates a new SinglePixelPackedSampleModel with the specified
       
   204      * width and height.  The new SinglePixelPackedSampleModel will have the
       
   205      * same storage data type and bit masks as this
       
   206      * SinglePixelPackedSampleModel.
       
   207      * @param w the width of the resulting <code>SampleModel</code>
       
   208      * @param h the height of the resulting <code>SampleModel</code>
       
   209      * @return a <code>SinglePixelPackedSampleModel</code> with the
       
   210      *         specified width and height.
       
   211      * @throws IllegalArgumentException if <code>w</code> or
       
   212      *         <code>h</code> is not greater than 0
       
   213      */
       
   214     public SampleModel createCompatibleSampleModel(int w, int h) {
       
   215       SampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h,
       
   216                                                               bitMasks);
       
   217       return sampleModel;
       
   218     }
       
   219 
       
   220     /**
       
   221      * Creates a DataBuffer that corresponds to this
       
   222      * SinglePixelPackedSampleModel.  The DataBuffer's data type and size
       
   223      * will be consistent with this SinglePixelPackedSampleModel.  The
       
   224      * DataBuffer will have a single bank.
       
   225      */
       
   226     public DataBuffer createDataBuffer() {
       
   227         DataBuffer dataBuffer = null;
       
   228 
       
   229         int size = (int)getBufferSize();
       
   230         switch (dataType) {
       
   231         case DataBuffer.TYPE_BYTE:
       
   232             dataBuffer = new DataBufferByte(size);
       
   233             break;
       
   234         case DataBuffer.TYPE_USHORT:
       
   235             dataBuffer = new DataBufferUShort(size);
       
   236             break;
       
   237         case DataBuffer.TYPE_INT:
       
   238             dataBuffer = new DataBufferInt(size);
       
   239             break;
       
   240         }
       
   241         return dataBuffer;
       
   242     }
       
   243 
       
   244     /** Returns the number of bits per sample for all bands. */
       
   245     public int[] getSampleSize() {
       
   246         int mask;
       
   247         int sampleSize[] = new int [numBands];
       
   248         for (int i=0; i<numBands; i++) {
       
   249             sampleSize[i] = 0;
       
   250             mask = bitMasks[i] >>> bitOffsets[i];
       
   251             while ((mask & 1) != 0) {
       
   252                 sampleSize[i] ++;
       
   253                 mask = mask >>> 1;
       
   254             }
       
   255         }
       
   256 
       
   257         return sampleSize;
       
   258     }
       
   259 
       
   260     /** Returns the number of bits per sample for the specified band. */
       
   261     public int getSampleSize(int band) {
       
   262         int sampleSize = 0;
       
   263         int mask = bitMasks[band] >>> bitOffsets[band];
       
   264         while ((mask & 1) != 0) {
       
   265             sampleSize ++;
       
   266             mask = mask >>> 1;
       
   267         }
       
   268 
       
   269         return sampleSize;
       
   270     }
       
   271 
       
   272     /** Returns the offset (in data array elements) of pixel (x,y).
       
   273      *  The data element containing pixel <code>x,y</code>
       
   274      *  can be retrieved from a DataBuffer <code>data</code> with a
       
   275      *  SinglePixelPackedSampleModel <code>sppsm</code> as:
       
   276      * <pre>
       
   277      *        data.getElem(sppsm.getOffset(x, y));
       
   278      * </pre>
       
   279      * @param x the X coordinate of the specified pixel
       
   280      * @param y the Y coordinate of the specified pixel
       
   281      * @return the offset of the specified pixel.
       
   282      */
       
   283     public int getOffset(int x, int y) {
       
   284         int offset = y * scanlineStride + x;
       
   285         return offset;
       
   286     }
       
   287 
       
   288     /** Returns the bit offsets into the data array element representing
       
   289      *  a pixel for all bands.
       
   290      *  @return the bit offsets representing a pixel for all bands.
       
   291      */
       
   292     public int [] getBitOffsets() {
       
   293       return (int[])bitOffsets.clone();
       
   294     }
       
   295 
       
   296     /** Returns the bit masks for all bands.
       
   297      *  @return the bit masks for all bands.
       
   298      */
       
   299     public int [] getBitMasks() {
       
   300       return (int[])bitMasks.clone();
       
   301     }
       
   302 
       
   303     /** Returns the scanline stride of this SinglePixelPackedSampleModel.
       
   304      *  @return the scanline stride of this
       
   305      *          <code>SinglePixelPackedSampleModel</code>.
       
   306      */
       
   307     public int getScanlineStride() {
       
   308       return scanlineStride;
       
   309     }
       
   310 
       
   311     /**
       
   312      * This creates a new SinglePixelPackedSampleModel with a subset of the
       
   313      * bands of this SinglePixelPackedSampleModel.  The new
       
   314      * SinglePixelPackedSampleModel can be used with any DataBuffer that the
       
   315      * existing SinglePixelPackedSampleModel can be used with.  The new
       
   316      * SinglePixelPackedSampleModel/DataBuffer combination will represent
       
   317      * an image with a subset of the bands of the original
       
   318      * SinglePixelPackedSampleModel/DataBuffer combination.
       
   319      * @exception RasterFormatException if the length of the bands argument is
       
   320      *                                  greater than the number of bands in
       
   321      *                                  the sample model.
       
   322      */
       
   323     public SampleModel createSubsetSampleModel(int bands[]) {
       
   324         if (bands.length > numBands)
       
   325             throw new RasterFormatException("There are only " +
       
   326                                             numBands +
       
   327                                             " bands");
       
   328         int newBitMasks[] = new int[bands.length];
       
   329         for (int i=0; i<bands.length; i++)
       
   330             newBitMasks[i] = bitMasks[bands[i]];
       
   331 
       
   332         return new SinglePixelPackedSampleModel(this.dataType, width, height,
       
   333                                            this.scanlineStride, newBitMasks);
       
   334     }
       
   335 
       
   336     /**
       
   337      * Returns data for a single pixel in a primitive array of type
       
   338      * TransferType.  For a SinglePixelPackedSampleModel, the array will
       
   339      * have one element, and the type will be the same as the storage
       
   340      * data type.  Generally, obj
       
   341      * should be passed in as null, so that the Object will be created
       
   342      * automatically and will be of the right primitive data type.
       
   343      * <p>
       
   344      * The following code illustrates transferring data for one pixel from
       
   345      * DataBuffer <code>db1</code>, whose storage layout is described by
       
   346      * SinglePixelPackedSampleModel <code>sppsm1</code>, to
       
   347      * DataBuffer <code>db2</code>, whose storage layout is described by
       
   348      * SinglePixelPackedSampleModel <code>sppsm2</code>.
       
   349      * The transfer will generally be more efficient than using
       
   350      * getPixel/setPixel.
       
   351      * <pre>
       
   352      *       SinglePixelPackedSampleModel sppsm1, sppsm2;
       
   353      *       DataBufferInt db1, db2;
       
   354      *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
       
   355      *                              db1), db2);
       
   356      * </pre>
       
   357      * Using getDataElements/setDataElements to transfer between two
       
   358      * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
       
   359      * the same number of bands, corresponding bands have the same number of
       
   360      * bits per sample, and the TransferTypes are the same.
       
   361      * <p>
       
   362      * If obj is non-null, it should be a primitive array of type TransferType.
       
   363      * Otherwise, a ClassCastException is thrown.  An
       
   364      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   365      * not in bounds, or if obj is non-null and is not large enough to hold
       
   366      * the pixel data.
       
   367      * @param x         The X coordinate of the pixel location.
       
   368      * @param y         The Y coordinate of the pixel location.
       
   369      * @param obj       If non-null, a primitive array in which to return
       
   370      *                  the pixel data.
       
   371      * @param data      The DataBuffer containing the image data.
       
   372      * @return the data for the specified pixel.
       
   373      * @see #setDataElements(int, int, Object, DataBuffer)
       
   374      */
       
   375     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
       
   376         // Bounds check for 'b' will be performed automatically
       
   377         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
       
   378             throw new ArrayIndexOutOfBoundsException
       
   379                 ("Coordinate out of bounds!");
       
   380         }
       
   381 
       
   382         int type = getTransferType();
       
   383 
       
   384         switch(type) {
       
   385 
       
   386         case DataBuffer.TYPE_BYTE:
       
   387 
       
   388             byte[] bdata;
       
   389 
       
   390             if (obj == null)
       
   391                 bdata = new byte[1];
       
   392             else
       
   393                 bdata = (byte[])obj;
       
   394 
       
   395             bdata[0] = (byte)data.getElem(y * scanlineStride + x);
       
   396 
       
   397             obj = (Object)bdata;
       
   398             break;
       
   399 
       
   400         case DataBuffer.TYPE_USHORT:
       
   401 
       
   402             short[] sdata;
       
   403 
       
   404             if (obj == null)
       
   405                 sdata = new short[1];
       
   406             else
       
   407                 sdata = (short[])obj;
       
   408 
       
   409             sdata[0] = (short)data.getElem(y * scanlineStride + x);
       
   410 
       
   411             obj = (Object)sdata;
       
   412             break;
       
   413 
       
   414         case DataBuffer.TYPE_INT:
       
   415 
       
   416             int[] idata;
       
   417 
       
   418             if (obj == null)
       
   419                 idata = new int[1];
       
   420             else
       
   421                 idata = (int[])obj;
       
   422 
       
   423             idata[0] = data.getElem(y * scanlineStride + x);
       
   424 
       
   425             obj = (Object)idata;
       
   426             break;
       
   427         }
       
   428 
       
   429         return obj;
       
   430     }
       
   431 
       
   432     /**
       
   433      * Returns all samples in for the specified pixel in an int array.
       
   434      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   435      * not in bounds.
       
   436      * @param x         The X coordinate of the pixel location.
       
   437      * @param y         The Y coordinate of the pixel location.
       
   438      * @param iArray    If non-null, returns the samples in this array
       
   439      * @param data      The DataBuffer containing the image data.
       
   440      * @return all samples for the specified pixel.
       
   441      * @see #setPixel(int, int, int[], DataBuffer)
       
   442      */
       
   443     public int [] getPixel(int x, int y, int iArray[], DataBuffer data) {
       
   444         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
       
   445             throw new ArrayIndexOutOfBoundsException
       
   446                 ("Coordinate out of bounds!");
       
   447         }
       
   448         int pixels[];
       
   449         if (iArray == null) {
       
   450             pixels = new int [numBands];
       
   451         } else {
       
   452             pixels = iArray;
       
   453         }
       
   454 
       
   455         int value = data.getElem(y * scanlineStride + x);
       
   456         for (int i=0; i<numBands; i++) {
       
   457             pixels[i] = (value & bitMasks[i]) >>> bitOffsets[i];
       
   458         }
       
   459         return pixels;
       
   460     }
       
   461 
       
   462     /**
       
   463      * Returns all samples for the specified rectangle of pixels in
       
   464      * an int array, one sample per array element.
       
   465      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   466      * not in bounds.
       
   467      * @param x         The X coordinate of the upper left pixel location.
       
   468      * @param y         The Y coordinate of the upper left pixel location.
       
   469      * @param w         The width of the pixel rectangle.
       
   470      * @param h         The height of the pixel rectangle.
       
   471      * @param iArray    If non-null, returns the samples in this array.
       
   472      * @param data      The DataBuffer containing the image data.
       
   473      * @return all samples for the specified region of pixels.
       
   474      * @see #setPixels(int, int, int, int, int[], DataBuffer)
       
   475      */
       
   476     public int[] getPixels(int x, int y, int w, int h,
       
   477                            int iArray[], DataBuffer data) {
       
   478         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
       
   479             throw new ArrayIndexOutOfBoundsException
       
   480                 ("Coordinate out of bounds!");
       
   481         }
       
   482         int pixels[];
       
   483         if (iArray != null) {
       
   484            pixels = iArray;
       
   485         } else {
       
   486            pixels = new int [w*h*numBands];
       
   487         }
       
   488         int lineOffset = y*scanlineStride + x;
       
   489         int dstOffset = 0;
       
   490 
       
   491         for (int i = 0; i < h; i++) {
       
   492            for (int j = 0; j < w; j++) {
       
   493               int value = data.getElem(lineOffset+j);
       
   494               for (int k=0; k < numBands; k++) {
       
   495                   pixels[dstOffset++] =
       
   496                      ((value & bitMasks[k]) >>> bitOffsets[k]);
       
   497               }
       
   498            }
       
   499            lineOffset += scanlineStride;
       
   500         }
       
   501         return pixels;
       
   502     }
       
   503 
       
   504     /**
       
   505      * Returns as int the sample in a specified band for the pixel
       
   506      * located at (x,y).
       
   507      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   508      * not in bounds.
       
   509      * @param x         The X coordinate of the pixel location.
       
   510      * @param y         The Y coordinate of the pixel location.
       
   511      * @param b         The band to return.
       
   512      * @param data      The DataBuffer containing the image data.
       
   513      * @return the sample in a specified band for the specified
       
   514      *         pixel.
       
   515      * @see #setSample(int, int, int, int, DataBuffer)
       
   516      */
       
   517     public int getSample(int x, int y, int b, DataBuffer data) {
       
   518         // Bounds check for 'b' will be performed automatically
       
   519         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
       
   520             throw new ArrayIndexOutOfBoundsException
       
   521                 ("Coordinate out of bounds!");
       
   522         }
       
   523         int sample = data.getElem(y * scanlineStride + x);
       
   524         return ((sample & bitMasks[b]) >>> bitOffsets[b]);
       
   525     }
       
   526 
       
   527     /**
       
   528      * Returns the samples for a specified band for the specified rectangle
       
   529      * of pixels in an int array, one sample per array element.
       
   530      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   531      * not in bounds.
       
   532      * @param x         The X coordinate of the upper left pixel location.
       
   533      * @param y         The Y coordinate of the upper left pixel location.
       
   534      * @param w         The width of the pixel rectangle.
       
   535      * @param h         The height of the pixel rectangle.
       
   536      * @param b         The band to return.
       
   537      * @param iArray    If non-null, returns the samples in this array.
       
   538      * @param data      The DataBuffer containing the image data.
       
   539      * @return the samples for the specified band for the specified
       
   540      *         region of pixels.
       
   541      * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
       
   542      */
       
   543     public int[] getSamples(int x, int y, int w, int h, int b,
       
   544                            int iArray[], DataBuffer data) {
       
   545         // Bounds check for 'b' will be performed automatically
       
   546         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
       
   547             throw new ArrayIndexOutOfBoundsException
       
   548                 ("Coordinate out of bounds!");
       
   549         }
       
   550         int samples[];
       
   551         if (iArray != null) {
       
   552            samples = iArray;
       
   553         } else {
       
   554            samples = new int [w*h];
       
   555         }
       
   556         int lineOffset = y*scanlineStride + x;
       
   557         int dstOffset = 0;
       
   558 
       
   559         for (int i = 0; i < h; i++) {
       
   560            for (int j = 0; j < w; j++) {
       
   561               int value = data.getElem(lineOffset+j);
       
   562               samples[dstOffset++] =
       
   563                  ((value & bitMasks[b]) >>> bitOffsets[b]);
       
   564            }
       
   565            lineOffset += scanlineStride;
       
   566         }
       
   567         return samples;
       
   568     }
       
   569 
       
   570     /**
       
   571      * Sets the data for a single pixel in the specified DataBuffer from a
       
   572      * primitive array of type TransferType.  For a
       
   573      * SinglePixelPackedSampleModel, only the first element of the array
       
   574      * will hold valid data, and the type of the array must be the same as
       
   575      * the storage data type of the SinglePixelPackedSampleModel.
       
   576      * <p>
       
   577      * The following code illustrates transferring data for one pixel from
       
   578      * DataBuffer <code>db1</code>, whose storage layout is described by
       
   579      * SinglePixelPackedSampleModel <code>sppsm1</code>,
       
   580      * to DataBuffer <code>db2</code>, whose storage layout is described by
       
   581      * SinglePixelPackedSampleModel <code>sppsm2</code>.
       
   582      * The transfer will generally be more efficient than using
       
   583      * getPixel/setPixel.
       
   584      * <pre>
       
   585      *       SinglePixelPackedSampleModel sppsm1, sppsm2;
       
   586      *       DataBufferInt db1, db2;
       
   587      *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
       
   588      *                              db1), db2);
       
   589      * </pre>
       
   590      * Using getDataElements/setDataElements to transfer between two
       
   591      * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
       
   592      * the same number of bands, corresponding bands have the same number of
       
   593      * bits per sample, and the TransferTypes are the same.
       
   594      * <p>
       
   595      * obj must be a primitive array of type TransferType.  Otherwise,
       
   596      * a ClassCastException is thrown.  An
       
   597      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   598      * not in bounds, or if obj is not large enough to hold the pixel data.
       
   599      * @param x         The X coordinate of the pixel location.
       
   600      * @param y         The Y coordinate of the pixel location.
       
   601      * @param obj       A primitive array containing pixel data.
       
   602      * @param data      The DataBuffer containing the image data.
       
   603      * @see #getDataElements(int, int, Object, DataBuffer)
       
   604      */
       
   605     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
       
   606         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
       
   607             throw new ArrayIndexOutOfBoundsException
       
   608                 ("Coordinate out of bounds!");
       
   609         }
       
   610 
       
   611         int type = getTransferType();
       
   612 
       
   613         switch(type) {
       
   614 
       
   615         case DataBuffer.TYPE_BYTE:
       
   616 
       
   617             byte[] barray = (byte[])obj;
       
   618             data.setElem(y*scanlineStride+x, ((int)barray[0])&0xff);
       
   619             break;
       
   620 
       
   621         case DataBuffer.TYPE_USHORT:
       
   622 
       
   623             short[] sarray = (short[])obj;
       
   624             data.setElem(y*scanlineStride+x, ((int)sarray[0])&0xffff);
       
   625             break;
       
   626 
       
   627         case DataBuffer.TYPE_INT:
       
   628 
       
   629             int[] iarray = (int[])obj;
       
   630             data.setElem(y*scanlineStride+x, iarray[0]);
       
   631             break;
       
   632         }
       
   633     }
       
   634 
       
   635     /**
       
   636      * Sets a pixel in the DataBuffer using an int array of samples for input.
       
   637      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   638      * not in bounds.
       
   639      * @param x         The X coordinate of the pixel location.
       
   640      * @param y         The Y coordinate of the pixel location.
       
   641      * @param iArray    The input samples in an int array.
       
   642      * @param data      The DataBuffer containing the image data.
       
   643      * @see #getPixel(int, int, int[], DataBuffer)
       
   644      */
       
   645     public void setPixel(int x, int y,
       
   646                          int iArray[],
       
   647                          DataBuffer data) {
       
   648         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
       
   649             throw new ArrayIndexOutOfBoundsException
       
   650                 ("Coordinate out of bounds!");
       
   651         }
       
   652         int lineOffset = y * scanlineStride + x;
       
   653         int value = data.getElem(lineOffset);
       
   654         for (int i=0; i < numBands; i++) {
       
   655             value &= ~bitMasks[i];
       
   656             value |= ((iArray[i] << bitOffsets[i]) & bitMasks[i]);
       
   657         }
       
   658         data.setElem(lineOffset, value);
       
   659     }
       
   660 
       
   661     /**
       
   662      * Sets all samples for a rectangle of pixels from an int array containing
       
   663      * one sample per array element.
       
   664      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   665      * not in bounds.
       
   666      * @param x         The X coordinate of the upper left pixel location.
       
   667      * @param y         The Y coordinate of the upper left pixel location.
       
   668      * @param w         The width of the pixel rectangle.
       
   669      * @param h         The height of the pixel rectangle.
       
   670      * @param iArray    The input samples in an int array.
       
   671      * @param data      The DataBuffer containing the image data.
       
   672      * @see #getPixels(int, int, int, int, int[], DataBuffer)
       
   673      */
       
   674     public void setPixels(int x, int y, int w, int h,
       
   675                           int iArray[], DataBuffer data) {
       
   676         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
       
   677             throw new ArrayIndexOutOfBoundsException
       
   678                 ("Coordinate out of bounds!");
       
   679         }
       
   680 
       
   681         int lineOffset = y*scanlineStride + x;
       
   682         int srcOffset = 0;
       
   683 
       
   684         for (int i = 0; i < h; i++) {
       
   685            for (int j = 0; j < w; j++) {
       
   686                int value = data.getElem(lineOffset+j);
       
   687                for (int k=0; k < numBands; k++) {
       
   688                    value &= ~bitMasks[k];
       
   689                    int srcValue = iArray[srcOffset++];
       
   690                    value |= ((srcValue << bitOffsets[k])
       
   691                              & bitMasks[k]);
       
   692                }
       
   693                data.setElem(lineOffset+j, value);
       
   694            }
       
   695            lineOffset += scanlineStride;
       
   696         }
       
   697     }
       
   698 
       
   699     /**
       
   700      * Sets a sample in the specified band for the pixel located at (x,y)
       
   701      * in the DataBuffer using an int for input.
       
   702      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   703      * not in bounds.
       
   704      * @param x         The X coordinate of the pixel location.
       
   705      * @param y         The Y coordinate of the pixel location.
       
   706      * @param b         The band to set.
       
   707      * @param s         The input sample as an int.
       
   708      * @param data      The DataBuffer containing the image data.
       
   709      * @see #getSample(int, int, int, DataBuffer)
       
   710      */
       
   711     public void setSample(int x, int y, int b, int s,
       
   712                           DataBuffer data) {
       
   713         // Bounds check for 'b' will be performed automatically
       
   714         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
       
   715             throw new ArrayIndexOutOfBoundsException
       
   716                 ("Coordinate out of bounds!");
       
   717         }
       
   718         int value = data.getElem(y*scanlineStride + x);
       
   719         value &= ~bitMasks[b];
       
   720         value |= (s << bitOffsets[b]) & bitMasks[b];
       
   721         data.setElem(y*scanlineStride + x,value);
       
   722     }
       
   723 
       
   724     /**
       
   725      * Sets the samples in the specified band for the specified rectangle
       
   726      * of pixels from an int array containing one sample per array element.
       
   727      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
       
   728      * not in bounds.
       
   729      * @param x         The X coordinate of the upper left pixel location.
       
   730      * @param y         The Y coordinate of the upper left pixel location.
       
   731      * @param w         The width of the pixel rectangle.
       
   732      * @param h         The height of the pixel rectangle.
       
   733      * @param b         The band to set.
       
   734      * @param iArray    The input samples in an int array.
       
   735      * @param data      The DataBuffer containing the image data.
       
   736      * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
       
   737      */
       
   738     public void setSamples(int x, int y, int w, int h, int b,
       
   739                           int iArray[], DataBuffer data) {
       
   740         // Bounds check for 'b' will be performed automatically
       
   741         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
       
   742             throw new ArrayIndexOutOfBoundsException
       
   743                 ("Coordinate out of bounds!");
       
   744         }
       
   745         int lineOffset = y*scanlineStride + x;
       
   746         int srcOffset = 0;
       
   747 
       
   748         for (int i = 0; i < h; i++) {
       
   749            for (int j = 0; j < w; j++) {
       
   750               int value = data.getElem(lineOffset+j);
       
   751               value &= ~bitMasks[b];
       
   752               int sample = iArray[srcOffset++];
       
   753               value |= ((int)sample << bitOffsets[b]) & bitMasks[b];
       
   754               data.setElem(lineOffset+j,value);
       
   755            }
       
   756            lineOffset += scanlineStride;
       
   757         }
       
   758     }
       
   759 
       
   760     public boolean equals(Object o) {
       
   761         if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
       
   762             return false;
       
   763         }
       
   764 
       
   765         SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel)o;
       
   766         return this.width == that.width &&
       
   767             this.height == that.height &&
       
   768             this.numBands == that.numBands &&
       
   769             this.dataType == that.dataType &&
       
   770             Arrays.equals(this.bitMasks, that.bitMasks) &&
       
   771             Arrays.equals(this.bitOffsets, that.bitOffsets) &&
       
   772             Arrays.equals(this.bitSizes, that.bitSizes) &&
       
   773             this.maxBitSize == that.maxBitSize &&
       
   774             this.scanlineStride == that.scanlineStride;
       
   775     }
       
   776 
       
   777     // If we implement equals() we must also implement hashCode
       
   778     public int hashCode() {
       
   779         int hash = 0;
       
   780         hash = width;
       
   781         hash <<= 8;
       
   782         hash ^= height;
       
   783         hash <<= 8;
       
   784         hash ^= numBands;
       
   785         hash <<= 8;
       
   786         hash ^= dataType;
       
   787         hash <<= 8;
       
   788         for (int i = 0; i < bitMasks.length; i++) {
       
   789             hash ^= bitMasks[i];
       
   790             hash <<= 8;
       
   791         }
       
   792         for (int i = 0; i < bitOffsets.length; i++) {
       
   793             hash ^= bitOffsets[i];
       
   794             hash <<= 8;
       
   795         }
       
   796         for (int i = 0; i < bitSizes.length; i++) {
       
   797             hash ^= bitSizes[i];
       
   798             hash <<= 8;
       
   799         }
       
   800         hash ^= maxBitSize;
       
   801         hash <<= 8;
       
   802         hash ^= scanlineStride;
       
   803         return hash;
       
   804     }
       
   805 }