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