001: /*
002: * $RCSfile: InvertOpImage.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:29 $
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:
026: /**
027: * An <code>OpImage</code> implementing the "Invert" operation as
028: * described in <code>javax.media.jai.operator.InvertDescriptor</code>.
029: *
030: * <p>This <code>OpImage</code> negates the pixel values of the source
031: * image on a per-band basis by subtracting the pixel values from the
032: * maximum value of the respective data type. Please note that data type
033: * byte is treated as unsigned with a maximum value of 0xFF. The value
034: * of the pixel (x, y) in the destination image is defined as:
035: * <pre>
036: * for (b = 0; b < dst.numBands; b++) {
037: * dst[y][x][b] = maximumValue - src[y][x][b];
038: * }
039: * </pre>
040: *
041: * @see javax.media.jai.operator.InvertDescriptor
042: * @see InvertRIF
043: *
044: */
045: final class InvertOpImage extends ColormapOpImage {
046:
047: /**
048: * Constructs an <code>InvertOpImage</code>.
049: *
050: * <p>The <code>layout</code> parameter may optionally contains the
051: * tile grid layout, sample model, and/or color model. The image
052: * dimension is set to the same values as that of the source image.
053: *
054: * <p>The image layout of the source image is used as the fall-back
055: * for the image layout of the destination image. Any layout parameters
056: * not specified in the <code>layout</code> argument are set to the
057: * same value as that of the source.
058: *
059: * @param source The source image.
060: * @param layout The destination image layout.
061: */
062: public InvertOpImage(RenderedImage source, Map config,
063: ImageLayout layout) {
064: super (source, layout, config, true);
065:
066: // Set flag to permit in-place operation.
067: permitInPlaceOperation();
068:
069: // Initialize the colormap if necessary.
070: initializeColormapOperation();
071: }
072:
073: /**
074: * Transform the colormap according to the rescaling parameters.
075: */
076: protected void transformColormap(byte[][] colormap) {
077:
078: for (int b = 0; b < 3; b++) {
079: byte[] map = colormap[b];
080: int mapSize = map.length;
081:
082: for (int i = 0; i < mapSize; i++) {
083: map[i] = (byte) (255 - (map[i] & 0xFF));
084: }
085: }
086: }
087:
088: /**
089: * Inverts the pixel values within a specified rectangle.
090: *
091: * @param sources Cobbled sources, guaranteed to provide all the
092: * source data necessary for computing the rectangle.
093: * @param dest The tile containing the rectangle to be computed.
094: * @param destRect The rectangle within the tile to be computed.
095: */
096: protected void computeRect(Raster[] sources, WritableRaster dest,
097: Rectangle destRect) {
098: // Retrieve format tags.
099: RasterFormatTag[] formatTags = getFormatTags();
100:
101: /* For ColormapOpImage, srcRect = destRect. */
102: RasterAccessor s = new RasterAccessor(sources[0], destRect,
103: formatTags[0], getSourceImage(0).getColorModel());
104: RasterAccessor d = new RasterAccessor(dest, destRect,
105: formatTags[1], getColorModel());
106:
107: if (d.isBinary()) {
108: byte[] srcBits = s.getBinaryDataArray();
109: byte[] dstBits = d.getBinaryDataArray();
110: int length = dstBits.length;
111: for (int i = 0; i < length; i++) {
112: dstBits[i] = (byte) (~(srcBits[i]));
113: }
114: d.copyBinaryDataToRaster();
115: } else {
116: switch (d.getDataType()) {
117: case DataBuffer.TYPE_BYTE:
118: computeRectByte(s, d);
119: break;
120: case DataBuffer.TYPE_USHORT:
121: computeRectUShort(s, d);
122: break;
123: case DataBuffer.TYPE_SHORT:
124: computeRectShort(s, d);
125: break;
126: case DataBuffer.TYPE_INT:
127: computeRectInt(s, d);
128: break;
129: case DataBuffer.TYPE_FLOAT:
130: case DataBuffer.TYPE_DOUBLE:
131: throw new RuntimeException(JaiI18N
132: .getString("InvertOpImage0"));
133: }
134:
135: d.copyDataToRaster();
136: }
137: }
138:
139: private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
140: int sLineStride = src.getScanlineStride();
141: int sPixelStride = src.getPixelStride();
142: int[] sBandOffsets = src.getBandOffsets();
143: byte[][] sData = src.getByteDataArrays();
144:
145: int dwidth = dst.getWidth();
146: int dheight = dst.getHeight();
147: int bands = dst.getNumBands();
148: int dLineStride = dst.getScanlineStride();
149: int dPixelStride = dst.getPixelStride();
150: int[] dBandOffsets = dst.getBandOffsets();
151: byte[][] dData = dst.getByteDataArrays();
152:
153: for (int b = 0; b < bands; b++) {
154: byte[] s = sData[b];
155: byte[] d = dData[b];
156:
157: int sLineOffset = sBandOffsets[b];
158: int dLineOffset = dBandOffsets[b];
159:
160: for (int h = 0; h < dheight; h++) {
161: int sPixelOffset = sLineOffset;
162: int dPixelOffset = dLineOffset;
163:
164: sLineOffset += sLineStride;
165: dLineOffset += dLineStride;
166:
167: int dstEnd = dPixelOffset + dwidth * dPixelStride;
168: while (dPixelOffset < dstEnd) {
169: d[dPixelOffset] = (byte) (255 - (s[sPixelOffset] & 0xFF));
170: sPixelOffset += sPixelStride;
171: dPixelOffset += dPixelStride;
172: }
173: }
174: }
175: }
176:
177: private void computeRectUShort(RasterAccessor src,
178: RasterAccessor dst) {
179: int sLineStride = src.getScanlineStride();
180: int sPixelStride = src.getPixelStride();
181: int[] sBandOffsets = src.getBandOffsets();
182: short[][] sData = src.getShortDataArrays();
183:
184: int dwidth = dst.getWidth();
185: int dheight = dst.getHeight();
186: int bands = dst.getNumBands();
187: int dLineStride = dst.getScanlineStride();
188: int dPixelStride = dst.getPixelStride();
189: int[] dBandOffsets = dst.getBandOffsets();
190: short[][] dData = dst.getShortDataArrays();
191:
192: for (int b = 0; b < bands; b++) {
193: short[] s = sData[b];
194: short[] d = dData[b];
195:
196: int sLineOffset = sBandOffsets[b];
197: int dLineOffset = dBandOffsets[b];
198:
199: for (int h = 0; h < dheight; h++) {
200: int sPixelOffset = sLineOffset;
201: int dPixelOffset = dLineOffset;
202:
203: sLineOffset += sLineStride;
204: dLineOffset += dLineStride;
205:
206: int dstEnd = dPixelOffset + dwidth * dPixelStride;
207: while (dPixelOffset < dstEnd) {
208: d[dPixelOffset] = (short) (65535 - (s[sPixelOffset] & 0xFFFF));
209: sPixelOffset += sPixelStride;
210: dPixelOffset += dPixelStride;
211: }
212: }
213: }
214: }
215:
216: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
217: int sLineStride = src.getScanlineStride();
218: int sPixelStride = src.getPixelStride();
219: int[] sBandOffsets = src.getBandOffsets();
220: short[][] sData = src.getShortDataArrays();
221:
222: int dwidth = dst.getWidth();
223: int dheight = dst.getHeight();
224: int bands = dst.getNumBands();
225: int dLineStride = dst.getScanlineStride();
226: int dPixelStride = dst.getPixelStride();
227: int[] dBandOffsets = dst.getBandOffsets();
228: short[][] dData = dst.getShortDataArrays();
229:
230: for (int b = 0; b < bands; b++) {
231: short[] s = sData[b];
232: short[] d = dData[b];
233:
234: int sLineOffset = sBandOffsets[b];
235: int dLineOffset = dBandOffsets[b];
236:
237: for (int h = 0; h < dheight; h++) {
238: int sPixelOffset = sLineOffset;
239: int dPixelOffset = dLineOffset;
240:
241: sLineOffset += sLineStride;
242: dLineOffset += dLineStride;
243:
244: int dstEnd = dPixelOffset + dwidth * dPixelStride;
245: while (dPixelOffset < dstEnd) {
246: d[dPixelOffset] = (short) (Short.MAX_VALUE - s[sPixelOffset]);
247:
248: sPixelOffset += sPixelStride;
249: dPixelOffset += dPixelStride;
250: }
251: }
252: }
253: }
254:
255: private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
256: int sLineStride = src.getScanlineStride();
257: int sPixelStride = src.getPixelStride();
258: int[] sBandOffsets = src.getBandOffsets();
259: int[][] sData = src.getIntDataArrays();
260:
261: int dwidth = dst.getWidth();
262: int dheight = dst.getHeight();
263: int bands = dst.getNumBands();
264: int dLineStride = dst.getScanlineStride();
265: int dPixelStride = dst.getPixelStride();
266: int[] dBandOffsets = dst.getBandOffsets();
267: int[][] dData = dst.getIntDataArrays();
268:
269: /*
270: * For the TAG_INT_COPIED case, the destination data type may
271: * be any of the integral data types. The "clamp" function must
272: * clamp to the appropriate range for that data type.
273: */
274: int[] s = sData[0];
275: int[] d = dData[0];
276: int pixels = d.length;
277:
278: /*
279: * The pixel data array is actually retrieved using getPixels
280: * so there's no need to worry about scanline stride, pixel
281: * stride, band offset, data offset, etc.
282: */
283: switch (sampleModel.getTransferType()) {
284: case DataBuffer.TYPE_BYTE:
285: for (int i = 0; i < pixels; i++) {
286: d[i] = (~s[i]) & 0xFF;
287: }
288: break;
289:
290: case DataBuffer.TYPE_USHORT:
291: for (int i = 0; i < pixels; i++) {
292: d[i] = (~s[i]) & 0xFFFF;
293: }
294: break;
295:
296: case DataBuffer.TYPE_SHORT:
297: for (int i = 0; i < pixels; i++) {
298: d[i] = Short.MAX_VALUE - s[i];
299: }
300: break;
301:
302: case DataBuffer.TYPE_INT:
303: for (int b = 0; b < bands; b++) {
304: s = sData[b];
305: d = dData[b];
306:
307: int sLineOffset = sBandOffsets[b];
308: int dLineOffset = dBandOffsets[b];
309:
310: for (int h = 0; h < dheight; h++) {
311: int sPixelOffset = sLineOffset;
312: int dPixelOffset = dLineOffset;
313:
314: sLineOffset += sLineStride;
315: dLineOffset += dLineStride;
316:
317: int dstEnd = dPixelOffset + dwidth * dPixelStride;
318: while (dPixelOffset < dstEnd) {
319: d[dPixelOffset] = Integer.MAX_VALUE
320: - s[sPixelOffset];
321:
322: sPixelOffset += sPixelStride;
323: dPixelOffset += dPixelStride;
324: }
325: }
326: }
327: break;
328: }
329: }
330: }
|