001: /*
002: * $RCSfile: ClampOpImage.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:16 $
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.WritableRaster;
019: import javax.media.jai.ImageLayout;
020: import javax.media.jai.PointOpImage;
021: import javax.media.jai.RasterAccessor;
022: import javax.media.jai.RasterFormatTag;
023: import java.util.Map;
024: import com.sun.media.jai.util.ImageUtil;
025:
026: /**
027: * An <code>OpImage</code> implementing the "Clamp" operation.
028: *
029: * <p>This <code>OpImage</code> maps all the pixel values of an image
030: * that are less than a lower bound to that lower bound value, and all that
031: * are greater than a upper bound to that upper bound value. All pixel values
032: * fall within these boundaries remain unchanged. The mapping is done on a
033: * per-band basis.
034: *
035: * <p>Each of the lower bound and upper bound arrays may have only
036: * one value in it. If that is the case, that value is applied to all bands.
037: * The number of elements in each array has to be consistent, i.e. either
038: * all arrays contain one element in them or all they have the same number
039: * of elements that matches the number of bands of the source image.
040: *
041: * @see javax.media.jai.operator.ClampDescriptor
042: * @see ClampCRIF
043: *
044: *
045: * @since EA2
046: */
047: final class ClampOpImage extends PointOpImage {
048:
049: /** Lookup table for byte data */
050: private byte[][] byteTable = null;
051:
052: /** The lower bound, one for each band. */
053: private final double[] low;
054:
055: /** The upper bound, one for each band. */
056: private final double[] high;
057:
058: private synchronized void initByteTable() {
059:
060: if (byteTable == null) {
061: /* Initialize byteTable. */
062: int numBands = getSampleModel().getNumBands();
063: byteTable = new byte[numBands][0x100];
064: for (int b = 0; b < numBands; b++) {
065: byte[] t = byteTable[b];
066: int l = (int) low[b];
067: int h = (int) high[b];
068:
069: byte bl = (byte) l;
070: byte bh = (byte) h;
071:
072: for (int i = 0; i < 0x100; i++) {
073: if (i < l) {
074: t[i] = bl;
075: } else if (i > h) {
076: t[i] = bh;
077: } else {
078: t[i] = (byte) i;
079: }
080: }
081: }
082: }
083: }
084:
085: /**
086: * Constructor.
087: *
088: * @param source The source image.
089: * @param layout The destination image layout.
090: * @param low The lower bound of the clamp.
091: * @param high The upper bound of the clamp.
092: */
093: public ClampOpImage(RenderedImage source, Map config,
094: ImageLayout layout, double[] low, double[] high) {
095: super (source, layout, config, true);
096:
097: int numBands = getSampleModel().getNumBands();
098:
099: if (low.length < numBands || high.length < numBands) {
100: this .low = new double[numBands];
101: this .high = new double[numBands];
102: for (int i = 0; i < numBands; i++) {
103: this .low[i] = low[0];
104: this .high[i] = high[0];
105: }
106: } else {
107: this .low = (double[]) low.clone();
108: this .high = (double[]) high.clone();
109: }
110:
111: // Set flag to permit in-place operation.
112: permitInPlaceOperation();
113: }
114:
115: /**
116: * Map the pixels inside a specified rectangle whose value is within a
117: * range to a constant on a per-band basis.
118: *
119: * @param sources Cobbled sources, guaranteed to provide all the
120: * source data necessary for computing the rectangle.
121: * @param dest The tile containing the rectangle to be computed.
122: * @param destRect The rectangle within the tile to be computed.
123: */
124: protected void computeRect(Raster[] sources, WritableRaster dest,
125: Rectangle destRect) {
126: // Retrieve format tags.
127: RasterFormatTag[] formatTags = getFormatTags();
128:
129: Rectangle srcRect = mapDestRect(destRect, 0);
130:
131: RasterAccessor src = new RasterAccessor(sources[0], srcRect,
132: formatTags[0], getSourceImage(0).getColorModel());
133: RasterAccessor dst = new RasterAccessor(dest, destRect,
134: formatTags[1], getColorModel());
135:
136: switch (dst.getDataType()) {
137: case DataBuffer.TYPE_BYTE:
138: computeRectByte(src, dst);
139: break;
140: case DataBuffer.TYPE_USHORT:
141: computeRectUShort(src, dst);
142: break;
143: case DataBuffer.TYPE_SHORT:
144: computeRectShort(src, dst);
145: break;
146: case DataBuffer.TYPE_INT:
147: computeRectInt(src, dst);
148: break;
149: case DataBuffer.TYPE_FLOAT:
150: computeRectFloat(src, dst);
151: break;
152: case DataBuffer.TYPE_DOUBLE:
153: computeRectDouble(src, dst);
154: break;
155: }
156:
157: dst.copyDataToRaster();
158: }
159:
160: private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
161: initByteTable();
162:
163: int dstWidth = dst.getWidth();
164: int dstHeight = dst.getHeight();
165: int dstBands = dst.getNumBands();
166:
167: int dstLineStride = dst.getScanlineStride();
168: int dstPixelStride = dst.getPixelStride();
169: int[] dstBandOffsets = dst.getBandOffsets();
170: byte[][] dstData = dst.getByteDataArrays();
171:
172: int srcLineStride = src.getScanlineStride();
173: int srcPixelStride = src.getPixelStride();
174: int[] srcBandOffsets = src.getBandOffsets();
175: byte[][] srcData = src.getByteDataArrays();
176:
177: for (int b = 0; b < dstBands; b++) {
178: byte[] d = dstData[b];
179: byte[] s = srcData[b];
180: byte[] t = byteTable[b];
181:
182: int dstLineOffset = dstBandOffsets[b];
183: int srcLineOffset = srcBandOffsets[b];
184:
185: for (int h = 0; h < dstHeight; h++) {
186: int dstPixelOffset = dstLineOffset;
187: int srcPixelOffset = srcLineOffset;
188:
189: dstLineOffset += dstLineStride;
190: srcLineOffset += srcLineStride;
191:
192: for (int w = 0; w < dstWidth; w++) {
193: d[dstPixelOffset] = t[s[srcPixelOffset]
194: & ImageUtil.BYTE_MASK];
195:
196: dstPixelOffset += dstPixelStride;
197: srcPixelOffset += srcPixelStride;
198: }
199: }
200: }
201: }
202:
203: private void computeRectUShort(RasterAccessor src,
204: RasterAccessor dst) {
205: int dstWidth = dst.getWidth();
206: int dstHeight = dst.getHeight();
207: int dstBands = dst.getNumBands();
208:
209: int dstLineStride = dst.getScanlineStride();
210: int dstPixelStride = dst.getPixelStride();
211: int[] dstBandOffsets = dst.getBandOffsets();
212: short[][] dstData = dst.getShortDataArrays();
213:
214: int srcLineStride = src.getScanlineStride();
215: int srcPixelStride = src.getPixelStride();
216: int[] srcBandOffsets = src.getBandOffsets();
217: short[][] srcData = src.getShortDataArrays();
218:
219: for (int b = 0; b < dstBands; b++) {
220: short[] d = dstData[b];
221: short[] s = srcData[b];
222: int lo = (int) low[b];
223: int hi = (int) high[b];
224:
225: short slo = (short) lo;
226: short shi = (short) hi;
227:
228: int dstLineOffset = dstBandOffsets[b];
229: int srcLineOffset = srcBandOffsets[b];
230:
231: for (int h = 0; h < dstHeight; h++) {
232: int dstPixelOffset = dstLineOffset;
233: int srcPixelOffset = srcLineOffset;
234:
235: dstLineOffset += dstLineStride;
236: srcLineOffset += srcLineStride;
237:
238: for (int w = 0; w < dstWidth; w++) {
239: int p = s[srcPixelOffset] & ImageUtil.USHORT_MASK;
240: if (p < lo) {
241: d[dstPixelOffset] = slo;
242: } else if (p > hi) {
243: d[dstPixelOffset] = shi;
244: } else {
245: d[dstPixelOffset] = (short) p;
246: }
247:
248: dstPixelOffset += dstPixelStride;
249: srcPixelOffset += srcPixelStride;
250: }
251: }
252: }
253: }
254:
255: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
256: int dstWidth = dst.getWidth();
257: int dstHeight = dst.getHeight();
258: int dstBands = dst.getNumBands();
259:
260: int dstLineStride = dst.getScanlineStride();
261: int dstPixelStride = dst.getPixelStride();
262: int[] dstBandOffsets = dst.getBandOffsets();
263: short[][] dstData = dst.getShortDataArrays();
264:
265: int srcLineStride = src.getScanlineStride();
266: int srcPixelStride = src.getPixelStride();
267: int[] srcBandOffsets = src.getBandOffsets();
268: short[][] srcData = src.getShortDataArrays();
269:
270: for (int b = 0; b < dstBands; b++) {
271: short[] d = dstData[b];
272: short[] s = srcData[b];
273: int lo = (int) low[b];
274: int hi = (int) high[b];
275:
276: short slo = (short) lo;
277: short shi = (short) hi;
278:
279: int dstLineOffset = dstBandOffsets[b];
280: int srcLineOffset = srcBandOffsets[b];
281:
282: for (int h = 0; h < dstHeight; h++) {
283: int dstPixelOffset = dstLineOffset;
284: int srcPixelOffset = srcLineOffset;
285:
286: dstLineOffset += dstLineStride;
287: srcLineOffset += srcLineStride;
288:
289: for (int w = 0; w < dstWidth; w++) {
290: short p = s[srcPixelOffset];
291: if (p < lo) {
292: d[dstPixelOffset] = slo;
293: } else if (p > hi) {
294: d[dstPixelOffset] = shi;
295: } else {
296: d[dstPixelOffset] = p;
297: }
298:
299: dstPixelOffset += dstPixelStride;
300: srcPixelOffset += srcPixelStride;
301: }
302: }
303: }
304: }
305:
306: private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
307: int dstWidth = dst.getWidth();
308: int dstHeight = dst.getHeight();
309: int dstBands = dst.getNumBands();
310:
311: int dstLineStride = dst.getScanlineStride();
312: int dstPixelStride = dst.getPixelStride();
313: int[] dstBandOffsets = dst.getBandOffsets();
314: int[][] dstData = dst.getIntDataArrays();
315:
316: int srcLineStride = src.getScanlineStride();
317: int srcPixelStride = src.getPixelStride();
318: int[] srcBandOffsets = src.getBandOffsets();
319: int[][] srcData = src.getIntDataArrays();
320:
321: for (int b = 0; b < dstBands; b++) {
322: int[] d = dstData[b];
323: int[] s = srcData[b];
324: double lo = low[b];
325: double hi = high[b];
326:
327: int ilo = (int) lo;
328: int ihi = (int) hi;
329:
330: int dstLineOffset = dstBandOffsets[b];
331: int srcLineOffset = srcBandOffsets[b];
332:
333: for (int h = 0; h < dstHeight; h++) {
334: int dstPixelOffset = dstLineOffset;
335: int srcPixelOffset = srcLineOffset;
336:
337: dstLineOffset += dstLineStride;
338: srcLineOffset += srcLineStride;
339:
340: for (int w = 0; w < dstWidth; w++) {
341: int p = s[srcPixelOffset];
342: if (p < lo) {
343: d[dstPixelOffset] = ilo;
344: } else if (p > hi) {
345: d[dstPixelOffset] = ihi;
346: } else {
347: d[dstPixelOffset] = p;
348: }
349:
350: dstPixelOffset += dstPixelStride;
351: srcPixelOffset += srcPixelStride;
352: }
353: }
354: }
355: }
356:
357: private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
358: int dstWidth = dst.getWidth();
359: int dstHeight = dst.getHeight();
360: int dstBands = dst.getNumBands();
361:
362: int dstLineStride = dst.getScanlineStride();
363: int dstPixelStride = dst.getPixelStride();
364: int[] dstBandOffsets = dst.getBandOffsets();
365: float[][] dstData = dst.getFloatDataArrays();
366:
367: int srcLineStride = src.getScanlineStride();
368: int srcPixelStride = src.getPixelStride();
369: int[] srcBandOffsets = src.getBandOffsets();
370: float[][] srcData = src.getFloatDataArrays();
371:
372: for (int b = 0; b < dstBands; b++) {
373: float[] d = dstData[b];
374: float[] s = srcData[b];
375: double lo = low[b];
376: double hi = high[b];
377:
378: float flo = (float) lo;
379: float fhi = (float) hi;
380:
381: int dstLineOffset = dstBandOffsets[b];
382: int srcLineOffset = srcBandOffsets[b];
383:
384: for (int h = 0; h < dstHeight; h++) {
385: int dstPixelOffset = dstLineOffset;
386: int srcPixelOffset = srcLineOffset;
387:
388: dstLineOffset += dstLineStride;
389: srcLineOffset += srcLineStride;
390:
391: for (int w = 0; w < dstWidth; w++) {
392: float p = s[srcPixelOffset];
393: if (p < lo) {
394: d[dstPixelOffset] = flo;
395: } else if (p > hi) {
396: d[dstPixelOffset] = fhi;
397: } else {
398: d[dstPixelOffset] = p;
399: }
400:
401: dstPixelOffset += dstPixelStride;
402: srcPixelOffset += srcPixelStride;
403: }
404: }
405: }
406: }
407:
408: private void computeRectDouble(RasterAccessor src,
409: RasterAccessor dst) {
410: int dstWidth = dst.getWidth();
411: int dstHeight = dst.getHeight();
412: int dstBands = dst.getNumBands();
413:
414: int dstLineStride = dst.getScanlineStride();
415: int dstPixelStride = dst.getPixelStride();
416: int[] dstBandOffsets = dst.getBandOffsets();
417: double[][] dstData = dst.getDoubleDataArrays();
418:
419: int srcLineStride = src.getScanlineStride();
420: int srcPixelStride = src.getPixelStride();
421: int[] srcBandOffsets = src.getBandOffsets();
422: double[][] srcData = src.getDoubleDataArrays();
423:
424: for (int b = 0; b < dstBands; b++) {
425: double[] d = dstData[b];
426: double[] s = srcData[b];
427: double lo = low[b];
428: double hi = high[b];
429:
430: int dstLineOffset = dstBandOffsets[b];
431: int srcLineOffset = srcBandOffsets[b];
432:
433: for (int h = 0; h < dstHeight; h++) {
434: int dstPixelOffset = dstLineOffset;
435: int srcPixelOffset = srcLineOffset;
436:
437: dstLineOffset += dstLineStride;
438: srcLineOffset += srcLineStride;
439:
440: for (int w = 0; w < dstWidth; w++) {
441: double p = s[srcPixelOffset];
442: if (p < lo) {
443: d[dstPixelOffset] = lo;
444: } else if (p > hi) {
445: d[dstPixelOffset] = hi;
446: } else {
447: d[dstPixelOffset] = p;
448: }
449:
450: dstPixelOffset += dstPixelStride;
451: srcPixelOffset += srcPixelStride;
452: }
453: }
454: }
455: }
456: }
|