1 /*
2  * $RCSfile: ExpOpImage.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:25 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.media.jai.opimage;
13 
14 import com.lightcrafts.mediax.jai.ColormapOpImage;
15 import java.awt.Rectangle;
16 import java.awt.image.DataBuffer;
17 import java.awt.image.Raster;
18 import java.awt.image.RenderedImage;
19 import java.awt.image.WritableRaster;
20 import com.lightcrafts.mediax.jai.ImageLayout;
21 import com.lightcrafts.mediax.jai.RasterAccessor;
22 import com.lightcrafts.mediax.jai.RasterFormatTag;
23 import java.util.Map;
24 import com.lightcrafts.media.jai.util.ImageUtil;
25 
26 /**
27  * An <code>OpImage</code> implementing the "Exp" operation as
28  * described in <code>com.lightcrafts.mediax.jai.operator.ExpDescriptor</code>.
29  *
30  * The result is rounded to the closest integer for intergral data types.
31  * <p> This <code>OpImage</code> takes the natural exponential of the pixel
32  * values of an image.  The operation is done on a per-pixel, per-band
33  * basis.
34  *
35  * @see com.lightcrafts.mediax.jai.operator.ExpDescriptor
36  * @see ExpCRIF
37  *
38  * @since EA2
39  *
40  */
41 final class ExpOpImage extends ColormapOpImage {
42 
43     /** A lookup table for byte data type. */
44     private byte[] byteTable = null;
45 
46     /**
47      * The largest unsigned short to get a non-overflowed exponential result.
48      * i.e. cloeset to 65536.
49      * exp(11) = 59874.14171, exp(12) = 162754.7914
50      */
51     private static int USHORT_UP_BOUND = 11;
52 
53     /**
54      * The largest short to get a non-overflowed exponential result.
55      * i.e. closest to 32767.
56      * exp(10) = 22026.46579, exp(11) = 59874.14171
57      */
58     private static int SHORT_UP_BOUND = 10;
59 
60     /**
61      * The largest int to get a non-overflown exponential result.
62      * i.e. cloeset to 2**31-1 = 2147483647.
63      * exp(21) = 1318815734, exp(22) = 3584912846.
64      */
65     private static int INT_UP_BOUND = 21;
66 
67     /**
68      * The smallest integer to get a non-zero exponential result is
69      * 0. i.e. exp(0) = 1; exp(-1) = 0.367879441, which will be stored as 0.
70      * all other negative values will result in 0.
71      */
72     private static int LOW_BOUND = 0;
73 
74     /**
75      * Constructor.
76      *
77      * <p> The layout of the source is used as the fall-back for
78      * the layout of the destination.  Any layout parameters not
79      * specified in the <code>layout</code> argument are set to
80      * the same value as that of the source.
81      *
82      * @param source  The source image.
83 
84      * @param layout  The destination image layout.
85      */
ExpOpImage(RenderedImage source, Map config, ImageLayout layout)86     public ExpOpImage(RenderedImage source,
87                       Map config,
88                       ImageLayout layout) {
89         super(source, layout, config, true);
90 
91         /* Set flag to permit in-place operation. */
92         permitInPlaceOperation();
93 
94         // Initialize the colormap if necessary.
95         initializeColormapOperation();
96     }
97 
98     /**
99      * Transform the colormap according to the rescaling parameters.
100      */
transformColormap(byte[][] colormap)101     protected void transformColormap(byte[][] colormap) {
102 	initByteTable();
103 
104         for(int b = 0; b < 3; b++) {
105             byte[] map = colormap[b];
106             int mapSize = map.length;
107 
108             for(int i = 0; i < mapSize; i++) {
109                 map[i] = byteTable[(map[i] & 0xFF)];
110             }
111         }
112     }
113 
114     /**
115      * Map the pixels inside a specified rectangle whose value is within a
116      * range to a constant on a per-band basis.
117      *
118      * @param sources   Cobbled sources, guaranteed to provide all the
119      *                  source data necessary for computing the rectangle.
120      * @param dest      The tile containing the rectangle to be computed.
121      * @param destRect  The rectangle within the tile to be computed.
122      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)123     protected void computeRect(Raster[] sources,
124                                WritableRaster dest,
125                                Rectangle destRect) {
126         /* Retrieve format tags. */
127         RasterFormatTag[] formatTags = getFormatTags();
128 
129         /* No need to mapSourceRect for PointOps. */
130         RasterAccessor s = new RasterAccessor(sources[0],
131                                               destRect,
132                                               formatTags[0],
133                                               getSourceImage(0).getColorModel());
134         RasterAccessor d = new RasterAccessor(dest,
135                                               destRect,
136                                               formatTags[1],
137                                               getColorModel());
138 
139         switch (d.getDataType()) {
140         case DataBuffer.TYPE_BYTE:
141             computeRectByte(s, d);
142             break;
143         case DataBuffer.TYPE_USHORT:
144             computeRectUShort(s, d);
145             break;
146         case DataBuffer.TYPE_SHORT:
147             computeRectShort(s, d);
148             break;
149         case DataBuffer.TYPE_INT:
150             computeRectInt(s, d);
151             break;
152         case DataBuffer.TYPE_FLOAT:
153             computeRectFloat(s, d);
154             break;
155         case DataBuffer.TYPE_DOUBLE:
156             computeRectDouble(s, d);
157             break;
158         }
159 
160         if (d.needsClamping()) {
161             d.clampDataArrays();
162         }
163         d.copyDataToRaster();
164     }
165 
computeRectByte(RasterAccessor src, RasterAccessor dst)166     private void computeRectByte(RasterAccessor src,
167                                  RasterAccessor dst) {
168 	initByteTable();
169 
170         int srcLineStride = src.getScanlineStride();
171         int srcPixelStride = src.getPixelStride();
172         int[] srcBandOffsets = src.getBandOffsets();
173         byte[][] srcData = src.getByteDataArrays();
174 
175         int dstLineStride = dst.getScanlineStride();
176         int dstPixelStride = dst.getPixelStride();
177         int[] dstBandOffsets = dst.getBandOffsets();
178         byte[][] dstData = dst.getByteDataArrays();
179 
180         int dstWidth = dst.getWidth();
181         int dstHeight = dst.getHeight();
182         int dstBands = dst.getNumBands();
183 
184         for (int b = 0; b < dstBands; b++) {
185             byte[] s = srcData[b];
186             byte[] d = dstData[b];
187 
188             int srcLineOffset = srcBandOffsets[b];
189             int dstLineOffset = dstBandOffsets[b];
190 
191             for (int h = 0; h < dstHeight; h++) {
192                 int srcPixelOffset = srcLineOffset;
193                 int dstPixelOffset = dstLineOffset;
194 
195                 srcLineOffset += srcLineStride;
196                 dstLineOffset += dstLineStride;
197 
198                 for (int w = 0; w < dstWidth; w++) {
199                     d[dstPixelOffset] = byteTable[s[srcPixelOffset] & ImageUtil.BYTE_MASK];
200 
201                     srcPixelOffset += srcPixelStride;
202                     dstPixelOffset += dstPixelStride;
203                 }
204             }
205         }
206     }
207 
computeRectUShort(RasterAccessor src, RasterAccessor dst)208     private void computeRectUShort(RasterAccessor src,
209                                    RasterAccessor dst) {
210 
211         int srcLineStride = src.getScanlineStride();
212         int srcPixelStride = src.getPixelStride();
213         int[] srcBandOffsets = src.getBandOffsets();
214         short[][] srcData = src.getShortDataArrays();
215 
216         int dstLineStride = dst.getScanlineStride();
217         int dstPixelStride = dst.getPixelStride();
218         int[] dstBandOffsets = dst.getBandOffsets();
219         short[][] dstData = dst.getShortDataArrays();
220 
221         int dstWidth = dst.getWidth();
222         int dstHeight = dst.getHeight();
223         int dstBands = dst.getNumBands();
224 
225         short max = (short)ImageUtil.USHORT_MASK;
226 
227         for (int b = 0; b < dstBands; b++) {
228             short[] s = srcData[b];
229             short[] d = dstData[b];
230 
231             int srcLineOffset = srcBandOffsets[b];
232             int dstLineOffset = dstBandOffsets[b];
233 
234             for (int h = 0; h < dstHeight; h++) {
235                 int srcPixelOffset = srcLineOffset;
236                 int dstPixelOffset = dstLineOffset;
237 
238                 srcLineOffset += srcLineStride;
239                 dstLineOffset += dstLineStride;
240 
241                 for (int w = 0; w < dstWidth; w++) {
242                     double p = s[srcPixelOffset] & ImageUtil.USHORT_MASK;
243                     if (p == 0) {
244                         d[dstPixelOffset] = 1;
245                     } else if (p > USHORT_UP_BOUND) {
246                         d[dstPixelOffset] = max;
247                     } else {
248                         d[dstPixelOffset] = (short)(Math.exp(p) + 0.5);
249                     }
250 
251                     srcPixelOffset += srcPixelStride;
252                     dstPixelOffset += dstPixelStride;
253                 }
254             }
255         }
256     }
257 
computeRectShort(RasterAccessor src, RasterAccessor dst)258     private void computeRectShort(RasterAccessor src,
259                                   RasterAccessor dst) {
260 
261         int srcLineStride = src.getScanlineStride();
262         int srcPixelStride = src.getPixelStride();
263         int[] srcBandOffsets = src.getBandOffsets();
264         short[][] srcData = src.getShortDataArrays();
265 
266         int dstLineStride = dst.getScanlineStride();
267         int dstPixelStride = dst.getPixelStride();
268         int[] dstBandOffsets = dst.getBandOffsets();
269         short[][] dstData = dst.getShortDataArrays();
270 
271         int dstWidth = dst.getWidth();
272         int dstHeight = dst.getHeight();
273         int dstBands = dst.getNumBands();
274 
275         for (int b = 0; b < dstBands; b++) {
276             short[] s = srcData[b];
277             short[] d = dstData[b];
278 
279             int srcLineOffset = srcBandOffsets[b];
280             int dstLineOffset = dstBandOffsets[b];
281 
282             for (int h = 0; h < dstHeight; h++) {
283                 int srcPixelOffset = srcLineOffset;
284                 int dstPixelOffset = dstLineOffset;
285 
286                 srcLineOffset += srcLineStride;
287                 dstLineOffset += dstLineStride;
288 
289                 for (int w = 0; w < dstWidth; w++) {
290                     double p = s[srcPixelOffset];
291                     if (p < LOW_BOUND) {
292                         d[dstPixelOffset] = 0;
293                     } else if (p == 0) {
294                         d[dstPixelOffset] = 1;
295                     } else if (p > SHORT_UP_BOUND) {
296                         d[dstPixelOffset] = Short.MAX_VALUE;
297                     } else {
298                         d[dstPixelOffset] = (short)(Math.exp(p) + 0.5);
299                     }
300 
301                     srcPixelOffset += srcPixelStride;
302                     dstPixelOffset += dstPixelStride;
303                 }
304             }
305         }
306     }
307 
computeRectInt(RasterAccessor src, RasterAccessor dst)308     private void computeRectInt(RasterAccessor src,
309                                 RasterAccessor dst) {
310 
311         int srcLineStride = src.getScanlineStride();
312         int srcPixelStride = src.getPixelStride();
313         int[] srcBandOffsets = src.getBandOffsets();
314         int[][] srcData = src.getIntDataArrays();
315 
316         int dstLineStride = dst.getScanlineStride();
317         int dstPixelStride = dst.getPixelStride();
318         int[] dstBandOffsets = dst.getBandOffsets();
319         int[][] dstData = dst.getIntDataArrays();
320 
321         int dstWidth = dst.getWidth();
322         int dstHeight = dst.getHeight();
323         int dstBands = dst.getNumBands();
324 
325         for (int b = 0; b < dstBands; b++) {
326             int[] s = srcData[b];
327             int[] d = dstData[b];
328 
329             int srcLineOffset = srcBandOffsets[b];
330             int dstLineOffset = dstBandOffsets[b];
331 
332             for (int h = 0; h < dstHeight; h++) {
333                 int srcPixelOffset = srcLineOffset;
334                 int dstPixelOffset = dstLineOffset;
335 
336                 srcLineOffset += srcLineStride;
337                 dstLineOffset += dstLineStride;
338 
339                 for (int w = 0; w < dstWidth; w++) {
340                     double p = s[srcPixelOffset];
341                     if (p < LOW_BOUND) {
342                         d[dstPixelOffset] = 0;
343                     } else if (p == 0) {
344                         d[dstPixelOffset] = 1;
345                     } else if (p > INT_UP_BOUND) {
346                         d[dstPixelOffset] = Integer.MAX_VALUE;
347                     } else {
348                         d[dstPixelOffset] = (int)(Math.exp(p) + 0.5);
349                     }
350 
351                     srcPixelOffset += srcPixelStride;
352                     dstPixelOffset += dstPixelStride;
353                 }
354             }
355         }
356     }
357 
computeRectFloat(RasterAccessor src, RasterAccessor dst)358     private void computeRectFloat(RasterAccessor src,
359                                   RasterAccessor dst) {
360 
361         int srcLineStride = src.getScanlineStride();
362         int srcPixelStride = src.getPixelStride();
363         int[] srcBandOffsets = src.getBandOffsets();
364         float[][] srcData = src.getFloatDataArrays();
365 
366         int dstLineStride = dst.getScanlineStride();
367         int dstPixelStride = dst.getPixelStride();
368         int[] dstBandOffsets = dst.getBandOffsets();
369         float[][] dstData = dst.getFloatDataArrays();
370 
371         int dstWidth = dst.getWidth();
372         int dstHeight = dst.getHeight();
373         int dstBands = dst.getNumBands();
374 
375         for (int b = 0; b < dstBands; b++) {
376             float[] s = srcData[b];
377             float[] d = dstData[b];
378 
379             int srcLineOffset = srcBandOffsets[b];
380             int dstLineOffset = dstBandOffsets[b];
381 
382             for (int h = 0; h < dstHeight; h++) {
383                 int srcPixelOffset = srcLineOffset;
384                 int dstPixelOffset = dstLineOffset;
385 
386                 srcLineOffset += srcLineStride;
387                 dstLineOffset += dstLineStride;
388 
389                 for (int w = 0; w < dstWidth; w++) {
390                     d[dstPixelOffset] = (float)Math.exp(s[srcPixelOffset]);
391 
392                     srcPixelOffset += srcPixelStride;
393                     dstPixelOffset += dstPixelStride;
394                 }
395             }
396         }
397     }
398 
computeRectDouble(RasterAccessor src, RasterAccessor dst)399     private void computeRectDouble(RasterAccessor src,
400                                    RasterAccessor dst) {
401 
402         int srcLineStride = src.getScanlineStride();
403         int srcPixelStride = src.getPixelStride();
404         int[] srcBandOffsets = src.getBandOffsets();
405         double[][] srcData = src.getDoubleDataArrays();
406 
407         int dstLineStride = dst.getScanlineStride();
408         int dstPixelStride = dst.getPixelStride();
409         int[] dstBandOffsets = dst.getBandOffsets();
410         double[][] dstData = dst.getDoubleDataArrays();
411 
412         int dstWidth = dst.getWidth();
413         int dstHeight = dst.getHeight();
414         int dstBands = dst.getNumBands();
415 
416         for (int b = 0; b < dstBands; b++) {
417             double[] s = srcData[b];
418             double[] d = dstData[b];
419 
420             int srcLineOffset = srcBandOffsets[b];
421             int dstLineOffset = dstBandOffsets[b];
422 
423             for (int h = 0; h < dstHeight; h++) {
424                 int srcPixelOffset = srcLineOffset;
425                 int dstPixelOffset = dstLineOffset;
426 
427                 srcLineOffset += srcLineStride;
428                 dstLineOffset += dstLineStride;
429 
430                 for (int w = 0; w < dstWidth; w++) {
431                     d[dstPixelOffset] = Math.exp(s[srcPixelOffset]);
432 
433                     srcPixelOffset += srcPixelStride;
434                     dstPixelOffset += dstPixelStride;
435                 }
436             }
437         }
438     }
439 
initByteTable()440     private synchronized void initByteTable() {
441 
442         if (byteTable != null)
443 	    return;
444 
445         byteTable = new byte[0x100];
446 
447         /*
448          * exp(5) = 148.4131591...
449          * exp(6) = 403.4287935...
450          * Calculate up to 5 and set the rest to the maximum value.
451          */
452         byteTable[0] = 1;
453 
454         for (int i = 1; i < 6; i++) {
455             byteTable[i] = (byte)(Math.exp(i) + 0.5);
456         }
457 
458         for (int i = 6; i < 0x100; i++) {
459             byteTable[i] = (byte)ImageUtil.BYTE_MASK;
460         }
461     }
462 }
463