001: /*
002: * $RCSfile: AddConstOpImage.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:12 $
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.WritableRaster;
020: import javax.media.jai.ImageLayout;
021: import javax.media.jai.OpImage;
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: // import com.sun.media.jai.test.OpImageTester;
028:
029: /**
030: * An <code>OpImage</code> implementing the "AddConst" operation.
031: *
032: * <p>This <code>OpImage</code> adds a set of constants, one for each
033: * band of the source image, to the pixels of a rendered image.
034: * The destination pixel values are calculated as:
035: * <pre>
036: * for (int h = 0; h < dstHeight; h++) {
037: * for (int w = 0; w < dstWidth; w++) {
038: * for (int b = 0; b < dstNumBands; b++) {
039: * if (constants.length < dstNumBands) {
040: * dst[h][w][b] = srcs[h][w][b] + constants[0];
041: * } else {
042: * dst[h][w][b] = srcs[h][w][b] + constants[b];
043: * }
044: * }
045: * }
046: * }
047: * </pre>
048: *
049: * @see javax.media.jai.operator.AddConstDescriptor
050: * @see AddConstCRIF
051: *
052: */
053: final class AddConstOpImage extends ColormapOpImage {
054:
055: /** The constants to be added, 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:
065: int nbands = constants.length;
066:
067: byteTable = new byte[nbands][256];
068:
069: // Initialize table which implements AddConst and clamp
070: for (int band = 0; band < nbands; band++) {
071: int k = ImageUtil.clampRoundInt(constants[band]);
072: byte[] t = byteTable[band];
073: for (int i = 0; i < 256; i++) {
074: int sum = i + k;
075: if (sum < 0) {
076: t[i] = (byte) 0;
077: } else if (sum > 255) {
078: t[i] = (byte) 255;
079: } else {
080: t[i] = (byte) sum;
081: }
082: }
083: }
084: }
085:
086: /**
087: * Constructor.
088: *
089: * @param source The source image.
090: * @param layout The destination image layout.
091: * @param constants The constants to be added, stored as reference.
092: */
093: public AddConstOpImage(RenderedImage source, Map config,
094: ImageLayout layout, double[] constants) {
095: super (source, layout, config, true);
096:
097: int numBands = getSampleModel().getNumBands();
098:
099: if (constants.length < numBands) {
100: this .constants = new double[numBands];
101: for (int i = 0; i < numBands; i++) {
102: this .constants[i] = constants[0];
103: }
104: } else {
105: this .constants = (double[]) constants.clone();
106: }
107:
108: // Set flag to permit in-place operation.
109: permitInPlaceOperation();
110:
111: // Initialize the colormap if necessary.
112: initializeColormapOperation();
113: }
114:
115: /**
116: * Transform the colormap according to the rescaling parameters.
117: */
118: protected void transformColormap(byte[][] colormap) {
119: initByteTable();
120:
121: for (int b = 0; b < 3; b++) {
122: byte[] map = colormap[b];
123: byte[] luTable = byteTable[b >= byteTable.length ? 0 : b];
124: int mapSize = map.length;
125:
126: for (int i = 0; i < mapSize; i++) {
127: map[i] = luTable[(map[i] & 0xFF)];
128: }
129: }
130: }
131:
132: /**
133: * Adds a constant to the pixel values within a specified rectangle.
134: *
135: * @param sources Cobbled sources, guaranteed to provide all the
136: * source data necessary for computing the rectangle.
137: * @param dest The tile containing the rectangle to be computed.
138: * @param destRect The rectangle within the tile to be computed.
139: */
140: protected void computeRect(Raster[] sources, WritableRaster dest,
141: Rectangle destRect) {
142: // Retrieve format tags.
143: RasterFormatTag[] formatTags = getFormatTags();
144:
145: Rectangle srcRect = mapDestRect(destRect, 0);
146:
147: RasterAccessor dst = new RasterAccessor(dest, destRect,
148: formatTags[1], getColorModel());
149: RasterAccessor src = new RasterAccessor(sources[0], srcRect,
150: formatTags[0], getSourceImage(0).getColorModel());
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: byte[] d = dstData[b];
198: byte[] s = srcData[b];
199: byte[] clamp = byteTable[b];
200:
201: int dstLineOffset = dstBandOffsets[b];
202: int srcLineOffset = srcBandOffsets[b];
203:
204: for (int h = 0; h < dstHeight; h++) {
205: int dstPixelOffset = dstLineOffset;
206: int srcPixelOffset = srcLineOffset;
207:
208: dstLineOffset += dstLineStride;
209: srcLineOffset += srcLineStride;
210:
211: int dstEnd = dstPixelOffset + dstWidth * dstPixelStride;
212: while (dstPixelOffset < dstEnd) {
213: d[dstPixelOffset] = clamp[s[srcPixelOffset] & 0xFF];
214:
215: dstPixelOffset += dstPixelStride;
216: srcPixelOffset += srcPixelStride;
217: }
218: }
219: }
220: }
221:
222: private void computeRectUShort(RasterAccessor src,
223: RasterAccessor dst) {
224: int dstWidth = dst.getWidth();
225: int dstHeight = dst.getHeight();
226: int dstBands = dst.getNumBands();
227:
228: int dstLineStride = dst.getScanlineStride();
229: int dstPixelStride = dst.getPixelStride();
230: int[] dstBandOffsets = dst.getBandOffsets();
231: short[][] dstData = dst.getShortDataArrays();
232:
233: int srcLineStride = src.getScanlineStride();
234: int srcPixelStride = src.getPixelStride();
235: int[] srcBandOffsets = src.getBandOffsets();
236: short[][] srcData = src.getShortDataArrays();
237:
238: for (int b = 0; b < dstBands; b++) {
239: int c = ImageUtil.clampRoundInt(constants[b]);
240: short[] d = dstData[b];
241: short[] s = srcData[b];
242:
243: int dstLineOffset = dstBandOffsets[b];
244: int srcLineOffset = srcBandOffsets[b];
245:
246: for (int h = 0; h < dstHeight; h++) {
247: int dstPixelOffset = dstLineOffset;
248: int srcPixelOffset = srcLineOffset;
249:
250: dstLineOffset += dstLineStride;
251: srcLineOffset += srcLineStride;
252:
253: for (int w = 0; w < dstWidth; w++) {
254: d[dstPixelOffset] = ImageUtil
255: .clampUShort((s[srcPixelOffset] & 0xFFFF)
256: + c);
257:
258: dstPixelOffset += dstPixelStride;
259: srcPixelOffset += srcPixelStride;
260: }
261: }
262: }
263: }
264:
265: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
266: int dstWidth = dst.getWidth();
267: int dstHeight = dst.getHeight();
268: int dstBands = dst.getNumBands();
269:
270: int dstLineStride = dst.getScanlineStride();
271: int dstPixelStride = dst.getPixelStride();
272: int[] dstBandOffsets = dst.getBandOffsets();
273: short[][] dstData = dst.getShortDataArrays();
274:
275: int srcLineStride = src.getScanlineStride();
276: int srcPixelStride = src.getPixelStride();
277: int[] srcBandOffsets = src.getBandOffsets();
278: short[][] srcData = src.getShortDataArrays();
279:
280: for (int b = 0; b < dstBands; b++) {
281: int c = ImageUtil.clampRoundInt(constants[b]);
282: short[] d = dstData[b];
283: short[] s = srcData[b];
284:
285: int dstLineOffset = dstBandOffsets[b];
286: int srcLineOffset = srcBandOffsets[b];
287:
288: for (int h = 0; h < dstHeight; h++) {
289: int dstPixelOffset = dstLineOffset;
290: int srcPixelOffset = srcLineOffset;
291:
292: dstLineOffset += dstLineStride;
293: srcLineOffset += srcLineStride;
294:
295: for (int w = 0; w < dstWidth; w++) {
296: d[dstPixelOffset] = ImageUtil
297: .clampShort(s[srcPixelOffset] + c);
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: long c = ImageUtil.clampRoundInt(constants[b]);
323: int[] d = dstData[b];
324: int[] s = srcData[b];
325:
326: int dstLineOffset = dstBandOffsets[b];
327: int srcLineOffset = srcBandOffsets[b];
328:
329: for (int h = 0; h < dstHeight; h++) {
330: int dstPixelOffset = dstLineOffset;
331: int srcPixelOffset = srcLineOffset;
332:
333: dstLineOffset += dstLineStride;
334: srcLineOffset += srcLineStride;
335:
336: for (int w = 0; w < dstWidth; w++) {
337: d[dstPixelOffset] = ImageUtil
338: .clampInt(s[srcPixelOffset] + c);
339:
340: dstPixelOffset += dstPixelStride;
341: srcPixelOffset += srcPixelStride;
342: }
343: }
344: }
345: }
346:
347: private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
348: int dstWidth = dst.getWidth();
349: int dstHeight = dst.getHeight();
350: int dstBands = dst.getNumBands();
351:
352: int dstLineStride = dst.getScanlineStride();
353: int dstPixelStride = dst.getPixelStride();
354: int[] dstBandOffsets = dst.getBandOffsets();
355: float[][] dstData = dst.getFloatDataArrays();
356:
357: int srcLineStride = src.getScanlineStride();
358: int srcPixelStride = src.getPixelStride();
359: int[] srcBandOffsets = src.getBandOffsets();
360: float[][] srcData = src.getFloatDataArrays();
361:
362: for (int b = 0; b < dstBands; b++) {
363: double c = constants[b];
364: float[] d = dstData[b];
365: float[] s = srcData[b];
366:
367: int dstLineOffset = dstBandOffsets[b];
368: int srcLineOffset = srcBandOffsets[b];
369:
370: for (int h = 0; h < dstHeight; h++) {
371: int dstPixelOffset = dstLineOffset;
372: int srcPixelOffset = srcLineOffset;
373:
374: dstLineOffset += dstLineStride;
375: srcLineOffset += srcLineStride;
376:
377: for (int w = 0; w < dstWidth; w++) {
378: d[dstPixelOffset] = ImageUtil
379: .clampFloat(s[srcPixelOffset] + c);
380:
381: dstPixelOffset += dstPixelStride;
382: srcPixelOffset += srcPixelStride;
383: }
384: }
385: }
386: }
387:
388: private void computeRectDouble(RasterAccessor src,
389: RasterAccessor dst) {
390: int dstWidth = dst.getWidth();
391: int dstHeight = dst.getHeight();
392: int dstBands = dst.getNumBands();
393:
394: int dstLineStride = dst.getScanlineStride();
395: int dstPixelStride = dst.getPixelStride();
396: int[] dstBandOffsets = dst.getBandOffsets();
397: double[][] dstData = dst.getDoubleDataArrays();
398:
399: int srcLineStride = src.getScanlineStride();
400: int srcPixelStride = src.getPixelStride();
401: int[] srcBandOffsets = src.getBandOffsets();
402: double[][] srcData = src.getDoubleDataArrays();
403:
404: for (int b = 0; b < dstBands; b++) {
405: double c = constants[b];
406: double[] d = dstData[b];
407: double[] s = srcData[b];
408:
409: int dstLineOffset = dstBandOffsets[b];
410: int srcLineOffset = srcBandOffsets[b];
411:
412: for (int h = 0; h < dstHeight; h++) {
413: int dstPixelOffset = dstLineOffset;
414: int srcPixelOffset = srcLineOffset;
415:
416: dstLineOffset += dstLineStride;
417: srcLineOffset += srcLineStride;
418:
419: for (int w = 0; w < dstWidth; w++) {
420: d[dstPixelOffset] = s[srcPixelOffset] + c;
421:
422: dstPixelOffset += dstPixelStride;
423: srcPixelOffset += srcPixelStride;
424: }
425: }
426: }
427: }
428:
429: // public static void main(String args[]) {
430: // System.out.println("AddConstOpImage Test");
431:
432: // ImageLayout layout;
433: // OpImage src, dst;
434: // Rectangle rect = new Rectangle(0, 0, 5, 5);
435:
436: // double[] constants = new double[3];
437: // constants[0] = 10.0;
438: // constants[1] = 20.0;
439: // constants[2] = 30.0;
440:
441: // System.out.println("1. PixelInterleaved byte 3-band");
442: // layout = OpImageTester.createImageLayout(
443: // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, false);
444: // src = OpImageTester.createRandomOpImage(layout);
445: // dst = new AddConstOpImage(src, null, null, constants);
446: // OpImageTester.testOpImage(dst, rect);
447: // OpImageTester.timeOpImage(dst, 10);
448:
449: // System.out.println("3. PixelInterleaved int 3-band");
450: // layout = OpImageTester.createImageLayout(
451: // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, false);
452: // src = OpImageTester.createRandomOpImage(layout);
453: // dst = new AddConstOpImage(src, null, null, constants);
454: // OpImageTester.testOpImage(dst, rect);
455: // OpImageTester.timeOpImage(dst, 10);
456: // }
457: }
|