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