1 /*
2 * Copyright (c) 1997, 2014, 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, 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 */
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 */
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 */
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 */
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 */
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, 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}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}.
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} of this
281 * {@code MultiPixelPackedSampleModel}.
282 */
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 */
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 */
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 */
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, 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 */
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, 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 */
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 */
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 */
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 */
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 */
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 }
700