1 /*
2  * $RCSfile: AndOpImage.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:14 $
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.WritableRaster;
18 import com.lightcrafts.mediax.jai.ImageLayout;
19 import com.lightcrafts.mediax.jai.PointOpImage;
20 import com.lightcrafts.mediax.jai.RasterAccessor;
21 import com.lightcrafts.mediax.jai.RasterFormatTag;
22 import java.util.Map;
23 // import com.lightcrafts.media.jai.test.OpImageTester;
24 
25 /**
26  * An <code>OpImage</code> implementing the "And" operation as
27  * described in <code>com.lightcrafts.mediax.jai.operator.AndDescriptor</code>.
28  *
29  * <p>This <code>OpImage</code> logically "ands" the pixel values of two source
30  * images on a per-band basis. In case the two source images have different
31  * number of bands, the number of bands for the destination image is the
32  * smaller band number of the two source images. That is
33  * <code>dstNumBands = Math.min(src1NumBands, src2NumBands)</code>.
34  * In case the two source images have different data types, the data type
35  * for the destination image is the bigger data type of the two source
36  * images.
37  *
38  * <p>The value of the pixel (x, y) in the destination image is defined as:
39  * <pre>
40  * for (b = 0; b < numBands; b++) {
41  *     dst[y][x][b] = src1[y][x][b] & src2[y][x][b];
42  * }
43  * </pre>
44  *
45  * The data type <code>byte</code> is treated as unsigned, with maximum
46  * value as 255 and minimum value as 0.
47  *
48  * @since EA2
49  * @see com.lightcrafts.mediax.jai.operator.AndDescriptor
50  * @see AndCRIF
51  *
52  */
53 final class AndOpImage extends PointOpImage {
54 
55     /**
56      * Constructs an <code>AndOpImage</code>.
57      *
58      * <p>The <code>layout</code> parameter may optionally contains the
59      * tile grid layout, sample model, and/or color model. The image
60      * dimension is determined by the intersection of the bounding boxes
61      * of the two source images.
62      *
63      * <p>The image layout of the first source image, <code>source1</code>,
64      * is used as the fall-back for the image layout of the destination
65      * image. Any layout parameters not specified in the <code>layout</code>
66      * argument are set to the same value as that of <code>source1</code>.
67      *
68      * @param source1  The first source image.
69      * @param source2  The second source image.
70      * @param layout   The destination image layout.
71      */
AndOpImage(RenderedImage source1, RenderedImage source2, Map config, ImageLayout layout)72     public AndOpImage(RenderedImage source1,
73                       RenderedImage source2,
74                       Map config,
75 		      ImageLayout layout) {
76         super(source1, source2, layout, config, true);
77 
78         // Set flag to permit in-place operation.
79         permitInPlaceOperation();
80     }
81 
82     /**
83      * Multiplies the pixel values of two source images within a specified
84      * rectangle.
85      *
86      * @param sources   Cobbled sources, guaranteed to provide all the
87      *                  source data necessary for computing the rectangle.
88      * @param dest      The tile containing the rectangle to be computed.
89      * @param destRect  The rectangle within the tile to be computed.
90      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)91     protected void computeRect(Raster[] sources,
92                                WritableRaster dest,
93                                Rectangle destRect) {
94         // Retrieve format tags.
95         RasterFormatTag[] formatTags = getFormatTags();
96 
97         /* For PointOpImage, srcRect = destRect. */
98         RasterAccessor s1 = new RasterAccessor(sources[0], destRect,
99                                                formatTags[0],
100                                                getSourceImage(0).getColorModel());
101         RasterAccessor s2 = new RasterAccessor(sources[1], destRect,
102                                                formatTags[1],
103                                                getSourceImage(1).getColorModel());
104         RasterAccessor d = new RasterAccessor(dest, destRect,
105                                               formatTags[2], getColorModel());
106 
107         if(d.isBinary()) {
108             byte[] src1Bits = s1.getBinaryDataArray();
109             byte[] src2Bits = s2.getBinaryDataArray();
110             byte[] dstBits = d.getBinaryDataArray();
111 
112             int length = dstBits.length;
113             for(int i = 0; i < length; i++) {
114                 dstBits[i] = (byte)(src1Bits[i] & src2Bits[i]);
115             }
116 
117             d.copyBinaryDataToRaster();
118 
119             return;
120         }
121 
122         int src1LineStride = s1.getScanlineStride();
123         int src1PixelStride = s1.getPixelStride();
124         int[] src1BandOffsets = s1.getBandOffsets();
125 
126         int src2LineStride = s2.getScanlineStride();
127         int src2PixelStride = s2.getPixelStride();
128         int[] src2BandOffsets = s2.getBandOffsets();
129 
130         int dstNumBands = d.getNumBands();
131         int dstWidth = d.getWidth();
132         int dstHeight = d.getHeight();
133         int dstLineStride = d.getScanlineStride();
134         int dstPixelStride = d.getPixelStride();
135         int[] dstBandOffsets = d.getBandOffsets();
136 
137         switch (d.getDataType()) {
138 
139         case DataBuffer.TYPE_BYTE:
140             byteLoop(dstNumBands, dstWidth, dstHeight,
141                      src1LineStride, src1PixelStride,
142                      src1BandOffsets, s1.getByteDataArrays(),
143                      src2LineStride, src2PixelStride,
144                      src2BandOffsets, s2.getByteDataArrays(),
145                      dstLineStride, dstPixelStride,
146                      dstBandOffsets, d.getByteDataArrays());
147             break;
148 
149         case DataBuffer.TYPE_USHORT:
150         case DataBuffer.TYPE_SHORT:
151             shortLoop(dstNumBands, dstWidth, dstHeight,
152 		      src1LineStride, src1PixelStride,
153 		      src1BandOffsets, s1.getShortDataArrays(),
154 		      src2LineStride, src2PixelStride,
155 		      src2BandOffsets, s2.getShortDataArrays(),
156 		      dstLineStride, dstPixelStride,
157 		      dstBandOffsets, d.getShortDataArrays());
158             break;
159 
160         case DataBuffer.TYPE_INT:
161             intLoop(dstNumBands, dstWidth, dstHeight,
162                     src1LineStride, src1PixelStride,
163                     src1BandOffsets, s1.getIntDataArrays(),
164                     src2LineStride, src2PixelStride,
165                     src2BandOffsets, s2.getIntDataArrays(),
166                     dstLineStride, dstPixelStride,
167                     dstBandOffsets, d.getIntDataArrays());
168             break;
169         }
170 
171         d.copyDataToRaster();
172     }
173 
byteLoop(int dstNumBands, int dstWidth, int dstHeight, int src1LineStride, int src1PixelStride, int[] src1BandOffsets, byte[][] src1Data, int src2LineStride, int src2PixelStride, int[] src2BandOffsets, byte[][] src2Data, int dstLineStride, int dstPixelStride, int[] dstBandOffsets, byte[][] dstData)174     private void byteLoop(int dstNumBands, int dstWidth, int dstHeight,
175                           int src1LineStride, int src1PixelStride,
176                           int[] src1BandOffsets, byte[][] src1Data,
177                           int src2LineStride, int src2PixelStride,
178                           int[] src2BandOffsets, byte[][] src2Data,
179                           int dstLineStride, int dstPixelStride,
180                           int[] dstBandOffsets, byte[][] dstData) {
181 
182 	for (int b = 0; b < dstNumBands; b++) {
183             byte[] s1 = src1Data[b];
184             byte[] s2 = src2Data[b];
185             byte[] d = dstData[b];
186             int src1LineOffset = src1BandOffsets[b];
187             int src2LineOffset = src2BandOffsets[b];
188             int dstLineOffset = dstBandOffsets[b];
189 
190             for (int h = 0; h < dstHeight; h++) {
191                 int src1PixelOffset = src1LineOffset;
192                 int src2PixelOffset = src2LineOffset;
193                 int dstPixelOffset = dstLineOffset;
194                 src1LineOffset += src1LineStride;
195                 src2LineOffset += src2LineStride;
196                 dstLineOffset += dstLineStride;
197 
198                 for (int w = 0; w < dstWidth; w++) {
199 		    d[dstPixelOffset] = (byte)(s1[src1PixelOffset] &
200 					       s2[src2PixelOffset]);
201                     src1PixelOffset += src1PixelStride;
202                     src2PixelOffset += src2PixelStride;
203                     dstPixelOffset += dstPixelStride;
204                 }
205             }
206         }
207     }
208 
shortLoop(int dstNumBands, int dstWidth, int dstHeight, int src1LineStride, int src1PixelStride, int[] src1BandOffsets, short[][] src1Data, int src2LineStride, int src2PixelStride, int[] src2BandOffsets, short[][] src2Data, int dstLineStride, int dstPixelStride, int[] dstBandOffsets, short[][] dstData)209     private void shortLoop(int dstNumBands, int dstWidth, int dstHeight,
210 			   int src1LineStride, int src1PixelStride,
211 			   int[] src1BandOffsets, short[][] src1Data,
212 			   int src2LineStride, int src2PixelStride,
213 			   int[] src2BandOffsets, short[][] src2Data,
214 			   int dstLineStride, int dstPixelStride,
215                             int[] dstBandOffsets, short[][] dstData) {
216 
217 	for (int b = 0; b < dstNumBands; b++) {
218             short[] s1 = src1Data[b];
219             short[] s2 = src2Data[b];
220             short[] d = dstData[b];
221             int src1LineOffset = src1BandOffsets[b];
222             int src2LineOffset = src2BandOffsets[b];
223             int dstLineOffset = dstBandOffsets[b];
224 
225             for (int h = 0; h < dstHeight; h++) {
226                 int src1PixelOffset = src1LineOffset;
227                 int src2PixelOffset = src2LineOffset;
228                 int dstPixelOffset = dstLineOffset;
229                 src1LineOffset += src1LineStride;
230                 src2LineOffset += src2LineStride;
231                 dstLineOffset += dstLineStride;
232 
233                 for (int w = 0; w < dstWidth; w++) {
234                     d[dstPixelOffset] = (short)(s1[src1PixelOffset] &
235 						s2[src2PixelOffset]);
236 
237                     src1PixelOffset += src1PixelStride;
238                     src2PixelOffset += src2PixelStride;
239                     dstPixelOffset += dstPixelStride;
240                 }
241             }
242         }
243     }
244 
intLoop(int dstNumBands, int dstWidth, int dstHeight, int src1LineStride, int src1PixelStride, int[] src1BandOffsets, int[][] src1Data, int src2LineStride, int src2PixelStride, int[] src2BandOffsets, int[][] src2Data, int dstLineStride, int dstPixelStride, int[] dstBandOffsets, int[][] dstData)245     private void intLoop(int dstNumBands, int dstWidth, int dstHeight,
246                          int src1LineStride, int src1PixelStride,
247                          int[] src1BandOffsets, int[][] src1Data,
248                          int src2LineStride, int src2PixelStride,
249                          int[] src2BandOffsets, int[][] src2Data,
250                          int dstLineStride, int dstPixelStride,
251                          int[] dstBandOffsets, int[][] dstData) {
252 
253 	for (int b = 0; b < dstNumBands; b++) {
254 	    int[] s1 = src1Data[b];
255 	    int[] s2 = src2Data[b];
256 	    int[] d = dstData[b];
257 	    int src1LineOffset = src1BandOffsets[b];
258 	    int src2LineOffset = src2BandOffsets[b];
259 	    int dstLineOffset = dstBandOffsets[b];
260 
261 	    for (int h = 0; h < dstHeight; h++) {
262 		int src1PixelOffset = src1LineOffset;
263 		int src2PixelOffset = src2LineOffset;
264 		int dstPixelOffset = dstLineOffset;
265 		src1LineOffset += src1LineStride;
266 		src2LineOffset += src2LineStride;
267 		dstLineOffset += dstLineStride;
268 
269 		for (int w = 0; w < dstWidth; w++) {
270 		    d[dstPixelOffset] = s1[src1PixelOffset] & s2[src2PixelOffset];
271 
272 		    src1PixelOffset += src1PixelStride;
273 		    src2PixelOffset += src2PixelStride;
274 		    dstPixelOffset += dstPixelStride;
275 		}
276 	    }
277 	}
278     }
279 
280 //     public static void main(String args[]) {
281 //         System.out.println("AndOpImage Test");
282 //         ImageLayout layout;
283 //         OpImage src1, src2, dst;
284 //         Rectangle rect = new Rectangle(0, 0, 5, 5);
285 
286 //         System.out.println("1. PixelInterleaved byte 3-band");
287 //         layout = OpImageTester.createImageLayout(
288 //             0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, false);
289 //         src1 = OpImageTester.createRandomOpImage(layout);
290 //         src2 = OpImageTester.createRandomOpImage(layout);
291 //         dst = new AndOpImage(src1, src2, null, null);
292 //         OpImageTester.testOpImage(dst, rect);
293 //         OpImageTester.timeOpImage(dst, 10);
294 
295 //         System.out.println("2. Banded byte 3-band");
296 //         layout = OpImageTester.createImageLayout(
297 //            0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, true);
298 //         src1 = OpImageTester.createRandomOpImage(layout);
299 //         src2 = OpImageTester.createRandomOpImage(layout);
300 //         dst = new AndOpImage(src1, src2, null, null);
301 //         OpImageTester.testOpImage(dst, rect);
302 //         OpImageTester.timeOpImage(dst, 10);
303 
304 //         System.out.println("3. PixelInterleaved int 3-band");
305 //         layout = OpImageTester.createImageLayout(
306 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, false);
307 //         src1 = OpImageTester.createRandomOpImage(layout);
308 //         src2 = OpImageTester.createRandomOpImage(layout);
309 //         dst = new AndOpImage(src1, src2, null, null);
310 //         OpImageTester.testOpImage(dst, rect);
311 //         OpImageTester.timeOpImage(dst, 10);
312 
313 //         System.out.println("4. Banded int 3-band");
314 //         layout = OpImageTester.createImageLayout(
315 //             0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, true);
316 //         src1 = OpImageTester.createRandomOpImage(layout);
317 //         src2 = OpImageTester.createRandomOpImage(layout);
318 //         dst = new AndOpImage(src1, src2, null, null);
319 //         OpImageTester.testOpImage(dst, rect);
320 //         OpImageTester.timeOpImage(dst, 10);
321 //     }
322 }
323