1 /*
2  * Copyright (c) 1997, 2018, 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} 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 data}
53  * and storing the pixel data in data elements of type
54  * {@code dataType}:
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} 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} is not
99      *         either {@code DataBuffer.TYPE_BYTE},
100      *         {@code DataBuffer.TYPE_USHORT}, or
101      *         {@code DataBuffer.TYPE_INT}
102      */
MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits)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} 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} or
137      *         {@code h} is not greater than 0
138      * @throws IllegalArgumentException if {@code dataType} is not
139      *         either {@code DataBuffer.TYPE_BYTE},
140      *         {@code DataBuffer.TYPE_USHORT}, or
141      *         {@code DataBuffer.TYPE_INT}
142      */
MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, int scanlineStride, int dataBitOffset)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} with the
171      * specified width and height.  The new
172      * {@code MultiPixelPackedSampleModel} has the
173      * same storage data type and number of bits per pixel as this
174      * {@code MultiPixelPackedSampleModel}.
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}.
180      * @throws IllegalArgumentException if {@code w} or
181      *         {@code h} is not greater than 0
182      */
createCompatibleSampleModel(int w, int h)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} that corresponds to this
191      * {@code MultiPixelPackedSampleModel}.  The
192      * {@code DataBuffer} object's data type and size
193      * is consistent with this {@code MultiPixelPackedSampleModel}.
194      * The {@code DataBuffer} has a single bank.
195      * @return a {@code DataBuffer} with the same data type and
196      * size as this {@code MultiPixelPackedSampleModel}.
197      */
createDataBuffer()198     public DataBuffer createDataBuffer() {
199         DataBuffer dataBuffer = null;
200 
201         int size = 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}, this is
220      * one.
221      * @return the number of data elements.
222      */
getNumDataElements()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      */
getSampleSize()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      */
getSampleSize(int band)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      */
getOffset(int x, int y)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}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      */
getBitOffset(int x)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}.
272      */
getScanlineStride()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} of this
281      * {@code MultiPixelPackedSampleModel}.
282      */
getPixelBitStride()283     public int getPixelBitStride() {
284         return pixelBitStride;
285     }
286 
287     /**
288      * Returns the data bit offset in bits.
289      * @return the {@code dataBitOffset} of this
290      * {@code MultiPixelPackedSampleModel}.
291      */
getDataBitOffset()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} and {@code setDataElements}
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      */
getTransferType()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} with a
316      * subset of the bands of this
317      * {@code MultiPixelPackedSampleModel}.  Since a
318      * {@code MultiPixelPackedSampleModel} 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} with a subset of bands of
323      * this {@code MultiPixelPackedSampleModel}.
324      * @exception RasterFormatException if the number of bands requested
325      * is not one.
326      * @throws IllegalArgumentException if {@code w} or
327      *         {@code h} is not greater than 0
328      */
createSubsetSampleModel(int[] bands)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} the sample in a specified band for the
341      * pixel located at (x,&nbsp;y).  An
342      * {@code ArrayIndexOutOfBoundsException} 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} 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      */
getSample(int x, int y, int b, DataBuffer data)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} using an
372      * {@code int} for input.
373      * An {@code ArrayIndexOutOfBoundsException} 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}
379      * @param data the {@code DataBuffer} where image data is stored
380      * @exception ArrayIndexOutOfBoundsException if the coordinates are
381      * not in bounds.
382      * @see #getSample(int, int, int, DataBuffer)
383      */
setSample(int x, int y, int b, int s, DataBuffer data)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},
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}
408      * should be passed in as {@code null}, so that the
409      * {@code Object} 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 db1}, whose storage layout is
414      * described by {@code MultiPixelPackedSampleModel}
415      * {@code mppsm1}, to {@code DataBuffer db2},
416      * whose storage layout is described by
417      * {@code MultiPixelPackedSampleModel mppsm2}.
418      * The transfer is generally more efficient than using
419      * {@code getPixel} or {@code setPixel}.
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} or {@code setDataElements}
427      * to transfer between two {@code DataBuffer/SampleModel} pairs
428      * is legitimate if the {@code SampleModels} 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} is not {@code null}, it should be a
433      * primitive array of type TransferType.  Otherwise, a
434      * {@code ClassCastException} is thrown.  An
435      * {@code ArrayIndexOutOfBoundsException} is thrown if the
436      * coordinates are not in bounds, or if {@code obj} is not
437      * {@code null} 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}.
442      * @param data the {@code DataBuffer} containing the image data.
443      * @return an {@code Object} containing data for the specified
444      *  pixel.
445      * @exception ClassCastException if {@code obj} is not a
446      *  primitive array of type TransferType or is not {@code null}
447      * @exception ArrayIndexOutOfBoundsException if the coordinates are
448      * not in bounds, or if {@code obj} is not {@code null} or
449      * not large enough to hold the pixel data
450      * @see #setDataElements(int, int, Object, DataBuffer)
451      */
getDataElements(int x, int y, Object obj, DataBuffer data)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} array.
521      * {@code ArrayIndexOutOfBoundsException} 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}
527      * @param data the {@code DataBuffer} 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      */
getPixel(int x, int y, int[] iArray, DataBuffer data)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} from a primitive array of type
555      * TransferType.  For a {@code MultiPixelPackedSampleModel},
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 db1}, whose storage layout is
563      * described by {@code MultiPixelPackedSampleModel}
564      * {@code mppsm1}, to {@code DataBuffer db2},
565      * whose storage layout is described by
566      * {@code MultiPixelPackedSampleModel mppsm2}.
567      * The transfer is generally more efficient than using
568      * {@code getPixel} or {@code setPixel}.
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} or {@code setDataElements} to
576      * transfer between two {@code DataBuffer/SampleModel} pairs is
577      * legitimate if the {@code SampleModel} 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} must be a primitive array of type TransferType.
582      * Otherwise, a {@code ClassCastException} is thrown.  An
583      * {@code ArrayIndexOutOfBoundsException} is thrown if the
584      * coordinates are not in bounds, or if {@code obj} 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} containing the image data
590      * @see #getDataElements(int, int, Object, DataBuffer)
591      */
setDataElements(int x, int y, Object obj, DataBuffer data)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} using an
633      * {@code int} array for input.
634      * {@code ArrayIndexOutOfBoundsException} 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} array
639      * @param data the {@code DataBuffer} containing the image data
640      * @see #getPixel(int, int, int[], DataBuffer)
641      */
setPixel(int x, int y, int[] iArray, DataBuffer data)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 
equals(Object o)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
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 }
700