1 /*
2  * $RCSfile: RasterAccessor.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:18 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.mediax.jai;
13 import java.awt.image.SampleModel;
14 import java.awt.image.ComponentSampleModel;
15 import java.awt.image.DataBuffer;
16 import java.awt.image.DataBufferByte;
17 import java.awt.image.DataBufferUShort;
18 import java.awt.image.DataBufferShort;
19 import java.awt.image.DataBufferInt;
20 import java.awt.image.Raster;
21 import java.awt.image.WritableRaster;
22 import java.awt.Rectangle;
23 import java.awt.image.RenderedImage;
24 import java.awt.image.ColorModel;
25 import java.awt.image.IndexColorModel;
26 import java.awt.image.ComponentColorModel;
27 import com.lightcrafts.media.jai.util.DataBufferUtils;
28 import com.lightcrafts.media.jai.util.ImageUtil;
29 
30 /**
31  * An adapter class for presenting non-binary image data in a
32  * <code>ComponentSampleModel</code> format and binary image data in
33  * a zero-offset byte array format even when the original data are not
34  * so stored.  <code>RasterAccessor</code> is meant to make the common
35  * (<code>ComponentSampleModel</code>) case fast and other formats
36  * possible without forcing the <code>OpImage</code> writer to cover more
37  * than one case per non-binary data type.
38  *
39  * <p>When constructing a <code>RasterAccessor</code> with a source(s) that
40  * has an IndexColorModel and a destination that has a
41  * non-<code>IndexColorModel</code>, <code>RasterAccessor</code> will
42  * perform expansion of the source pixels. If the source(s) and the
43  * destination have an IndexColorModel, then <code>RasterAccessor</code>
44  * will assume that the operation can correctly process an IndexColorModel
45  * source and will not expand the source pixels (colormap indices) into
46  * color components. Refer to {@link JAI#KEY_REPLACE_INDEX_COLOR_MODEL}
47  * for a mechanism by which the destination image's <code>ColorModel</code>
48  * is set to a non-<code>IndexColorModel</code> to cause
49  * <code>RasterAccessor</code> to expand the source's
50  * <code>IndexColorModel</code>.
51  *
52  * <p> Binary data are handled as a special case.  In general image data
53  * are considered to be binary when the image has a single-banded
54  * <code>MultiPixelPackedSampleModel</code> with one bit per pixel.  This
55  * may be verified by invoking the <code>isBinary()</code> method.  For this
56  * case the methods <code>getBinaryDataArray()</code> and
57  * <code>copyBinaryDataToRaster()</code> should be used to access and set,
58  * respectively, the binary data in packed form.  If the binary data are
59  * to be accessed in expanded form, i.e., as bytes, then the usual byte
60  * methods <code>getByteDataArray()</code>, <code>getByteDataArrays()</code>,
61  * and <code>copyDataToRaster()</code> should be used.
62  *
63  */
64 public class RasterAccessor {
65 
66     /**
67      * Value indicating how far COPY_MASK info is shifted to avoid
68      * interfering with the data type info.
69      */
70     private static final int COPY_MASK_SHIFT = 7;
71 
72     /* Value indicating how many bits the COPY_MASK is */
73     private static final int COPY_MASK_SIZE = 2;
74 
75     /** The bits of a FormatTag associated with how dataArrays are obtained. */
76     public static final int COPY_MASK =
77         ((1 << COPY_MASK_SIZE) - 1) << COPY_MASK_SHIFT;
78 
79     /** Flag indicating data is raster's data. */
80     public static final int UNCOPIED = 0x0 << COPY_MASK_SHIFT;
81 
82     /** Flag indicating data is a copy of the raster's data. */
83     public static final int COPIED = 0x1 << COPY_MASK_SHIFT;
84 
85     /**
86      * Value indicating how far EXPANSION_MASK info is shifted to avoid
87      * interfering with the data type info.
88      */
89     private static final int EXPANSION_MASK_SHIFT =
90         COPY_MASK_SHIFT+COPY_MASK_SIZE;
91 
92     /** Value indicating how many bits the EXPANSION_MASK is */
93     private static final int EXPANSION_MASK_SIZE = 2;
94 
95     /** The bits of a FormatTag associated with how ColorModels are used. */
96     public static final int EXPANSION_MASK =
97         ((1 << EXPANSION_MASK_SIZE) - 1) << EXPANSION_MASK_SHIFT;
98 
99     /** Flag indicating ColorModel data should be used only in copied case */
100     public static final int DEFAULTEXPANSION = 0x0 << EXPANSION_MASK_SHIFT;
101 
102     /** Flag indicating ColorModel data should be interpreted. */
103     public static final int EXPANDED = 0x1 << EXPANSION_MASK_SHIFT;
104 
105     /** Flag indicating ColorModel info should be ignored */
106     public static final int UNEXPANDED = 0x02 << EXPANSION_MASK_SHIFT;
107 
108     /** The bits of a FormatTagID associated with pixel datatype. */
109     public static final int DATATYPE_MASK = (0x1 << COPY_MASK_SHIFT) - 1;
110 
111     /** FormatTagID indicating data in byte arrays and uncopied. */
112     public static final int
113         TAG_BYTE_UNCOPIED = DataBuffer.TYPE_BYTE | UNCOPIED;
114 
115     /** FormatTagID indicating data in unsigned short arrays and uncopied. */
116     public static final int
117         TAG_USHORT_UNCOPIED = DataBuffer.TYPE_USHORT | UNCOPIED;
118 
119     /** FormatTagID indicating data in short arrays and uncopied. */
120     public static final int
121         TAG_SHORT_UNCOPIED = DataBuffer.TYPE_SHORT | UNCOPIED;
122 
123     /** FormatTagID indicating data in int arrays and uncopied. */
124     public static final int
125         TAG_INT_UNCOPIED = DataBuffer.TYPE_INT | UNCOPIED;
126 
127     /** FormatTagID indicating data in float arrays and uncopied. */
128     public static final int
129         TAG_FLOAT_UNCOPIED = DataBuffer.TYPE_FLOAT | UNCOPIED;
130 
131     /** FormatTagID indicating data in double arrays and uncopied. */
132     public static final int
133         TAG_DOUBLE_UNCOPIED = DataBuffer.TYPE_DOUBLE | UNCOPIED;
134 
135     /** FormatTagID indicating data in int arrays and copied. */
136     public static final int
137         TAG_INT_COPIED = DataBuffer.TYPE_INT | COPIED;
138 
139     /** FormatTagID indicating data in float arrays and copied. */
140     public static final int
141         TAG_FLOAT_COPIED = DataBuffer.TYPE_FLOAT | COPIED;
142 
143     /** FormatTagID indicating data in double arrays and copied. */
144     public static final int
145         TAG_DOUBLE_COPIED = DataBuffer.TYPE_DOUBLE | COPIED;
146 
147     /** FormatTagID indicating data in byte arrays and expanded. */
148     public static final int
149         TAG_BYTE_EXPANDED = DataBuffer.TYPE_BYTE | EXPANDED;
150 
151     /**
152      * FormatTagID corresponding to the binary case.  This occurs when
153      * the image has a <code>MultiPixelPackedSampleModel</code> with a
154      * single band and one bit per pixel.
155      */
156     private static final int TAG_BINARY =
157         DataBuffer.TYPE_BYTE | COPIED | UNEXPANDED;
158 
159     /** The raster that is the source of pixel data. */
160     protected Raster raster;
161 
162     /** The width of the rectangle this RasterAccessor addresses. */
163     protected int rectWidth;
164 
165     /** The height of the rectangle this RasterAccessor addresses. */
166     protected int rectHeight;
167 
168     /** The x coordinate of upper-left corner of the rectangle this
169      *  RasterAccessor addresses.
170      */
171     protected int rectX;
172 
173     /** The y coordinate of upper-left corner of the rectangle this
174      *  RasterAccessor addresses.
175      */
176     protected int rectY;
177 
178     /** Tag indicating the data type of the data and whether it's copied */
179     protected int formatTagID;
180 
181     /**
182      * The image data for the binary case.  The data will be packed as
183      * eight bits per byte with no bit offset, i.e., the first bit in each
184      * image line will be the left-most bit of the first byte of the line.
185      * The line stride in bytes will be <code>(int)((rectWidth+7)/8)</code>.
186      * The length of the array will be <code>rectHeight</code> multiplied
187      * by the line stride.
188      *
189      * @since JAI 1.1
190      */
191     protected byte binaryDataArray[] = null;
192 
193     /**
194      *  The image data in a two-dimensional byte array.  This
195      *  value will be non-null only if getDataType() returns
196      *  DataBuffer.TYPE_BYTE.  byteDataArrays.length will equal
197      *  numBands.  Note that often the numBands subArrays will all
198      *  point to the same place in memory.
199      *
200      *  <p> For the case of binary data this variable will not be initialized
201      *  until <code>getByteDataArrays()</code> or
202      *  <code>getByteDataArray(int b)</code> is invoked.
203      */
204     protected byte byteDataArrays[][] = null;
205 
206     /**
207      *  The image data in a two-dimensional short array.  This
208      *  value will be non-null only if getDataType() returns
209      *  DataBuffer.TYPE_USHORT or DataBuffer.TYPE_SHORT.
210      *  shortDataArrays.length will equal
211      *  numBands.  Note that often the numBands subArrays will all
212      *  point to the same place in memory.
213      */
214     protected short shortDataArrays[][] = null;
215 
216     /**
217      *  The image data in a two-dimensional int array.  This
218      *  value will be non-null only if getDataType() returns
219      *  DataBuffer.TYPE_INT.  intDataArrays.length will equal
220      *  numBands.  Note that often the numBands subArrays will all
221      *  point to the same place in memory.
222      */
223     protected int intDataArrays[][] = null;
224 
225     /**
226      *  The image data in a two-dimensional float array.  This
227      *  value will be non-null only if getDataType() returns
228      *  DataBuffer.TYPE_FLOAT.  floatDataArrays.length will equal
229      *  numBands.  Note that often the numBand subArrays will all
230      *  point to the same place in memory.
231      */
232     protected float floatDataArrays[][] = null;
233 
234     /**
235      *  The image data in a two-dimensional double array.  This
236      *  value will be non-null only if getDataType() returns
237      *  DataBuffer.TYPE_DOUBLE.  doubleDataArrays.length will equal
238      *  numBands.  Note that often the numBand subArrays will all
239      *  point to the same place in memory.
240      */
241     protected double doubleDataArrays[][] = null;
242 
243     /**
244      * The bandOffset + subRasterOffset + DataBufferOffset into each of
245      * the numBand data arrays
246      */
247     protected int bandDataOffsets[];
248 
249     /** Offset from a pixel's offset to a band of that pixel */
250     protected int bandOffsets[];
251 
252     /** The number of bands per pixel in the data array. */
253     protected int numBands;
254 
255     /** The scanline stride of the image data in each data array */
256     protected int scanlineStride;
257 
258     /** The pixel stride of the image data in each data array */
259     protected int pixelStride;
260 
261     /**
262      * Finds the appropriate tags for the constructor, based on the
263      * SampleModel and ColorModel of all the source and destination.
264      *
265      * @param srcs The operations sources; may be <code>null</code> which
266      * is taken to be equivalent to zero sources.
267      * @param dst The operation destination.
268      * @return An array containing <code>RasterFormatTag</code>s for the
269      * sources in the first src.length elements and a
270      * <code>RasterFormatTag</code> for the destination in the last element.
271      * @throws NullPointerException if <code>dst</code> is <code>null</code>.
272      */
273     public static
findCompatibleTags(RenderedImage srcs[], RenderedImage dst)274     RasterFormatTag[] findCompatibleTags(RenderedImage srcs[],
275                                          RenderedImage dst) {
276         int tagIDs[];
277         if (srcs != null) {
278            tagIDs = new int[srcs.length + 1];
279         } else {
280            tagIDs = new int[1];
281 	}
282         SampleModel dstSampleModel = dst.getSampleModel();
283         int dstDataType = dstSampleModel.getTransferType();
284 
285         int defaultDataType = dstDataType;
286         boolean binaryDst = ImageUtil.isBinary(dstSampleModel);
287         if (binaryDst) {
288             defaultDataType = DataBuffer.TYPE_BYTE;
289         } else if((dstDataType == DataBuffer.TYPE_BYTE) ||
290             (dstDataType == DataBuffer.TYPE_USHORT) ||
291             (dstDataType == DataBuffer.TYPE_SHORT)) {
292             defaultDataType = DataBuffer.TYPE_INT;
293         }
294 
295         // use highest precision datatype of all srcs & dst
296         if (srcs != null) {
297             int numSources = srcs.length;
298             int i;
299             for (i = 0; i < numSources; i++) {
300                 SampleModel srcSampleModel = srcs[i].getSampleModel();
301                 int srcDataType = srcSampleModel.getTransferType();
302                 if (!(binaryDst && ImageUtil.isBinary(srcSampleModel)) &&
303                     srcDataType > defaultDataType) {
304                     defaultDataType = srcDataType;
305                 }
306             }
307         }
308 
309         // Set the tag. For binary data at this point this should
310         // equal DataBuffer.TYPE_BYTE | COPIED.
311         int tagID = defaultDataType | COPIED;
312 
313         if (dstSampleModel instanceof ComponentSampleModel) {
314             if (srcs != null) {
315                int numSources = srcs.length;
316                int i;
317                for (i = 0; i < numSources; i++) {
318                    SampleModel srcSampleModel = srcs[i].getSampleModel();
319                    int srcDataType = srcSampleModel.getTransferType();
320                    if (!(srcSampleModel instanceof ComponentSampleModel) ||
321                        (srcDataType != dstDataType)) {
322                        break;
323                    }
324                }
325                if (i == numSources) {
326                    tagID = dstDataType | UNCOPIED;
327                }
328             } else {
329                tagID = dstDataType | UNCOPIED;
330             }
331         }
332 
333         // If the source has an IndexColorModel but the dest does not,
334         // perform expansion of the source pixels.  If both have an
335         // IndexColorModel, assume the operation knows what it is doing.
336         RasterFormatTag rft[] = new RasterFormatTag[tagIDs.length];
337         if (srcs != null) {
338             for (int i = 0; i < srcs.length; i++) {
339                 // dst can't be EXPANDED
340                 if ((srcs[i].getColorModel() instanceof IndexColorModel)) {
341                     if (dst.getColorModel() instanceof IndexColorModel) {
342                         tagIDs[i] = tagID | UNEXPANDED;
343                     } else {
344                         tagIDs[i] = tagID | EXPANDED;
345                     }
346                 } else if (srcs[i].getColorModel() instanceof
347                            ComponentColorModel ||
348                            (binaryDst &&
349                             ImageUtil.isBinary(srcs[i].getSampleModel()))){
350                     tagIDs[i] = tagID | UNEXPANDED;
351                 } else {
352 		    tagIDs[i] = tagID | DEFAULTEXPANSION;
353 	        }
354             }
355             tagIDs[srcs.length] = tagID | UNEXPANDED;
356 
357             for (int i = 0; i < srcs.length; i++) {
358                 rft[i] =
359                    new RasterFormatTag(srcs[i].getSampleModel(), tagIDs[i]);
360             }
361             // get the dest
362             rft[srcs.length] =
363                    new RasterFormatTag(dstSampleModel,tagIDs[srcs.length]);
364         } else {	// no sources, dest only
365             rft[0] = new RasterFormatTag(dstSampleModel, tagID | UNEXPANDED);
366         }
367 
368         return rft;
369     }
370 
371     /**
372      * Returns the most efficient FormatTagID that is compatible with
373      * the destination SampleModel and all source SampleModels.
374      * Since there is no <code>ColorModel</code> associated with
375      * a <code>SampleModel</code>, this method does not expand the data
376      * buffer as it has no access to the Raster's ColorModel.
377      */
findCompatibleTag(SampleModel[] srcSampleModels, SampleModel dstSampleModel)378     public static int findCompatibleTag(SampleModel[] srcSampleModels,
379                                         SampleModel dstSampleModel) {
380         int dstDataType = dstSampleModel.getTransferType();
381 
382         int tag = dstDataType | COPIED;
383         if (ImageUtil.isBinary(dstSampleModel)) {
384             tag = DataBuffer.TYPE_BYTE | COPIED;
385         } else if (dstDataType == DataBuffer.TYPE_BYTE ||
386             dstDataType == DataBuffer.TYPE_USHORT ||
387             dstDataType == DataBuffer.TYPE_SHORT) {
388             tag = TAG_INT_COPIED;
389         }
390 
391         if (dstSampleModel instanceof ComponentSampleModel) {
392             if (srcSampleModels != null) {
393                int numSources = srcSampleModels.length;
394                int i;
395                for (i = 0; i < numSources; i++) {
396                    int srcDataType = srcSampleModels[i].getTransferType();
397 
398                    if (!(srcSampleModels[i] instanceof ComponentSampleModel) ||
399                        srcDataType != dstDataType) {
400                        break;
401                    }
402                }
403                if (i == numSources) {
404                    tag = dstDataType | UNCOPIED;
405                }
406             } else {
407                tag = dstDataType | UNCOPIED;
408             }
409         }
410         return tag | UNEXPANDED;  // only called when colormodel not around
411                                   // so never expand
412     }
413 
414 
415     /**
416      * Constructs a RasterAccessor object out of a Raster, Rectangle
417      * and formatTagID returned from RasterFormat.findCompatibleTag().
418      *
419      * <p> The <code>RasterFormatTag</code> must agree with the raster's
420      * <code>SampleModel</code> and <code>ColorModel</code>.  It is best
421      * to obtain the correct tag using the <code>findCompatibleTags</code>
422      * static method.
423      *
424      * @param raster The raster to be accessed
425      * @param rect   A <code>Rectangle</code> from the raster to be accessed
426      * @param rft    The <code>RasterFormatTag</code> associated with the Raster
427      * @param theColorModel The <code>ColorModel</code> for color components
428      *
429      * @throws ClassCastException if the data type of
430      *         <code>RasterFormatTag</code> does not agree with the actual
431      *         data type of the <code>Raster</code>.
432      * @throws IllegalArgumentException if <code>raster</code>,
433      *         <code>rect</code>, or <code>rft</code> is <code>null</code>.
434      * @throws IllegalArgumentException if the <code>Rectangle</code>
435      *         is not contained within <code>Raster</code>'s bounds.
436      */
RasterAccessor(Raster raster, Rectangle rect, RasterFormatTag rft, ColorModel theColorModel)437     public RasterAccessor(Raster raster,
438                           Rectangle rect,
439                           RasterFormatTag rft,
440                           ColorModel theColorModel) {
441 
442         if(raster == null || rect == null || rft == null) {
443 	    throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
444         }
445 
446 	// If requesting a region that lies outside the bounds,
447 	// throw an exception.
448 	if (!raster.getBounds().contains(rect)) {
449             throw new IllegalArgumentException(
450 			JaiI18N.getString("RasterAccessor2"));
451 	}
452 
453         this.raster = raster;
454         this.rectX = rect.x;
455         this.rectY = rect.y;
456         this.rectWidth = rect.width;
457         this.rectHeight = rect.height;
458         this.formatTagID = rft.getFormatTagID();
459         if ((formatTagID & COPY_MASK) == UNCOPIED) {
460 
461             this.numBands = rft.getNumBands();
462             this.pixelStride = rft.getPixelStride();
463 
464             ComponentSampleModel csm =
465                 (ComponentSampleModel)raster.getSampleModel();
466             this.scanlineStride = csm.getScanlineStride();
467 
468             int bankIndices[] = null;
469 
470             // if the rft isPixelSequential we can rely on it's
471             // version of bandOffsets and bankIndicies.  If it's
472             // not the SampleModel passed in might not completely
473             // match the one that was passed to the the
474             // RasterFormatTag constructor so we have to get them
475             // from the passed in Raster/SampleModel
476             if (rft.isPixelSequential()) {
477                 this.bandOffsets = rft.getBandOffsets();
478                 bankIndices = rft.getBankIndices();
479             } else {
480                 this.bandOffsets = csm.getBandOffsets();
481                 bankIndices = csm.getBankIndices();
482             }
483 
484             this.bandDataOffsets = new int[numBands];
485 
486 	    int dataBufferOffsets[] = raster.getDataBuffer().getOffsets();
487 
488             int subRasterOffset =
489              (rectY-raster.getSampleModelTranslateY())*scanlineStride+
490              (rectX-raster.getSampleModelTranslateX())*pixelStride;
491 
492             if (dataBufferOffsets.length == 1) {
493                 int theDataBufferOffset = dataBufferOffsets[0];
494                 for (int i = 0; i < numBands; i++) {
495                     bandDataOffsets[i] = bandOffsets[i] +
496                           theDataBufferOffset + subRasterOffset;
497                 }
498             } else if (dataBufferOffsets.length == bandDataOffsets.length) {
499                 for (int i = 0; i < numBands; i++) {
500                     bandDataOffsets[i] = bandOffsets[i] +
501                         dataBufferOffsets[i] + subRasterOffset;
502                 }
503             } else {
504             throw new RuntimeException(JaiI18N.getString("RasterAccessor0"));
505             }
506 
507             switch (formatTagID & DATATYPE_MASK) {
508             case DataBuffer.TYPE_BYTE:
509                 DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer();
510                 byteDataArrays = new byte[numBands][];
511                 for (int i = 0; i < numBands; i++) {
512                     byteDataArrays[i] = dbb.getData(bankIndices[i]);
513                 }
514                 break;
515 
516             case DataBuffer.TYPE_USHORT:
517                 DataBufferUShort dbus =
518                     (DataBufferUShort)raster.getDataBuffer();
519                 shortDataArrays = new short[numBands][];
520                 for (int i = 0; i < numBands; i++) {
521                     shortDataArrays[i] = dbus.getData(bankIndices[i]);
522                 }
523                 break;
524 
525             case DataBuffer.TYPE_SHORT:
526                 DataBufferShort dbs = (DataBufferShort)raster.getDataBuffer();
527                 shortDataArrays = new short[numBands][];
528                 for (int i = 0; i < numBands; i++) {
529                     shortDataArrays[i] = dbs.getData(bankIndices[i]);
530                 }
531                 break;
532 
533             case DataBuffer.TYPE_INT:
534                 DataBufferInt dbi = (DataBufferInt)raster.getDataBuffer();
535                 intDataArrays = new int[numBands][];
536                 for (int i = 0; i < numBands; i++) {
537                     intDataArrays[i] = dbi.getData(bankIndices[i]);
538                 }
539                 break;
540 
541             case DataBuffer.TYPE_FLOAT:
542                 DataBuffer dbf = (DataBuffer)raster.getDataBuffer();
543                 floatDataArrays = new float[numBands][];
544                 for (int i = 0; i < numBands; i++) {
545                     floatDataArrays[i] =
546                         DataBufferUtils.getDataFloat(dbf, bankIndices[i]);
547                 }
548                 break;
549 
550             case DataBuffer.TYPE_DOUBLE:
551                 DataBuffer dbd = (DataBuffer)raster.getDataBuffer();
552                 doubleDataArrays = new double[numBands][];
553                 for (int i = 0; i < numBands; i++) {
554                     doubleDataArrays[i] =
555                         DataBufferUtils.getDataDouble(dbd, bankIndices[i]);
556                 }
557                 break;
558             }
559             // only do this if not copied and expanded
560             if ((formatTagID & EXPANSION_MASK) == EXPANDED &&
561                 theColorModel instanceof IndexColorModel) {
562                 IndexColorModel icm = (IndexColorModel)theColorModel;
563 
564                 int newNumBands = icm.getNumComponents();
565 
566                 int mapSize = icm.getMapSize();
567                 int newBandDataOffsets[] = new int[newNumBands];
568                 int newScanlineStride = rectWidth*newNumBands;
569                 int newPixelStride = newNumBands;
570                 byte ctable[][] = new byte[newNumBands][mapSize];
571 
572                 icm.getReds(ctable[0]);
573                 icm.getGreens(ctable[1]);
574                 icm.getBlues(ctable[2]);
575                 byte rtable[] = ctable[0];
576                 byte gtable[] = ctable[1];
577                 byte btable[] = ctable[2];
578 
579                 byte atable[] = null;
580                 if (newNumBands == 4) {
581                     icm.getAlphas(ctable[3]);
582                     atable = ctable[3];
583                 }
584 
585                 for (int i = 0; i < newNumBands; i++) {
586                     newBandDataOffsets[i] = i;
587                 }
588 
589                 switch (formatTagID & DATATYPE_MASK) {
590                 case DataBuffer.TYPE_BYTE: {
591                     byte newBArray[] =
592                         new byte[rectWidth*rectHeight*newNumBands];
593                     byte byteDataArray[] = byteDataArrays[0];
594                     int scanlineOffset = bandDataOffsets[0];
595                     int newScanlineOffset = 0;
596                     for (int j = 0; j < rectHeight; j++)  {
597                         int pixelOffset = scanlineOffset;
598                         int newPixelOffset = newScanlineOffset;
599                         for (int i = 0; i < rectWidth; i++)  {
600                             int index = byteDataArray[pixelOffset] & 0xff;
601                             for (int k = 0; k < newNumBands; k++) {
602                             newBArray[newPixelOffset+k] =
603                                         ctable[k][index];
604                             }
605                             pixelOffset += pixelStride;
606                             newPixelOffset += newPixelStride;
607                         }
608                         scanlineOffset += scanlineStride;
609                         newScanlineOffset += newScanlineStride;
610                     }
611                     byteDataArrays = new byte[newNumBands][];
612                     for (int i = 0; i < newNumBands; i++) {
613                         byteDataArrays[i] = newBArray;
614                     }
615                     }
616                     break;
617 
618                 case DataBuffer.TYPE_USHORT: {
619                     short newIArray[] =
620                         new short[rectWidth*rectHeight*newNumBands];
621                     short shortDataArray[] = shortDataArrays[0];
622                     int scanlineOffset = bandDataOffsets[0];
623                     int newScanlineOffset = 0;
624                     for (int j = 0; j < rectHeight; j++)  {
625                         int pixelOffset = scanlineOffset;
626                         int newPixelOffset = newScanlineOffset;
627                         for (int i = 0; i < rectWidth; i++)  {
628                             int index = (shortDataArray[pixelOffset] & 0xffff);
629                             for (int k = 0; k < newNumBands; k++) {
630                                 newIArray[newPixelOffset+k] =
631                                         (short)(ctable[k][index] & 0xff);
632                             }
633                             pixelOffset += pixelStride;
634                             newPixelOffset += newPixelStride;
635                         }
636                         scanlineOffset += scanlineStride;
637                         newScanlineOffset += newScanlineStride;
638                     }
639 
640                     shortDataArrays = new short[newNumBands][];
641                     for (int i = 0; i < newNumBands; i++) {
642                         shortDataArrays[i] = newIArray;
643                     }
644                     }
645                     break;
646 
647                 case DataBuffer.TYPE_SHORT: {
648                     short newIArray[] =
649                         new short[rectWidth*rectHeight*newNumBands];
650                     short shortDataArray[] = shortDataArrays[0];
651                     int scanlineOffset = bandDataOffsets[0];
652                     int newScanlineOffset = 0;
653                     for (int j = 0; j < rectHeight; j++)  {
654                         int pixelOffset = scanlineOffset;
655                         int newPixelOffset = newScanlineOffset;
656                         for (int i = 0; i < rectWidth; i++)  {
657                             int index = shortDataArray[pixelOffset];
658                             for (int k = 0; k < newNumBands; k++) {
659                                 newIArray[newPixelOffset+k] =
660                                         (short)(ctable[k][index] & 0xff);
661                             }
662                             pixelOffset += pixelStride;
663                             newPixelOffset += newPixelStride;
664                         }
665                         scanlineOffset += scanlineStride;
666                         newScanlineOffset += newScanlineStride;
667                     }
668 
669                     shortDataArrays = new short[newNumBands][];
670                     for (int i = 0; i < newNumBands; i++) {
671                         shortDataArrays[i] = newIArray;
672                     }
673                     }
674                     break;
675 
676                 case DataBuffer.TYPE_INT: {
677                     int newIArray[] =
678                         new int[rectWidth*rectHeight*newNumBands];
679                     int intDataArray[] = intDataArrays[0];
680                     int scanlineOffset = bandDataOffsets[0];
681                     int newScanlineOffset = 0;
682                     for (int j = 0; j < rectHeight; j++)  {
683                         int pixelOffset = scanlineOffset;
684                         int newPixelOffset = newScanlineOffset;
685                         for (int i = 0; i < rectWidth; i++)  {
686                             int index = intDataArray[pixelOffset];
687                             for (int k = 0; k < newNumBands; k++) {
688                                 newIArray[newPixelOffset+k] =
689                                         (ctable[k][index] & 0xff);
690                             }
691                             pixelOffset += pixelStride;
692                             newPixelOffset += newPixelStride;
693                         }
694                         scanlineOffset += scanlineStride;
695                         newScanlineOffset += newScanlineStride;
696                     }
697 
698                     intDataArrays = new int[newNumBands][];
699                     for (int i = 0; i < newNumBands; i++) {
700                         intDataArrays[i] = newIArray;
701                     }
702                     }
703                     break;
704 
705                 case DataBuffer.TYPE_FLOAT: {
706                     float newFArray[] =
707                           new float[rectWidth*rectHeight*newNumBands];
708                     float floatDataArray[] = floatDataArrays[0];
709                     int scanlineOffset = bandDataOffsets[0];
710                     int newScanlineOffset = 0;
711                     for (int j = 0; j < rectHeight; j++)  {
712                         int pixelOffset = scanlineOffset;
713                         int newPixelOffset = newScanlineOffset;
714                         for (int i = 0; i < rectWidth; i++)  {
715                             int index = (int)floatDataArray[pixelOffset];
716                             for (int k = 0; k < newNumBands; k++) {
717                                 newFArray[newPixelOffset+k] =
718                                         (ctable[k][index] & 0xff);
719                             }
720                             pixelOffset += pixelStride;
721                             newPixelOffset += newPixelStride;
722                         }
723                         scanlineOffset += scanlineStride;
724                         newScanlineOffset += newScanlineStride;
725                     }
726                     floatDataArrays = new float[newNumBands][];
727                     for (int i = 0; i < newNumBands; i++) {
728                         floatDataArrays[i] = newFArray;
729                     }
730                     }
731                     break;
732 
733                 case DataBuffer.TYPE_DOUBLE: {
734                     double newDArray[] =
735                           new double[rectWidth*rectHeight*newNumBands];
736                     double doubleDataArray[] = doubleDataArrays[0];
737                     int scanlineOffset = bandDataOffsets[0];
738                     int newScanlineOffset = 0;
739                     for (int j = 0; j < rectHeight; j++)  {
740                         int pixelOffset = scanlineOffset;
741                         int newPixelOffset = newScanlineOffset;
742                         for (int i = 0; i < rectWidth; i++)  {
743                             int index = (int)doubleDataArray[pixelOffset];
744                             for (int k = 0; k < newNumBands; k++) {
745                                 newDArray[newPixelOffset+k] =
746                                         (ctable[k][index] & 0xff);
747                             }
748                             pixelOffset += pixelStride;
749                             newPixelOffset += newPixelStride;
750                         }
751                         scanlineOffset += scanlineStride;
752                         newScanlineOffset += newScanlineStride;
753                     }
754                     doubleDataArrays = new double[newNumBands][];
755                     for (int i = 0; i < newNumBands; i++) {
756                         doubleDataArrays[i] = newDArray;
757                     }
758                     }
759                     break;
760                 }
761                 this.numBands = newNumBands;
762                 this.pixelStride =  newPixelStride;
763                 this.scanlineStride = newScanlineStride;
764                 this.bandDataOffsets = newBandDataOffsets;
765                 this.bandOffsets = newBandDataOffsets;
766             }
767         } else if ((formatTagID & COPY_MASK) == COPIED &&
768                    (formatTagID & EXPANSION_MASK) != UNEXPANDED &&
769                    theColorModel != null) {
770             this.numBands = theColorModel instanceof IndexColorModel ?
771                             theColorModel.getNumComponents() :
772                             raster.getSampleModel().getNumBands();
773             this.pixelStride = this.numBands;
774             this.scanlineStride = rectWidth*numBands;
775             this.bandOffsets = new int[numBands];
776 
777             for (int i = 0; i < numBands; i++) {
778                 bandOffsets[i] = i;
779             }
780             this.bandDataOffsets = bandOffsets;
781 
782             Object odata  = null;
783             int offset = 0;
784 
785             int[] components = new int[theColorModel.getNumComponents()];
786 
787             switch (formatTagID & DATATYPE_MASK) {
788 
789             case DataBuffer.TYPE_INT:
790                 int idata[] = new int[rectWidth*rectHeight*numBands];
791                 intDataArrays = new int[numBands][];
792                 for (int i = 0; i < numBands; i++) {
793                     intDataArrays[i] = idata;
794                 }
795 
796                 odata = raster.getDataElements(rectX, rectY, null);
797                 offset = 0;
798 
799                 for (int j = rectY; j < rectY+rectHeight; j++) {
800                     for (int i = rectX; i < rectX+rectWidth; i++) {
801                         raster.getDataElements(i,j,odata);
802 
803                         theColorModel.getComponents(odata, components, 0);
804 
805                         idata[offset] = components[0];
806                         idata[offset+1] = components[1];
807                         idata[offset+2] = components[2];
808                         if (numBands > 3) {
809                            idata[offset+3] = components[3];
810                         }
811 
812                         offset += pixelStride;
813                     }
814                 }
815                 break;
816 
817             case DataBuffer.TYPE_FLOAT:
818                 float fdata[] = new float[rectWidth*rectHeight*numBands];
819                 floatDataArrays = new float[numBands][];
820                 for (int i = 0; i < numBands; i++) {
821                     floatDataArrays[i] = fdata;
822                 }
823                 odata = null;
824                 offset = 0;
825                 for (int j = rectY; j < rectY+rectHeight; j++) {
826                     for (int i = rectX; i < rectX+rectWidth; i++) {
827                         odata = raster.getDataElements(i,j,odata);
828 
829                         theColorModel.getComponents(odata, components, 0);
830 
831                         fdata[offset] = components[0];
832                         fdata[offset+1] = components[1];
833                         fdata[offset+2] = components[2];
834                         if (numBands > 3) {
835                            fdata[offset+3] = components[3];
836                         }
837                         offset += pixelStride;
838                     }
839                 }
840                 break;
841 
842             case DataBuffer.TYPE_DOUBLE:
843                 double ddata[] = new double[rectWidth*rectHeight*numBands];
844                 doubleDataArrays = new double[numBands][];
845                 for (int i = 0; i < numBands; i++) {
846                     doubleDataArrays[i] = ddata;
847                 }
848                 odata = null;
849                 offset = 0;
850                 for (int j = rectY; j < rectY+rectHeight; j++) {
851                     for (int i = rectX; i < rectX+rectWidth; i++) {
852                         odata = raster.getDataElements(i,j,odata);
853 
854                         theColorModel.getComponents(odata, components, 0);
855 
856                         ddata[offset] = components[0];
857                         ddata[offset+1] = components[1];
858                         ddata[offset+2] = components[2];
859                         if (numBands > 3) {
860                            ddata[offset+3] = components[3];
861                         }
862                         offset += pixelStride;
863                     }
864                 }
865                 break;
866             }
867         } else {
868             // if ((formatTagID & COPY_MASK) == COPIED &&
869             // (formatTagID & EXPANSION_MASK) == UNEXPANDED) {
870             // this has become a catchall case.  Specifically for
871             // Rasters with null colormodels.  So we take out the
872             // if as the boolean clause will get way complicated
873             // otherwise.
874             this.numBands = rft.getNumBands();
875             this.pixelStride = this.numBands;
876             this.scanlineStride = rectWidth*numBands;
877             this.bandDataOffsets = rft.getBandOffsets();
878             this.bandOffsets = this.bandDataOffsets;
879 
880             switch (formatTagID & DATATYPE_MASK) {
881             case DataBuffer.TYPE_INT:
882                 int idata[] = raster.getPixels(rectX,rectY,
883                                                rectWidth,rectHeight,
884                                                (int[])null);
885                 intDataArrays = new int[numBands][];
886                 for (int i = 0; i < numBands; i++) {
887                     intDataArrays[i] = idata;
888                 }
889                 break;
890 
891             case DataBuffer.TYPE_FLOAT:
892                 float fdata[] = raster.getPixels(rectX,rectY,
893                                                  rectWidth,rectHeight,
894                                                  (float[])null);
895                 floatDataArrays = new float[numBands][];
896                 for (int i = 0; i < numBands; i++) {
897                     floatDataArrays[i] = fdata;
898                 }
899                 break;
900 
901             case DataBuffer.TYPE_DOUBLE:
902                 double ddata[] = raster.getPixels(rectX,rectY,
903                                               rectWidth,rectHeight,
904                                               (double[])null);
905                 doubleDataArrays = new double[numBands][];
906                 for (int i = 0; i < numBands; i++) {
907                     doubleDataArrays[i] = ddata;
908                 }
909                 break;
910             }
911         }
912     }
913 
914     /**
915      * Returns the x coordinate of the upper-left corner of the
916      * RasterAccessor's accessible area.
917      */
getX()918     public int getX() {
919        return rectX;
920     }
921 
922     /**
923      * Returns the y coordinate of the upper-left corner of the
924      * RasterAccessor's accessible area.
925      */
getY()926     public int getY() {
927        return rectY;
928     }
929 
930     /** Returns the width of the
931      * RasterAccessor's accessible area.
932      */
getWidth()933     public int getWidth() {
934        return rectWidth;
935     }
936 
937     /** Returns the height of the
938      * RasterAccessor's accessible area.
939      */
getHeight()940     public int getHeight() {
941        return rectHeight;
942     }
943 
944     /** Returns the numBands of the presented area. */
getNumBands()945     public int getNumBands() {
946        return numBands;
947     }
948 
949 
950     /**
951      * Whether the <code>RasterAccessor</code> represents binary data.
952      * This occurs when the <code>Raster</code> has a
953      * <code>MultiPixelPackedSampleModel</code> with a single band and
954      * one bit per pixel.
955      *
956      * @since JAI 1.1
957      */
isBinary()958     public boolean isBinary() {
959         return (formatTagID & TAG_BINARY) == TAG_BINARY &&
960             ImageUtil.isBinary(raster.getSampleModel());
961     }
962 
963     /**
964      * For the case of binary data (<code>isBinary()</code> returns
965      * <code>true</code>), return the binary data as a packed byte array.
966      * The data will be packed as eight bits per byte with no bit offset,
967      * i.e., the first bit in each image line will be the left-most of the
968      * first byte of the line.  The line stride in bytes will be
969      * <code>(int)((getWidth()+7)/8)</code>.  The length of the returned
970      * array will be the line stride multiplied by <code>getHeight()</code>
971      *
972      * @return the binary data as a packed array of bytes with zero offset
973      * of <code>null</code> if the data are not binary.
974      *
975      * @since JAI 1.1
976      */
getBinaryDataArray()977     public byte[] getBinaryDataArray() {
978         if(binaryDataArray == null && isBinary()) {
979             binaryDataArray =
980             ImageUtil.getPackedBinaryData(raster, new Rectangle(rectX, rectY,
981                                                                 rectWidth,
982                                                                 rectHeight));
983         }
984         return binaryDataArray;
985     }
986 
987     /**
988      *  Returns the image data as a byte array.  Non-null only if
989      *  getDataType = DataBuffer.TYPE_BYTE.
990      *
991      *  <p> For the case of binary data the corresponding instance variable
992      *  <code>byteDataArrays</code> will not be initialized until this
993      *  method or <code>getByteDataArray(int b)</code> is invoked.  The
994      *  binary data will be returned as bytes with value 0 or 1.
995      */
getByteDataArrays()996     public byte[][] getByteDataArrays() {
997         if(byteDataArrays == null && isBinary()) {
998             byte[] bdata =
999                 ImageUtil.getUnpackedBinaryData(raster,
1000                                                 new Rectangle(rectX, rectY,
1001                                                               rectWidth,
1002                                                               rectHeight));
1003             byteDataArrays = new byte[][] {bdata};
1004         }
1005         return byteDataArrays;
1006     }
1007 
1008     /**
1009      *  Returns the image data as a byte array for a specific band.
1010      *  Non-null only if getDataType = DataBuffer.TYPE_BYTE.
1011      */
getByteDataArray(int b)1012     public byte[] getByteDataArray(int b) {
1013         byte[][] bda = getByteDataArrays();
1014         return (bda == null ? null : bda[b]);
1015     }
1016 
1017     /**
1018      *  Returns the image data as a short array.  Non-null only if
1019      *  getDataType = DataBuffer.TYPE_USHORT or DataBuffer.TYPE_SHORT.
1020      */
getShortDataArrays()1021     public short[][] getShortDataArrays() {
1022         return shortDataArrays;
1023     }
1024 
1025     /**
1026      *  Returns the image data as a short array for a specific band.
1027      *  Non-null only if getDataType = DataBuffer.TYPE_USHORT or
1028      *  DataBuffer.TYPE_SHORT.
1029      */
getShortDataArray(int b)1030     public short[] getShortDataArray(int b) {
1031         return (shortDataArrays == null ? null : shortDataArrays[b]);
1032     }
1033 
1034     /**
1035      *  Returns the image data as an int array.  Non-null only if
1036      *  getDataType = DataBuffer.TYPE_INT.
1037      */
getIntDataArrays()1038     public int[][] getIntDataArrays() {
1039         return intDataArrays;
1040     }
1041 
1042     /**
1043      *  Returns the image data as an int array for a specific band.
1044      *  Non-null only if getDataType = DataBuffer.TYPE_INT.
1045      */
getIntDataArray(int b)1046     public int[] getIntDataArray(int b) {
1047         return (intDataArrays == null ? null : intDataArrays[b]);
1048     }
1049 
1050     /**
1051      *  Returns the image data as a float array.  Non-null only if
1052      *  getDataType = DataBuffer.TYPE_FLOAT.
1053      */
getFloatDataArrays()1054     public float[][] getFloatDataArrays() {
1055         return floatDataArrays;
1056     }
1057 
1058     /**
1059      *  Returns the image data as a float array for a specific band.
1060      *  Non-null only if getDataType = DataBuffer.TYPE_FLOAT.
1061      */
getFloatDataArray(int b)1062     public float[] getFloatDataArray(int b) {
1063         return (floatDataArrays == null ? null : floatDataArrays[b]);
1064     }
1065 
1066     /**
1067      *  Returns the image data as a double array.  Non-null only if
1068      *  getDataType = DataBuffer.TYPE_DOUBLE
1069      */
getDoubleDataArrays()1070     public double[][] getDoubleDataArrays() {
1071         return doubleDataArrays;
1072     }
1073 
1074     /**
1075      *  Returns the image data as a double array for a specific band.
1076      *  Non-null only if getDataType = DataBuffer.TYPE_DOUBLE
1077      */
getDoubleDataArray(int b)1078     public double[] getDoubleDataArray(int b) {
1079         return (doubleDataArrays == null ? null : doubleDataArrays[b]);
1080     }
1081 
1082     /**
1083      *  Returns the image data as an Object for a specific band.
1084      *
1085      *  @param b The index of the image band of interest.
1086      */
getDataArray(int b)1087     public Object getDataArray(int b) {
1088         Object dataArray = null;
1089         switch(getDataType()) {
1090         case DataBuffer.TYPE_BYTE:
1091             dataArray = getByteDataArray(b);
1092             break;
1093 
1094         case DataBuffer.TYPE_SHORT:
1095         case DataBuffer.TYPE_USHORT:
1096             dataArray = getShortDataArray(b);
1097             break;
1098 
1099         case DataBuffer.TYPE_INT:
1100             dataArray = getIntDataArray(b);
1101             break;
1102 
1103         case DataBuffer.TYPE_FLOAT:
1104             dataArray = getFloatDataArray(b);
1105             break;
1106 
1107         case DataBuffer.TYPE_DOUBLE:
1108             dataArray = getDoubleDataArray(b);
1109             break;
1110 
1111         default:
1112             dataArray = null;
1113         }
1114 
1115         return dataArray;
1116     }
1117 
1118     /**  Returns the bandDataOffsets into the dataArrays. */
getBandOffsets()1119     public int[] getBandOffsets() {
1120         return bandDataOffsets;
1121     }
1122 
1123     /**
1124      * Returns the offset of all band's samples from any
1125      * pixel offset.
1126      */
getOffsetsForBands()1127     public int[] getOffsetsForBands() {
1128 	return bandOffsets;
1129     }
1130 
1131     /**
1132      * Returns the offset of a specific band's first sample into the
1133      * DataBuffer including the DataBuffer's offset.
1134      */
getBandOffset(int b)1135     public int getBandOffset(int b) {
1136         return bandDataOffsets[b];
1137     }
1138 
1139     /**
1140      * Returns the offset of a specified band's sample from any
1141      * pixel offset.
1142      */
getOffsetForBand(int b)1143     public int getOffsetForBand(int b) {
1144 	return bandOffsets[b];
1145     }
1146 
1147     /**
1148      * Returns the scanlineStride for the image data.
1149      *
1150      * <p> For binary data this stride is applies to the arrays returned by
1151      * <code>getByteDataArray()</code> and <code>getByteDataArrays()</code>
1152      * if the data are accessed as bytes; it does not apply to the array
1153      * returned by <code>getBinaryDataArray()</code> when the data are
1154      * accessed as bits packed into bytes.
1155      */
getScanlineStride()1156     public int getScanlineStride() {
1157         return scanlineStride;
1158     }
1159 
1160     /** Returns the pixelStride for the image data. */
getPixelStride()1161     public int getPixelStride() {
1162         return pixelStride;
1163     }
1164 
1165     /**
1166      *  Returns the data type of the RasterAccessor object. Note that
1167      *  this datatype is not necessarily the same data type as the
1168      *  underlying raster.
1169      */
getDataType()1170     public int getDataType() {
1171         return formatTagID & DATATYPE_MASK;
1172     }
1173 
1174     /**
1175      *  Returns true if the RasterAccessors's data is copied from it's
1176      *  raster.
1177      */
isDataCopy()1178     public boolean isDataCopy() {
1179         return ((formatTagID & COPY_MASK) == COPIED);
1180     }
1181 
1182 
1183     /**
1184      * For the case of binary data (<code>isBinary()</code> returns
1185      * <code>true</code>), copy the binary data back into the
1186      * <code>Raster</code> of the <code>RasterAccessor</code>.  If
1187      * this method is invoked in the non-binary case it does nothing.
1188      * Any bit offset in the original <code>SampleModel</code> will be
1189      * accounted for.
1190      *
1191      * @since JAI 1.1
1192      */
1193     // Note: ALL branches of this method have been tested. (bpb 10 May 2000)
copyBinaryDataToRaster()1194     public void copyBinaryDataToRaster() {
1195         if(binaryDataArray == null || !isBinary()) {
1196             return;
1197         }
1198 
1199         ImageUtil.setPackedBinaryData(binaryDataArray,
1200                                       (WritableRaster)raster,
1201                                       new Rectangle(rectX, rectY,
1202                                                     rectWidth, rectHeight));
1203     }
1204 
1205     /**
1206      *  Copies data back into the RasterAccessor's raster.  Note that
1207      *  the data is cast from the intermediate data format to
1208      *  the raster's format.  If clamping is needed, the call
1209      *  clampDataArrays() method needs to be called before
1210      *  calling the copyDataToRaster() method.
1211      *  Note: the raster is expected to be writable - typically a
1212      *  destination raster - otherwise, a run-time exception will occur.
1213      *
1214      * <p> If the data are binary, then the target bit will be set if
1215      * and only if the corresponding byte is non-zero.
1216      */
copyDataToRaster()1217     public void copyDataToRaster() {
1218         if (isDataCopy()) {
1219 
1220             // Writeback should only be necessary on destRasters which
1221             // should be writable so this cast should succeed.
1222             WritableRaster wr = (WritableRaster)raster;
1223             switch (getDataType()) {
1224             case DataBuffer.TYPE_BYTE:
1225                 // Note: ALL branches of this case have been tested.
1226                 // (bpb 10 May 2000)
1227                 if(!isBinary()) {
1228                     // If this exception occurs then there is a logic
1229                     // error within this accessor since the only case
1230                     // wherein byte data should be COPIED is when the
1231                     // data set is binary.
1232                     throw new RuntimeException(JaiI18N.getString("RasterAccessor1"));
1233                 }
1234 
1235                 // This case only occurs for binary src and dst.
1236 
1237                 ImageUtil.setUnpackedBinaryData(byteDataArrays[0],
1238                                                 wr,
1239                                                 new Rectangle(rectX, rectY,
1240                                                               rectWidth,
1241                                                               rectHeight));
1242                 break;
1243             case DataBuffer.TYPE_INT:
1244                 wr.setPixels(rectX,rectY,
1245                              rectWidth,rectHeight,
1246                              intDataArrays[0]);
1247                 break;
1248 
1249             case DataBuffer.TYPE_FLOAT:
1250                 wr.setPixels(rectX,rectY,
1251                              rectWidth,rectHeight,
1252                              floatDataArrays[0]);
1253                 break;
1254 
1255             case DataBuffer.TYPE_DOUBLE:
1256                 wr.setPixels(rectX,rectY,
1257                              rectWidth,rectHeight,
1258                              doubleDataArrays[0]);
1259                 break;
1260             }
1261         }
1262     }
1263 
1264     /**
1265      *  Indicates if the RasterAccessor has a larger dynamic range than
1266      *  the underlying Raster.  Except in special cases, where the op
1267      *  knows something special, this call will determine whether or
1268      *  not clampDataArrays() needs to be called.
1269      */
needsClamping()1270     public boolean needsClamping() {
1271         int bits[] = raster.getSampleModel().getSampleSize();
1272 
1273         // Do we even need a clamp?  We do if there's any band
1274         // of the source image stored in that's less than 32 bits
1275         // and is stored in a byte, short or int format.  (The automatic
1276         // casts between floats/doubles and 32-bit ints in setPixel()
1277         // do what we want.)
1278 
1279         for (int i = 0; i < bits.length; i++) {
1280 	    if (bits[i] < 32) {
1281 	      return true;
1282             }
1283         }
1284         return false;
1285     }
1286 
1287     /**
1288      * Clamps data array values to a range that the underlying raster
1289      * can deal with.  For example, if the underlying raster stores
1290      * data as bytes, but the samples are unpacked into integer arrays by
1291      * the RasterAccessor for an operation, the operation will
1292      * need to call clampDataArrays() so that the data in the int
1293      * arrays is restricted to the range 0..255 before a setPixels()
1294      * call is made on the underlying raster.  Note that some
1295      * operations (for example, lookup) can guarantee that their
1296      * results don't need clamping so they can call
1297      * RasterAccessor.copyDataToRaster() without first calling this
1298      * function.
1299      */
clampDataArrays()1300     public void clampDataArrays () {
1301         int bits[] = raster.getSampleModel().getSampleSize();
1302 
1303         // Do we even need a clamp?  We do if there's any band
1304         // of the source image stored in that's less than 32 bits
1305         // and is stored in a byte, short or int format.  (The automatic
1306         // casts between floats/doubles and 32-bit ints in setPixel()
1307         // do what we want.)
1308 
1309         boolean needClamp = false;
1310         boolean uniformBitSize = true;
1311 	int bitSize = bits[0];
1312         for (int i = 0; i < bits.length; i++) {
1313             if (bits[i] < 32) {
1314                 needClamp = true;
1315             }
1316             if (bits[i] != bitSize) {
1317                uniformBitSize = false;
1318             }
1319         }
1320         if (!needClamp) {
1321             return;
1322         }
1323 
1324         int dataType = raster.getDataBuffer().getDataType();
1325         double hiVals[] = new double[bits.length];
1326         double loVals[] = new double[bits.length];
1327 
1328         if (dataType == DataBuffer.TYPE_USHORT &&
1329             uniformBitSize && bits[0] == 16) {
1330             for (int i = 0; i < bits.length; i++) {
1331                 hiVals[i] = (double)0xFFFF;
1332                 loVals[i] = (double)0;
1333             }
1334         } else if (dataType == DataBuffer.TYPE_SHORT &&
1335             uniformBitSize && bits[0] == 16) {
1336             for (int i = 0; i < bits.length; i++) {
1337                 hiVals[i] = (double)Short.MAX_VALUE;
1338                 loVals[i] = (double)Short.MIN_VALUE;
1339             }
1340         } else if (dataType == DataBuffer.TYPE_INT &&
1341             uniformBitSize && bits[0] == 32) {
1342             for (int i = 0; i < bits.length; i++) {
1343                 hiVals[i] = (double)Integer.MAX_VALUE;
1344                 loVals[i] = (double)Integer.MIN_VALUE;
1345             }
1346         } else {
1347             for (int i = 0; i < bits.length; i++) {
1348                 hiVals[i] = (double)((1 << bits[i]) - 1);
1349                 loVals[i] = (double)0;
1350             }
1351         }
1352         clampDataArray(hiVals,loVals);
1353     }
1354 
clampDataArray(double hiVals[], double loVals[])1355     private void clampDataArray(double hiVals[], double loVals[]) {
1356         switch (getDataType()) {
1357         case DataBuffer.TYPE_INT:
1358             clampIntArrays(toIntArray(hiVals),toIntArray(loVals));
1359             break;
1360 
1361         case DataBuffer.TYPE_FLOAT:
1362             clampFloatArrays(toFloatArray(hiVals),toFloatArray(loVals));
1363             break;
1364 
1365         case DataBuffer.TYPE_DOUBLE:
1366             clampDoubleArrays(hiVals,loVals);
1367             break;
1368         }
1369     }
1370 
toIntArray(double vals[])1371     private int[] toIntArray(double vals[]) {
1372         int returnVals[] = new int[vals.length];
1373         for (int i = 0; i < vals.length; i++) {
1374             returnVals[i] = (int)vals[i];
1375         }
1376         return returnVals;
1377     }
1378 
toFloatArray(double vals[])1379     private float[] toFloatArray(double vals[]) {
1380         float returnVals[] = new float[vals.length];
1381         for (int i = 0; i < vals.length; i++) {
1382             returnVals[i] = (float)vals[i];
1383         }
1384         return returnVals;
1385     }
1386 
clampIntArrays(int hiVals[], int loVals[])1387     private void clampIntArrays(int hiVals[], int loVals[]) {
1388         int width = rectWidth;
1389         int height = rectHeight;
1390         for (int k = 0; k < numBands; k++)  {
1391             int data[] = intDataArrays[k];
1392             int scanlineOffset = bandDataOffsets[k];
1393             int hiVal = hiVals[k];
1394             int loVal = loVals[k];
1395             for (int j = 0; j < height; j++)  {
1396                 int pixelOffset = scanlineOffset;
1397                 for (int i = 0; i < width; i++)  {
1398                     int tmp = data[pixelOffset];
1399                     if (tmp < loVal) {
1400                         data[pixelOffset] = loVal;
1401                     } else if (tmp > hiVal) {
1402                         data[pixelOffset] = hiVal;
1403                     }
1404                     pixelOffset += pixelStride;
1405                 }
1406                 scanlineOffset += scanlineStride;
1407             }
1408         }
1409     }
1410 
clampFloatArrays(float hiVals[], float loVals[])1411     private void clampFloatArrays(float hiVals[], float loVals[]) {
1412         int width = rectWidth;
1413         int height = rectHeight;
1414         for (int k = 0; k < numBands; k++)  {
1415             float data[] = floatDataArrays[k];
1416             int scanlineOffset = bandDataOffsets[k];
1417             float hiVal = hiVals[k];
1418             float loVal = loVals[k];
1419             for (int j = 0; j < height; j++)  {
1420                 int pixelOffset = scanlineOffset;
1421                 for (int i = 0; i < width; i++)  {
1422                     float tmp = data[pixelOffset];
1423                     if (tmp < loVal) {
1424                         data[pixelOffset] = loVal;
1425                     } else if (tmp > hiVal) {
1426                         data[pixelOffset] = hiVal;
1427                     }
1428                     pixelOffset += pixelStride;
1429                 }
1430                 scanlineOffset += scanlineStride;
1431             }
1432         }
1433     }
1434 
clampDoubleArrays(double hiVals[], double loVals[])1435     private void clampDoubleArrays(double hiVals[], double loVals[]) {
1436         int width = rectWidth;
1437         int height = rectHeight;
1438         for (int k = 0; k < numBands; k++)  {
1439             double data[] = doubleDataArrays[k];
1440             int scanlineOffset = bandDataOffsets[k];
1441             double hiVal = hiVals[k];
1442             double loVal = loVals[k];
1443             for (int j = 0; j < height; j++)  {
1444                 int pixelOffset = scanlineOffset;
1445                 for (int i = 0; i < width; i++)  {
1446                     double tmp = data[pixelOffset];
1447                     if (tmp < loVal) {
1448                         data[pixelOffset] = loVal;
1449                     } else if (tmp > hiVal) {
1450                         data[pixelOffset] = hiVal;
1451                     }
1452                     pixelOffset += pixelStride;
1453                 }
1454                 scanlineOffset += scanlineStride;
1455             }
1456         }
1457     }
1458 }
1459