1 /*
2  * $RCSfile: ComponentSampleModelJAI.java,v $
3  *
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Use is subject to license terms.
7  *
8  * $Revision: 1.1 $
9  * $Date: 2005/02/11 04:57:07 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.mediax.jai;
13 import java.awt.image.ComponentSampleModel;
14 import java.awt.image.DataBuffer;
15 import java.awt.image.DataBufferByte;
16 import java.awt.image.DataBufferShort;
17 import java.awt.image.DataBufferInt;
18 import java.awt.image.DataBufferUShort;
19 import java.awt.image.SampleModel;
20 
21 import com.lightcrafts.media.jai.util.DataBufferUtils;
22 
23 /**
24  *  This class represents image data which is stored such that each sample
25  *  of a pixel occupies one data element of the <code>DataBuffer</code>.  It stores the
26  *  N samples which make up a pixel in N separate data array elements.
27  *  Different bands may be in different banks of the <code>DataBuffer</code>.
28  *  Accessor methods are provided so that image data can be manipulated
29  *  directly. This class can support different kinds of interleaving, e.g.
30  *  band interleaving, scanline interleaving, and pixel interleaving.
31  *  Pixel stride is the number of data array elements between two samples
32  *  for the same band on the same scanline. Scanline stride is the number
33  *  of data array elements between a given sample and the corresponding sample
34  *  in the same column of the next scanline.  Band offsets denote the number
35  *  of data array elements from the first data array element of the bank
36  *  of the <code>DataBuffer</code> holding each band to the first sample of the band.
37  *  The bands are numbered from 0 to N-1.  This class can represent image
38  *  data for the dataTypes enumerated in java.awt.image.DataBuffer (all
39  *  samples of a given <code>ComponentSampleModel</code> are stored with the same precision)
40  *  . This class adds support for <code>Double</code> and <code>Float</code> data types in addition
41  * to those supported by the <code>ComponentSampleModel</code> class in Java 2D.
42  * All strides and offsets must be non-negative.
43  *  @see java.awt.image.ComponentSampleModel
44  */
45 
46 public class ComponentSampleModelJAI extends ComponentSampleModel {
47 
48     /**
49      * Constructs a <code>ComponentSampleModel</code> with the specified
50      * parameters.  The number of bands will be given by the length of
51      * the bandOffsets array.  All bands will be stored in the first
52      * bank of the <code>DataBuffer</code>.
53      *
54      * @param dataType 	The data type for storing samples.
55      * @param w 	The width (in pixels) of the region of
56      * image data described.
57      * @param h 	The height (in pixels) of the region of
58      * image data described.
59      * @param pixelStride The pixel stride of the region of image
60      * data described.
61      * @param scanlineStride The line stride of the region of image
62      * data described.
63      * @param bandOffsets The offsets of all bands.
64      */
ComponentSampleModelJAI(int dataType, int w, int h, int pixelStride, int scanlineStride, int bandOffsets[])65     public ComponentSampleModelJAI(int dataType,
66                                    int w, int h,
67                                    int pixelStride,
68                                    int scanlineStride,
69                                    int bandOffsets[]) {
70         super(dataType, w, h, pixelStride, scanlineStride, bandOffsets);
71     }
72 
73 
74     /**
75      * Constructs a <code>ComponentSampleModel</code> with the specified
76      * parameters.  The number of bands will be given by the length of
77      * the bandOffsets array.  Different bands may be stored in
78      * different banks of the <code>DataBuffer</code>.
79      *
80      * @param dataType 	The data type for storing samples.
81      * @param w 	The width (in pixels) of the region of
82      * image data described.
83      * @param h 	The height (in pixels) of the region of
84      * image data described.
85      * @param pixelStride The pixel stride of the region of image
86      * data described.
87      * @param scanlineStride The line stride of the region of image
88      * data described.
89      * @param bankIndices The bank indices of all bands.
90      * @param bandOffsets The band offsets of all bands.
91      */
ComponentSampleModelJAI(int dataType, int w, int h, int pixelStride, int scanlineStride, int bankIndices[], int bandOffsets[])92     public ComponentSampleModelJAI(int dataType,
93                                    int w, int h,
94                                    int pixelStride,
95                                    int scanlineStride,
96                                    int bankIndices[],
97                                    int bandOffsets[]) {
98         super(dataType, w, h, pixelStride, scanlineStride,
99               bankIndices, bandOffsets);
100     }
101 
102     /**
103      * Returns the size of the data buffer (in data elements) needed
104      * for a data buffer that matches this <code>ComponentSampleModel</code>.
105      */
getBufferSize()106      private long getBufferSize() {
107          int maxBandOff=bandOffsets[0];
108          for (int i=1; i<bandOffsets.length; i++)
109              maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
110 
111          long size = 0;
112          if (maxBandOff >= 0)
113              size += maxBandOff+1;
114          if (pixelStride > 0)
115              size += pixelStride * (width-1);
116          if (scanlineStride > 0)
117              size += scanlineStride*(height-1);
118          return size;
119      }
120 
121      /**
122       * Preserves band ordering with new step factor...
123       */
JAIorderBands(int orig[], int step)124     private int[] JAIorderBands(int orig[], int step) {
125         int map[] = new int[orig.length];
126         int ret[] = new int[orig.length];
127 
128         for (int i=0; i<map.length; i++) map[i] = i;
129 
130         for (int i = 0; i < ret.length; i++) {
131             int index = i;
132             for (int j = i+1; j < ret.length; j++) {
133                 if (orig[map[index]] > orig[map[j]]) {
134                     index = j;
135                 }
136             }
137             ret[map[index]] = i*step;
138             map[index]  = map[i];
139         }
140         return ret;
141     }
142 
143     /**
144      * Creates a new <code>ComponentSampleModel</code> with the specified
145      * width and height.  The new <code>SampleModel</code> will have the same
146      * number of bands, storage data type, interleaving scheme, and
147      * pixel stride as this <code>SampleModel</code>.
148      *
149      * @param w The width in pixels.
150      * @param h The height in pixels
151      */
createCompatibleSampleModel(int w, int h)152     public SampleModel createCompatibleSampleModel(int w, int h) {
153         SampleModel ret=null;
154         long size;
155         int minBandOff=bandOffsets[0];
156         int maxBandOff=bandOffsets[0];
157         for (int i=1; i<bandOffsets.length; i++) {
158             minBandOff = Math.min(minBandOff,bandOffsets[i]);
159             maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
160         }
161         maxBandOff -= minBandOff;
162 
163         int bands   = bandOffsets.length;
164         int bandOff[];
165         int pStride = Math.abs(pixelStride);
166         int lStride = Math.abs(scanlineStride);
167         int bStride = Math.abs(maxBandOff);
168 
169         if (pStride > lStride) {
170             if (pStride > bStride) {
171                 if (lStride > bStride) { // pix > line > band
172                     bandOff = new int[bandOffsets.length];
173                     for (int i=0; i<bands; i++)
174                         bandOff[i] = bandOffsets[i]-minBandOff;
175                     lStride = bStride+1;
176                     pStride = lStride*h;
177                 } else { // pix > band > line
178                     bandOff = JAIorderBands(bandOffsets,lStride*h);
179                     pStride = bands*lStride*h;
180                 }
181             } else { // band > pix > line
182                 pStride = lStride*h;
183                 bandOff = JAIorderBands(bandOffsets,pStride*w);
184             }
185         } else {
186             if (pStride > bStride) { // line > pix > band
187                 bandOff = new int[bandOffsets.length];
188                 for (int i=0; i<bands; i++)
189                     bandOff[i] = bandOffsets[i]-minBandOff;
190                 pStride = bStride+1;
191                 lStride = pStride*w;
192             } else {
193                 if (lStride > bStride) { // line > band > pix
194                     bandOff = JAIorderBands(bandOffsets,pStride*w);
195                     lStride = bands*pStride*w;
196                 } else { // band > line > pix
197                     lStride = pStride*w;
198                     bandOff = JAIorderBands(bandOffsets,lStride*h);
199                 }
200             }
201         }
202 
203         // make sure we make room for negative offsets...
204         int base = 0;
205         if (scanlineStride < 0) {
206             base += lStride*h;
207             lStride *= -1;
208         }
209         if (pixelStride    < 0) {
210             base += pStride*w;
211             pStride *= -1;
212         }
213 
214         for (int i=0; i<bands; i++)
215             bandOff[i] += base;
216         return new ComponentSampleModelJAI(dataType, w, h, pStride,
217                                            lStride, bankIndices, bandOff);
218     }
219 
220     /**
221      * This creates a new <code>ComponentSampleModel</code> with a subset of the bands
222      * of this <code>ComponentSampleModel</code>.  The new <code>ComponentSampleModel</code> can be
223      * used with any <code>DataBuffer</code> that the existing <code>ComponentSampleModel</code>
224      * can be used with.  The new <code>ComponentSampleModel</code>/<code>DataBuffer</code>
225      * combination will represent an image with a subset of the bands
226      * of the original <code>ComponentSampleModel</code>/<code>DataBuffer</code> combination.
227      *
228      * @param bands subset of bands of this <code>ComponentSampleModel</code>
229      */
createSubsetSampleModel(int bands[])230     public SampleModel createSubsetSampleModel(int bands[]) {
231         int newBankIndices[] = new int[bands.length];
232         int newBandOffsets[] = new int[bands.length];
233         for (int i=0; i<bands.length; i++) {
234             int b = bands[i];
235             newBankIndices[i] = bankIndices[b];
236             newBandOffsets[i] = bandOffsets[b];
237         }
238         return new ComponentSampleModelJAI(this.dataType, width, height,
239                                            this.pixelStride,
240                                            this.scanlineStride,
241                                            newBankIndices,
242                                            newBandOffsets);
243     }
244 
245     /**
246      * Creates a <code>DataBuffer</code> that corresponds to this <code>ComponentSampleModel</code>.
247      * The <code>DataBuffer</code>'s data type, number of banks, and size
248      * will be consistent with this <code>ComponentSampleModel</code>.
249      */
createDataBuffer()250     public DataBuffer createDataBuffer() {
251         DataBuffer dataBuffer = null;
252 
253         int size = (int)getBufferSize();
254         switch (dataType) {
255         case DataBuffer.TYPE_BYTE:
256             dataBuffer = new DataBufferByte(size, numBanks);
257             break;
258         case DataBuffer.TYPE_USHORT:
259             dataBuffer = new DataBufferUShort(size, numBanks);
260             break;
261         case DataBuffer.TYPE_INT:
262             dataBuffer = new DataBufferInt(size, numBanks);
263             break;
264         case DataBuffer.TYPE_SHORT:
265             dataBuffer = new DataBufferShort(size, numBanks);
266             break;
267         case DataBuffer.TYPE_FLOAT:
268             dataBuffer = DataBufferUtils.createDataBufferFloat(size, numBanks);
269             break;
270         case DataBuffer.TYPE_DOUBLE:
271             dataBuffer = DataBufferUtils.createDataBufferDouble(size, numBanks);
272             break;
273 	default:
274             throw new RuntimeException(JaiI18N.getString("RasterFactory3"));
275         }
276 
277         return dataBuffer;
278     }
279 
280 
281     /**
282      * Returns data for a single pixel in a primitive array of type
283      * TransferType.  For a <code>ComponentSampleModel</code>, this will be the same
284      * as the data type, and samples will be returned one per array
285      * element.  Generally, obj
286      * should be passed in as null, so that the <code>Object</code> will be created
287      * automatically and will be of the right primitive data type.
288      * <p>
289      * The following code illustrates transferring data for one pixel from
290      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is described by
291      * <code>ComponentSampleModel</code> <code>csm1</code>, to <code>DataBuffer</code> <code>db2</code>,
292      * whose storage layout is described by
293      * <code>ComponentSampleModel</code> <code>csm2</code>.
294      * The transfer will generally be more efficient than using
295      * getPixel/setPixel.
296      * <pre>
297      * 	     ComponentSampleModel csm1, csm2;
298      *	     DataBufferInt db1, db2;
299      * 	     csm2.setDataElements(x, y,
300      *                            csm1.getDataElements(x, y, null, db1), db2);
301      * </pre>
302      * Using getDataElements/setDataElements to transfer between two
303      * <code>DataBuffer</code>/SampleModel pairs is legitimate if the <code>SampleModel</code>s have
304      * the same number of bands, corresponding bands have the same number of
305      * bits per sample, and the TransferTypes are the same.
306      * <p>
307      * @param x 	The X coordinate of the pixel location.
308      * @param y 	The Y coordinate of the pixel location.
309      * @param obj       If non-null, a primitive array in which to return
310      *                  the pixel data.
311      * @param data      The <code>DataBuffer</code> containing the image data.
312      * @throws <code>ClassCastException</code> if obj is non-null and is not
313      *          a primitive array of type TransferType.
314      * @throws <code>ArrayIndexOutOfBoundsException</code> if the coordinates
315      *         are not in bounds, or if obj is non-null and is not large
316      *         enough to hold the pixel data.
317      */
getDataElements(int x, int y, Object obj, DataBuffer data)318     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
319 
320 	int type = getTransferType();
321 	int numDataElems = getNumDataElements();
322 	int pixelOffset = y*scanlineStride + x*pixelStride;
323 
324 	switch(type) {
325 
326 	case DataBuffer.TYPE_BYTE:
327 
328 	    byte[] bdata;
329 
330 	    if (obj == null)
331 		bdata = new byte[numDataElems];
332 	    else
333 		bdata = (byte[])obj;
334 
335 	    for (int i=0; i<numDataElems; i++) {
336 		bdata[i] = (byte)data.getElem(bankIndices[i],
337                                               pixelOffset + bandOffsets[i]);
338 	    }
339 
340 	    obj = (Object)bdata;
341 	    break;
342 
343 	case DataBuffer.TYPE_USHORT:
344 
345 	    short[] usdata;
346 
347 	    if (obj == null)
348 		usdata = new short[numDataElems];
349 	    else
350 		usdata = (short[])obj;
351 
352 	    for (int i=0; i<numDataElems; i++) {
353 		usdata[i] = (short)data.getElem(bankIndices[i],
354                                                pixelOffset + bandOffsets[i]);
355 	    }
356 
357 	    obj = (Object)usdata;
358 	    break;
359 
360 	case DataBuffer.TYPE_INT:
361 
362 	    int[] idata;
363 
364 	    if (obj == null)
365 		idata = new int[numDataElems];
366 	    else
367 		idata = (int[])obj;
368 
369 	    for (int i=0; i<numDataElems; i++) {
370 		idata[i] = data.getElem(bankIndices[i],
371                                         pixelOffset + bandOffsets[i]);
372 	    }
373 
374 	    obj = (Object)idata;
375 	    break;
376 
377         case DataBuffer.TYPE_SHORT:
378 
379             short[] sdata;
380 
381             if (obj == null)
382                 sdata = new short[numDataElems];
383             else
384                 sdata = (short[])obj;
385 
386             for (int i=0; i<numDataElems; i++) {
387                 sdata[i] = (short)data.getElem(bankIndices[i],
388                                                pixelOffset + bandOffsets[i]);
389             }
390 
391             obj = (Object)sdata;
392             break;
393 
394         case DataBuffer.TYPE_FLOAT:
395 
396             float[] fdata;
397 
398             if (obj == null)
399                 fdata = new float[numDataElems];
400             else
401                 fdata = (float[])obj;
402 
403             for (int i=0; i<numDataElems; i++) {
404                 fdata[i] = data.getElemFloat(bankIndices[i],
405                                              pixelOffset + bandOffsets[i]);
406             }
407 
408             obj = (Object)fdata;
409             break;
410 
411         case DataBuffer.TYPE_DOUBLE:
412 
413             double[] ddata;
414 
415             if (obj == null)
416                 ddata = new double[numDataElems];
417             else
418                 ddata = (double[])obj;
419 
420             for (int i=0; i<numDataElems; i++) {
421                 ddata[i] = data.getElemDouble(bankIndices[i],
422                                               pixelOffset + bandOffsets[i]);
423             }
424 
425             obj = (Object)ddata;
426             break;
427 
428 	default:
429             throw new RuntimeException(JaiI18N.getString("RasterFactory3"));
430 
431 	}
432 
433 	return obj;
434     }
435 
436 
437     /**
438      * Returns the pixel data for the specified rectangle of pixels in a
439      * primitive array of type TransferType.
440      * For image data supported by the Java 2D API, this
441      * will be one of the dataTypes supported by java.awt.image.DataBuffer.
442      * Data may be returned in a packed format, thus increasing efficiency
443      * for data transfers. Generally, obj should be passed in as null, so
444      * that the <code>Object</code> will be created automatically and will be of the right
445      * primitive data type.
446      * <p>
447      * The following code illustrates transferring data for a rectangular
448      * region of pixels from
449      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is described by
450      * <code>SampleModel</code> <code>sm1</code>, to <code>DataBuffer</code> <code>db2</code>, whose
451      * storage layout is described by <code>SampleModel</code> <code>sm2</code>.
452      * The transfer will generally be more efficient than using
453      * getPixels/setPixels.
454      * <pre>
455      *       SampleModel sm1, sm2;
456      *       DataBuffer db1, db2;
457      *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w,
458      *                           h, null, db1), db2);
459      * </pre>
460      * Using getDataElements/setDataElements to transfer between two
461      * <code>DataBuffer</code>/SampleModel pairs is legitimate if the <code>SampleModel</code>s have
462      * the same number of bands, corresponding bands have the same number of
463      * bits per sample, and the TransferTypes are the same.
464      * <p>
465      * @param x         The minimum X coordinate of the pixel rectangle.
466      * @param y         The minimum Y coordinate of the pixel rectangle.
467      * @param w         The width of the pixel rectangle.
468      * @param h         The height of the pixel rectangle.
469      * @param obj       If non-null, a primitive array in which to return
470      *                  the pixel data.
471      * @param data      The <code>DataBuffer</code> containing the image data.
472      * @see #getNumDataElements
473      * @see #getTransferType
474      * @see java.awt.image.DataBuffer
475      * @throws <code>ClassCastException</code> if obj is non-null and is not
476      *          a primitive array of type TransferType.
477      * @throws <code>ArrayIndexOutOfBoundsException</code> if the coordinates
478      *         are not in bounds, or if obj is non-null and is not large
479      *         enough to hold the pixel data.
480      */
getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data)481     public Object getDataElements(int x, int y, int w, int h,
482                                   Object obj, DataBuffer data) {
483 
484         int type = getTransferType();
485         int numDataElems = getNumDataElements();
486         int cnt = 0;
487         Object o = null;
488 
489         switch(type) {
490 
491         case DataBuffer.TYPE_BYTE: {
492             byte[] btemp;
493             byte[] bdata;
494 
495             if (obj == null)
496                 bdata = new byte[numDataElems*w*h];
497             else
498                 bdata = (byte[])obj;
499 
500             for (int i=y; i<y+h; i++) {
501                 for (int j=x; j<x+w; j++) {
502                     o = getDataElements(j, i, o, data);
503                     btemp = (byte[])o;
504                     for (int k=0; k<numDataElems; k++) {
505                         bdata[cnt++] = btemp[k];
506                     }
507                 }
508             }
509             obj = (Object)bdata;
510             break;
511         }
512 
513         case DataBuffer.TYPE_USHORT: {
514 
515             short[] usdata;
516             short[] ustemp;
517 
518             if (obj == null)
519                 usdata = new short[numDataElems*w*h];
520             else
521                 usdata = (short[])obj;
522 
523             for (int i=y; i<y+h; i++) {
524                 for (int j=x; j<x+w; j++) {
525                     o = getDataElements(j, i, o, data);
526                     ustemp = (short[])o;
527                     for (int k=0; k<numDataElems; k++) {
528                         usdata[cnt++] = ustemp[k];
529                     }
530                 }
531             }
532 
533             obj = (Object)usdata;
534             break;
535         }
536 
537         case DataBuffer.TYPE_INT: {
538 
539             int[] idata;
540             int[] itemp;
541 
542             if (obj == null)
543                 idata = new int[numDataElems*w*h];
544             else
545                 idata = (int[])obj;
546 
547             for (int i=y; i<y+h; i++) {
548                 for (int j=x; j<x+w; j++) {
549                     o = getDataElements(j, i, o, data);
550                     itemp = (int[])o;
551                     for (int k=0; k<numDataElems; k++) {
552                         idata[cnt++] = itemp[k];
553                     }
554                 }
555             }
556 
557             obj = (Object)idata;
558             break;
559         }
560 
561         case DataBuffer.TYPE_SHORT: {
562 
563             short[] sdata;
564             short[] stemp;
565 
566             if (obj == null)
567                 sdata = new short[numDataElems*w*h];
568             else
569                 sdata = (short[])obj;
570 
571             for (int i=y; i<y+h; i++) {
572                 for (int j=x; j<x+w; j++) {
573                     o = getDataElements(j, i, o, data);
574                     stemp = (short[])o;
575                     for (int k=0; k<numDataElems; k++) {
576                         sdata[cnt++] = stemp[k];
577                     }
578                 }
579             }
580 
581             obj = (Object)sdata;
582             break;
583         }
584 
585         case DataBuffer.TYPE_FLOAT: {
586 
587             float[] fdata;
588             float[] ftemp;
589 
590             if (obj == null)
591                 fdata = new float[numDataElems*w*h];
592             else
593                 fdata = (float[])obj;
594 
595             for (int i=y; i<y+h; i++) {
596                 for (int j=x; j<x+w; j++) {
597                     o = getDataElements(j, i, o, data);
598                     ftemp = (float[])o;
599                     for (int k=0; k<numDataElems; k++) {
600                         fdata[cnt++] = ftemp[k];
601                     }
602                 }
603             }
604 
605             obj = (Object)fdata;
606             break;
607         }
608 
609         case DataBuffer.TYPE_DOUBLE: {
610 
611             double[] ddata;
612             double[] dtemp;
613 
614             if (obj == null)
615                 ddata = new double[numDataElems*w*h];
616             else
617                 ddata = (double[])obj;
618 
619             for (int i=y; i<y+h; i++) {
620                 for (int j=x; j<x+w; j++) {
621                     o = getDataElements(j, i, o, data);
622                     dtemp = (double[])o;
623                     for (int k=0; k<numDataElems; k++) {
624                         ddata[cnt++] = dtemp[k];
625                     }
626                 }
627             }
628 
629             obj = (Object)ddata;
630             break;
631         }
632 
633 	default:
634             throw new RuntimeException(JaiI18N.getString("RasterFactory3"));
635         }
636 
637         return obj;
638     }
639 
640 
641 
642 
643 
644 
645     /**
646      * Sets the data for a single pixel in the specified <code>DataBuffer</code> from a
647      * primitive array of type TransferType.  For a <code>ComponentSampleModel</code>,
648      * this will be the same as the data type, and samples are transferred
649      * one per array element.
650      * <p>
651      * The following code illustrates transferring data for one pixel from
652      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is described by
653      * <code>ComponentSampleModel</code> <code>csm1</code>, to <code>DataBuffer</code> <code>db2</code>,
654      * whose storage layout is described by
655      * <code>ComponentSampleModel</code> <code>csm2</code>.
656      * The transfer will generally be more efficient than using
657      * getPixel/setPixel.
658      * <pre>
659      * 	     ComponentSampleModel csm1, csm2;
660      *	     DataBufferInt db1, db2;
661      * 	     csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
662      *                            db2);
663      * </pre>
664      * Using getDataElements/setDataElements to transfer between two
665      * <code>DataBuffer</code>/SampleModel pairs is legitimate if the <code>SampleModel</code>s have
666      * the same number of bands, corresponding bands have the same number of
667      * bits per sample, and the TransferTypes are the same.
668      * <p>
669      * @param x 	The X coordinate of the pixel location.
670      * @param y 	The Y coordinate of the pixel location.
671      * @param obj       A primitive array containing pixel data.
672      * @param data      The <code>DataBuffer</code> containing the image data.
673      * @throws <code>ClassCastException</code> if obj is non-null and is not
674      *          a primitive array of type TransferType.
675      * @throws <code>ArrayIndexOutOfBoundsException</code> if the coordinates
676      *         are not in bounds, or if obj is non-null and is not large
677      *         enough to hold the pixel data.
678      */
setDataElements(int x, int y, Object obj, DataBuffer data)679     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
680 
681 	int type = getTransferType();
682 	int numDataElems = getNumDataElements();
683 	int pixelOffset = y*scanlineStride + x*pixelStride;
684 
685 	switch(type) {
686 
687 	case DataBuffer.TYPE_BYTE:
688 
689 	    byte[] barray = (byte[])obj;
690 
691 	    for (int i=0; i<numDataElems; i++) {
692 		data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
693 			   ((int)barray[i])&0xff);
694 	    }
695 	    break;
696 
697 	case DataBuffer.TYPE_USHORT:
698 
699 	    short[] usarray = (short[])obj;
700 
701 	    for (int i=0; i<numDataElems; i++) {
702 		data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
703 			   ((int)usarray[i])&0xffff);
704 	    }
705 	    break;
706 
707 	case DataBuffer.TYPE_INT:
708 
709 	    int[] iarray = (int[])obj;
710 
711 	    for (int i=0; i<numDataElems; i++) {
712 		data.setElem(bankIndices[i],
713                              pixelOffset + bandOffsets[i], iarray[i]);
714 	    }
715 	    break;
716 
717         case DataBuffer.TYPE_SHORT:
718 
719             short[] sarray = (short[])obj;
720 
721             for (int i=0; i<numDataElems; i++) {
722                 data.setElem(bankIndices[i],
723                              pixelOffset + bandOffsets[i], sarray[i]);
724             }
725             break;
726 
727         case DataBuffer.TYPE_FLOAT:
728 
729             float[] farray = (float[])obj;
730 
731             for (int i=0; i<numDataElems; i++) {
732                 data.setElemFloat(bankIndices[i],
733                                   pixelOffset + bandOffsets[i], farray[i]);
734             }
735             break;
736 
737         case DataBuffer.TYPE_DOUBLE:
738 
739             double[] darray = (double[])obj;
740 
741             for (int i=0; i<numDataElems; i++) {
742                 data.setElemDouble(bankIndices[i],
743                                    pixelOffset + bandOffsets[i], darray[i]);
744             }
745             break;
746 
747 	default:
748             throw new RuntimeException(JaiI18N.getString("RasterFactory3"));
749 	}
750     }
751 
752     /**
753      * Sets the data for a rectangle of pixels in the specified <code>DataBuffer</code>
754      * from a primitive array of type TransferType.  For image data supported
755      * by the Java 2D API, this will be one of the dataTypes supported by
756      * java.awt.image.DataBuffer.  Data in the array may be in a packed
757      * format, thus increasing efficiency for data transfers.
758      * <p>
759      * The following code illustrates transferring data for a rectangular
760      * region of pixels from
761      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is described by
762      * <code>SampleModel</code> <code>sm1</code>, to <code>DataBuffer</code> <code>db2</code>, whose
763      * storage layout is described by <code>SampleModel</code> <code>sm2</code>.
764      * The transfer will generally be more efficient than using
765      * getPixels/setPixels.
766      * <pre>
767      *       SampleModel sm1, sm2;
768      *       DataBuffer db1, db2;
769      *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w, h,
770      *                           null, db1), db2);
771      * </pre>
772      * Using getDataElements/setDataElements to transfer between two
773      * <code>DataBuffer</code>/SampleModel pairs is legitimate if the <code>SampleModel</code>s have
774      * the same number of bands, corresponding bands have the same number of
775      * bits per sample, and the TransferTypes are the same.
776      * <p>
777      * @param x         The minimum X coordinate of the pixel rectangle.
778      * @param y         The minimum Y coordinate of the pixel rectangle.
779      * @param w         The width of the pixel rectangle.
780      * @param h         The height of the pixel rectangle.
781      * @param obj       A primitive array containing pixel data.
782      * @param data      The <code>DataBuffer</code> containing the image data.
783      * @throws <code>ClassCastException</code> if obj is non-null and is not
784      *          a primitive array of type TransferType.
785      * @throws <code>ArrayIndexOutOfBoundsException</code> if the coordinates
786      *         are not in bounds, or if obj is non-null and is not large
787      *         enough to hold the pixel data.
788      * @see #getNumDataElements
789      * @see #getTransferType
790      * @see java.awt.image.DataBuffer
791      */
setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data)792     public void setDataElements(int x, int y, int w, int h,
793                                 Object obj, DataBuffer data) {
794         int cnt = 0;
795         Object o = null;
796         int type = getTransferType();
797         int numDataElems = getNumDataElements();
798 
799         switch(type) {
800 
801         case DataBuffer.TYPE_BYTE: {
802 
803             byte[] barray = (byte[])obj;
804             byte[] btemp = new byte[numDataElems];
805 
806             for (int i=y; i<y+h; i++) {
807                 for (int j=x; j<x+w; j++) {
808                     for (int k=0; k<numDataElems; k++) {
809                         btemp[k] = barray[cnt++];
810                     }
811 
812                     setDataElements(j, i, btemp, data);
813                 }
814             }
815             break;
816         }
817 
818         case DataBuffer.TYPE_USHORT: {
819 
820             short[] usarray = (short[])obj;
821             short[] ustemp = new short[numDataElems];
822 
823             for (int i=y; i<y+h; i++) {
824                 for (int j=x; j<x+w; j++) {
825                     for (int k=0; k<numDataElems; k++) {
826                         ustemp[k] = usarray[cnt++];
827                     }
828                     setDataElements(j, i, ustemp, data);
829                 }
830             }
831             break;
832         }
833 
834         case DataBuffer.TYPE_INT: {
835 
836             int[] iArray = (int[])obj;
837             int[] itemp = new int[numDataElems];
838 
839             for (int i=y; i<y+h; i++) {
840                 for (int j=x; j<x+w; j++) {
841                     for (int k=0; k<numDataElems; k++) {
842                         itemp[k] = iArray[cnt++];
843                     }
844 
845                     setDataElements(j, i, itemp, data);
846                 }
847             }
848             break;
849         }
850 
851         case DataBuffer.TYPE_SHORT: {
852 
853             short[] sArray = (short[])obj;
854             short[] stemp = new short[numDataElems];
855 
856             for (int i=y; i<y+h; i++) {
857                 for (int j=x; j<x+w; j++) {
858                     for (int k=0; k<numDataElems; k++) {
859                         stemp[k] = sArray[cnt++];
860                     }
861 
862                     setDataElements(j, i, stemp, data);
863                 }
864             }
865             break;
866         }
867 
868         case DataBuffer.TYPE_FLOAT: {
869 
870             float[] fArray = (float[])obj;
871             float[] ftemp = new float[numDataElems];
872 
873             for (int i=y; i<y+h; i++) {
874                 for (int j=x; j<x+w; j++) {
875                     for (int k=0; k<numDataElems; k++) {
876                         ftemp[k] = fArray[cnt++];
877                     }
878 
879                     setDataElements(j, i, ftemp, data);
880                 }
881             }
882             break;
883         }
884 
885         case DataBuffer.TYPE_DOUBLE: {
886 
887             double[] dArray = (double[])obj;
888             double[] dtemp = new double[numDataElems];
889 
890             for (int i=y; i<y+h; i++) {
891                 for (int j=x; j<x+w; j++) {
892                     for (int k=0; k<numDataElems; k++) {
893                         dtemp[k] = dArray[cnt++];
894                     }
895 
896                     setDataElements(j, i, dtemp, data);
897                 }
898             }
899             break;
900         }
901 
902 	default:
903             throw new RuntimeException(JaiI18N.getString("RasterFactory3"));
904         }
905     }
906 
907     /**
908      * Sets a sample in the specified band for the pixel located at (x,y)
909      * in the <code>DataBuffer</code> using a <code>float</code> for input.
910      * <code>ArrayIndexOutOfBoundsException</code> may be thrown if the coordinates are
911      * not in bounds.
912      * @param x 	The X coordinate of the pixel location.
913      * @param y 	The Y coordinate of the pixel location.
914      * @param b 	The band to set.
915      * @param s 	The input sample as a <code>float</code>.
916      * @param data 	The <code>DataBuffer</code> containing the image data.
917      *
918      * @throws <code>ArrayIndexOutOfBoundsException</code> if coordinates are not in bounds
919      */
setSample(int x, int y, int b, float s, DataBuffer data)920     public void setSample(int x, int y, int b,
921                           float s,
922                           DataBuffer data) {
923         data.setElemFloat(bankIndices[b],
924                           y*scanlineStride + x*pixelStride + bandOffsets[b],
925                           s);
926     }
927 
928     /**
929      * Returns the sample in a specified band
930      * for the pixel located at (x,y) as a <code>float</code>.
931      * <code>ArrayIndexOutOfBoundsException</code> may be thrown if the coordinates are
932      * not in bounds.
933      * @param x 	The X coordinate of the pixel location.
934      * @param y 	The Y coordinate of the pixel location.
935      * @param b 	The band to return.
936      * @param data 	The <code>DataBuffer</code> containing the image data.
937      * @return sample   The floating point sample value
938      * @throws <code>ArrayIndexOutOfBoundsException</code> if coordinates are not in bounds
939      */
getSampleFloat(int x, int y, int b, DataBuffer data)940     public float getSampleFloat(int x, int y, int b,
941                                 DataBuffer data) {
942         float sample =
943             data.getElemFloat(bankIndices[b],
944                               y*scanlineStride + x*pixelStride +
945                               bandOffsets[b]);
946         return sample;
947     }
948 
949     /**
950      * Sets a sample in the specified band for the pixel located at (x,y)
951      * in the <code>DataBuffer</code> using a <code>double</code> for input.
952      * <code>ArrayIndexOutOfBoundsException</code> may be thrown if the coordinates are
953      * not in bounds.
954      * @param x 	The X coordinate of the pixel location.
955      * @param y 	The Y coordinate of the pixel location.
956      * @param b 	The band to set.
957      * @param s 	The input sample as a <code>double</code>.
958      * @param data 	The <code>DataBuffer</code> containing the image data.
959      *
960      * @throws <code>ArrayIndexOutOfBoundsException</code> if coordinates are not in bounds
961      */
setSample(int x, int y, int b, double s, DataBuffer data)962     public void setSample(int x, int y, int b,
963                           double s,
964                           DataBuffer data) {
965         data.setElemDouble(bankIndices[b],
966                            y*scanlineStride + x*pixelStride + bandOffsets[b],
967                            s);
968     }
969 
970     /**
971      * Returns the sample in a specified band
972      * for a pixel located at (x,y) as a <code>double</code>.
973      * <code>ArrayIndexOutOfBoundsException</code> may be thrown if the coordinates are
974      * not in bounds.
975      * @param x 	The X coordinate of the pixel location.
976      * @param y 	The Y coordinate of the pixel location.
977      * @param b 	The band to return.
978      * @param data 	The <code>DataBuffer</code> containing the image data.
979      * @return sample   The <code>double</code> sample value
980      * @throws <code>ArrayIndexOutOfBoundsException</code> if coordinates are not in bounds
981      */
getSampleDouble(int x, int y, int b, DataBuffer data)982     public double getSampleDouble(int x, int y, int b,
983                                   DataBuffer data) {
984         double sample =
985             data.getElemDouble(bankIndices[b],
986                                y*scanlineStride + x*pixelStride +
987                                bandOffsets[b]);
988         return sample;
989     }
990 
991     /**
992      * Returns all samples for a rectangle of pixels in a <code>double</code>
993      * array, one sample per array element.
994      * <code>ArrayIndexOutOfBoundsException</code> may be thrown if the coordinates are
995      * not in bounds.
996      * @param x         The X coordinate of the upper left pixel location.
997      * @param y         The Y coordinate of the upper left pixel location.
998      * @param w         The width of the pixel rectangle.
999      * @param h         The height of the pixel rectangle.
1000      * @param dArray    If non-null, returns the samples in this array.
1001      * @param data      The <code>DataBuffer</code> containing the image data.
1002      * @throws <code>ArrayIndexOutOfBoundsException</code> if coordinates are not in bounds
1003      */
getPixels(int x, int y, int w, int h, double dArray[], DataBuffer data)1004     public double[] getPixels(int x, int y, int w, int h,
1005                               double dArray[], DataBuffer data) {
1006         double pixels[];
1007         int    Offset = 0;
1008 
1009         if (dArray != null)
1010             pixels = dArray;
1011         else
1012             pixels = new double[numBands * w * h];
1013 
1014         for (int i=y; i<(h+y); i++) {
1015             for (int j=x; j<(w+x); j++) {
1016                 for (int k=0; k<numBands; k++) {
1017                     pixels[Offset++] = getSampleDouble(j, i, k, data);
1018                 }
1019             }
1020         }
1021 
1022         return pixels;
1023     }
1024 
1025     /** Returns a <code>String</code> containing the values of all valid fields. */
toString()1026     public String toString() {
1027         String ret =  "ComponentSampleModelJAI: " +
1028                        "  dataType=" + this.getDataType() +
1029                        "  numBands=" + this.getNumBands() +
1030                        "  width=" +this.getWidth() +
1031                        "  height=" +this.getHeight() +
1032                        "  bandOffsets=[ ";
1033         for (int i = 0; i < numBands; i++) {
1034             ret += this.getBandOffsets()[i] + " ";
1035         }
1036         ret += "]";
1037         return ret;
1038     }
1039 }
1040 
1041