1 /*
2  * $RCSfile: AddOpImage.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:56:12 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.media.jai.opimage;
13 import java.awt.Rectangle;
14 import java.awt.image.DataBuffer;
15 import java.awt.image.Raster;
16 import java.awt.image.RenderedImage;
17 import java.awt.image.SampleModel;
18 import java.awt.image.WritableRaster;
19 import com.lightcrafts.mediax.jai.ImageLayout;
20 import com.lightcrafts.mediax.jai.PointOpImage;
21 import com.lightcrafts.mediax.jai.RasterAccessor;
22 import com.lightcrafts.mediax.jai.RasterFormatTag;
23 import com.lightcrafts.mediax.jai.RasterFactory;
24 import java.util.Map;
25 import com.lightcrafts.media.jai.util.ImageUtil;
26 import com.lightcrafts.media.jai.util.JDKWorkarounds;
27 /// import com.lightcrafts.media.jai.test.OpImageTester;
28 
29 /**
30  * An <code>OpImage</code> implementing the "Add" operation as
31  * described in <code>com.lightcrafts.mediax.jai.operator.AddDescriptor</code>.
32  *
33  * <p>This <code>OpImage</code> adds the pixel values of two source
34  * images on a per-band basis. In case the two source images have different
35  * number of bands, the number of bands for the destination image is the
36  * smaller band number of the two source images. That is
37  * <code>dstNumBands = Math.min(src1NumBands, src2NumBands)</code>.
38  * In case the two source images have different data types, the data type
39  * for the destination image is the higher data type of the two source
40  * images.
41  *
42  * <p>The value of the pixel (x, y) in the destination image is defined as:
43  * <pre>
44  * for (b = 0; b < numBands; b++) {
45  *     dst[y][x][b] = src1[y][x][b] + src2[y][x][b];
46  * }
47  * </pre>
48  *
49  * <p>If the result of the addition overflows/underflows the
50  * maximum/minimum value supported by the destination image, then it
51  * will be clamped to the maximum/minimum value respectively. The
52  * data type <code>byte</code> is treated as unsigned, with maximum
53  * value as 255 and minimum value as 0.
54  *
55  * @see com.lightcrafts.mediax.jai.operator.AddDescriptor
56  * @see AddCRIF
57  *
58  */
59 final class AddOpImage extends PointOpImage {
60 
61     /* Source 1 band increment */
62     private int s1bd = 1;
63 
64     /* Source 2 band increment */
65     private int s2bd = 1;
66 
67     /* Bilevel data flag. */
68     private boolean areBinarySampleModels = false;
69 
70     /**
71      * Constructs an <code>AddOpImage</code>.
72      *
73      * <p>The <code>layout</code> parameter may optionally contains the
74      * tile grid layout, sample model, and/or color model. The image
75      * dimension is determined by the intersection of the bounding boxes
76      * of the two source images.
77      *
78      * <p>The image layout of the first source image, <code>source1</code>,
79      * is used as the fall-back for the image layout of the destination
80      * image. Any layout parameters not specified in the <code>layout</code>
81      * argument are set to the same value as that of <code>source1</code>.
82      *
83      * @param source1  The first source image.
84      * @param source2  The second source image.
85      * @param layout   The destination image layout.
86      */
AddOpImage(RenderedImage source1, RenderedImage source2, Map config, ImageLayout layout)87     public AddOpImage(RenderedImage source1,
88                       RenderedImage source2,
89                       Map config,
90 		      ImageLayout layout) {
91         super(source1, source2, layout, config, true);
92 
93         if(ImageUtil.isBinary(getSampleModel()) &&
94            ImageUtil.isBinary(source1.getSampleModel()) &&
95            ImageUtil.isBinary(source2.getSampleModel())) {
96             // Binary processing case: RasterAccessor
97             areBinarySampleModels = true;
98         } else {
99             // Get the source band counts.
100             int numBands1 = source1.getSampleModel().getNumBands();
101             int numBands2 = source2.getSampleModel().getNumBands();
102 
103             // Handle the special case of adding a single band image to
104             // each band of a multi-band image.
105             int numBandsDst;
106             if(layout != null && layout.isValid(ImageLayout.SAMPLE_MODEL_MASK)) {
107                 SampleModel sm = layout.getSampleModel(null);
108                 numBandsDst = sm.getNumBands();
109 
110                 // One of the sources must be single-banded and the other must
111                 // have at most the number of bands in the SampleModel hint.
112                 if(numBandsDst > 1 &&
113                    ((numBands1 == 1 && numBands2 > 1) ||
114                     (numBands2 == 1 && numBands1 > 1))) {
115                     // Clamp the destination band count to the number of
116                     // bands in the multi-band source.
117                     numBandsDst = Math.min(Math.max(numBands1, numBands2),
118                                            numBandsDst);
119 
120                     // Create a new SampleModel if necessary.
121                     if(numBandsDst != sampleModel.getNumBands()) {
122                         sampleModel =
123                             RasterFactory.createComponentSampleModel(
124                                 sm,
125                                 sampleModel.getTransferType(),
126                                 sampleModel.getWidth(),
127                                 sampleModel.getHeight(),
128                                 numBandsDst);
129 
130                         if(colorModel != null &&
131                            !JDKWorkarounds.areCompatibleDataModels(sampleModel,
132                                                                    colorModel)) {
133                             colorModel =
134                                 ImageUtil.getCompatibleColorModel(sampleModel,
135                                                                   config);
136                         }
137                     }
138 
139                     // Set the source band increments.
140                     s1bd = numBands1 == 1 ? 0 : 1;
141                     s2bd = numBands2 == 1 ? 0 : 1;
142                 }
143             }
144         }
145 
146         // Set flag to permit in-place operation.
147         permitInPlaceOperation();
148     }
149 
150     /**
151      * Adds the pixel values of two source images within a specified
152      * rectangle.
153      *
154      * @param sources   Cobbled sources, guaranteed to provide all the
155      *                  source data necessary for computing the rectangle.
156      * @param dest      The tile containing the rectangle to be computed.
157      * @param destRect  The rectangle within the tile to be computed.
158      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)159     protected void computeRect(Raster[] sources,
160                                WritableRaster dest,
161                                Rectangle destRect) {
162         if(areBinarySampleModels) {
163             // Retrieve format tags.
164             RasterFormatTag[] formatTags = getFormatTags();
165 
166             // For PointOpImage, srcRect = destRect.
167             RasterAccessor s1 =
168                 new RasterAccessor(sources[0], destRect,
169                                    formatTags[0],
170                                    getSourceImage(0).getColorModel());
171             RasterAccessor s2 =
172                 new RasterAccessor(sources[1], destRect,
173                                    formatTags[1],
174                                    getSourceImage(1).getColorModel());
175             RasterAccessor d =
176                 new RasterAccessor(dest, destRect,
177                                    formatTags[2], getColorModel());
178 
179             if(d.isBinary()) {
180                 byte[] src1Bits = s1.getBinaryDataArray();
181                 byte[] src2Bits = s2.getBinaryDataArray();
182                 byte[] dstBits = d.getBinaryDataArray();
183 
184                 int length = dstBits.length;
185                 for(int i = 0; i < length; i++) {
186                     // "Add" is equivalent to "Or" when 1+1 is clamped to 1.
187                     dstBits[i] = (byte)(src1Bits[i] | src2Bits[i]);
188                 }
189 
190                 d.copyBinaryDataToRaster();
191 
192                 return;
193             }
194         }
195 
196         // Retrieve format tags.
197         RasterFormatTag[] formatTags = getFormatTags();
198 
199         RasterAccessor s1 = new RasterAccessor(sources[0], destRect,
200                                                formatTags[0],
201                                                getSourceImage(0).getColorModel());
202         RasterAccessor s2 = new RasterAccessor(sources[1], destRect,
203                                                formatTags[1],
204                                                getSourceImage(1).getColorModel());
205         RasterAccessor d = new RasterAccessor(dest, destRect,
206                                               formatTags[2], getColorModel());
207 
208         switch (d.getDataType()) {
209         case DataBuffer.TYPE_BYTE:
210             computeRectByte(s1, s2, d);
211             break;
212         case DataBuffer.TYPE_USHORT:
213             computeRectUShort(s1, s2, d);
214             break;
215         case DataBuffer.TYPE_SHORT:
216             computeRectShort(s1, s2, d);
217             break;
218         case DataBuffer.TYPE_INT:
219             computeRectInt(s1, s2, d);
220             break;
221         case DataBuffer.TYPE_FLOAT:
222             computeRectFloat(s1, s2, d);
223             break;
224         case DataBuffer.TYPE_DOUBLE:
225             computeRectDouble(s1, s2, d);
226             break;
227         }
228 
229         if (d.needsClamping()) {
230             d.clampDataArrays();
231         }
232         d.copyDataToRaster();
233     }
234 
computeRectByte(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)235     private void computeRectByte(RasterAccessor src1,
236                                  RasterAccessor src2,
237                                  RasterAccessor dst) {
238         int s1LineStride = src1.getScanlineStride();
239         int s1PixelStride = src1.getPixelStride();
240         int[] s1BandOffsets = src1.getBandOffsets();
241         byte[][] s1Data = src1.getByteDataArrays();
242 
243         int s2LineStride = src2.getScanlineStride();
244         int s2PixelStride = src2.getPixelStride();
245         int[] s2BandOffsets = src2.getBandOffsets();
246         byte[][] s2Data = src2.getByteDataArrays();
247 
248         int dwidth = dst.getWidth();
249         int dheight = dst.getHeight();
250         int bands = dst.getNumBands();
251         int dLineStride = dst.getScanlineStride();
252         int dPixelStride = dst.getPixelStride();
253         int[] dBandOffsets = dst.getBandOffsets();
254         byte[][] dData = dst.getByteDataArrays();
255 
256         for (int b = 0, s1b = 0, s2b = 0; b < bands;
257              b++, s1b += s1bd, s2b += s2bd) {
258             byte[] s1 = s1Data[s1b];
259             byte[] s2 = s2Data[s2b];
260             byte[] d = dData[b];
261 
262             int s1LineOffset = s1BandOffsets[s1b];
263             int s2LineOffset = s2BandOffsets[s2b];
264             int dLineOffset = dBandOffsets[b];
265 
266             for (int h = 0; h < dheight; h++) {
267                 int s1PixelOffset = s1LineOffset;
268                 int s2PixelOffset = s2LineOffset;
269                 int dPixelOffset = dLineOffset;
270 
271                 s1LineOffset += s1LineStride;
272                 s2LineOffset += s2LineStride;
273                 dLineOffset += dLineStride;
274 
275                 int sum = 0;
276                 for (int w = 0; w < dwidth; w++) {
277                     //
278                     // The next two lines are a fast way to do
279                     // an add with saturation on U8 elements.
280                     // It eliminates the need to do clamping.
281                     //
282                     sum = (s1[s1PixelOffset]&0xFF) + (s2[s2PixelOffset]&0xFF);
283                     d[dPixelOffset] = (byte)((((sum<<23) >> 31) | sum) & 0xFF);
284 
285                     s1PixelOffset += s1PixelStride;
286                     s2PixelOffset += s2PixelStride;
287                     dPixelOffset += dPixelStride;
288                 }
289             }
290         }
291     }
292 
computeRectUShort(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)293     private void computeRectUShort(RasterAccessor src1,
294                                    RasterAccessor src2,
295                                    RasterAccessor dst) {
296         int s1LineStride = src1.getScanlineStride();
297         int s1PixelStride = src1.getPixelStride();
298         int[] s1BandOffsets = src1.getBandOffsets();
299         short[][] s1Data = src1.getShortDataArrays();
300 
301         int s2LineStride = src2.getScanlineStride();
302         int s2PixelStride = src2.getPixelStride();
303         int[] s2BandOffsets = src2.getBandOffsets();
304         short[][] s2Data = src2.getShortDataArrays();
305 
306         int dwidth = dst.getWidth();
307         int dheight = dst.getHeight();
308         int bands = dst.getNumBands();
309         int dLineStride = dst.getScanlineStride();
310         int dPixelStride = dst.getPixelStride();
311         int[] dBandOffsets = dst.getBandOffsets();
312         short[][] dData = dst.getShortDataArrays();
313 
314         for (int b = 0, s1b = 0, s2b = 0; b < bands;
315              b++, s1b += s1bd, s2b += s2bd) {
316             short[] s1 = s1Data[s1b];
317             short[] s2 = s2Data[s2b];
318             short[] d = dData[b];
319 
320             int s1LineOffset = s1BandOffsets[s1b];
321             int s2LineOffset = s2BandOffsets[s2b];
322             int dLineOffset = dBandOffsets[b];
323 
324             for (int h = 0; h < dheight; h++) {
325                 int s1PixelOffset = s1LineOffset;
326                 int s2PixelOffset = s2LineOffset;
327                 int dPixelOffset = dLineOffset;
328 
329                 s1LineOffset += s1LineStride;
330                 s2LineOffset += s2LineStride;
331                 dLineOffset += dLineStride;
332 
333                 for (int w = 0; w < dwidth; w++) {
334                     d[dPixelOffset] = ImageUtil.clampUShortPositive(
335                                           (int)(s1[s1PixelOffset]&0xFFFF) +
336                                           (int)(s2[s2PixelOffset]&0xFFFF));
337 
338                     s1PixelOffset += s1PixelStride;
339                     s2PixelOffset += s2PixelStride;
340                     dPixelOffset += dPixelStride;
341                 }
342             }
343         }
344     }
345 
computeRectShort(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)346     private void computeRectShort(RasterAccessor src1,
347                                   RasterAccessor src2,
348                                   RasterAccessor dst) {
349         int s1LineStride = src1.getScanlineStride();
350         int s1PixelStride = src1.getPixelStride();
351         int[] s1BandOffsets = src1.getBandOffsets();
352         short[][] s1Data = src1.getShortDataArrays();
353 
354         int s2LineStride = src2.getScanlineStride();
355         int s2PixelStride = src2.getPixelStride();
356         int[] s2BandOffsets = src2.getBandOffsets();
357         short[][] s2Data = src2.getShortDataArrays();
358 
359         int dwidth = dst.getWidth();
360         int dheight = dst.getHeight();
361         int bands = dst.getNumBands();
362         int dLineStride = dst.getScanlineStride();
363         int dPixelStride = dst.getPixelStride();
364         int[] dBandOffsets = dst.getBandOffsets();
365         short[][] dData = dst.getShortDataArrays();
366 
367         for (int b = 0, s1b = 0, s2b = 0; b < bands;
368              b++, s1b += s1bd, s2b += s2bd) {
369             short[] s1 = s1Data[s1b];
370             short[] s2 = s2Data[s2b];
371             short[] d = dData[b];
372 
373             int s1LineOffset = s1BandOffsets[s1b];
374             int s2LineOffset = s2BandOffsets[s2b];
375             int dLineOffset = dBandOffsets[b];
376 
377             for (int h = 0; h < dheight; h++) {
378                 int s1PixelOffset = s1LineOffset;
379                 int s2PixelOffset = s2LineOffset;
380                 int dPixelOffset = dLineOffset;
381 
382                 s1LineOffset += s1LineStride;
383                 s2LineOffset += s2LineStride;
384                 dLineOffset += dLineStride;
385 
386                 for (int w = 0; w < dwidth; w++) {
387                     d[dPixelOffset] = ImageUtil.clampShort((int)s1[s1PixelOffset] +
388                                                  (int)s2[s2PixelOffset]);
389 
390                     s1PixelOffset += s1PixelStride;
391                     s2PixelOffset += s2PixelStride;
392                     dPixelOffset += dPixelStride;
393                 }
394             }
395         }
396     }
397 
computeRectInt(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)398     private void computeRectInt(RasterAccessor src1,
399                                 RasterAccessor src2,
400                                 RasterAccessor dst) {
401         int s1LineStride = src1.getScanlineStride();
402         int s1PixelStride = src1.getPixelStride();
403         int[] s1BandOffsets = src1.getBandOffsets();
404         int[][] s1Data = src1.getIntDataArrays();
405 
406         int s2LineStride = src2.getScanlineStride();
407         int s2PixelStride = src2.getPixelStride();
408         int[] s2BandOffsets = src2.getBandOffsets();
409         int[][] s2Data = src2.getIntDataArrays();
410 
411         int dwidth = dst.getWidth();
412         int dheight = dst.getHeight();
413         int bands = dst.getNumBands();
414         int dLineStride = dst.getScanlineStride();
415         int dPixelStride = dst.getPixelStride();
416         int[] dBandOffsets = dst.getBandOffsets();
417         int[][] dData = dst.getIntDataArrays();
418 
419         /*
420          * The destination data type may be any of the integral data types.
421          * The "clamp" function must clamp to the appropriate range for
422          * that data type.
423          */
424         switch (sampleModel.getTransferType()) {
425         case DataBuffer.TYPE_BYTE:
426             for (int b = 0, s1b = 0, s2b = 0; b < bands;
427                  b++, s1b += s1bd, s2b += s2bd) {
428                 int[] s1 = s1Data[s1b];
429                 int[] s2 = s2Data[s2b];
430                 int[] d = dData[b];
431 
432                 int s1LineOffset = s1BandOffsets[s1b];
433                 int s2LineOffset = s2BandOffsets[s2b];
434                 int dLineOffset = dBandOffsets[b];
435 
436                 for (int h = 0; h < dheight; h++) {
437                     int s1PixelOffset = s1LineOffset;
438                     int s2PixelOffset = s2LineOffset;
439                     int dPixelOffset = dLineOffset;
440 
441                     s1LineOffset += s1LineStride;
442                     s2LineOffset += s2LineStride;
443                     dLineOffset += dLineStride;
444 
445                     int sum = 0;
446                     for (int w = 0; w < dwidth; w++) {
447                         //
448                         // The next two lines are a fast way to do
449                         // an add with saturation on U8 elements.
450                         // It eliminates the need to do clamping.
451                         //
452                         sum = (s1[s1PixelOffset]&0xFF) + (s2[s2PixelOffset]&0xFF);
453                         d[dPixelOffset] = ((((sum<<23) >> 31) | sum) & 0xFF);
454 
455                         s1PixelOffset += s1PixelStride;
456                         s2PixelOffset += s2PixelStride;
457                         dPixelOffset += dPixelStride;
458                     }
459                 }
460             }
461             break;
462 
463         case DataBuffer.TYPE_USHORT:
464             for (int b = 0, s1b = 0, s2b = 0; b < bands;
465                  b++, s1b += s1bd, s2b += s2bd) {
466                 int[] s1 = s1Data[s1b];
467                 int[] s2 = s2Data[s2b];
468                 int[] d = dData[b];
469 
470                 int s1LineOffset = s1BandOffsets[s1b];
471                 int s2LineOffset = s2BandOffsets[s2b];
472                 int dLineOffset = dBandOffsets[b];
473 
474                 for (int h = 0; h < dheight; h++) {
475                     int s1PixelOffset = s1LineOffset;
476                     int s2PixelOffset = s2LineOffset;
477                     int dPixelOffset = dLineOffset;
478 
479                     s1LineOffset += s1LineStride;
480                     s2LineOffset += s2LineStride;
481                     dLineOffset += dLineStride;
482 
483                     for (int w = 0; w < dwidth; w++) {
484                         d[dPixelOffset] = ImageUtil.clampUShortPositive(
485                                               (int)(s1[s1PixelOffset]&0xFFFF) +
486                                               (int)(s2[s2PixelOffset]&0xFFFF));
487 
488                         s1PixelOffset += s1PixelStride;
489                         s2PixelOffset += s2PixelStride;
490                         dPixelOffset += dPixelStride;
491                     }
492                 }
493             }
494             break;
495 
496         case DataBuffer.TYPE_SHORT:
497             for (int b = 0, s1b = 0, s2b = 0; b < bands;
498                  b++, s1b += s1bd, s2b += s2bd) {
499                 int[] s1 = s1Data[s1b];
500                 int[] s2 = s2Data[s2b];
501                 int[] d = dData[b];
502 
503                 int s1LineOffset = s1BandOffsets[s1b];
504                 int s2LineOffset = s2BandOffsets[s2b];
505                 int dLineOffset = dBandOffsets[b];
506 
507                 for (int h = 0; h < dheight; h++) {
508                     int s1PixelOffset = s1LineOffset;
509                     int s2PixelOffset = s2LineOffset;
510                     int dPixelOffset = dLineOffset;
511 
512                     s1LineOffset += s1LineStride;
513                     s2LineOffset += s2LineStride;
514                     dLineOffset += dLineStride;
515 
516                     for (int w = 0; w < dwidth; w++) {
517                         d[dPixelOffset] = ImageUtil.clampShort((int)s1[s1PixelOffset] +
518                                                      (int)s2[s2PixelOffset]);
519 
520                         s1PixelOffset += s1PixelStride;
521                         s2PixelOffset += s2PixelStride;
522                         dPixelOffset += dPixelStride;
523                     }
524                 }
525             }
526             break;
527 
528         case DataBuffer.TYPE_INT:
529             for (int b = 0, s1b = 0, s2b = 0; b < bands;
530                  b++, s1b += s1bd, s2b += s2bd) {
531                 int[] s1 = s1Data[s1b];
532                 int[] s2 = s2Data[s2b];
533                 int[] d = dData[b];
534 
535                 int s1LineOffset = s1BandOffsets[s1b];
536                 int s2LineOffset = s2BandOffsets[s2b];
537                 int dLineOffset = dBandOffsets[b];
538 
539                 for (int h = 0; h < dheight; h++) {
540                     int s1PixelOffset = s1LineOffset;
541                     int s2PixelOffset = s2LineOffset;
542                     int dPixelOffset = dLineOffset;
543 
544                     s1LineOffset += s1LineStride;
545                     s2LineOffset += s2LineStride;
546                     dLineOffset += dLineStride;
547 
548                     for (int w = 0; w < dwidth; w++) {
549                         d[dPixelOffset] = ImageUtil.clampInt((long)s1[s1PixelOffset] +
550                                                    (long)s2[s2PixelOffset]);
551 
552                         s1PixelOffset += s1PixelStride;
553                         s2PixelOffset += s2PixelStride;
554                         dPixelOffset += dPixelStride;
555                     }
556                 }
557             }
558             break;
559         }
560     }
561 
computeRectFloat(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)562     private void computeRectFloat(RasterAccessor src1,
563                                   RasterAccessor src2,
564                                   RasterAccessor dst) {
565         int s1LineStride = src1.getScanlineStride();
566         int s1PixelStride = src1.getPixelStride();
567         int[] s1BandOffsets = src1.getBandOffsets();
568         float[][] s1Data = src1.getFloatDataArrays();
569 
570         int s2LineStride = src2.getScanlineStride();
571         int s2PixelStride = src2.getPixelStride();
572         int[] s2BandOffsets = src2.getBandOffsets();
573         float[][] s2Data = src2.getFloatDataArrays();
574 
575         int dwidth = dst.getWidth();
576         int dheight = dst.getHeight();
577         int bands = dst.getNumBands();
578         int dLineStride = dst.getScanlineStride();
579         int dPixelStride = dst.getPixelStride();
580         int[] dBandOffsets = dst.getBandOffsets();
581         float[][] dData = dst.getFloatDataArrays();
582 
583         for (int b = 0, s1b = 0, s2b = 0; b < bands;
584              b++, s1b += s1bd, s2b += s2bd) {
585             float[] s1 = s1Data[s1b];
586             float[] s2 = s2Data[s2b];
587             float[] d = dData[b];
588 
589             int s1LineOffset = s1BandOffsets[s1b];
590             int s2LineOffset = s2BandOffsets[s2b];
591             int dLineOffset = dBandOffsets[b];
592 
593             for (int h = 0; h < dheight; h++) {
594                 int s1PixelOffset = s1LineOffset;
595                 int s2PixelOffset = s2LineOffset;
596                 int dPixelOffset = dLineOffset;
597 
598                 s1LineOffset += s1LineStride;
599                 s2LineOffset += s2LineStride;
600                 dLineOffset += dLineStride;
601 
602                 for (int w = 0; w < dwidth; w++) {
603                     d[dPixelOffset] = s1[s1PixelOffset] + s2[s2PixelOffset];
604 
605                     s1PixelOffset += s1PixelStride;
606                     s2PixelOffset += s2PixelStride;
607                     dPixelOffset += dPixelStride;
608                 }
609             }
610         }
611     }
612 
computeRectDouble(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)613     private void computeRectDouble(RasterAccessor src1,
614                                    RasterAccessor src2,
615                                    RasterAccessor dst) {
616         int s1LineStride = src1.getScanlineStride();
617         int s1PixelStride = src1.getPixelStride();
618         int[] s1BandOffsets = src1.getBandOffsets();
619         double[][] s1Data = src1.getDoubleDataArrays();
620 
621         int s2LineStride = src2.getScanlineStride();
622         int s2PixelStride = src2.getPixelStride();
623         int[] s2BandOffsets = src2.getBandOffsets();
624         double[][] s2Data = src2.getDoubleDataArrays();
625 
626         int dwidth = dst.getWidth();
627         int dheight = dst.getHeight();
628         int bands = dst.getNumBands();
629         int dLineStride = dst.getScanlineStride();
630         int dPixelStride = dst.getPixelStride();
631         int[] dBandOffsets = dst.getBandOffsets();
632         double[][] dData = dst.getDoubleDataArrays();
633 
634         for (int b = 0, s1b = 0, s2b = 0; b < bands;
635              b++, s1b += s1bd, s2b += s2bd) {
636             double[] s1 = s1Data[s1b];
637             double[] s2 = s2Data[s2b];
638             double[] d = dData[b];
639 
640             int s1LineOffset = s1BandOffsets[s1b];
641             int s2LineOffset = s2BandOffsets[s2b];
642             int dLineOffset = dBandOffsets[b];
643 
644             for (int h = 0; h < dheight; h++) {
645                 int s1PixelOffset = s1LineOffset;
646                 int s2PixelOffset = s2LineOffset;
647                 int dPixelOffset = dLineOffset;
648 
649                 s1LineOffset += s1LineStride;
650                 s2LineOffset += s2LineStride;
651                 dLineOffset += dLineStride;
652 
653                 for (int w = 0; w < dwidth; w++) {
654                     d[dPixelOffset] = s1[s1PixelOffset] + s2[s2PixelOffset];
655 
656                     s1PixelOffset += s1PixelStride;
657                     s2PixelOffset += s2PixelStride;
658                     dPixelOffset += dPixelStride;
659                 }
660             }
661         }
662     }
663 
664 //     public static void main(String args[]) {
665 //         System.out.println("AddOpImage Test");
666 //         ImageLayout layout;
667 //         OpImage src1, src2, dst;
668 //         Rectangle rect = new Rectangle(0, 0, 5, 5);
669 
670 //         System.out.println("1. PixelInterleaved byte 3-band");
671 //         layout = OpImageTester.createImageLayout(
672 //             0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, false);
673 //         src1 = OpImageTester.createRandomOpImage(layout);
674 //         src2 = OpImageTester.createRandomOpImage(layout);
675 //         dst = new AddOpImage(src1, src2, null, null);
676 //         OpImageTester.testOpImage(dst, rect);
677 //         OpImageTester.timeOpImage(dst, 10);
678 
679 //         System.out.println("2. Banded byte 3-band");
680 //         layout = OpImageTester.createImageLayout(
681 //            0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, true);
682 //         src1 = OpImageTester.createRandomOpImage(layout);
683 //         src2 = OpImageTester.createRandomOpImage(layout);
684 //         dst = new AddOpImage(src1, src2, null, null);
685 //         OpImageTester.testOpImage(dst, rect);
686 //         OpImageTester.timeOpImage(dst, 10);
687 
688 //         System.out.println("3. PixelInterleaved int 3-band");
689 //         layout = OpImageTester.createImageLayout(
690 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, false);
691 //         src1 = OpImageTester.createRandomOpImage(layout);
692 //         src2 = OpImageTester.createRandomOpImage(layout);
693 //         dst = new AddOpImage(src1, src2, null, null);
694 //         OpImageTester.testOpImage(dst, rect);
695 //         OpImageTester.timeOpImage(dst, 10);
696 
697 //         System.out.println("4. Banded int 3-band");
698 //         layout = OpImageTester.createImageLayout(
699 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, true);
700 //         src1 = OpImageTester.createRandomOpImage(layout);
701 //         src2 = OpImageTester.createRandomOpImage(layout);
702 //         dst = new AddOpImage(src1, src2, null, null);
703 //         OpImageTester.testOpImage(dst, rect);
704 //         OpImageTester.timeOpImage(dst, 10);
705 
706 //         System.out.println("5. PixelInterleaved float 3-band");
707 //         layout = OpImageTester.createImageLayout(
708 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_FLOAT, 3, false);
709 //         src1 = OpImageTester.createRandomOpImage(layout);
710 //         src2 = OpImageTester.createRandomOpImage(layout);
711 //         dst = new AddOpImage(src1, src2, null, null);
712 //         OpImageTester.testOpImage(dst, rect);
713 //         OpImageTester.timeOpImage(dst, 10);
714 
715 //         System.out.println("6. Banded float 3-band");
716 //         layout = OpImageTester.createImageLayout(
717 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_FLOAT, 3, true);
718 //         src1 = OpImageTester.createRandomOpImage(layout);
719 //         src2 = OpImageTester.createRandomOpImage(layout);
720 //         dst = new AddOpImage(src1, src2, null, null);
721 //         OpImageTester.testOpImage(dst, rect);
722 //         OpImageTester.timeOpImage(dst, 10);
723 
724 //         System.out.println("7. PixelInterleaved double 3-band");
725 //         layout = OpImageTester.createImageLayout(
726 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_DOUBLE, 3, false);
727 //         src1 = OpImageTester.createRandomOpImage(layout);
728 //         src2 = OpImageTester.createRandomOpImage(layout);
729 //         dst = new AddOpImage(src1, src2, null, null);
730 //         OpImageTester.testOpImage(dst, rect);
731 //         OpImageTester.timeOpImage(dst, 10);
732 
733 //         System.out.println("8. Banded double 3-band");
734 //         layout = OpImageTester.createImageLayout(
735 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_DOUBLE, 3, true);
736 //         src1 = OpImageTester.createRandomOpImage(layout);
737 //         src2 = OpImageTester.createRandomOpImage(layout);
738 //         dst = new AddOpImage(src1, src2, null, null);
739 //         OpImageTester.testOpImage(dst, rect);
740 //         OpImageTester.timeOpImage(dst, 10);
741 //     }
742 }
743