001: /*
002: * $RCSfile: LogOpImage.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:30 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import javax.media.jai.ColormapOpImage;
015: import java.awt.Rectangle;
016: import java.awt.image.DataBuffer;
017: import java.awt.image.Raster;
018: import java.awt.image.RenderedImage;
019: import java.awt.image.SampleModel;
020: import java.awt.image.WritableRaster;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.RasterAccessor;
023: import javax.media.jai.RasterFormatTag;
024: import java.util.Map;
025: import com.sun.media.jai.util.ImageUtil;
026:
027: /**
028: * An <code>OpImage</code> implementing the "Log" operation as
029: * described in <code>javax.media.jai.operator.LogDescriptor</code>.
030: *
031: * <p> This <code>OpImage</code> takes the natural logarithm of the pixel
032: * values of an image. The operation is done on a per-pixel, per-band
033: * basis.
034: *
035: * <p> For all integral data types, the log of 0 is set to 0. For
036: * signed integral data types (<code>short</code> and <code>int</code>),
037: * the log of a negative pixel value is set to -1.
038: *
039: * <p> For all floating point data types ((<code>float</code> and
040: * <code>double</code>), the log of 0 is set to <code>-Infinity</code>,
041: * and the log of a negative pixel value is set to <code>NaN</code>.
042: *
043: * @see javax.media.jai.operator.LogDescriptor
044: * @see LogCRIF
045: *
046: * @since EA2
047: *
048: */
049: final class LogOpImage extends ColormapOpImage {
050:
051: /** A lookup table for byte data type. */
052: private byte[] byteTable = null;
053:
054: /**
055: * Constructor.
056: *
057: * <p> The layout of the source is used as the fall-back for
058: * the layout of the destination. Any layout parameters not
059: * specified in the <code>layout</code> argument are set to
060: * the same value as that of the source.
061: *
062: * @param source The source image.
063:
064: * @param layout The destination image layout.
065: */
066: public LogOpImage(RenderedImage source, Map config,
067: ImageLayout layout) {
068: super (source, layout, config, true);
069:
070: /* Set flag to permit in-place operation. */
071: permitInPlaceOperation();
072:
073: // Initialize the colormap if necessary.
074: initializeColormapOperation();
075: }
076:
077: /**
078: * Transform the colormap according to the rescaling parameters.
079: */
080: protected void transformColormap(byte[][] colormap) {
081: initByteTable();
082:
083: for (int b = 0; b < 3; b++) {
084: byte[] map = colormap[b];
085: int mapSize = map.length;
086:
087: for (int i = 0; i < mapSize; i++) {
088: map[i] = byteTable[(map[i] & 0xFF)];
089: }
090: }
091: }
092:
093: /**
094: * Finds the natural logarithm of the pixels within a specified
095: * rectangle.
096: *
097: * @param sources Cobbled sources, guaranteed to provide all the
098: * source data necessary for computing the rectangle.
099: * @param dest The tile containing the rectangle to be computed.
100: * @param destRect The rectangle within the tile to be computed.
101: */
102: protected void computeRect(Raster[] sources, WritableRaster dest,
103: Rectangle destRect) {
104: /* Retrieve format tags. */
105: RasterFormatTag[] formatTags = getFormatTags();
106:
107: /* No need to mapSourceRect for PointOps. */
108: RasterAccessor s = new RasterAccessor(sources[0], destRect,
109: formatTags[0], getSourceImage(0).getColorModel());
110: RasterAccessor d = new RasterAccessor(dest, destRect,
111: formatTags[1], getColorModel());
112:
113: switch (d.getDataType()) {
114: case DataBuffer.TYPE_BYTE:
115: computeRectByte(s, d);
116: break;
117: case DataBuffer.TYPE_USHORT:
118: computeRectUShort(s, d);
119: break;
120: case DataBuffer.TYPE_SHORT:
121: computeRectShort(s, d);
122: break;
123: case DataBuffer.TYPE_INT:
124: computeRectInt(s, d);
125: break;
126: case DataBuffer.TYPE_FLOAT:
127: computeRectFloat(s, d);
128: break;
129: case DataBuffer.TYPE_DOUBLE:
130: computeRectDouble(s, d);
131: break;
132: }
133:
134: if (d.needsClamping()) {
135: d.clampDataArrays();
136: }
137: d.copyDataToRaster();
138: }
139:
140: private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
141: initByteTable();
142:
143: int srcLineStride = src.getScanlineStride();
144: int srcPixelStride = src.getPixelStride();
145: int[] srcBandOffsets = src.getBandOffsets();
146: byte[][] srcData = src.getByteDataArrays();
147:
148: int dstLineStride = dst.getScanlineStride();
149: int dstPixelStride = dst.getPixelStride();
150: int[] dstBandOffsets = dst.getBandOffsets();
151: byte[][] dstData = dst.getByteDataArrays();
152:
153: int dstWidth = dst.getWidth();
154: int dstHeight = dst.getHeight();
155: int dstBands = dst.getNumBands();
156:
157: for (int b = 0; b < dstBands; b++) {
158: byte[] s = srcData[b];
159: byte[] d = dstData[b];
160:
161: int srcLineOffset = srcBandOffsets[b];
162: int dstLineOffset = dstBandOffsets[b];
163:
164: for (int h = 0; h < dstHeight; h++) {
165: int srcPixelOffset = srcLineOffset;
166: int dstPixelOffset = dstLineOffset;
167:
168: srcLineOffset += srcLineStride;
169: dstLineOffset += dstLineStride;
170:
171: for (int w = 0; w < dstWidth; w++) {
172: d[dstPixelOffset] = byteTable[s[srcPixelOffset]
173: & ImageUtil.BYTE_MASK];
174:
175: srcPixelOffset += srcPixelStride;
176: dstPixelOffset += dstPixelStride;
177: }
178: }
179: }
180: }
181:
182: private void computeRectUShort(RasterAccessor src,
183: RasterAccessor dst) {
184:
185: int srcLineStride = src.getScanlineStride();
186: int srcPixelStride = src.getPixelStride();
187: int[] srcBandOffsets = src.getBandOffsets();
188: short[][] srcData = src.getShortDataArrays();
189:
190: int dstLineStride = dst.getScanlineStride();
191: int dstPixelStride = dst.getPixelStride();
192: int[] dstBandOffsets = dst.getBandOffsets();
193: short[][] dstData = dst.getShortDataArrays();
194:
195: int dstWidth = dst.getWidth();
196: int dstHeight = dst.getHeight();
197: int dstBands = dst.getNumBands();
198:
199: for (int b = 0; b < dstBands; b++) {
200: short[] s = srcData[b];
201: short[] d = dstData[b];
202:
203: int srcLineOffset = srcBandOffsets[b];
204: int dstLineOffset = dstBandOffsets[b];
205:
206: for (int h = 0; h < dstHeight; h++) {
207: int srcPixelOffset = srcLineOffset;
208: int dstPixelOffset = dstLineOffset;
209:
210: srcLineOffset += srcLineStride;
211: dstLineOffset += dstLineStride;
212:
213: for (int w = 0; w < dstWidth; w++) {
214: /*
215: * For unsigned pixels, there are two choices:
216: * 0, or > 0. The standard function takes care of all.
217: */
218: d[dstPixelOffset] = (short) (Math
219: .log(s[srcPixelOffset]
220: & ImageUtil.USHORT_MASK) + 0.5);
221:
222: srcPixelOffset += srcPixelStride;
223: dstPixelOffset += dstPixelStride;
224: }
225: }
226: }
227: }
228:
229: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
230:
231: int srcLineStride = src.getScanlineStride();
232: int srcPixelStride = src.getPixelStride();
233: int[] srcBandOffsets = src.getBandOffsets();
234: short[][] srcData = src.getShortDataArrays();
235:
236: int dstLineStride = dst.getScanlineStride();
237: int dstPixelStride = dst.getPixelStride();
238: int[] dstBandOffsets = dst.getBandOffsets();
239: short[][] dstData = dst.getShortDataArrays();
240:
241: int dstWidth = dst.getWidth();
242: int dstHeight = dst.getHeight();
243: int dstBands = dst.getNumBands();
244:
245: for (int b = 0; b < dstBands; b++) {
246: short[] s = srcData[b];
247: short[] d = dstData[b];
248:
249: int srcLineOffset = srcBandOffsets[b];
250: int dstLineOffset = dstBandOffsets[b];
251:
252: for (int h = 0; h < dstHeight; h++) {
253: int srcPixelOffset = srcLineOffset;
254: int dstPixelOffset = dstLineOffset;
255:
256: srcLineOffset += srcLineStride;
257: dstLineOffset += dstLineStride;
258:
259: for (int w = 0; w < dstWidth; w++) {
260: /*
261: * For signed pixels, there are three choices:
262: * < 0, 0, > 0. The standard function takes care of all.
263: */
264: d[dstPixelOffset] = (short) (Math
265: .log(s[srcPixelOffset]) + 0.5);
266:
267: srcPixelOffset += srcPixelStride;
268: dstPixelOffset += dstPixelStride;
269: }
270: }
271: }
272: }
273:
274: private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
275:
276: int srcLineStride = src.getScanlineStride();
277: int srcPixelStride = src.getPixelStride();
278: int[] srcBandOffsets = src.getBandOffsets();
279: int[][] srcData = src.getIntDataArrays();
280:
281: int dstLineStride = dst.getScanlineStride();
282: int dstPixelStride = dst.getPixelStride();
283: int[] dstBandOffsets = dst.getBandOffsets();
284: int[][] dstData = dst.getIntDataArrays();
285:
286: int dstWidth = dst.getWidth();
287: int dstHeight = dst.getHeight();
288: int dstBands = dst.getNumBands();
289:
290: for (int b = 0; b < dstBands; b++) {
291: int[] s = srcData[b];
292: int[] d = dstData[b];
293:
294: int srcLineOffset = srcBandOffsets[b];
295: int dstLineOffset = dstBandOffsets[b];
296:
297: for (int h = 0; h < dstHeight; h++) {
298: int srcPixelOffset = srcLineOffset;
299: int dstPixelOffset = dstLineOffset;
300:
301: srcLineOffset += srcLineStride;
302: dstLineOffset += dstLineStride;
303:
304: for (int w = 0; w < dstWidth; w++) {
305: /*
306: * For signed pixels, there are three choices:
307: * < 0, 0, > 0.
308: */
309: double p = s[srcPixelOffset];
310: if (p > 0) {
311: d[dstPixelOffset] = (int) (Math.log(p) + 0.5);
312: } else if (p == 0) {
313: d[dstPixelOffset] = 0;
314: } else {
315: d[dstPixelOffset] = -1;
316: }
317:
318: srcPixelOffset += srcPixelStride;
319: dstPixelOffset += dstPixelStride;
320: }
321: }
322: }
323: }
324:
325: private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
326:
327: int srcLineStride = src.getScanlineStride();
328: int srcPixelStride = src.getPixelStride();
329: int[] srcBandOffsets = src.getBandOffsets();
330: float[][] srcData = src.getFloatDataArrays();
331:
332: int dstLineStride = dst.getScanlineStride();
333: int dstPixelStride = dst.getPixelStride();
334: int[] dstBandOffsets = dst.getBandOffsets();
335: float[][] dstData = dst.getFloatDataArrays();
336:
337: int dstWidth = dst.getWidth();
338: int dstHeight = dst.getHeight();
339: int dstBands = dst.getNumBands();
340:
341: for (int b = 0; b < dstBands; b++) {
342: float[] s = srcData[b];
343: float[] d = dstData[b];
344:
345: int srcLineOffset = srcBandOffsets[b];
346: int dstLineOffset = dstBandOffsets[b];
347:
348: for (int h = 0; h < dstHeight; h++) {
349: int srcPixelOffset = srcLineOffset;
350: int dstPixelOffset = dstLineOffset;
351:
352: srcLineOffset += srcLineStride;
353: dstLineOffset += dstLineStride;
354:
355: for (int w = 0; w < dstWidth; w++) {
356: /*
357: * For signed pixels, there are three choices:
358: * < 0, 0, > 0. The standard function takes care of all.
359: */
360: d[dstPixelOffset] = (float) Math
361: .log(s[srcPixelOffset]);
362:
363: srcPixelOffset += srcPixelStride;
364: dstPixelOffset += dstPixelStride;
365: }
366: }
367: }
368: }
369:
370: private void computeRectDouble(RasterAccessor src,
371: RasterAccessor dst) {
372:
373: int srcLineStride = src.getScanlineStride();
374: int srcPixelStride = src.getPixelStride();
375: int[] srcBandOffsets = src.getBandOffsets();
376: double[][] srcData = src.getDoubleDataArrays();
377:
378: int dstLineStride = dst.getScanlineStride();
379: int dstPixelStride = dst.getPixelStride();
380: int[] dstBandOffsets = dst.getBandOffsets();
381: double[][] dstData = dst.getDoubleDataArrays();
382:
383: int dstWidth = dst.getWidth();
384: int dstHeight = dst.getHeight();
385: int dstBands = dst.getNumBands();
386:
387: for (int b = 0; b < dstBands; b++) {
388: double[] s = srcData[b];
389: double[] d = dstData[b];
390:
391: int srcLineOffset = srcBandOffsets[b];
392: int dstLineOffset = dstBandOffsets[b];
393:
394: for (int h = 0; h < dstHeight; h++) {
395: int srcPixelOffset = srcLineOffset;
396: int dstPixelOffset = dstLineOffset;
397:
398: srcLineOffset += srcLineStride;
399: dstLineOffset += dstLineStride;
400:
401: for (int w = 0; w < dstWidth; w++) {
402: /*
403: * For signed pixels, there are three choices:
404: * < 0, 0, > 0. The standard function takes care of all.
405: */
406: d[dstPixelOffset] = Math.log(s[srcPixelOffset]);
407:
408: srcPixelOffset += srcPixelStride;
409: dstPixelOffset += dstPixelStride;
410: }
411: }
412: }
413: }
414:
415: private synchronized void initByteTable() {
416:
417: if (byteTable != null)
418: return;
419:
420: byteTable = new byte[0x100];
421:
422: byteTable[0] = 0; // minimum byte value
423: byteTable[1] = 0;
424:
425: for (int i = 2; i < 0x100; i++) {
426: byteTable[i] = (byte) (Math.log(i) + 0.5);
427: }
428: }
429: }
|