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