1 /*
2 * Portions Copyright 1997-2006 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 image data which is stored such that each sample
42 * of a pixel occupies one data element of the DataBuffer. It stores the
43 * N samples which make up a pixel in N separate data array elements.
44 * Different bands may be in different banks of the DataBuffer.
45 * Accessor methods are provided so that image data can be manipulated
46 * directly. This class can support different kinds of interleaving, e.g.
47 * band interleaving, scanline interleaving, and pixel interleaving.
48 * Pixel stride is the number of data array elements between two samples
49 * for the same band on the same scanline. Scanline stride is the number
50 * of data array elements between a given sample and the corresponding sample
51 * in the same column of the next scanline. Band offsets denote the number
52 * of data array elements from the first data array element of the bank
53 * of the DataBuffer holding each band to the first sample of the band.
54 * The bands are numbered from 0 to N-1. This class can represent image
55 * data for which each sample is an unsigned integral number which can be
56 * stored in 8, 16, or 32 bits (using <code>DataBuffer.TYPE_BYTE</code>,
57 * <code>DataBuffer.TYPE_USHORT</code>, or <code>DataBuffer.TYPE_INT</code>,
58 * respectively), data for which each sample is a signed integral number
59 * which can be stored in 16 bits (using <code>DataBuffer.TYPE_SHORT</code>),
60 * or data for which each sample is a signed float or double quantity
61 * (using <code>DataBuffer.TYPE_FLOAT</code> or
62 * <code>DataBuffer.TYPE_DOUBLE</code>, respectively).
63 * All samples of a given ComponentSampleModel
64 * are stored with the same precision. All strides and offsets must be
65 * non-negative. This class supports
66 * {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
67 * {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
68 * {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
69 * {@link DataBuffer#TYPE_INT TYPE_INT},
70 * {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT},
71 * {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE},
72 * @see java.awt.image.PixelInterleavedSampleModel
73 * @see java.awt.image.BandedSampleModel
74 */
75
76 public class ComponentSampleModel extends SampleModel
77 {
78 /** Offsets for all bands in data array elements. */
79 protected int bandOffsets[];
80
81 /** Index for each bank storing a band of image data. */
82 protected int[] bankIndices;
83
84 /**
85 * The number of bands in this
86 * <code>ComponentSampleModel</code>.
87 */
88 protected int numBands = 1;
89
90 /**
91 * The number of banks in this
92 * <code>ComponentSampleModel</code>.
93 */
94 protected int numBanks = 1;
95
96 /**
97 * Line stride (in data array elements) of the region of image
98 * data described by this ComponentSampleModel.
99 */
100 protected int scanlineStride;
101
102 /** Pixel stride (in data array elements) of the region of image
103 * data described by this ComponentSampleModel.
104 */
105 protected int pixelStride;
106
107 static private native void initIDs();
108 static {
109 ColorModel.loadLibraries();
110 initIDs();
111 }
112
113 /**
114 * Constructs a ComponentSampleModel with the specified parameters.
115 * The number of bands will be given by the length of the bandOffsets array.
116 * All bands will be stored in the first bank of the DataBuffer.
117 * @param dataType the data type for storing samples
118 * @param w the width (in pixels) of the region of
119 * image data described
120 * @param h the height (in pixels) of the region of
121 * image data described
122 * @param pixelStride the pixel stride of the region of image
123 * data described
124 * @param scanlineStride the line stride of the region of image
125 * data described
126 * @param bandOffsets the offsets of all bands
127 * @throws IllegalArgumentException if <code>w</code> or
128 * <code>h</code> is not greater than 0
129 * @throws IllegalArgumentException if <code>pixelStride</code>
130 * is less than 0
131 * @throws IllegalArgumentException if <code>scanlineStride</code>
132 * is less than 0
133 * @throws IllegalArgumentException if <code>numBands</code>
134 * is less than 1
135 * @throws IllegalArgumentException if the product of <code>w</code>
136 * and <code>h</code> is greater than
137 * <code>Integer.MAX_VALUE</code>
138 * @throws IllegalArgumentException if <code>dataType</code> is not
139 * one of the supported data types
140 */
141 public ComponentSampleModel(int dataType,
142 int w, int h,
143 int pixelStride,
144 int scanlineStride,
145 int bandOffsets[]) {
146 super(dataType, w, h, bandOffsets.length);
147 this.dataType = dataType;
148 this.pixelStride = pixelStride;
149 this.scanlineStride = scanlineStride;
150 this.bandOffsets = (int[])bandOffsets.clone();
151 numBands = bandOffsets.length;
152 if (pixelStride < 0) {
153 throw new IllegalArgumentException("Pixel stride must be >= 0");
154 }
155 // TODO - bug 4296691 - remove this check
156 if (scanlineStride < 0) {
157 throw new IllegalArgumentException("Scanline stride must be >= 0");
158 }
159 if (numBands < 1) {
160 throw new IllegalArgumentException("Must have at least one band.");
161 }
162 if ((dataType < DataBuffer.TYPE_BYTE) ||
163 (dataType > DataBuffer.TYPE_DOUBLE)) {
164 throw new IllegalArgumentException("Unsupported dataType.");
165 }
166 bankIndices = new int[numBands];
167 for (int i=0; i<numBands; i++) {
168 bankIndices[i] = 0;
169 }
170 }
171
172
173 /**
174 * Constructs a ComponentSampleModel with the specified parameters.
175 * The number of bands will be given by the length of the bandOffsets array.
176 * Different bands may be stored in different banks of the DataBuffer.
177 *
178 * @param dataType the data type for storing samples
179 * @param w the width (in pixels) of the region of
180 * image data described
181 * @param h the height (in pixels) of the region of
182 * image data described
183 * @param pixelStride the pixel stride of the region of image
184 * data described
185 * @param scanlineStride The line stride of the region of image
186 * data described
187 * @param bankIndices the bank indices of all bands
188 * @param bandOffsets the band offsets of all bands
189 * @throws IllegalArgumentException if <code>w</code> or
190 * <code>h</code> is not greater than 0
191 * @throws IllegalArgumentException if <code>pixelStride</code>
192 * is less than 0
193 * @throws IllegalArgumentException if <code>scanlineStride</code>
194 * is less than 0
195 * @throws IllegalArgumentException if the length of
196 * <code>bankIndices</code> does not equal the length of
197 * <code>bankOffsets</code>
198 * @throws IllegalArgumentException if any of the bank indices
199 * of <code>bandIndices</code> is less than 0
200 * @throws IllegalArgumentException if <code>dataType</code> is not
201 * one of the supported data types
202 */
203 public ComponentSampleModel(int dataType,
204 int w, int h,
205 int pixelStride,
206 int scanlineStride,
207 int bankIndices[],
208 int bandOffsets[]) {
209 super(dataType, w, h, bandOffsets.length);
210 this.dataType = dataType;
211 this.pixelStride = pixelStride;
212 this.scanlineStride = scanlineStride;
213 this.bandOffsets = (int[])bandOffsets.clone();
214 this.bankIndices = (int[]) bankIndices.clone();
215 if (pixelStride < 0) {
216 throw new IllegalArgumentException("Pixel stride must be >= 0");
217 }
218 // TODO - bug 4296691 - remove this check
219 if (scanlineStride < 0) {
220 throw new IllegalArgumentException("Scanline stride must be >= 0");
221 }
222 if ((dataType < DataBuffer.TYPE_BYTE) ||
223 (dataType > DataBuffer.TYPE_DOUBLE)) {
224 throw new IllegalArgumentException("Unsupported dataType.");
225 }
226 int maxBank = bankIndices[0];
227 if (maxBank < 0) {
228 throw new IllegalArgumentException("Index of bank 0 is less than "+
229 "0 ("+maxBank+")");
230 }
231 for (int i=1; i < bankIndices.length; i++) {
232 if (bankIndices[i] > maxBank) {
233 maxBank = bankIndices[i];
234 }
235 else if (bankIndices[i] < 0) {
236 throw new IllegalArgumentException("Index of bank "+i+
237 " is less than 0 ("+
238 maxBank+")");
239 }
240 }
241 numBanks = maxBank+1;
242 numBands = bandOffsets.length;
243 if (bandOffsets.length != bankIndices.length) {
244 throw new IllegalArgumentException("Length of bandOffsets must "+
245 "equal length of bankIndices.");
246 }
247 }
248
249 /**
250 * Returns the size of the data buffer (in data elements) needed
251 * for a data buffer that matches this ComponentSampleModel.
252 */
253 private long getBufferSize() {
254 int maxBandOff=bandOffsets[0];
255 for (int i=1; i<bandOffsets.length; i++)
256 maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
257
258 long size = 0;
259 if (maxBandOff >= 0)
260 size += maxBandOff+1;
261 if (pixelStride > 0)
262 size += pixelStride * (width-1);
263 if (scanlineStride > 0)
264 size += scanlineStride*(height-1);
265 return size;
266 }
267
268 /**
269 * Preserves band ordering with new step factor...
270 */
271 int []orderBands(int orig[], int step) {
272 int map[] = new int[orig.length];
273 int ret[] = new int[orig.length];
274
275 for (int i=0; i<map.length; i++) map[i] = i;
276
277 for (int i = 0; i < ret.length; i++) {
278 int index = i;
279 for (int j = i+1; j < ret.length; j++) {
280 if (orig[map[index]] > orig[map[j]]) {
281 index = j;
282 }
283 }
284 ret[map[index]] = i*step;
285 map[index] = map[i];
286 }
287 return ret;
288 }
289
290 /**
291 * Creates a new <code>ComponentSampleModel</code> with the specified
292 * width and height. The new <code>SampleModel</code> will have the same
293 * number of bands, storage data type, interleaving scheme, and
294 * pixel stride as this <code>SampleModel</code>.
295 * @param w the width of the resulting <code>SampleModel</code>
296 * @param h the height of the resulting <code>SampleModel</code>
297 * @return a new <code>ComponentSampleModel</code> with the specified size
298 * @throws IllegalArgumentException if <code>w</code> or
299 * <code>h</code> is not greater than 0
300 */
301 public SampleModel createCompatibleSampleModel(int w, int h) {
302 SampleModel ret=null;
303 long size;
304 int minBandOff=bandOffsets[0];
305 int maxBandOff=bandOffsets[0];
306 for (int i=1; i<bandOffsets.length; i++) {
307 minBandOff = Math.min(minBandOff,bandOffsets[i]);
308 maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
309 }
310 maxBandOff -= minBandOff;
311
312 int bands = bandOffsets.length;
313 int bandOff[];
314 int pStride = Math.abs(pixelStride);
315 int lStride = Math.abs(scanlineStride);
316 int bStride = Math.abs(maxBandOff);
317
318 if (pStride > lStride) {
319 if (pStride > bStride) {
320 if (lStride > bStride) { // pix > line > band
321 bandOff = new int[bandOffsets.length];
322 for (int i=0; i<bands; i++)
323 bandOff[i] = bandOffsets[i]-minBandOff;
324 lStride = bStride+1;
325 pStride = lStride*h;
326 } else { // pix > band > line
327 bandOff = orderBands(bandOffsets,lStride*h);
328 pStride = bands*lStride*h;
329 }
330 } else { // band > pix > line
331 pStride = lStride*h;
332 bandOff = orderBands(bandOffsets,pStride*w);
333 }
334 } else {
335 if (pStride > bStride) { // line > pix > band
336 bandOff = new int[bandOffsets.length];
337 for (int i=0; i<bands; i++)
338 bandOff[i] = bandOffsets[i]-minBandOff;
339 pStride = bStride+1;
340 lStride = pStride*w;
341 } else {
342 if (lStride > bStride) { // line > band > pix
343 bandOff = orderBands(bandOffsets,pStride*w);
344 lStride = bands*pStride*w;
345 } else { // band > line > pix
346 lStride = pStride*w;
347 bandOff = orderBands(bandOffsets,lStride*h);
348 }
349 }
350 }
351
352 // make sure we make room for negative offsets...
353 int base = 0;
354 if (scanlineStride < 0) {
355 base += lStride*h;
356 lStride *= -1;
357 }
358 if (pixelStride < 0) {
359 base += pStride*w;
360 pStride *= -1;
361 }
362
363 for (int i=0; i<bands; i++)
364 bandOff[i] += base;
365 return new ComponentSampleModel(dataType, w, h, pStride,
366 lStride, bankIndices, bandOff);
367 }
368
369 /**
370 * Creates a new ComponentSampleModel with a subset of the bands
371 * of this ComponentSampleModel. The new ComponentSampleModel can be
372 * used with any DataBuffer that the existing ComponentSampleModel
373 * can be used with. The new ComponentSampleModel/DataBuffer
374 * combination will represent an image with a subset of the bands
375 * of the original ComponentSampleModel/DataBuffer combination.
376 * @param bands a subset of bands from this
377 * <code>ComponentSampleModel</code>
378 * @return a <code>ComponentSampleModel</code> created with a subset
379 * of bands from this <code>ComponentSampleModel</code>.
380 */
381 public SampleModel createSubsetSampleModel(int bands[]) {
382 if (bands.length > bankIndices.length)
383 throw new RasterFormatException("There are only " +
384 bankIndices.length +
385 " bands");
386 int newBankIndices[] = new int[bands.length];
387 int newBandOffsets[] = new int[bands.length];
388
389 for (int i=0; i<bands.length; i++) {
390 newBankIndices[i] = bankIndices[bands[i]];
391 newBandOffsets[i] = bandOffsets[bands[i]];
392 }
393
394 return new ComponentSampleModel(this.dataType, width, height,
395 this.pixelStride,
396 this.scanlineStride,
397 newBankIndices, newBandOffsets);
398 }
399
400 /**
401 * Creates a <code>DataBuffer</code> that corresponds to this
402 * <code>ComponentSampleModel</code>.
403 * The <code>DataBuffer</code> object's data type, number of banks,
404 * and size are be consistent with this <code>ComponentSampleModel</code>.
405 * @return a <code>DataBuffer</code> whose data type, number of banks
406 * and size are consistent with this
407 * <code>ComponentSampleModel</code>.
408 */
409 public DataBuffer createDataBuffer() {
410 DataBuffer dataBuffer = null;
411
412 int size = (int)getBufferSize();
413 switch (dataType) {
414 case DataBuffer.TYPE_BYTE:
415 dataBuffer = new DataBufferByte(size, numBanks);
416 break;
417 case DataBuffer.TYPE_USHORT:
418 dataBuffer = new DataBufferUShort(size, numBanks);
419 break;
420 case DataBuffer.TYPE_SHORT:
421 dataBuffer = new DataBufferShort(size, numBanks);
422 break;
423 case DataBuffer.TYPE_INT:
424 dataBuffer = new DataBufferInt(size, numBanks);
425 break;
426 case DataBuffer.TYPE_FLOAT:
427 dataBuffer = new DataBufferFloat(size, numBanks);
428 break;
429 case DataBuffer.TYPE_DOUBLE:
430 dataBuffer = new DataBufferDouble(size, numBanks);
431 break;
432 }
433
434 return dataBuffer;
435 }
436
437
438 /** Gets the offset for the first band of pixel (x,y).
439 * A sample of the first band can be retrieved from a
440 * <code>DataBuffer</code>
441 * <code>data</code> with a <code>ComponentSampleModel</code>
442 * <code>csm</code> as
443 * <pre>
444 * data.getElem(csm.getOffset(x, y));
445 * </pre>
446 * @param x the X location of the pixel
447 * @param y the Y location of the pixel
448 * @return the offset for the first band of the specified pixel.
449 */
450 public int getOffset(int x, int y) {
451 int offset = y*scanlineStride + x*pixelStride + bandOffsets[0];
452 return offset;
453 }
454
455 /** Gets the offset for band b of pixel (x,y).
456 * A sample of band <code>b</code> can be retrieved from a
457 * <code>DataBuffer</code> <code>data</code>
458 * with a <code>ComponentSampleModel</code> <code>csm</code> as
459 * <pre>
460 * data.getElem(csm.getOffset(x, y, b));
461 * </pre>
462 * @param x the X location of the specified pixel
463 * @param y the Y location of the specified pixel
464 * @param b the specified band
465 * @return the offset for the specified band of the specified pixel.
466 */
467 public int getOffset(int x, int y, int b) {
468 int offset = y*scanlineStride + x*pixelStride + bandOffsets[b];
469 return offset;
470 }
471
472 /** Returns the number of bits per sample for all bands.
473 * @return an array containing the number of bits per sample
474 * for all bands, where each element in the array
475 * represents a band.
476 */
477 public final int[] getSampleSize() {
478 int sampleSize[] = new int [numBands];
479 int sizeInBits = getSampleSize(0);
480
481 for (int i=0; i<numBands; i++)
482 sampleSize[i] = sizeInBits;
483
484 return sampleSize;
485 }
486
487 /** Returns the number of bits per sample for the specified band.
488 * @param band the specified band
489 * @return the number of bits per sample for the specified band.
490 */
491 public final int getSampleSize(int band) {
492 return DataBuffer.getDataTypeSize(dataType);
493 }
494
495 /** Returns the bank indices for all bands.
496 * @return the bank indices for all bands.
497 */
498 public final int [] getBankIndices() {
499 return (int[]) bankIndices.clone();
500 }
501
502 /** Returns the band offset for all bands.
503 * @return the band offsets for all bands.
504 */
505 public final int [] getBandOffsets() {
506 return (int[])bandOffsets.clone();
507 }
508
509 /** Returns the scanline stride of this ComponentSampleModel.
510 * @return the scanline stride of this <code>ComponentSampleModel</code>.
511 */
512 public final int getScanlineStride() {
513 return scanlineStride;
514 }
515
516 /** Returns the pixel stride of this ComponentSampleModel.
517 * @return the pixel stride of this <code>ComponentSampleModel</code>.
518 */
519 public final int getPixelStride() {
520 return pixelStride;
521 }
522
523 /**
524 * Returns the number of data elements needed to transfer a pixel
525 * with the
526 * {@link #getDataElements(int, int, Object, DataBuffer) } and
527 * {@link #setDataElements(int, int, Object, DataBuffer) }
528 * methods.
529 * For a <code>ComponentSampleModel</code>, this is identical to the
530 * number of bands.
531 * @return the number of data elements needed to transfer a pixel with
532 * the <code>getDataElements</code> and
533 * <code>setDataElements</code> methods.
534 * @see java.awt.image.SampleModel#getNumDataElements
535 * @see #getNumBands
536 */
537 public final int getNumDataElements() {
538 return getNumBands();
539 }
540
541 /**
542 * Returns data for a single pixel in a primitive array of type
543 * <code>TransferType</code>. For a <code>ComponentSampleModel</code>,
544 * this is the same as the data type, and samples are returned
545 * one per array element. Generally, <code>obj</code> should
546 * be passed in as <code>null</code>, so that the <code>Object</code>
547 * is created automatically and is the right primitive data type.
548 * <p>
549 * The following code illustrates transferring data for one pixel from
550 * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
551 * described by <code>ComponentSampleModel</code> <code>csm1</code>,
552 * to <code>DataBuffer</code> <code>db2</code>, whose storage layout
553 * is described by <code>ComponentSampleModel</code> <code>csm2</code>.
554 * The transfer is usually more efficient than using
555 * <code>getPixel</code> and <code>setPixel</code>.
556 * <pre>
557 * ComponentSampleModel csm1, csm2;
558 * DataBufferInt db1, db2;
559 * csm2.setDataElements(x, y,
560 * csm1.getDataElements(x, y, null, db1), db2);
561 * </pre>
562 *
563 * Using <code>getDataElements</code> and <code>setDataElements</code>
564 * to transfer between two <code>DataBuffer/SampleModel</code>
565 * pairs is legitimate if the <code>SampleModel</code> objects have
566 * the same number of bands, corresponding bands have the same number of
567 * bits per sample, and the <code>TransferType</code>s are the same.
568 * <p>
569 * If <code>obj</code> is not <code>null</code>, it should be a
570 * primitive array of type <code>TransferType</code>.
571 * Otherwise, a <code>ClassCastException</code> is thrown. An
572 * <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
573 * coordinates are not in bounds, or if <code>obj</code> is not
574 * <code>null</code> and is not large enough to hold
575 * the pixel data.
576 *
577 * @param x the X coordinate of the pixel location
578 * @param y the Y coordinate of the pixel location
579 * @param obj if non-<code>null</code>, a primitive array
580 * in which to return the pixel data
581 * @param data the <code>DataBuffer</code> containing the image data
582 * @return the data of the specified pixel
583 * @see #setDataElements(int, int, Object, DataBuffer)
584 *
585 * @throws NullPointerException if data is null.
586 * @throws ArrayIndexOutOfBoundsException if the coordinates are
587 * not in bounds, or if obj is too small to hold the ouput.
588 */
589 public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
590 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
591 throw new ArrayIndexOutOfBoundsException
592 ("Coordinate out of bounds!");
593 }
594
595 int type = getTransferType();
596 int numDataElems = getNumDataElements();
597 int pixelOffset = y*scanlineStride + x*pixelStride;
598
599 switch(type) {
600
601 case DataBuffer.TYPE_BYTE:
602
603 byte[] bdata;
604
605 if (obj == null)
606 bdata = new byte[numDataElems];
607 else
608 bdata = (byte[])obj;
609
610 for (int i=0; i<numDataElems; i++) {
611 bdata[i] = (byte)data.getElem(bankIndices[i],
612 pixelOffset + bandOffsets[i]);
613 }
614
615 obj = (Object)bdata;
616 break;
617
618 case DataBuffer.TYPE_USHORT:
619 case DataBuffer.TYPE_SHORT:
620
621 short[] sdata;
622
623 if (obj == null)
624 sdata = new short[numDataElems];
625 else
626 sdata = (short[])obj;
627
628 for (int i=0; i<numDataElems; i++) {
629 sdata[i] = (short)data.getElem(bankIndices[i],
630 pixelOffset + bandOffsets[i]);
631 }
632
633 obj = (Object)sdata;
634 break;
635
636 case DataBuffer.TYPE_INT:
637
638 int[] idata;
639
640 if (obj == null)
641 idata = new int[numDataElems];
642 else
643 idata = (int[])obj;
644
645 for (int i=0; i<numDataElems; i++) {
646 idata[i] = data.getElem(bankIndices[i],
647 pixelOffset + bandOffsets[i]);
648 }
649
650 obj = (Object)idata;
651 break;
652
653 case DataBuffer.TYPE_FLOAT:
654
655 float[] fdata;
656
657 if (obj == null)
658 fdata = new float[numDataElems];
659 else
660 fdata = (float[])obj;
661
662 for (int i=0; i<numDataElems; i++) {
663 fdata[i] = data.getElemFloat(bankIndices[i],
664 pixelOffset + bandOffsets[i]);
665 }
666
667 obj = (Object)fdata;
668 break;
669
670 case DataBuffer.TYPE_DOUBLE:
671
672 double[] ddata;
673
674 if (obj == null)
675 ddata = new double[numDataElems];
676 else
677 ddata = (double[])obj;
678
679 for (int i=0; i<numDataElems; i++) {
680 ddata[i] = data.getElemDouble(bankIndices[i],
681 pixelOffset + bandOffsets[i]);
682 }
683
684 obj = (Object)ddata;
685 break;
686 }
687
688 return obj;
689 }
690
691 /**
692 * Returns all samples for the specified pixel in an int array,
693 * one sample per array element.
694 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
695 * the coordinates are not in bounds.
696 * @param x the X coordinate of the pixel location
697 * @param y the Y coordinate of the pixel location
698 * @param iArray If non-null, returns the samples in this array
699 * @param data The DataBuffer containing the image data
700 * @return the samples of the specified pixel.
701 * @see #setPixel(int, int, int[], DataBuffer)
702 *
703 * @throws NullPointerException if data is null.
704 * @throws ArrayIndexOutOfBoundsException if the coordinates are
705 * not in bounds, or if iArray is too small to hold the output.
706 */
707 public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
708 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
709 throw new ArrayIndexOutOfBoundsException
710 ("Coordinate out of bounds!");
711 }
712 int pixels[];
713 if (iArray != null) {
714 pixels = iArray;
715 } else {
716 pixels = new int [numBands];
717 }
718 int pixelOffset = y*scanlineStride + x*pixelStride;
719 for (int i=0; i<numBands; i++) {
720 pixels[i] = data.getElem(bankIndices[i],
721 pixelOffset + bandOffsets[i]);
722 }
723 return pixels;
724 }
725
726 /**
727 * Returns all samples for the specified rectangle of pixels in
728 * an int array, one sample per array element.
729 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
730 * the coordinates are not in bounds.
731 * @param x The X coordinate of the upper left pixel location
732 * @param y The Y coordinate of the upper left pixel location
733 * @param w The width of the pixel rectangle
734 * @param h The height of the pixel rectangle
735 * @param iArray If non-null, returns the samples in this array
736 * @param data The DataBuffer containing the image data
737 * @return the samples of the pixels within the specified region.
738 * @see #setPixels(int, int, int, int, int[], DataBuffer)
739 */
740 public int[] getPixels(int x, int y, int w, int h,
741 int iArray[], DataBuffer data) {
742 if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
743 throw new ArrayIndexOutOfBoundsException
744 ("Coordinate out of bounds!");
745 }
746 int pixels[];
747 if (iArray != null) {
748 pixels = iArray;
749 } else {
750 pixels = new int [w*h*numBands];
751 }
752 int lineOffset = y*scanlineStride + x*pixelStride;
753 int srcOffset = 0;
754
755 for (int i = 0; i < h; i++) {
756 int pixelOffset = lineOffset;
757 for (int j = 0; j < w; j++) {
758 for (int k=0; k < numBands; k++) {
759 pixels[srcOffset++] =
760 data.getElem(bankIndices[k], pixelOffset + bandOffsets[k]);
761 }
762 pixelOffset += pixelStride;
763 }
764 lineOffset += scanlineStride;
765 }
766 return pixels;
767 }
768
769 /**
770 * Returns as int the sample in a specified band for the pixel
771 * located at (x,y).
772 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
773 * the coordinates are not in bounds.
774 * @param x the X coordinate of the pixel location
775 * @param y the Y coordinate of the pixel location
776 * @param b the band to return
777 * @param data the <code>DataBuffer</code> containing the image data
778 * @return the sample in a specified band for the specified pixel
779 * @see #setSample(int, int, int, int, DataBuffer)
780 */
781 public int getSample(int x, int y, int b, DataBuffer data) {
782 // Bounds check for 'b' will be performed automatically
783 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
784 throw new ArrayIndexOutOfBoundsException
785 ("Coordinate out of bounds!");
786 }
787 int sample = data.getElem(bankIndices[b],
788 y*scanlineStride + x*pixelStride +
789 bandOffsets[b]);
790 return sample;
791 }
792
793 /**
794 * Returns the sample in a specified band
795 * for the pixel located at (x,y) as a float.
796 * An <code>ArrayIndexOutOfBoundsException</code> might be
797 * thrown if the coordinates are not in bounds.
798 * @param x The X coordinate of the pixel location
799 * @param y The Y coordinate of the pixel location
800 * @param b The band to return
801 * @param data The DataBuffer containing the image data
802 * @return a float value representing the sample in the specified
803 * band for the specified pixel.
804 */
805 public float getSampleFloat(int x, int y, int b, DataBuffer data) {
806 // Bounds check for 'b' will be performed automatically
807 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
808 throw new ArrayIndexOutOfBoundsException
809 ("Coordinate out of bounds!");
810 }
811
812 float sample = data.getElemFloat(bankIndices[b],
813 y*scanlineStride + x*pixelStride +
814 bandOffsets[b]);
815 return sample;
816 }
817
818 /**
819 * Returns the sample in a specified band
820 * for a pixel located at (x,y) as a double.
821 * An <code>ArrayIndexOutOfBoundsException</code> might be
822 * thrown if the coordinates are not in bounds.
823 * @param x The X coordinate of the pixel location
824 * @param y The Y coordinate of the pixel location
825 * @param b The band to return
826 * @param data The DataBuffer containing the image data
827 * @return a double value representing the sample in the specified
828 * band for the specified pixel.
829 */
830 public double getSampleDouble(int x, int y, int b, DataBuffer data) {
831 // Bounds check for 'b' will be performed automatically
832 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
833 throw new ArrayIndexOutOfBoundsException
834 ("Coordinate out of bounds!");
835 }
836
837 double sample = data.getElemDouble(bankIndices[b],
838 y*scanlineStride + x*pixelStride +
839 bandOffsets[b]);
840 return sample;
841 }
842
843 /**
844 * Returns the samples in a specified band for the specified rectangle
845 * of pixels in an int array, one sample per data array element.
846 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
847 * the coordinates are not in bounds.
848 * @param x The X coordinate of the upper left pixel location
849 * @param y The Y coordinate of the upper left pixel location
850 * @param w the width of the pixel rectangle
851 * @param h the height of the pixel rectangle
852 * @param b the band to return
853 * @param iArray if non-<code>null</code>, returns the samples
854 * in this array
855 * @param data the <code>DataBuffer</code> containing the image data
856 * @return the samples in the specified band of the specified pixel
857 * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
858 */
859 public int[] getSamples(int x, int y, int w, int h, int b,
860 int iArray[], DataBuffer data) {
861 // Bounds check for 'b' will be performed automatically
862 if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
863 throw new ArrayIndexOutOfBoundsException
864 ("Coordinate out of bounds!");
865 }
866 int samples[];
867 if (iArray != null) {
868 samples = iArray;
869 } else {
870 samples = new int [w*h];
871 }
872 int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b];
873 int srcOffset = 0;
874
875 for (int i = 0; i < h; i++) {
876 int sampleOffset = lineOffset;
877 for (int j = 0; j < w; j++) {
878 samples[srcOffset++] = data.getElem(bankIndices[b],
879 sampleOffset);
880 sampleOffset += pixelStride;
881 }
882 lineOffset += scanlineStride;
883 }
884 return samples;
885 }
886
887 /**
888 * Sets the data for a single pixel in the specified
889 * <code>DataBuffer</code> from a primitive array of type
890 * <code>TransferType</code>. For a <code>ComponentSampleModel</code>,
891 * this is the same as the data type, and samples are transferred
892 * one per array element.
893 * <p>
894 * The following code illustrates transferring data for one pixel from
895 * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
896 * described by <code>ComponentSampleModel</code> <code>csm1</code>,
897 * to <code>DataBuffer</code> <code>db2</code>, whose storage layout
898 * is described by <code>ComponentSampleModel</code> <code>csm2</code>.
899 * The transfer is usually more efficient than using
900 * <code>getPixel</code> and <code>setPixel</code>.
901 * <pre>
902 * ComponentSampleModel csm1, csm2;
903 * DataBufferInt db1, db2;
904 * csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
905 * db2);
906 * </pre>
907 * Using <code>getDataElements</code> and <code>setDataElements</code>
908 * to transfer between two <code>DataBuffer/SampleModel</code> pairs
909 * is legitimate if the <code>SampleModel</code> objects have
910 * the same number of bands, corresponding bands have the same number of
911 * bits per sample, and the <code>TransferType</code>s are the same.
912 * <p>
913 * A <code>ClassCastException</code> is thrown if <code>obj</code> is not
914 * a primitive array of type <code>TransferType</code>.
915 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
916 * the coordinates are not in bounds, or if <code>obj</code> is not large
917 * enough to hold the pixel data.
918 * @param x the X coordinate of the pixel location
919 * @param y the Y coordinate of the pixel location
920 * @param obj a primitive array containing pixel data
921 * @param data the DataBuffer containing the image data
922 * @see #getDataElements(int, int, Object, DataBuffer)
923 */
924 public void setDataElements(int x, int y, Object obj, DataBuffer data) {
925 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
926 throw new ArrayIndexOutOfBoundsException
927 ("Coordinate out of bounds!");
928 }
929
930 int type = getTransferType();
931 int numDataElems = getNumDataElements();
932 int pixelOffset = y*scanlineStride + x*pixelStride;
933
934 switch(type) {
935
936 case DataBuffer.TYPE_BYTE:
937
938 byte[] barray = (byte[])obj;
939
940 for (int i=0; i<numDataElems; i++) {
941 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
942 ((int)barray[i])&0xff);
943 }
944 break;
945
946 case DataBuffer.TYPE_USHORT:
947 case DataBuffer.TYPE_SHORT:
948
949 short[] sarray = (short[])obj;
950
951 for (int i=0; i<numDataElems; i++) {
952 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
953 ((int)sarray[i])&0xffff);
954 }
955 break;
956
957 case DataBuffer.TYPE_INT:
958
959 int[] iarray = (int[])obj;
960
961 for (int i=0; i<numDataElems; i++) {
962 data.setElem(bankIndices[i],
963 pixelOffset + bandOffsets[i], iarray[i]);
964 }
965 break;
966
967 case DataBuffer.TYPE_FLOAT:
968
969 float[] farray = (float[])obj;
970
971 for (int i=0; i<numDataElems; i++) {
972 data.setElemFloat(bankIndices[i],
973 pixelOffset + bandOffsets[i], farray[i]);
974 }
975 break;
976
977 case DataBuffer.TYPE_DOUBLE:
978
979 double[] darray = (double[])obj;
980
981 for (int i=0; i<numDataElems; i++) {
982 data.setElemDouble(bankIndices[i],
983 pixelOffset + bandOffsets[i], darray[i]);
984 }
985 break;
986
987 }
988 }
989
990 /**
991 * Sets a pixel in the <code>DataBuffer</code> using an int array of
992 * samples for input. An <code>ArrayIndexOutOfBoundsException</code>
993 * might be thrown if the coordinates are
994 * not in bounds.
995 * @param x The X coordinate of the pixel location
996 * @param y The Y coordinate of the pixel location
997 * @param iArray The input samples in an int array
998 * @param data The DataBuffer containing the image data
999 * @see #getPixel(int, int, int[], DataBuffer)
1000 */
1001 public void setPixel(int x, int y, int iArray[], DataBuffer data) {
1002 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1003 throw new ArrayIndexOutOfBoundsException
1004 ("Coordinate out of bounds!");
1005 }
1006 int pixelOffset = y*scanlineStride + x*pixelStride;
1007 for (int i=0; i<numBands; i++) {
1008 data.setElem(bankIndices[i],
1009 pixelOffset + bandOffsets[i],iArray[i]);
1010 }
1011 }
1012
1013 /**
1014 * Sets all samples for a rectangle of pixels from an int array containing
1015 * one sample per array element.
1016 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
1017 * coordinates are not in bounds.
1018 * @param x The X coordinate of the upper left pixel location
1019 * @param y The Y coordinate of the upper left pixel location
1020 * @param w The width of the pixel rectangle
1021 * @param h The height of the pixel rectangle
1022 * @param iArray The input samples in an int array
1023 * @param data The DataBuffer containing the image data
1024 * @see #getPixels(int, int, int, int, int[], DataBuffer)
1025 */
1026 public void setPixels(int x, int y, int w, int h,
1027 int iArray[], DataBuffer data) {
1028 if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
1029 throw new ArrayIndexOutOfBoundsException
1030 ("Coordinate out of bounds!");
1031 }
1032
1033 int lineOffset = y*scanlineStride + x*pixelStride;
1034 int srcOffset = 0;
1035
1036 for (int i = 0; i < h; i++) {
1037 int pixelOffset = lineOffset;
1038 for (int j = 0; j < w; j++) {
1039 for (int k=0; k < numBands; k++) {
1040 data.setElem(bankIndices[k], pixelOffset + bandOffsets[k],
1041 iArray[srcOffset++]);
1042 }
1043 pixelOffset += pixelStride;
1044 }
1045 lineOffset += scanlineStride;
1046 }
1047 }
1048
1049 /**
1050 * Sets a sample in the specified band for the pixel located at (x,y)
1051 * in the <code>DataBuffer</code> using an int for input.
1052 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
1053 * coordinates are not in bounds.
1054 * @param x The X coordinate of the pixel location
1055 * @param y The Y coordinate of the pixel location
1056 * @param b the band to set
1057 * @param s the input sample as an int
1058 * @param data the DataBuffer containing the image data
1059 * @see #getSample(int, int, int, DataBuffer)
1060 */
1061 public void setSample(int x, int y, int b, int s,
1062 DataBuffer data) {
1063 // Bounds check for 'b' will be performed automatically
1064 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1065 throw new ArrayIndexOutOfBoundsException
1066 ("Coordinate out of bounds!");
1067 }
1068 data.setElem(bankIndices[b],
1069 y*scanlineStride + x*pixelStride + bandOffsets[b], s);
1070 }
1071
1072 /**
1073 * Sets a sample in the specified band for the pixel located at (x,y)
1074 * in the <code>DataBuffer</code> using a float for input.
1075 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
1076 * the coordinates are not in bounds.
1077 * @param x The X coordinate of the pixel location
1078 * @param y The Y coordinate of the pixel location
1079 * @param b The band to set
1080 * @param s The input sample as a float
1081 * @param data The DataBuffer containing the image data
1082 * @see #getSample(int, int, int, DataBuffer)
1083 */
1084 public void setSample(int x, int y, int b,
1085 float s ,
1086 DataBuffer data) {
1087 // Bounds check for 'b' will be performed automatically
1088 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1089 throw new ArrayIndexOutOfBoundsException
1090 ("Coordinate out of bounds!");
1091 }
1092 data.setElemFloat(bankIndices[b],
1093 y*scanlineStride + x*pixelStride + bandOffsets[b],
1094 s);
1095 }
1096
1097 /**
1098 * Sets a sample in the specified band for the pixel located at (x,y)
1099 * in the <code>DataBuffer</code> using a double for input.
1100 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
1101 * the coordinates are not in bounds.
1102 * @param x The X coordinate of the pixel location
1103 * @param y The Y coordinate of the pixel location
1104 * @param b The band to set
1105 * @param s The input sample as a double
1106 * @param data The DataBuffer containing the image data
1107 * @see #getSample(int, int, int, DataBuffer)
1108 */
1109 public void setSample(int x, int y, int b,
1110 double s,
1111 DataBuffer data) {
1112 // Bounds check for 'b' will be performed automatically
1113 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1114 throw new ArrayIndexOutOfBoundsException
1115 ("Coordinate out of bounds!");
1116 }
1117 data.setElemDouble(bankIndices[b],
1118 y*scanlineStride + x*pixelStride + bandOffsets[b],
1119 s);
1120 }
1121
1122 /**
1123 * Sets the samples in the specified band for the specified rectangle
1124 * of pixels from an int array containing one sample per data array element.
1125 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
1126 * coordinates are not in bounds.
1127 * @param x The X coordinate of the upper left pixel location
1128 * @param y The Y coordinate of the upper left pixel location
1129 * @param w The width of the pixel rectangle
1130 * @param h The height of the pixel rectangle
1131 * @param b The band to set
1132 * @param iArray The input samples in an int array
1133 * @param data The DataBuffer containing the image data
1134 * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
1135 */
1136 public void setSamples(int x, int y, int w, int h, int b,
1137 int iArray[], DataBuffer data) {
1138 // Bounds check for 'b' will be performed automatically
1139 if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
1140 throw new ArrayIndexOutOfBoundsException
1141 ("Coordinate out of bounds!");
1142 }
1143 int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b];
1144 int srcOffset = 0;
1145
1146 for (int i = 0; i < h; i++) {
1147 int sampleOffset = lineOffset;
1148 for (int j = 0; j < w; j++) {
1149 data.setElem(bankIndices[b], sampleOffset, iArray[srcOffset++]);
1150 sampleOffset += pixelStride;
1151 }
1152 lineOffset += scanlineStride;
1153 }
1154 }
1155
1156 public boolean equals(Object o) {
1157 if ((o == null) || !(o instanceof ComponentSampleModel)) {
1158 return false;
1159 }
1160
1161 ComponentSampleModel that = (ComponentSampleModel)o;
1162 return this.width == that.width &&
1163 this.height == that.height &&
1164 this.numBands == that.numBands &&
1165 this.dataType == that.dataType &&
1166 Arrays.equals(this.bandOffsets, that.bandOffsets) &&
1167 Arrays.equals(this.bankIndices, that.bankIndices) &&
1168 this.numBands == that.numBands &&
1169 this.numBanks == that.numBanks &&
1170 this.scanlineStride == that.scanlineStride &&
1171 this.pixelStride == that.pixelStride;
1172 }
1173
1174 // If we implement equals() we must also implement hashCode
1175 public int hashCode() {
1176 int hash = 0;
1177 hash = width;
1178 hash <<= 8;
1179 hash ^= height;
1180 hash <<= 8;
1181 hash ^= numBands;
1182 hash <<= 8;
1183 hash ^= dataType;
1184 hash <<= 8;
1185 for (int i = 0; i < bandOffsets.length; i++) {
1186 hash ^= bandOffsets[i];
1187 hash <<= 8;
1188 }
1189 for (int i = 0; i < bankIndices.length; i++) {
1190 hash ^= bankIndices[i];
1191 hash <<= 8;
1192 }
1193 hash ^= numBands;
1194 hash <<= 8;
1195 hash ^= numBanks;
1196 hash <<= 8;
1197 hash ^= scanlineStride;
1198 hash <<= 8;
1199 hash ^= pixelStride;
1200 return hash;
1201 }
1202 }