001: /*
002: * $RCSfile: WarpNearestOpImage.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:47 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.ColorModel;
016: import java.awt.image.DataBuffer;
017: import java.awt.image.IndexColorModel;
018: import java.awt.image.RenderedImage;
019: import java.awt.image.WritableRaster;
020: import javax.media.jai.ImageLayout;
021: import javax.media.jai.Interpolation;
022: import javax.media.jai.PlanarImage;
023: import javax.media.jai.RasterAccessor;
024: import javax.media.jai.RasterFormatTag;
025: import javax.media.jai.RasterFormatTag;
026: import java.util.Map;
027: import javax.media.jai.Warp;
028: import javax.media.jai.WarpOpImage;
029: import javax.media.jai.iterator.RandomIter;
030: import javax.media.jai.iterator.RandomIterFactory;
031:
032: /**
033: * An <code>OpImage</code> implementing the general "Warp" operation as
034: * described in <code>javax.media.jai.operator.WarpDescriptor</code>.
035: * It supports the nearest-neighbor interpolation.
036: *
037: * <p>The layout for the destination image may be specified via the
038: * <code>ImageLayout</code> parameter. However, only those settings
039: * suitable for this operation will be used. The unsuitable settings
040: * will be replaced by default suitable values.
041: *
042: * @since EA2
043: * @see javax.media.jai.Warp
044: * @see javax.media.jai.WarpOpImage
045: * @see javax.media.jai.operator.WarpDescriptor
046: * @see WarpRIF
047: *
048: */
049: final class WarpNearestOpImage extends WarpOpImage {
050:
051: /**
052: * Constructs a WarpNearestOpImage.
053: *
054: * @param source The source image.
055: * @param layout The destination image layout.
056: * @param warp An object defining the warp algorithm.
057: * @param interp An object describing the interpolation method.
058: */
059: public WarpNearestOpImage(RenderedImage source, Map config,
060: ImageLayout layout, Warp warp, Interpolation interp,
061: double[] backgroundValues) {
062: super (source, layout, config, false, null, // extender
063: interp, warp, backgroundValues);
064:
065: /*
066: * If the source has IndexColorModel, override the default setting
067: * in OpImage. The dest shall have exactly the same SampleModel and
068: * ColorModel as the source.
069: * Note, in this case, the source should have an integral data type.
070: */
071: ColorModel srcColorModel = source.getColorModel();
072: if (srcColorModel instanceof IndexColorModel) {
073: sampleModel = source.getSampleModel()
074: .createCompatibleSampleModel(tileWidth, tileHeight);
075: colorModel = srcColorModel;
076: }
077: }
078:
079: /** Warps a rectangle. */
080: protected void computeRect(PlanarImage[] sources,
081: WritableRaster dest, Rectangle destRect) {
082: // Retrieve format tags.
083: RasterFormatTag[] formatTags = getFormatTags();
084:
085: RasterAccessor d = new RasterAccessor(dest, destRect,
086: formatTags[1], getColorModel());
087:
088: switch (d.getDataType()) {
089: case DataBuffer.TYPE_BYTE:
090: computeRectByte(sources[0], d);
091: break;
092: case DataBuffer.TYPE_USHORT:
093: computeRectUShort(sources[0], d);
094: break;
095: case DataBuffer.TYPE_SHORT:
096: computeRectShort(sources[0], d);
097: break;
098: case DataBuffer.TYPE_INT:
099: computeRectInt(sources[0], d);
100: break;
101: case DataBuffer.TYPE_FLOAT:
102: computeRectFloat(sources[0], d);
103: break;
104: case DataBuffer.TYPE_DOUBLE:
105: computeRectDouble(sources[0], d);
106: break;
107: }
108:
109: if (d.isDataCopy()) {
110: d.clampDataArrays();
111: d.copyDataToRaster();
112: }
113: }
114:
115: private void computeRectByte(PlanarImage src, RasterAccessor dst) {
116: RandomIter iter = RandomIterFactory
117: .create(src, src.getBounds());
118:
119: int minX = src.getMinX();
120: int maxX = src.getMaxX();
121: int minY = src.getMinY();
122: int maxY = src.getMaxY();
123:
124: int dstWidth = dst.getWidth();
125: int dstHeight = dst.getHeight();
126: int dstBands = dst.getNumBands();
127:
128: int lineStride = dst.getScanlineStride();
129: int pixelStride = dst.getPixelStride();
130: int[] bandOffsets = dst.getBandOffsets();
131: byte[][] data = dst.getByteDataArrays();
132:
133: float[] warpData = new float[2 * dstWidth];
134:
135: int lineOffset = 0;
136:
137: byte[] backgroundByte = new byte[dstBands];
138: for (int i = 0; i < dstBands; i++)
139: backgroundByte[i] = (byte) backgroundValues[i];
140:
141: for (int h = 0; h < dstHeight; h++) {
142: int pixelOffset = lineOffset;
143: lineOffset += lineStride;
144:
145: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
146: warpData);
147: int count = 0;
148: for (int w = 0; w < dstWidth; w++) {
149: /*
150: * The warp object subtract 0.5 from backward mapped
151: * source coordinate. Need to do a round to get the
152: * nearest neighbor. This is different from the standard
153: * nearest implementation.
154: */
155: int sx = round(warpData[count++]);
156: int sy = round(warpData[count++]);
157:
158: if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) {
159: /* Fill with a background color. */
160: if (setBackground) {
161: for (int b = 0; b < dstBands; b++) {
162: data[b][pixelOffset + bandOffsets[b]] = backgroundByte[b];
163: }
164: }
165: } else {
166: for (int b = 0; b < dstBands; b++) {
167: data[b][pixelOffset + bandOffsets[b]] = (byte) (iter
168: .getSample(sx, sy, b) & 0xFF);
169: }
170: }
171:
172: pixelOffset += pixelStride;
173: }
174: }
175: }
176:
177: private void computeRectUShort(PlanarImage src, RasterAccessor dst) {
178: RandomIter iter = RandomIterFactory
179: .create(src, src.getBounds());
180:
181: int minX = src.getMinX();
182: int maxX = src.getMaxX();
183: int minY = src.getMinY();
184: int maxY = src.getMaxY();
185:
186: int dstWidth = dst.getWidth();
187: int dstHeight = dst.getHeight();
188: int dstBands = dst.getNumBands();
189:
190: int lineStride = dst.getScanlineStride();
191: int pixelStride = dst.getPixelStride();
192: int[] bandOffsets = dst.getBandOffsets();
193: short[][] data = dst.getShortDataArrays();
194:
195: float[] warpData = new float[2 * dstWidth];
196:
197: int lineOffset = 0;
198:
199: short[] backgroundUShort = new short[dstBands];
200: for (int i = 0; i < dstBands; i++)
201: backgroundUShort[i] = (short) backgroundValues[i];
202:
203: for (int h = 0; h < dstHeight; h++) {
204: int pixelOffset = lineOffset;
205: lineOffset += lineStride;
206:
207: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
208: warpData);
209: int count = 0;
210: for (int w = 0; w < dstWidth; w++) {
211: /*
212: * The warp object subtract 0.5 from backward mapped
213: * source coordinate. Need to do a round to get the
214: * nearest neighbor. This is different from the standard
215: * nearest implementation.
216: */
217: int sx = round(warpData[count++]);
218: int sy = round(warpData[count++]);
219:
220: if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) {
221: /* Fill with a background color. */
222: if (setBackground) {
223: for (int b = 0; b < dstBands; b++) {
224: data[b][pixelOffset + bandOffsets[b]] = backgroundUShort[b];
225: }
226: }
227: } else {
228: for (int b = 0; b < dstBands; b++) {
229: data[b][pixelOffset + bandOffsets[b]] = (short) (iter
230: .getSample(sx, sy, b) & 0xFFFF);
231: }
232: }
233:
234: pixelOffset += pixelStride;
235: }
236: }
237: }
238:
239: private void computeRectShort(PlanarImage src, RasterAccessor dst) {
240: RandomIter iter = RandomIterFactory
241: .create(src, src.getBounds());
242:
243: int minX = src.getMinX();
244: int maxX = src.getMaxX();
245: int minY = src.getMinY();
246: int maxY = src.getMaxY();
247:
248: int dstWidth = dst.getWidth();
249: int dstHeight = dst.getHeight();
250: int dstBands = dst.getNumBands();
251:
252: int lineStride = dst.getScanlineStride();
253: int pixelStride = dst.getPixelStride();
254: int[] bandOffsets = dst.getBandOffsets();
255: short[][] data = dst.getShortDataArrays();
256:
257: float[] warpData = new float[2 * dstWidth];
258:
259: int lineOffset = 0;
260:
261: short[] backgroundShort = new short[dstBands];
262: for (int i = 0; i < dstBands; i++)
263: backgroundShort[i] = (short) backgroundValues[i];
264:
265: for (int h = 0; h < dstHeight; h++) {
266: int pixelOffset = lineOffset;
267: lineOffset += lineStride;
268:
269: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
270: warpData);
271: int count = 0;
272: for (int w = 0; w < dstWidth; w++) {
273: /*
274: * The warp object subtract 0.5 from backward mapped
275: * source coordinate. Need to do a round to get the
276: * nearest neighbor. This is different from the standard
277: * nearest implementation.
278: */
279: int sx = round(warpData[count++]);
280: int sy = round(warpData[count++]);
281:
282: if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) {
283: /* Fill with a background color. */
284: if (setBackground) {
285: for (int b = 0; b < dstBands; b++) {
286: data[b][pixelOffset + bandOffsets[b]] = backgroundShort[b];
287: }
288: }
289: } else {
290: for (int b = 0; b < dstBands; b++) {
291: data[b][pixelOffset + bandOffsets[b]] = (short) iter
292: .getSample(sx, sy, b);
293: }
294: }
295:
296: pixelOffset += pixelStride;
297: }
298: }
299: }
300:
301: private void computeRectInt(PlanarImage src, RasterAccessor dst) {
302: RandomIter iter = RandomIterFactory
303: .create(src, src.getBounds());
304:
305: int minX = src.getMinX();
306: int maxX = src.getMaxX();
307: int minY = src.getMinY();
308: int maxY = src.getMaxY();
309:
310: int dstWidth = dst.getWidth();
311: int dstHeight = dst.getHeight();
312: int dstBands = dst.getNumBands();
313:
314: int lineStride = dst.getScanlineStride();
315: int pixelStride = dst.getPixelStride();
316: int[] bandOffsets = dst.getBandOffsets();
317: int[][] data = dst.getIntDataArrays();
318:
319: float[] warpData = new float[2 * dstWidth];
320:
321: int lineOffset = 0;
322:
323: int[] backgroundInt = new int[dstBands];
324: for (int i = 0; i < dstBands; i++)
325: backgroundInt[i] = (int) backgroundValues[i];
326:
327: for (int h = 0; h < dstHeight; h++) {
328: int pixelOffset = lineOffset;
329: lineOffset += lineStride;
330:
331: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
332: warpData);
333: int count = 0;
334: for (int w = 0; w < dstWidth; w++) {
335: /*
336: * The warp object subtract 0.5 from backward mapped
337: * source coordinate. Need to do a round to get the
338: * nearest neighbor. This is different from the standard
339: * nearest implementation.
340: */
341: int sx = round(warpData[count++]);
342: int sy = round(warpData[count++]);
343:
344: if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) {
345: /* Fill with a background color. */
346: if (setBackground) {
347: for (int b = 0; b < dstBands; b++) {
348: data[b][pixelOffset + bandOffsets[b]] = backgroundInt[b];
349: }
350: }
351: } else {
352: for (int b = 0; b < dstBands; b++) {
353: data[b][pixelOffset + bandOffsets[b]] = iter
354: .getSample(sx, sy, b);
355: }
356: }
357:
358: pixelOffset += pixelStride;
359: }
360: }
361: }
362:
363: private void computeRectFloat(PlanarImage src, RasterAccessor dst) {
364: RandomIter iter = RandomIterFactory
365: .create(src, src.getBounds());
366:
367: int minX = src.getMinX();
368: int maxX = src.getMaxX();
369: int minY = src.getMinY();
370: int maxY = src.getMaxY();
371:
372: int dstWidth = dst.getWidth();
373: int dstHeight = dst.getHeight();
374: int dstBands = dst.getNumBands();
375:
376: int lineStride = dst.getScanlineStride();
377: int pixelStride = dst.getPixelStride();
378: int[] bandOffsets = dst.getBandOffsets();
379: float[][] data = dst.getFloatDataArrays();
380:
381: float[] warpData = new float[2 * dstWidth];
382:
383: int lineOffset = 0;
384:
385: float[] backgroundFloat = new float[dstBands];
386: for (int i = 0; i < dstBands; i++)
387: backgroundFloat[i] = (float) backgroundValues[i];
388:
389: for (int h = 0; h < dstHeight; h++) {
390: int pixelOffset = lineOffset;
391: lineOffset += lineStride;
392:
393: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
394: warpData);
395: int count = 0;
396: for (int w = 0; w < dstWidth; w++) {
397: /*
398: * The warp object subtract 0.5 from backward mapped
399: * source coordinate. Need to do a round to get the
400: * nearest neighbor. This is different from the standard
401: * nearest implementation.
402: */
403: int sx = round(warpData[count++]);
404: int sy = round(warpData[count++]);
405:
406: if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) {
407: /* Fill with a background color. */
408: if (setBackground) {
409: for (int b = 0; b < dstBands; b++) {
410: data[b][pixelOffset + bandOffsets[b]] = backgroundFloat[b];
411: }
412: }
413: } else {
414: for (int b = 0; b < dstBands; b++) {
415: data[b][pixelOffset + bandOffsets[b]] = iter
416: .getSampleFloat(sx, sy, b);
417: }
418: }
419:
420: pixelOffset += pixelStride;
421: }
422: }
423: }
424:
425: private void computeRectDouble(PlanarImage src, RasterAccessor dst) {
426: RandomIter iter = RandomIterFactory
427: .create(src, src.getBounds());
428:
429: int minX = src.getMinX();
430: int maxX = src.getMaxX();
431: int minY = src.getMinY();
432: int maxY = src.getMaxY();
433:
434: int dstWidth = dst.getWidth();
435: int dstHeight = dst.getHeight();
436: int dstBands = dst.getNumBands();
437:
438: int lineStride = dst.getScanlineStride();
439: int pixelStride = dst.getPixelStride();
440: int[] bandOffsets = dst.getBandOffsets();
441: double[][] data = dst.getDoubleDataArrays();
442:
443: float[] warpData = new float[2 * dstWidth];
444:
445: int lineOffset = 0;
446:
447: for (int h = 0; h < dstHeight; h++) {
448: int pixelOffset = lineOffset;
449: lineOffset += lineStride;
450:
451: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
452: warpData);
453: int count = 0;
454: for (int w = 0; w < dstWidth; w++) {
455: /*
456: * The warp object subtract 0.5 from backward mapped
457: * source coordinate. Need to do a round to get the
458: * nearest neighbor. This is different from the standard
459: * nearest implementation.
460: */
461: int sx = round(warpData[count++]);
462: int sy = round(warpData[count++]);
463:
464: if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) {
465: /* Fill with a background color. */
466: if (setBackground) {
467: for (int b = 0; b < dstBands; b++) {
468: data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b];
469: }
470: }
471: } else {
472: for (int b = 0; b < dstBands; b++) {
473: data[b][pixelOffset + bandOffsets[b]] = iter
474: .getSampleDouble(sx, sy, b);
475: }
476: }
477:
478: pixelOffset += pixelStride;
479: }
480: }
481: }
482:
483: /** Returns the "round" value of a float. */
484: private static final int round(float f) {
485: return f >= 0 ? (int) (f + 0.5F) : (int) (f - 0.5F);
486: }
487: }
|