1 /*
2  * $RCSfile: SubtractFromConstOpImage.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:45 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.media.jai.opimage;
13 
14 import com.lightcrafts.mediax.jai.ColormapOpImage;
15 import com.lightcrafts.media.jai.util.ImageUtil;
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.WritableRaster;
21 import com.lightcrafts.mediax.jai.ImageLayout;
22 import com.lightcrafts.mediax.jai.RasterAccessor;
23 import com.lightcrafts.mediax.jai.RasterFormatTag;
24 import java.util.Map;
25 
26 /**
27  * An <code>OpImage</code> implementing the "SubtractFromConst" operation.
28  *
29  * <p>This <code>OpImage</code> subtracts the pixels of a rendered
30  * image from a set of constants, one for each band of the source image.
31  * The destination pixel values are calculated as:
32  * <pre>
33  *     for (int h = 0; h < dstHeight; h++) {
34  *         for (int w = 0; w < dstWidth; w++) {
35  *             for (int b = 0; b < dstNumBands; b++) {
36  *                 if (constants.length < dstNumBands) {
37  *                     dst[h][w][b] = constants[0] - srcs[h][w][b];
38  *                 } else {
39  *                     dst[h][w][b] = constants[b] - srcs[h][w][b];
40  *                 }
41  *             }
42  *         }
43  *     }
44  * </pre>
45  *
46  * @see com.lightcrafts.mediax.jai.operator.SubtractFromConstDescriptor
47  * @see SubtractFromConstCRIF
48  *
49  *
50  * @since EA2
51  */
52 final class SubtractFromConstOpImage extends ColormapOpImage {
53 
54     /** The constants to be subtracted from, one for each band. */
55     protected double constants[];
56     private byte[][] byteTable = null;
57 
initByteTable()58     private synchronized void initByteTable() {
59 
60 	if (byteTable != null)
61 	    return;
62 
63         int nbands = constants.length;
64 
65         byteTable = new byte[nbands][256];
66 
67         // Initialize table which implements SubtractFromConst and clamp
68         for(int band=0; band<nbands; band++) {
69             int k = ImageUtil.clampRoundInt(constants[band]);
70             byte[] t = byteTable[band];
71             for (int i = 0; i < 256; i++) {
72                 int diff = k - i;
73                 if (diff < 0) {
74                     t[i] = (byte)0;
75                 } else if (diff > 255) {
76                     t[i] = (byte)255;
77                 } else {
78                     t[i] = (byte)diff;
79                 }
80             }
81         }
82     }
83 
84     /**
85      * Constructor.
86      *
87      * @param source     The source image.
88      * @param layout     The destination image layout.
89      * @param constants  The constants to be subtracted from.
90      */
SubtractFromConstOpImage(RenderedImage source, Map config, ImageLayout layout, double[] constants)91     public SubtractFromConstOpImage(RenderedImage source,
92                                     Map config,
93                                     ImageLayout layout,
94                                     double[] constants) {
95         super(source, layout, config, true);
96 
97         int numBands = getSampleModel().getNumBands();
98 
99         if (constants.length < numBands) {
100             this.constants = new double[numBands];
101             for (int i = 0; i < numBands; i++) {
102                 this.constants[i] = constants[0];
103             }
104         } else {
105             this.constants = (double[])constants.clone();
106         }
107 
108         // Set flag to permit in-place operation.
109         permitInPlaceOperation();
110 
111         // Initialize the colormap if necessary.
112         initializeColormapOperation();
113     }
114 
115     /**
116      * Transform the colormap according to the rescaling parameters.
117      */
transformColormap(byte[][] colormap)118     protected void transformColormap(byte[][] colormap) {
119 	initByteTable();
120 
121         for(int b = 0; b < 3; b++) {
122             byte[] map = colormap[b];
123 	    byte[] luTable = byteTable[b >= byteTable.length ? 0 : b];
124             int mapSize = map.length;
125 
126             for(int i = 0; i < mapSize; i++) {
127                 map[i] = luTable[(map[i] & 0xFF)];
128             }
129         }
130     }
131 
132     /**
133      * Subtracts the pixel values within a specified rectangle from a constant.
134      *
135      * @param sources   Cobbled sources, guaranteed to provide all the
136      *                  source data necessary for computing the rectangle.
137      * @param dest      The tile containing the rectangle to be computed.
138      * @param destRect  The rectangle within the tile to be computed.
139      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)140     protected void computeRect(Raster[] sources,
141                                WritableRaster dest,
142                                Rectangle destRect) {
143         // Retrieve format tags.
144         RasterFormatTag[] formatTags = getFormatTags();
145 
146         Rectangle srcRect = mapDestRect(destRect, 0);
147 
148         RasterAccessor dst = new RasterAccessor(dest, destRect,
149                                                 formatTags[1], getColorModel());
150         RasterAccessor src = new RasterAccessor(sources[0], srcRect,
151                                                 formatTags[0],
152                                                 getSource(0).getColorModel());
153 
154         switch (dst.getDataType()) {
155         case DataBuffer.TYPE_BYTE:
156             computeRectByte(src, dst);
157             break;
158         case DataBuffer.TYPE_USHORT:
159             computeRectUShort(src, dst);
160             break;
161         case DataBuffer.TYPE_SHORT:
162             computeRectShort(src, dst);
163             break;
164         case DataBuffer.TYPE_INT:
165             computeRectInt(src, dst);
166             break;
167         case DataBuffer.TYPE_FLOAT:
168             computeRectFloat(src, dst);
169             break;
170         case DataBuffer.TYPE_DOUBLE:
171             computeRectDouble(src, dst);
172             break;
173         }
174 
175         if (dst.needsClamping()) {
176             /* Further clamp down to underlying raster data type. */
177             dst.clampDataArrays();
178         }
179         dst.copyDataToRaster();
180     }
181 
computeRectByte(RasterAccessor src, RasterAccessor dst)182     private void computeRectByte(RasterAccessor src,
183                                  RasterAccessor dst) {
184 	initByteTable();
185 
186         int dstWidth = dst.getWidth();
187         int dstHeight = dst.getHeight();
188         int dstBands = dst.getNumBands();
189 
190         int dstLineStride = dst.getScanlineStride();
191         int dstPixelStride = dst.getPixelStride();
192         int[] dstBandOffsets = dst.getBandOffsets();
193         byte[][] dstData = dst.getByteDataArrays();
194 
195         int srcLineStride = src.getScanlineStride();
196         int srcPixelStride = src.getPixelStride();
197         int[] srcBandOffsets = src.getBandOffsets();
198         byte[][] srcData = src.getByteDataArrays();
199 
200         for (int b = 0; b < dstBands; b++) {
201             int c = ImageUtil.clampRoundInt(constants[b]);
202             byte[] d = dstData[b];
203             byte[] s = srcData[b];
204             byte[] clamp = byteTable[b];
205 
206             int dstLineOffset = dstBandOffsets[b];
207             int srcLineOffset = srcBandOffsets[b];
208 
209             for (int h = 0; h < dstHeight; h++) {
210                 int dstPixelOffset = dstLineOffset;
211                 int srcPixelOffset = srcLineOffset;
212 
213                 dstLineOffset += dstLineStride;
214                 srcLineOffset += srcLineStride;
215 
216                 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride;
217                 while (dstPixelOffset < dstEnd) {
218                     d[dstPixelOffset] = clamp[s[srcPixelOffset] & 0xFF];
219 
220                     dstPixelOffset += dstPixelStride;
221                     srcPixelOffset += srcPixelStride;
222                 }
223             }
224         }
225     }
226 
computeRectUShort(RasterAccessor src, RasterAccessor dst)227     private void computeRectUShort(RasterAccessor src,
228                                    RasterAccessor dst) {
229         int dstWidth = dst.getWidth();
230         int dstHeight = dst.getHeight();
231         int dstBands = dst.getNumBands();
232 
233         int dstLineStride = dst.getScanlineStride();
234         int dstPixelStride = dst.getPixelStride();
235         int[] dstBandOffsets = dst.getBandOffsets();
236         short[][] dstData = dst.getShortDataArrays();
237 
238         int srcLineStride = src.getScanlineStride();
239         int srcPixelStride = src.getPixelStride();
240         int[] srcBandOffsets = src.getBandOffsets();
241         short[][] srcData = src.getShortDataArrays();
242 
243         for (int b = 0; b < dstBands; b++) {
244             int c = ImageUtil.clampRoundInt(constants[b]);
245             short[] d = dstData[b];
246             short[] s = srcData[b];
247 
248             int dstLineOffset = dstBandOffsets[b];
249             int srcLineOffset = srcBandOffsets[b];
250 
251             for (int h = 0; h < dstHeight; h++) {
252                 int dstPixelOffset = dstLineOffset;
253                 int srcPixelOffset = srcLineOffset;
254 
255                 dstLineOffset += dstLineStride;
256                 srcLineOffset += srcLineStride;
257 
258                 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride;
259                 while (dstPixelOffset < dstEnd) {
260                     d[dstPixelOffset] = ImageUtil.clampUShort(
261                                         c - (s[srcPixelOffset] & 0xFFFF));
262 
263                     dstPixelOffset += dstPixelStride;
264                     srcPixelOffset += srcPixelStride;
265                 }
266             }
267         }
268     }
269 
computeRectShort(RasterAccessor src, RasterAccessor dst)270     private void computeRectShort(RasterAccessor src,
271                                   RasterAccessor dst) {
272         int dstWidth = dst.getWidth();
273         int dstHeight = dst.getHeight();
274         int dstBands = dst.getNumBands();
275 
276         int dstLineStride = dst.getScanlineStride();
277         int dstPixelStride = dst.getPixelStride();
278         int[] dstBandOffsets = dst.getBandOffsets();
279         short[][] dstData = dst.getShortDataArrays();
280 
281         int srcLineStride = src.getScanlineStride();
282         int srcPixelStride = src.getPixelStride();
283         int[] srcBandOffsets = src.getBandOffsets();
284         short[][] srcData = src.getShortDataArrays();
285 
286         for (int b = 0; b < dstBands; b++) {
287             int c = ImageUtil.clampRoundInt(constants[b]);
288             short[] d = dstData[b];
289             short[] s = srcData[b];
290 
291             int dstLineOffset = dstBandOffsets[b];
292             int srcLineOffset = srcBandOffsets[b];
293 
294             for (int h = 0; h < dstHeight; h++) {
295                 int dstPixelOffset = dstLineOffset;
296                 int srcPixelOffset = srcLineOffset;
297 
298                 dstLineOffset += dstLineStride;
299                 srcLineOffset += srcLineStride;
300 
301                 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride;
302                 while (dstPixelOffset < dstEnd) {
303                     d[dstPixelOffset] = ImageUtil.clampShort(c - s[srcPixelOffset]);
304 
305                     dstPixelOffset += dstPixelStride;
306                     srcPixelOffset += srcPixelStride;
307                 }
308             }
309         }
310     }
311 
computeRectInt(RasterAccessor src, RasterAccessor dst)312     private void computeRectInt(RasterAccessor src,
313                                 RasterAccessor dst) {
314         int dstWidth = dst.getWidth();
315         int dstHeight = dst.getHeight();
316         int dstBands = dst.getNumBands();
317 
318         int dstLineStride = dst.getScanlineStride();
319         int dstPixelStride = dst.getPixelStride();
320         int[] dstBandOffsets = dst.getBandOffsets();
321         int[][] dstData = dst.getIntDataArrays();
322 
323         int srcLineStride = src.getScanlineStride();
324         int srcPixelStride = src.getPixelStride();
325         int[] srcBandOffsets = src.getBandOffsets();
326         int[][] srcData = src.getIntDataArrays();
327 
328         for (int b = 0; b < dstBands; b++) {
329             long c = ImageUtil.clampRoundInt(constants[b]);
330             int[] d = dstData[b];
331             int[] s = srcData[b];
332 
333             int dstLineOffset = dstBandOffsets[b];
334             int srcLineOffset = srcBandOffsets[b];
335 
336             for (int h = 0; h < dstHeight; h++) {
337                 int dstPixelOffset = dstLineOffset;
338                 int srcPixelOffset = srcLineOffset;
339 
340                 dstLineOffset += dstLineStride;
341                 srcLineOffset += srcLineStride;
342 
343                 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride;
344                 while (dstPixelOffset < dstEnd) {
345                     d[dstPixelOffset] = ImageUtil.clampInt(c - s[srcPixelOffset]);
346 
347                     dstPixelOffset += dstPixelStride;
348                     srcPixelOffset += srcPixelStride;
349                 }
350             }
351         }
352     }
353 
computeRectFloat(RasterAccessor src, RasterAccessor dst)354     private void computeRectFloat(RasterAccessor src,
355                                   RasterAccessor dst) {
356         int dstWidth = dst.getWidth();
357         int dstHeight = dst.getHeight();
358         int dstBands = dst.getNumBands();
359 
360         int dstLineStride = dst.getScanlineStride();
361         int dstPixelStride = dst.getPixelStride();
362         int[] dstBandOffsets = dst.getBandOffsets();
363         float[][] dstData = dst.getFloatDataArrays();
364 
365         int srcLineStride = src.getScanlineStride();
366         int srcPixelStride = src.getPixelStride();
367         int[] srcBandOffsets = src.getBandOffsets();
368         float[][] srcData = src.getFloatDataArrays();
369 
370         for (int b = 0; b < dstBands; b++) {
371             double c = constants[b];
372             float[] d = dstData[b];
373             float[] s = srcData[b];
374 
375             int dstLineOffset = dstBandOffsets[b];
376             int srcLineOffset = srcBandOffsets[b];
377 
378             for (int h = 0; h < dstHeight; h++) {
379                 int dstPixelOffset = dstLineOffset;
380                 int srcPixelOffset = srcLineOffset;
381 
382                 dstLineOffset += dstLineStride;
383                 srcLineOffset += srcLineStride;
384 
385                 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride;
386                 while (dstPixelOffset < dstEnd) {
387                     d[dstPixelOffset] =
388                         ImageUtil.clampFloat(c - s[srcPixelOffset]);
389 
390                     dstPixelOffset += dstPixelStride;
391                     srcPixelOffset += srcPixelStride;
392                 }
393             }
394         }
395     }
396 
computeRectDouble(RasterAccessor src, RasterAccessor dst)397     private void computeRectDouble(RasterAccessor src,
398                                    RasterAccessor dst) {
399         int dstWidth = dst.getWidth();
400         int dstHeight = dst.getHeight();
401         int dstBands = dst.getNumBands();
402 
403         int dstLineStride = dst.getScanlineStride();
404         int dstPixelStride = dst.getPixelStride();
405         int[] dstBandOffsets = dst.getBandOffsets();
406         double[][] dstData = dst.getDoubleDataArrays();
407 
408         int srcLineStride = src.getScanlineStride();
409         int srcPixelStride = src.getPixelStride();
410         int[] srcBandOffsets = src.getBandOffsets();
411         double[][] srcData = src.getDoubleDataArrays();
412 
413         for (int b = 0; b < dstBands; b++) {
414             double c = constants[b];
415             double[] d = dstData[b];
416             double[] s = srcData[b];
417 
418             int dstLineOffset = dstBandOffsets[b];
419             int srcLineOffset = srcBandOffsets[b];
420 
421             for (int h = 0; h < dstHeight; h++) {
422                 int dstPixelOffset = dstLineOffset;
423                 int srcPixelOffset = srcLineOffset;
424 
425                 dstLineOffset += dstLineStride;
426                 srcLineOffset += srcLineStride;
427 
428                 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride;
429                 while (dstPixelOffset < dstEnd) {
430                     d[dstPixelOffset] = c - s[srcPixelOffset];
431 
432                     dstPixelOffset += dstPixelStride;
433                     srcPixelOffset += srcPixelStride;
434                 }
435             }
436         }
437     }
438 }
439