001: /*
002: * $RCSfile: MaxOpImage.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:33 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.DataBuffer;
016: import java.awt.image.Raster;
017: import java.awt.image.RenderedImage;
018: import java.awt.image.SampleModel;
019: import java.awt.image.WritableRaster;
020: import javax.media.jai.ImageLayout;
021: import javax.media.jai.OpImage;
022: import javax.media.jai.PointOpImage;
023: import javax.media.jai.RasterAccessor;
024: import javax.media.jai.RasterFormatTag;
025: import java.util.Map;
026: import java.lang.ref.SoftReference;
027:
028: /**
029: * An <code>OpImage</code> implementing the "Max" operation as
030: * described in <code>javax.media.jai.operator.MaxDescriptor</code>.
031: *
032: * <p>This <code>OpImage</code> chooses the maximum pixel values of the
033: * two source images on a per-band basis. In case the two source images
034: * have different number of bands, the number of bands for the destination
035: * image is the smaller band number of the two source images. That is
036: * <code>dstNumBands = Math.min(src1NumBands, src2NumBands)</code>.
037: * In case the two source images have different data types, the data type
038: * for the destination image is the higher data type of the two source
039: * images.
040: *
041: * <p>The value of the pixel (x, y) in the destination image is defined as:
042: * <pre>
043: * for (b = 0; b < numBands; b++) {
044: * dst[y][x][b] = Math.max(src1[y][x][b], src2[y][x][b]);
045: * }
046: * </pre>
047: *
048: * @see javax.media.jai.operator.MaxDescriptor
049: * @see MaxRIF
050: *
051: */
052: final class MaxOpImage extends PointOpImage {
053:
054: private static long negativeZeroFloatBits = Float
055: .floatToIntBits(-0.0f);
056: private static long negativeZeroDoubleBits = Double
057: .doubleToLongBits(-0.0d);
058: private static byte[] byteTable = null;
059: private static SoftReference softRef = null;
060:
061: private synchronized void allocByteTable() {
062: if ((softRef == null) || (softRef.get() == null)) {
063:
064: //
065: // First time or reference has been cleared.
066: // Create the table and make a soft reference to it.
067: //
068: byteTable = new byte[256 * 256];
069: softRef = new SoftReference(byteTable);
070:
071: // Initialize table which implements Min
072: int idx = 0;
073: for (int i1 = 0; i1 < 256; i1++) {
074: int base = i1 << 8;
075: for (int i2 = 0; i2 < i1; i2++) {
076: byteTable[base + i2] = (byte) i1;
077: }
078: for (int i2 = i1; i2 < 256; i2++) {
079: byteTable[base + i2] = (byte) i2;
080: }
081: }
082: }
083: }
084:
085: /**
086: * Construct a <code>MaxOpImage</code>.
087: *
088: * @param source1 The first source image.
089: * @param source2 The second source image.
090: * @param layout The destination image layout.
091: */
092: public MaxOpImage(RenderedImage source1, RenderedImage source2,
093: Map config, ImageLayout layout) {
094: super (source1, source2, layout, config, true);
095:
096: if (sampleModel.getTransferType() == DataBuffer.TYPE_BYTE) {
097: allocByteTable();
098: }
099:
100: // Set flag to permit in-place operation.
101: permitInPlaceOperation();
102: }
103:
104: /**
105: * Return the maximum pixel value of the source images for a
106: * specified rectangle.
107: *
108: * @param sources Cobbled sources, guaranteed to provide all the
109: * source data necessary for computing the rectangle.
110: * @param dest The tile containing the rectangle to be computed.
111: * @param destRect The rectangle within the tile to be computed.
112: */
113: protected void computeRect(Raster[] sources, WritableRaster dest,
114: Rectangle destRect) {
115: // Retrieve format tags.
116: RasterFormatTag[] formatTags = getFormatTags();
117:
118: /* For PointOpImage, srcRect = destRect. */
119: RasterAccessor s1 = new RasterAccessor(sources[0], destRect,
120: formatTags[0], getSourceImage(0).getColorModel());
121: RasterAccessor s2 = new RasterAccessor(sources[1], destRect,
122: formatTags[1], getSourceImage(1).getColorModel());
123: RasterAccessor d = new RasterAccessor(dest, destRect,
124: formatTags[2], getColorModel());
125:
126: switch (d.getDataType()) {
127: case DataBuffer.TYPE_BYTE:
128: computeRectByte(s1, s2, d);
129: break;
130: case DataBuffer.TYPE_USHORT:
131: computeRectUShort(s1, s2, d);
132: break;
133: case DataBuffer.TYPE_SHORT:
134: computeRectShort(s1, s2, d);
135: break;
136: case DataBuffer.TYPE_INT:
137: computeRectInt(s1, s2, d);
138: break;
139: case DataBuffer.TYPE_FLOAT:
140: computeRectFloat(s1, s2, d);
141: break;
142: case DataBuffer.TYPE_DOUBLE:
143: computeRectDouble(s1, s2, d);
144: break;
145: }
146:
147: if (d.isDataCopy()) {
148: d.clampDataArrays();
149: d.copyDataToRaster();
150: }
151: }
152:
153: private void computeRectByte(RasterAccessor src1,
154: RasterAccessor src2, RasterAccessor dst) {
155: int s1LineStride = src1.getScanlineStride();
156: int s1PixelStride = src1.getPixelStride();
157: int[] s1BandOffsets = src1.getBandOffsets();
158: byte[][] s1Data = src1.getByteDataArrays();
159:
160: int s2LineStride = src2.getScanlineStride();
161: int s2PixelStride = src2.getPixelStride();
162: int[] s2BandOffsets = src2.getBandOffsets();
163: byte[][] s2Data = src2.getByteDataArrays();
164:
165: int dwidth = dst.getWidth();
166: int dheight = dst.getHeight();
167: int bands = dst.getNumBands();
168: int dLineStride = dst.getScanlineStride();
169: int dPixelStride = dst.getPixelStride();
170: int[] dBandOffsets = dst.getBandOffsets();
171: byte[][] dData = dst.getByteDataArrays();
172:
173: for (int b = 0; b < bands; b++) {
174: byte[] s1 = s1Data[b];
175: byte[] s2 = s2Data[b];
176: byte[] d = dData[b];
177:
178: int s1LineOffset = s1BandOffsets[b];
179: int s2LineOffset = s2BandOffsets[b];
180: int dLineOffset = dBandOffsets[b];
181:
182: for (int h = 0; h < dheight; h++) {
183: int s1PixelOffset = s1LineOffset;
184: int s2PixelOffset = s2LineOffset;
185: int dPixelOffset = dLineOffset;
186:
187: s1LineOffset += s1LineStride;
188: s2LineOffset += s2LineStride;
189: dLineOffset += dLineStride;
190:
191: int dstEnd = dPixelOffset + dwidth * dPixelStride;
192: while (dPixelOffset < dstEnd) {
193: int i1 = s1[s1PixelOffset] & 0xFF;
194: int i2 = s2[s2PixelOffset] & 0xFF;
195: d[dPixelOffset] = byteTable[(i1 << 8) + i2];
196:
197: s1PixelOffset += s1PixelStride;
198: s2PixelOffset += s2PixelStride;
199: dPixelOffset += dPixelStride;
200: }
201: }
202: }
203: }
204:
205: private void computeRectUShort(RasterAccessor src1,
206: RasterAccessor src2, RasterAccessor dst) {
207: int s1LineStride = src1.getScanlineStride();
208: int s1PixelStride = src1.getPixelStride();
209: int[] s1BandOffsets = src1.getBandOffsets();
210: short[][] s1Data = src1.getShortDataArrays();
211:
212: int s2LineStride = src2.getScanlineStride();
213: int s2PixelStride = src2.getPixelStride();
214: int[] s2BandOffsets = src2.getBandOffsets();
215: short[][] s2Data = src2.getShortDataArrays();
216:
217: int dwidth = dst.getWidth();
218: int dheight = dst.getHeight();
219: int bands = dst.getNumBands();
220: int dLineStride = dst.getScanlineStride();
221: int dPixelStride = dst.getPixelStride();
222: int[] dBandOffsets = dst.getBandOffsets();
223: short[][] dData = dst.getShortDataArrays();
224:
225: for (int b = 0; b < bands; b++) {
226: short[] s1 = s1Data[b];
227: short[] s2 = s2Data[b];
228: short[] d = dData[b];
229:
230: int s1LineOffset = s1BandOffsets[b];
231: int s2LineOffset = s2BandOffsets[b];
232: int dLineOffset = dBandOffsets[b];
233:
234: for (int h = 0; h < dheight; h++) {
235: int s1PixelOffset = s1LineOffset;
236: int s2PixelOffset = s2LineOffset;
237: int dPixelOffset = dLineOffset;
238:
239: s1LineOffset += s1LineStride;
240: s2LineOffset += s2LineStride;
241: dLineOffset += dLineStride;
242:
243: for (int w = 0; w < dwidth; w++) {
244: d[dPixelOffset] = maxUShort(s1[s1PixelOffset],
245: s2[s2PixelOffset]);
246:
247: s1PixelOffset += s1PixelStride;
248: s2PixelOffset += s2PixelStride;
249: dPixelOffset += dPixelStride;
250: }
251: }
252: }
253: }
254:
255: private void computeRectShort(RasterAccessor src1,
256: RasterAccessor src2, RasterAccessor dst) {
257: int s1LineStride = src1.getScanlineStride();
258: int s1PixelStride = src1.getPixelStride();
259: int[] s1BandOffsets = src1.getBandOffsets();
260: short[][] s1Data = src1.getShortDataArrays();
261:
262: int s2LineStride = src2.getScanlineStride();
263: int s2PixelStride = src2.getPixelStride();
264: int[] s2BandOffsets = src2.getBandOffsets();
265: short[][] s2Data = src2.getShortDataArrays();
266:
267: int dwidth = dst.getWidth();
268: int dheight = dst.getHeight();
269: int bands = dst.getNumBands();
270: int dLineStride = dst.getScanlineStride();
271: int dPixelStride = dst.getPixelStride();
272: int[] dBandOffsets = dst.getBandOffsets();
273: short[][] dData = dst.getShortDataArrays();
274:
275: for (int b = 0; b < bands; b++) {
276: short[] s1 = s1Data[b];
277: short[] s2 = s2Data[b];
278: short[] d = dData[b];
279:
280: int s1LineOffset = s1BandOffsets[b];
281: int s2LineOffset = s2BandOffsets[b];
282: int dLineOffset = dBandOffsets[b];
283:
284: for (int h = 0; h < dheight; h++) {
285: int s1PixelOffset = s1LineOffset;
286: int s2PixelOffset = s2LineOffset;
287: int dPixelOffset = dLineOffset;
288:
289: s1LineOffset += s1LineStride;
290: s2LineOffset += s2LineStride;
291: dLineOffset += dLineStride;
292:
293: for (int w = 0; w < dwidth; w++) {
294: d[dPixelOffset] = maxShort(s1[s1PixelOffset],
295: s2[s2PixelOffset]);
296:
297: s1PixelOffset += s1PixelStride;
298: s2PixelOffset += s2PixelStride;
299: dPixelOffset += dPixelStride;
300: }
301: }
302: }
303: }
304:
305: private void computeRectInt(RasterAccessor src1,
306: RasterAccessor src2, RasterAccessor dst) {
307: int s1LineStride = src1.getScanlineStride();
308: int s1PixelStride = src1.getPixelStride();
309: int[] s1BandOffsets = src1.getBandOffsets();
310: int[][] s1Data = src1.getIntDataArrays();
311:
312: int s2LineStride = src2.getScanlineStride();
313: int s2PixelStride = src2.getPixelStride();
314: int[] s2BandOffsets = src2.getBandOffsets();
315: int[][] s2Data = src2.getIntDataArrays();
316:
317: int dwidth = dst.getWidth();
318: int dheight = dst.getHeight();
319: int bands = dst.getNumBands();
320: int dLineStride = dst.getScanlineStride();
321: int dPixelStride = dst.getPixelStride();
322: int[] dBandOffsets = dst.getBandOffsets();
323: int[][] dData = dst.getIntDataArrays();
324:
325: for (int b = 0; b < bands; b++) {
326: int[] s1 = s1Data[b];
327: int[] s2 = s2Data[b];
328: int[] d = dData[b];
329:
330: int s1LineOffset = s1BandOffsets[b];
331: int s2LineOffset = s2BandOffsets[b];
332: int dLineOffset = dBandOffsets[b];
333:
334: for (int h = 0; h < dheight; h++) {
335: int s1PixelOffset = s1LineOffset;
336: int s2PixelOffset = s2LineOffset;
337: int dPixelOffset = dLineOffset;
338:
339: s1LineOffset += s1LineStride;
340: s2LineOffset += s2LineStride;
341: dLineOffset += dLineStride;
342:
343: for (int w = 0; w < dwidth; w++) {
344: d[dPixelOffset] = maxInt(s1[s1PixelOffset],
345: s2[s2PixelOffset]);
346:
347: s1PixelOffset += s1PixelStride;
348: s2PixelOffset += s2PixelStride;
349: dPixelOffset += dPixelStride;
350: }
351: }
352: }
353: }
354:
355: private void computeRectFloat(RasterAccessor src1,
356: RasterAccessor src2, RasterAccessor dst) {
357: int s1LineStride = src1.getScanlineStride();
358: int s1PixelStride = src1.getPixelStride();
359: int[] s1BandOffsets = src1.getBandOffsets();
360: float[][] s1Data = src1.getFloatDataArrays();
361:
362: int s2LineStride = src2.getScanlineStride();
363: int s2PixelStride = src2.getPixelStride();
364: int[] s2BandOffsets = src2.getBandOffsets();
365: float[][] s2Data = src2.getFloatDataArrays();
366:
367: int dwidth = dst.getWidth();
368: int dheight = dst.getHeight();
369: int bands = dst.getNumBands();
370: int dLineStride = dst.getScanlineStride();
371: int dPixelStride = dst.getPixelStride();
372: int[] dBandOffsets = dst.getBandOffsets();
373: float[][] dData = dst.getFloatDataArrays();
374:
375: for (int b = 0; b < bands; b++) {
376: float[] s1 = s1Data[b];
377: float[] s2 = s2Data[b];
378: float[] d = dData[b];
379:
380: int s1LineOffset = s1BandOffsets[b];
381: int s2LineOffset = s2BandOffsets[b];
382: int dLineOffset = dBandOffsets[b];
383:
384: for (int h = 0; h < dheight; h++) {
385: int s1PixelOffset = s1LineOffset;
386: int s2PixelOffset = s2LineOffset;
387: int dPixelOffset = dLineOffset;
388:
389: s1LineOffset += s1LineStride;
390: s2LineOffset += s2LineStride;
391: dLineOffset += dLineStride;
392:
393: for (int w = 0; w < dwidth; w++) {
394: d[dPixelOffset] = maxFloat(s1[s1PixelOffset],
395: s2[s2PixelOffset]);
396:
397: s1PixelOffset += s1PixelStride;
398: s2PixelOffset += s2PixelStride;
399: dPixelOffset += dPixelStride;
400: }
401: }
402: }
403: }
404:
405: private void computeRectDouble(RasterAccessor src1,
406: RasterAccessor src2, RasterAccessor dst) {
407: int s1LineStride = src1.getScanlineStride();
408: int s1PixelStride = src1.getPixelStride();
409: int[] s1BandOffsets = src1.getBandOffsets();
410: double[][] s1Data = src1.getDoubleDataArrays();
411:
412: int s2LineStride = src2.getScanlineStride();
413: int s2PixelStride = src2.getPixelStride();
414: int[] s2BandOffsets = src2.getBandOffsets();
415: double[][] s2Data = src2.getDoubleDataArrays();
416:
417: int dwidth = dst.getWidth();
418: int dheight = dst.getHeight();
419: int bands = dst.getNumBands();
420: int dLineStride = dst.getScanlineStride();
421: int dPixelStride = dst.getPixelStride();
422: int[] dBandOffsets = dst.getBandOffsets();
423: double[][] dData = dst.getDoubleDataArrays();
424:
425: for (int b = 0; b < bands; b++) {
426: double[] s1 = s1Data[b];
427: double[] s2 = s2Data[b];
428: double[] d = dData[b];
429:
430: int s1LineOffset = s1BandOffsets[b];
431: int s2LineOffset = s2BandOffsets[b];
432: int dLineOffset = dBandOffsets[b];
433:
434: for (int h = 0; h < dheight; h++) {
435: int s1PixelOffset = s1LineOffset;
436: int s2PixelOffset = s2LineOffset;
437: int dPixelOffset = dLineOffset;
438:
439: s1LineOffset += s1LineStride;
440: s2LineOffset += s2LineStride;
441: dLineOffset += dLineStride;
442:
443: for (int w = 0; w < dwidth; w++) {
444: d[dPixelOffset] = maxDouble(s1[s1PixelOffset],
445: s2[s2PixelOffset]);
446:
447: s1PixelOffset += s1PixelStride;
448: s2PixelOffset += s2PixelStride;
449: dPixelOffset += dPixelStride;
450: }
451: }
452: }
453: }
454:
455: private final short maxUShort(short a, short b) {
456: return (a & 0xFFFF) > (b & 0xFFFF) ? a : b;
457: }
458:
459: private final short maxShort(short a, short b) {
460: return a > b ? a : b;
461: }
462:
463: private final int maxInt(int a, int b) {
464: return a > b ? a : b;
465: }
466:
467: private final float maxFloat(float a, float b) {
468: if (a != a)
469: return a; // a is NaN
470: if ((a == 0.0f) && (b == 0.0f)
471: && (Float.floatToIntBits(a) == negativeZeroFloatBits)) {
472: return b;
473: }
474: return (a >= b) ? a : b;
475: }
476:
477: private final double maxDouble(double a, double b) {
478: if (a != a)
479: return a; // a is NaN
480: if ((a == 0.0d)
481: && (b == 0.0d)
482: && (Double.doubleToLongBits(a) == negativeZeroDoubleBits)) {
483: return b;
484: }
485: return (a >= b) ? a : b;
486: }
487: }
|