View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * 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  /**
39   * The <code>MultiPixelPackedSampleModel</code> class represents
40   * one-banded images and can pack multiple one-sample
41   * pixels into one data element.  Pixels are not allowed to span data elements.
42   * The data type can be DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
43   * or DataBuffer.TYPE_INT.  Each pixel must be a power of 2 number of bits
44   * and a power of 2 number of pixels must fit exactly in one data element.
45   * Pixel bit stride is equal to the number of bits per pixel.  Scanline
46   * stride is in data elements and the last several data elements might be
47   * padded with unused pixels.  Data bit offset is the offset in bits from
48   * the beginning of the {@link DataBuffer} to the first pixel and must be
49   * a multiple of pixel bit stride.
50   * <p>
51   * The following code illustrates extracting the bits for pixel
52   * <code>x,&nbsp;y</code> from <code>DataBuffer</code> <code>data</code>
53   * and storing the pixel data in data elements of type
54   * <code>dataType</code>:
55   * <pre>{@code
56   *      int dataElementSize = DataBuffer.getDataTypeSize(dataType);
57   *      int bitnum = dataBitOffset + x*pixelBitStride;
58   *      int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
59   *      int shift = dataElementSize - (bitnum & (dataElementSize-1))
60   *                  - pixelBitStride;
61   *      int pixel = (element >> shift) & ((1 << pixelBitStride) - 1);
62   * }</pre>
63   */
64  
65  public class MultiPixelPackedSampleModel extends SampleModel
66  {
67      /** The number of bits from one pixel to the next. */
68      int pixelBitStride;
69  
70      /** Bitmask that extracts the rightmost pixel of a data element. */
71      int bitMask;
72  
73      /**
74        * The number of pixels that fit in a data element.  Also used
75        * as the number of bits per pixel.
76        */
77      int pixelsPerDataElement;
78  
79      /** The size of a data element in bits. */
80      int dataElementSize;
81  
82      /** The bit offset into the data array where the first pixel begins.
83       */
84      int dataBitOffset;
85  
86      /** ScanlineStride of the data buffer described in data array elements. */
87      int scanlineStride;
88  
89      /**
90       * Constructs a <code>MultiPixelPackedSampleModel</code> with the
91       * specified data type, width, height and number of bits per pixel.
92       * @param dataType  the data type for storing samples
93       * @param w         the width, in pixels, of the region of
94       *                  image data described
95       * @param h         the height, in pixels, of the region of
96       *                  image data described
97       * @param numberOfBits the number of bits per pixel
98       * @throws IllegalArgumentException if <code>dataType</code> is not
99       *         either <code>DataBuffer.TYPE_BYTE</code>,
100      *         <code>DataBuffer.TYPE_USHORT</code>, or
101      *         <code>DataBuffer.TYPE_INT</code>
102      */
103     public MultiPixelPackedSampleModel(int dataType,
104                                        int w,
105                                        int h,
106                                        int numberOfBits) {
107         this(dataType,w,h,
108              numberOfBits,
109             (w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
110                 DataBuffer.getDataTypeSize(dataType),
111              0);
112         if (dataType != DataBuffer.TYPE_BYTE &&
113             dataType != DataBuffer.TYPE_USHORT &&
114             dataType != DataBuffer.TYPE_INT) {
115             throw new IllegalArgumentException("Unsupported data type "+
116                                                dataType);
117         }
118     }
119 
120     /**
121      * Constructs a <code>MultiPixelPackedSampleModel</code> with
122      * specified data type, width, height, number of bits per pixel,
123      * scanline stride and data bit offset.
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 numberOfBits the number of bits per pixel
130      * @param scanlineStride the line stride of the image data
131      * @param dataBitOffset the data bit offset for the region of image
132      *                  data described
133      * @exception RasterFormatException if the number of bits per pixel
134      *                  is not a power of 2 or if a power of 2 number of
135      *                  pixels do not fit in one data element.
136      * @throws IllegalArgumentException if <code>w</code> or
137      *         <code>h</code> is not greater than 0
138      * @throws IllegalArgumentException if <code>dataType</code> is not
139      *         either <code>DataBuffer.TYPE_BYTE</code>,
140      *         <code>DataBuffer.TYPE_USHORT</code>, or
141      *         <code>DataBuffer.TYPE_INT</code>
142      */
143     public MultiPixelPackedSampleModel(int dataType, int w, int h,
144                                        int numberOfBits,
145                                        int scanlineStride,
146                                        int dataBitOffset) {
147         super(dataType, w, h, 1);
148         if (dataType != DataBuffer.TYPE_BYTE &&
149             dataType != DataBuffer.TYPE_USHORT &&
150             dataType != DataBuffer.TYPE_INT) {
151             throw new IllegalArgumentException("Unsupported data type "+
152                                                dataType);
153         }
154         this.dataType = dataType;
155         this.pixelBitStride = numberOfBits;
156         this.scanlineStride = scanlineStride;
157         this.dataBitOffset = dataBitOffset;
158         this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
159         this.pixelsPerDataElement = dataElementSize/numberOfBits;
160         if (pixelsPerDataElement*numberOfBits != dataElementSize) {
161            throw new RasterFormatException("MultiPixelPackedSampleModel " +
162                                              "does not allow pixels to " +
163                                              "span data element boundaries");
164         }
165         this.bitMask = (1 << numberOfBits) - 1;
166     }
167 
168 
169     /**
170      * Creates a new <code>MultiPixelPackedSampleModel</code> with the
171      * specified width and height.  The new
172      * <code>MultiPixelPackedSampleModel</code> has the
173      * same storage data type and number of bits per pixel as this
174      * <code>MultiPixelPackedSampleModel</code>.
175      * @param w the specified width
176      * @param h the specified height
177      * @return a {@link SampleModel} with the specified width and height
178      * and with the same storage data type and number of bits per pixel
179      * as this <code>MultiPixelPackedSampleModel</code>.
180      * @throws IllegalArgumentException if <code>w</code> or
181      *         <code>h</code> is not greater than 0
182      */
183     public SampleModel createCompatibleSampleModel(int w, int h) {
184       SampleModel sampleModel =
185             new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
186       return sampleModel;
187     }
188 
189     /**
190      * Creates a <code>DataBuffer</code> that corresponds to this
191      * <code>MultiPixelPackedSampleModel</code>.  The
192      * <code>DataBuffer</code> object's data type and size
193      * is consistent with this <code>MultiPixelPackedSampleModel</code>.
194      * The <code>DataBuffer</code> has a single bank.
195      * @return a <code>DataBuffer</code> with the same data type and
196      * size as this <code>MultiPixelPackedSampleModel</code>.
197      */
198     public DataBuffer createDataBuffer() {
199         DataBuffer dataBuffer = null;
200 
201         int size = (int)scanlineStride*height;
202         switch (dataType) {
203         case DataBuffer.TYPE_BYTE:
204             dataBuffer = new DataBufferByte(size+(dataBitOffset+7)/8);
205             break;
206         case DataBuffer.TYPE_USHORT:
207             dataBuffer = new DataBufferUShort(size+(dataBitOffset+15)/16);
208             break;
209         case DataBuffer.TYPE_INT:
210             dataBuffer = new DataBufferInt(size+(dataBitOffset+31)/32);
211             break;
212         }
213         return dataBuffer;
214     }
215 
216     /**
217      * Returns the number of data elements needed to transfer one pixel
218      * via the {@link #getDataElements} and {@link #setDataElements}
219      * methods.  For a <code>MultiPixelPackedSampleModel</code>, this is
220      * one.
221      * @return the number of data elements.
222      */
223     public int getNumDataElements() {
224         return 1;
225     }
226 
227     /**
228      * Returns the number of bits per sample for all bands.
229      * @return the number of bits per sample.
230      */
231     public int[] getSampleSize() {
232         int sampleSize[] = {pixelBitStride};
233         return sampleSize;
234     }
235 
236     /**
237      * Returns the number of bits per sample for the specified band.
238      * @param band the specified band
239      * @return the number of bits per sample for the specified band.
240      */
241     public int getSampleSize(int band) {
242         return pixelBitStride;
243     }
244 
245     /**
246      * Returns the offset of pixel (x,&nbsp;y) in data array elements.
247      * @param x the X coordinate of the specified pixel
248      * @param y the Y coordinate of the specified pixel
249      * @return the offset of the specified pixel.
250      */
251     public int getOffset(int x, int y) {
252         int offset = y * scanlineStride;
253         offset +=  (x*pixelBitStride+dataBitOffset)/dataElementSize;
254         return offset;
255     }
256 
257     /**
258      *  Returns the offset, in bits, into the data element in which it is
259      *  stored for the <code>x</code>th pixel of a scanline.
260      *  This offset is the same for all scanlines.
261      *  @param x the specified pixel
262      *  @return the bit offset of the specified pixel.
263      */
264     public int getBitOffset(int x){
265        return  (x*pixelBitStride+dataBitOffset)%dataElementSize;
266     }
267 
268     /**
269      * Returns the scanline stride.
270      * @return the scanline stride of this
271      * <code>MultiPixelPackedSampleModel</code>.
272      */
273     public int getScanlineStride() {
274         return scanlineStride;
275     }
276 
277     /**
278      * Returns the pixel bit stride in bits.  This value is the same as
279      * the number of bits per pixel.
280      * @return the <code>pixelBitStride</code> of this
281      * <code>MultiPixelPackedSampleModel</code>.
282      */
283     public int getPixelBitStride() {
284         return pixelBitStride;
285     }
286 
287     /**
288      * Returns the data bit offset in bits.
289      * @return the <code>dataBitOffset</code> of this
290      * <code>MultiPixelPackedSampleModel</code>.
291      */
292     public int getDataBitOffset() {
293         return dataBitOffset;
294     }
295 
296     /**
297      *  Returns the TransferType used to transfer pixels by way of the
298      *  <code>getDataElements</code> and <code>setDataElements</code>
299      *  methods. The TransferType might or might not be the same as the
300      *  storage DataType.  The TransferType is one of
301      *  DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
302      *  or DataBuffer.TYPE_INT.
303      *  @return the transfertype.
304      */
305     public int getTransferType() {
306         if (pixelBitStride > 16)
307             return DataBuffer.TYPE_INT;
308         else if (pixelBitStride > 8)
309             return DataBuffer.TYPE_USHORT;
310         else
311             return DataBuffer.TYPE_BYTE;
312     }
313 
314     /**
315      * Creates a new <code>MultiPixelPackedSampleModel</code> with a
316      * subset of the bands of this
317      * <code>MultiPixelPackedSampleModel</code>.  Since a
318      * <code>MultiPixelPackedSampleModel</code> only has one band, the
319      * bands argument must have a length of one and indicate the zeroth
320      * band.
321      * @param bands the specified bands
322      * @return a new <code>SampleModel</code> with a subset of bands of
323      * this <code>MultiPixelPackedSampleModel</code>.
324      * @exception RasterFormatException if the number of bands requested
325      * is not one.
326      * @throws IllegalArgumentException if <code>w</code> or
327      *         <code>h</code> is not greater than 0
328      */
329     public SampleModel createSubsetSampleModel(int bands[]) {
330         if (bands != null) {
331            if (bands.length != 1)
332             throw new RasterFormatException("MultiPixelPackedSampleModel has "
333                                             + "only one band.");
334         }
335         SampleModel sm = createCompatibleSampleModel(width, height);
336         return sm;
337     }
338 
339     /**
340      * Returns as <code>int</code> the sample in a specified band for the
341      * pixel located at (x,&nbsp;y).  An
342      * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
343      * coordinates are not in bounds.
344      * @param x         the X coordinate of the specified pixel
345      * @param y         the Y coordinate of the specified pixel
346      * @param b         the band to return, which is assumed to be 0
347      * @param data      the <code>DataBuffer</code> containing the image
348      *                  data
349      * @return the specified band containing the sample of the specified
350      * pixel.
351      * @exception ArrayIndexOutOfBoundsException if the specified
352      *          coordinates are not in bounds.
353      * @see #setSample(int, int, int, int, DataBuffer)
354      */
355     public int getSample(int x, int y, int b, DataBuffer data) {
356         // 'b' must be 0
357         if ((x < 0) || (y < 0) || (x >= width) || (y >= height) ||
358             (b != 0)) {
359             throw new ArrayIndexOutOfBoundsException
360                 ("Coordinate out of bounds!");
361         }
362         int bitnum = dataBitOffset + x*pixelBitStride;
363         int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
364         int shift = dataElementSize - (bitnum & (dataElementSize-1))
365                     - pixelBitStride;
366         return (element >> shift) & bitMask;
367     }
368 
369     /**
370      * Sets a sample in the specified band for the pixel located at
371      * (x,&nbsp;y) in the <code>DataBuffer</code> using an
372      * <code>int</code> for input.
373      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
374      * coordinates are not in bounds.
375      * @param x the X coordinate of the specified pixel
376      * @param y the Y coordinate of the specified pixel
377      * @param b the band to return, which is assumed to be 0
378      * @param s the input sample as an <code>int</code>
379      * @param data the <code>DataBuffer</code> where image data is stored
380      * @exception ArrayIndexOutOfBoundsException if the coordinates are
381      * not in bounds.
382      * @see #getSample(int, int, int, DataBuffer)
383      */
384     public void setSample(int x, int y, int b, int s,
385                           DataBuffer data) {
386         // 'b' must be 0
387         if ((x < 0) || (y < 0) || (x >= width) || (y >= height) ||
388             (b != 0)) {
389             throw new ArrayIndexOutOfBoundsException
390                 ("Coordinate out of bounds!");
391         }
392         int bitnum = dataBitOffset + x * pixelBitStride;
393         int index = y * scanlineStride + (bitnum / dataElementSize);
394         int shift = dataElementSize - (bitnum & (dataElementSize-1))
395                     - pixelBitStride;
396         int element = data.getElem(index);
397         element &= ~(bitMask << shift);
398         element |= (s & bitMask) << shift;
399         data.setElem(index,element);
400     }
401 
402     /**
403      * Returns data for a single pixel in a primitive array of type
404      * TransferType.  For a <code>MultiPixelPackedSampleModel</code>,
405      * the array has one element, and the type is the smallest of
406      * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
407      * that can hold a single pixel.  Generally, <code>obj</code>
408      * should be passed in as <code>null</code>, so that the
409      * <code>Object</code> is created automatically and is the
410      * correct primitive data type.
411      * <p>
412      * The following code illustrates transferring data for one pixel from
413      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
414      * described by <code>MultiPixelPackedSampleModel</code>
415      * <code>mppsm1</code>, to <code>DataBuffer</code> <code>db2</code>,
416      * whose storage layout is described by
417      * <code>MultiPixelPackedSampleModel</code> <code>mppsm2</code>.
418      * The transfer is generally more efficient than using
419      * <code>getPixel</code> or <code>setPixel</code>.
420      * <pre>
421      *       MultiPixelPackedSampleModel mppsm1, mppsm2;
422      *       DataBufferInt db1, db2;
423      *       mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
424      *                              db1), db2);
425      * </pre>
426      * Using <code>getDataElements</code> or <code>setDataElements</code>
427      * to transfer between two <code>DataBuffer/SampleModel</code> pairs
428      * is legitimate if the <code>SampleModels</code> have the same number
429      * of bands, corresponding bands have the same number of
430      * bits per sample, and the TransferTypes are the same.
431      * <p>
432      * If <code>obj</code> is not <code>null</code>, it should be a
433      * primitive array of type TransferType.  Otherwise, a
434      * <code>ClassCastException</code> is thrown.  An
435      * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
436      * coordinates are not in bounds, or if <code>obj</code> is not
437      * <code>null</code> and is not large enough to hold the pixel data.
438      * @param x the X coordinate of the specified pixel
439      * @param y the Y coordinate of the specified pixel
440      * @param obj a primitive array in which to return the pixel data or
441      *          <code>null</code>.
442      * @param data the <code>DataBuffer</code> containing the image data.
443      * @return an <code>Object</code> containing data for the specified
444      *  pixel.
445      * @exception ClassCastException if <code>obj</code> is not a
446      *  primitive array of type TransferType or is not <code>null</code>
447      * @exception ArrayIndexOutOfBoundsException if the coordinates are
448      * not in bounds, or if <code>obj</code> is not <code>null</code> or
449      * not large enough to hold the pixel data
450      * @see #setDataElements(int, int, Object, DataBuffer)
451      */
452     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
453         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
454             throw new ArrayIndexOutOfBoundsException
455                 ("Coordinate out of bounds!");
456         }
457 
458         int type = getTransferType();
459         int bitnum = dataBitOffset + x*pixelBitStride;
460         int shift = dataElementSize - (bitnum & (dataElementSize-1))
461                     - pixelBitStride;
462         int element = 0;
463 
464         switch(type) {
465 
466         case DataBuffer.TYPE_BYTE:
467 
468             byte[] bdata;
469 
470             if (obj == null)
471                 bdata = new byte[1];
472             else
473                 bdata = (byte[])obj;
474 
475             element = data.getElem(y*scanlineStride +
476                                     bitnum/dataElementSize);
477             bdata[0] = (byte)((element >> shift) & bitMask);
478 
479             obj = (Object)bdata;
480             break;
481 
482         case DataBuffer.TYPE_USHORT:
483 
484             short[] sdata;
485 
486             if (obj == null)
487                 sdata = new short[1];
488             else
489                 sdata = (short[])obj;
490 
491             element = data.getElem(y*scanlineStride +
492                                    bitnum/dataElementSize);
493             sdata[0] = (short)((element >> shift) & bitMask);
494 
495             obj = (Object)sdata;
496             break;
497 
498         case DataBuffer.TYPE_INT:
499 
500             int[] idata;
501 
502             if (obj == null)
503                 idata = new int[1];
504             else
505                 idata = (int[])obj;
506 
507             element = data.getElem(y*scanlineStride +
508                                    bitnum/dataElementSize);
509             idata[0] = (element >> shift) & bitMask;
510 
511             obj = (Object)idata;
512             break;
513         }
514 
515         return obj;
516     }
517 
518     /**
519      * Returns the specified single band pixel in the first element
520      * of an <code>int</code> array.
521      * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
522      * coordinates are not in bounds.
523      * @param x the X coordinate of the specified pixel
524      * @param y the Y coordinate of the specified pixel
525      * @param iArray the array containing the pixel to be returned or
526      *  <code>null</code>
527      * @param data the <code>DataBuffer</code> where image data is stored
528      * @return an array containing the specified pixel.
529      * @exception ArrayIndexOutOfBoundsException if the coordinates
530      *  are not in bounds
531      * @see #setPixel(int, int, int[], DataBuffer)
532      */
533     public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
534         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
535             throw new ArrayIndexOutOfBoundsException
536                 ("Coordinate out of bounds!");
537         }
538         int pixels[];
539         if (iArray != null) {
540            pixels = iArray;
541         } else {
542            pixels = new int [numBands];
543         }
544         int bitnum = dataBitOffset + x*pixelBitStride;
545         int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
546         int shift = dataElementSize - (bitnum & (dataElementSize-1))
547                     - pixelBitStride;
548         pixels[0] = (element >> shift) & bitMask;
549         return pixels;
550     }
551 
552     /**
553      * Sets the data for a single pixel in the specified
554      * <code>DataBuffer</code> from a primitive array of type
555      * TransferType.  For a <code>MultiPixelPackedSampleModel</code>,
556      * only the first element of the array holds valid data,
557      * and the type must be the smallest of
558      * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
559      * that can hold a single pixel.
560      * <p>
561      * The following code illustrates transferring data for one pixel from
562      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
563      * described by <code>MultiPixelPackedSampleModel</code>
564      * <code>mppsm1</code>, to <code>DataBuffer</code> <code>db2</code>,
565      * whose storage layout is described by
566      * <code>MultiPixelPackedSampleModel</code> <code>mppsm2</code>.
567      * The transfer is generally more efficient than using
568      * <code>getPixel</code> or <code>setPixel</code>.
569      * <pre>
570      *       MultiPixelPackedSampleModel mppsm1, mppsm2;
571      *       DataBufferInt db1, db2;
572      *       mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
573      *                              db1), db2);
574      * </pre>
575      * Using <code>getDataElements</code> or <code>setDataElements</code> to
576      * transfer between two <code>DataBuffer/SampleModel</code> pairs is
577      * legitimate if the <code>SampleModel</code> objects have
578      * the same number of bands, corresponding bands have the same number of
579      * bits per sample, and the TransferTypes are the same.
580      * <p>
581      * <code>obj</code> must be a primitive array of type TransferType.
582      * Otherwise, a <code>ClassCastException</code> is thrown.  An
583      * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
584      * coordinates are not in bounds, or if <code>obj</code> is not large
585      * enough to hold the pixel data.
586      * @param x the X coordinate of the pixel location
587      * @param y the Y coordinate of the pixel location
588      * @param obj a primitive array containing pixel data
589      * @param data the <code>DataBuffer</code> containing the image data
590      * @see #getDataElements(int, int, Object, DataBuffer)
591      */
592     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
593         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
594             throw new ArrayIndexOutOfBoundsException
595                 ("Coordinate out of bounds!");
596         }
597 
598         int type = getTransferType();
599         int bitnum = dataBitOffset + x * pixelBitStride;
600         int index = y * scanlineStride + (bitnum / dataElementSize);
601         int shift = dataElementSize - (bitnum & (dataElementSize-1))
602                     - pixelBitStride;
603         int element = data.getElem(index);
604         element &= ~(bitMask << shift);
605 
606         switch(type) {
607 
608         case DataBuffer.TYPE_BYTE:
609 
610             byte[] barray = (byte[])obj;
611             element |= ( ((int)(barray[0])&0xff) & bitMask) << shift;
612             data.setElem(index, element);
613             break;
614 
615         case DataBuffer.TYPE_USHORT:
616 
617             short[] sarray = (short[])obj;
618             element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift;
619             data.setElem(index, element);
620             break;
621 
622         case DataBuffer.TYPE_INT:
623 
624             int[] iarray = (int[])obj;
625             element |= (iarray[0] & bitMask) << shift;
626             data.setElem(index, element);
627             break;
628         }
629     }
630 
631     /**
632      * Sets a pixel in the <code>DataBuffer</code> using an
633      * <code>int</code> array for input.
634      * <code>ArrayIndexOutOfBoundsException</code> is thrown if
635      * the coordinates are not in bounds.
636      * @param x the X coordinate of the pixel location
637      * @param y the Y coordinate of the pixel location
638      * @param iArray the input pixel in an <code>int</code> array
639      * @param data the <code>DataBuffer</code> containing the image data
640      * @see #getPixel(int, int, int[], DataBuffer)
641      */
642     public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
643         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
644             throw new ArrayIndexOutOfBoundsException
645                 ("Coordinate out of bounds!");
646         }
647         int bitnum = dataBitOffset + x * pixelBitStride;
648         int index = y * scanlineStride + (bitnum / dataElementSize);
649         int shift = dataElementSize - (bitnum & (dataElementSize-1))
650                     - pixelBitStride;
651         int element = data.getElem(index);
652         element &= ~(bitMask << shift);
653         element |= (iArray[0] & bitMask) << shift;
654         data.setElem(index,element);
655     }
656 
657     public boolean equals(Object o) {
658         if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) {
659             return false;
660         }
661 
662         MultiPixelPackedSampleModel that = (MultiPixelPackedSampleModel)o;
663         return this.width == that.width &&
664             this.height == that.height &&
665             this.numBands == that.numBands &&
666             this.dataType == that.dataType &&
667             this.pixelBitStride == that.pixelBitStride &&
668             this.bitMask == that.bitMask &&
669             this.pixelsPerDataElement == that.pixelsPerDataElement &&
670             this.dataElementSize == that.dataElementSize &&
671             this.dataBitOffset == that.dataBitOffset &&
672             this.scanlineStride == that.scanlineStride;
673     }
674 
675     // If we implement equals() we must also implement hashCode
676     public int hashCode() {
677         int hash = 0;
678         hash = width;
679         hash <<= 8;
680         hash ^= height;
681         hash <<= 8;
682         hash ^= numBands;
683         hash <<= 8;
684         hash ^= dataType;
685         hash <<= 8;
686         hash ^= pixelBitStride;
687         hash <<= 8;
688         hash ^= bitMask;
689         hash <<= 8;
690         hash ^= pixelsPerDataElement;
691         hash <<= 8;
692         hash ^= dataElementSize;
693         hash <<= 8;
694         hash ^= dataBitOffset;
695         hash <<= 8;
696         hash ^= scanlineStride;
697         return hash;
698     }
699 }