001: /*
002: * $RCSfile: ExpOpImage.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:25 $
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 "Exp" operation as
029: * described in <code>javax.media.jai.operator.ExpDescriptor</code>.
030: *
031: * The result is rounded to the closest integer for intergral data types.
032: * <p> This <code>OpImage</code> takes the natural exponential of the pixel
033: * values of an image. The operation is done on a per-pixel, per-band
034: * basis.
035: *
036: * @see javax.media.jai.operator.ExpDescriptor
037: * @see ExpCRIF
038: *
039: * @since EA2
040: *
041: */
042: final class ExpOpImage extends ColormapOpImage {
043:
044: /** A lookup table for byte data type. */
045: private byte[] byteTable = null;
046:
047: /**
048: * The largest unsigned short to get a non-overflowed exponential result.
049: * i.e. cloeset to 65536.
050: * exp(11) = 59874.14171, exp(12) = 162754.7914
051: */
052: private static int USHORT_UP_BOUND = 11;
053:
054: /**
055: * The largest short to get a non-overflowed exponential result.
056: * i.e. closest to 32767.
057: * exp(10) = 22026.46579, exp(11) = 59874.14171
058: */
059: private static int SHORT_UP_BOUND = 10;
060:
061: /**
062: * The largest int to get a non-overflown exponential result.
063: * i.e. cloeset to 2**31-1 = 2147483647.
064: * exp(21) = 1318815734, exp(22) = 3584912846.
065: */
066: private static int INT_UP_BOUND = 21;
067:
068: /**
069: * The smallest integer to get a non-zero exponential result is
070: * 0. i.e. exp(0) = 1; exp(-1) = 0.367879441, which will be stored as 0.
071: * all other negative values will result in 0.
072: */
073: private static int LOW_BOUND = 0;
074:
075: /**
076: * Constructor.
077: *
078: * <p> The layout of the source is used as the fall-back for
079: * the layout of the destination. Any layout parameters not
080: * specified in the <code>layout</code> argument are set to
081: * the same value as that of the source.
082: *
083: * @param source The source image.
084:
085: * @param layout The destination image layout.
086: */
087: public ExpOpImage(RenderedImage source, Map config,
088: ImageLayout layout) {
089: super (source, layout, config, true);
090:
091: /* Set flag to permit in-place operation. */
092: permitInPlaceOperation();
093:
094: // Initialize the colormap if necessary.
095: initializeColormapOperation();
096: }
097:
098: /**
099: * Transform the colormap according to the rescaling parameters.
100: */
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: */
123: protected void computeRect(Raster[] sources, WritableRaster dest,
124: Rectangle destRect) {
125: /* Retrieve format tags. */
126: RasterFormatTag[] formatTags = getFormatTags();
127:
128: /* No need to mapSourceRect for PointOps. */
129: RasterAccessor s = new RasterAccessor(sources[0], destRect,
130: formatTags[0], getSourceImage(0).getColorModel());
131: RasterAccessor d = new RasterAccessor(dest, destRect,
132: formatTags[1], getColorModel());
133:
134: switch (d.getDataType()) {
135: case DataBuffer.TYPE_BYTE:
136: computeRectByte(s, d);
137: break;
138: case DataBuffer.TYPE_USHORT:
139: computeRectUShort(s, d);
140: break;
141: case DataBuffer.TYPE_SHORT:
142: computeRectShort(s, d);
143: break;
144: case DataBuffer.TYPE_INT:
145: computeRectInt(s, d);
146: break;
147: case DataBuffer.TYPE_FLOAT:
148: computeRectFloat(s, d);
149: break;
150: case DataBuffer.TYPE_DOUBLE:
151: computeRectDouble(s, d);
152: break;
153: }
154:
155: if (d.needsClamping()) {
156: d.clampDataArrays();
157: }
158: d.copyDataToRaster();
159: }
160:
161: private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
162: initByteTable();
163:
164: int srcLineStride = src.getScanlineStride();
165: int srcPixelStride = src.getPixelStride();
166: int[] srcBandOffsets = src.getBandOffsets();
167: byte[][] srcData = src.getByteDataArrays();
168:
169: int dstLineStride = dst.getScanlineStride();
170: int dstPixelStride = dst.getPixelStride();
171: int[] dstBandOffsets = dst.getBandOffsets();
172: byte[][] dstData = dst.getByteDataArrays();
173:
174: int dstWidth = dst.getWidth();
175: int dstHeight = dst.getHeight();
176: int dstBands = dst.getNumBands();
177:
178: for (int b = 0; b < dstBands; b++) {
179: byte[] s = srcData[b];
180: byte[] d = dstData[b];
181:
182: int srcLineOffset = srcBandOffsets[b];
183: int dstLineOffset = dstBandOffsets[b];
184:
185: for (int h = 0; h < dstHeight; h++) {
186: int srcPixelOffset = srcLineOffset;
187: int dstPixelOffset = dstLineOffset;
188:
189: srcLineOffset += srcLineStride;
190: dstLineOffset += dstLineStride;
191:
192: for (int w = 0; w < dstWidth; w++) {
193: d[dstPixelOffset] = byteTable[s[srcPixelOffset]
194: & ImageUtil.BYTE_MASK];
195:
196: srcPixelOffset += srcPixelStride;
197: dstPixelOffset += dstPixelStride;
198: }
199: }
200: }
201: }
202:
203: private void computeRectUShort(RasterAccessor src,
204: RasterAccessor dst) {
205:
206: int srcLineStride = src.getScanlineStride();
207: int srcPixelStride = src.getPixelStride();
208: int[] srcBandOffsets = src.getBandOffsets();
209: short[][] srcData = src.getShortDataArrays();
210:
211: int dstLineStride = dst.getScanlineStride();
212: int dstPixelStride = dst.getPixelStride();
213: int[] dstBandOffsets = dst.getBandOffsets();
214: short[][] dstData = dst.getShortDataArrays();
215:
216: int dstWidth = dst.getWidth();
217: int dstHeight = dst.getHeight();
218: int dstBands = dst.getNumBands();
219:
220: short max = (short) ImageUtil.USHORT_MASK;
221:
222: for (int b = 0; b < dstBands; b++) {
223: short[] s = srcData[b];
224: short[] d = dstData[b];
225:
226: int srcLineOffset = srcBandOffsets[b];
227: int dstLineOffset = dstBandOffsets[b];
228:
229: for (int h = 0; h < dstHeight; h++) {
230: int srcPixelOffset = srcLineOffset;
231: int dstPixelOffset = dstLineOffset;
232:
233: srcLineOffset += srcLineStride;
234: dstLineOffset += dstLineStride;
235:
236: for (int w = 0; w < dstWidth; w++) {
237: double p = s[srcPixelOffset]
238: & ImageUtil.USHORT_MASK;
239: if (p == 0) {
240: d[dstPixelOffset] = 1;
241: } else if (p > USHORT_UP_BOUND) {
242: d[dstPixelOffset] = max;
243: } else {
244: d[dstPixelOffset] = (short) (Math.exp(p) + 0.5);
245: }
246:
247: srcPixelOffset += srcPixelStride;
248: dstPixelOffset += dstPixelStride;
249: }
250: }
251: }
252: }
253:
254: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
255:
256: int srcLineStride = src.getScanlineStride();
257: int srcPixelStride = src.getPixelStride();
258: int[] srcBandOffsets = src.getBandOffsets();
259: short[][] srcData = src.getShortDataArrays();
260:
261: int dstLineStride = dst.getScanlineStride();
262: int dstPixelStride = dst.getPixelStride();
263: int[] dstBandOffsets = dst.getBandOffsets();
264: short[][] dstData = dst.getShortDataArrays();
265:
266: int dstWidth = dst.getWidth();
267: int dstHeight = dst.getHeight();
268: int dstBands = dst.getNumBands();
269:
270: for (int b = 0; b < dstBands; b++) {
271: short[] s = srcData[b];
272: short[] d = dstData[b];
273:
274: int srcLineOffset = srcBandOffsets[b];
275: int dstLineOffset = dstBandOffsets[b];
276:
277: for (int h = 0; h < dstHeight; h++) {
278: int srcPixelOffset = srcLineOffset;
279: int dstPixelOffset = dstLineOffset;
280:
281: srcLineOffset += srcLineStride;
282: dstLineOffset += dstLineStride;
283:
284: for (int w = 0; w < dstWidth; w++) {
285: double p = s[srcPixelOffset];
286: if (p < LOW_BOUND) {
287: d[dstPixelOffset] = 0;
288: } else if (p == 0) {
289: d[dstPixelOffset] = 1;
290: } else if (p > SHORT_UP_BOUND) {
291: d[dstPixelOffset] = Short.MAX_VALUE;
292: } else {
293: d[dstPixelOffset] = (short) (Math.exp(p) + 0.5);
294: }
295:
296: srcPixelOffset += srcPixelStride;
297: dstPixelOffset += dstPixelStride;
298: }
299: }
300: }
301: }
302:
303: private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
304:
305: int srcLineStride = src.getScanlineStride();
306: int srcPixelStride = src.getPixelStride();
307: int[] srcBandOffsets = src.getBandOffsets();
308: int[][] srcData = src.getIntDataArrays();
309:
310: int dstLineStride = dst.getScanlineStride();
311: int dstPixelStride = dst.getPixelStride();
312: int[] dstBandOffsets = dst.getBandOffsets();
313: int[][] dstData = dst.getIntDataArrays();
314:
315: int dstWidth = dst.getWidth();
316: int dstHeight = dst.getHeight();
317: int dstBands = dst.getNumBands();
318:
319: for (int b = 0; b < dstBands; b++) {
320: int[] s = srcData[b];
321: int[] d = dstData[b];
322:
323: int srcLineOffset = srcBandOffsets[b];
324: int dstLineOffset = dstBandOffsets[b];
325:
326: for (int h = 0; h < dstHeight; h++) {
327: int srcPixelOffset = srcLineOffset;
328: int dstPixelOffset = dstLineOffset;
329:
330: srcLineOffset += srcLineStride;
331: dstLineOffset += dstLineStride;
332:
333: for (int w = 0; w < dstWidth; w++) {
334: double p = s[srcPixelOffset];
335: if (p < LOW_BOUND) {
336: d[dstPixelOffset] = 0;
337: } else if (p == 0) {
338: d[dstPixelOffset] = 1;
339: } else if (p > INT_UP_BOUND) {
340: d[dstPixelOffset] = Integer.MAX_VALUE;
341: } else {
342: d[dstPixelOffset] = (int) (Math.exp(p) + 0.5);
343: }
344:
345: srcPixelOffset += srcPixelStride;
346: dstPixelOffset += dstPixelStride;
347: }
348: }
349: }
350: }
351:
352: private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
353:
354: int srcLineStride = src.getScanlineStride();
355: int srcPixelStride = src.getPixelStride();
356: int[] srcBandOffsets = src.getBandOffsets();
357: float[][] srcData = src.getFloatDataArrays();
358:
359: int dstLineStride = dst.getScanlineStride();
360: int dstPixelStride = dst.getPixelStride();
361: int[] dstBandOffsets = dst.getBandOffsets();
362: float[][] dstData = dst.getFloatDataArrays();
363:
364: int dstWidth = dst.getWidth();
365: int dstHeight = dst.getHeight();
366: int dstBands = dst.getNumBands();
367:
368: for (int b = 0; b < dstBands; b++) {
369: float[] s = srcData[b];
370: float[] d = dstData[b];
371:
372: int srcLineOffset = srcBandOffsets[b];
373: int dstLineOffset = dstBandOffsets[b];
374:
375: for (int h = 0; h < dstHeight; h++) {
376: int srcPixelOffset = srcLineOffset;
377: int dstPixelOffset = dstLineOffset;
378:
379: srcLineOffset += srcLineStride;
380: dstLineOffset += dstLineStride;
381:
382: for (int w = 0; w < dstWidth; w++) {
383: d[dstPixelOffset] = (float) Math
384: .exp(s[srcPixelOffset]);
385:
386: srcPixelOffset += srcPixelStride;
387: dstPixelOffset += dstPixelStride;
388: }
389: }
390: }
391: }
392:
393: private void computeRectDouble(RasterAccessor src,
394: RasterAccessor dst) {
395:
396: int srcLineStride = src.getScanlineStride();
397: int srcPixelStride = src.getPixelStride();
398: int[] srcBandOffsets = src.getBandOffsets();
399: double[][] srcData = src.getDoubleDataArrays();
400:
401: int dstLineStride = dst.getScanlineStride();
402: int dstPixelStride = dst.getPixelStride();
403: int[] dstBandOffsets = dst.getBandOffsets();
404: double[][] dstData = dst.getDoubleDataArrays();
405:
406: int dstWidth = dst.getWidth();
407: int dstHeight = dst.getHeight();
408: int dstBands = dst.getNumBands();
409:
410: for (int b = 0; b < dstBands; b++) {
411: double[] s = srcData[b];
412: double[] d = dstData[b];
413:
414: int srcLineOffset = srcBandOffsets[b];
415: int dstLineOffset = dstBandOffsets[b];
416:
417: for (int h = 0; h < dstHeight; h++) {
418: int srcPixelOffset = srcLineOffset;
419: int dstPixelOffset = dstLineOffset;
420:
421: srcLineOffset += srcLineStride;
422: dstLineOffset += dstLineStride;
423:
424: for (int w = 0; w < dstWidth; w++) {
425: d[dstPixelOffset] = Math.exp(s[srcPixelOffset]);
426:
427: srcPixelOffset += srcPixelStride;
428: dstPixelOffset += dstPixelStride;
429: }
430: }
431: }
432: }
433:
434: private synchronized void initByteTable() {
435:
436: if (byteTable != null)
437: return;
438:
439: byteTable = new byte[0x100];
440:
441: /*
442: * exp(5) = 148.4131591...
443: * exp(6) = 403.4287935...
444: * Calculate up to 5 and set the rest to the maximum value.
445: */
446: byteTable[0] = 1;
447:
448: for (int i = 1; i < 6; i++) {
449: byteTable[i] = (byte) (Math.exp(i) + 0.5);
450: }
451:
452: for (int i = 6; i < 0x100; i++) {
453: byteTable[i] = (byte) ImageUtil.BYTE_MASK;
454: }
455: }
456: }
|