001: /*
002: * $RCSfile: WarpBilinearOpImage.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.BorderExtender;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.Interpolation;
023: import javax.media.jai.PlanarImage;
024: import javax.media.jai.RasterAccessor;
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 bilinear interpolation.
036: *
037: * @since EA2
038: * @see javax.media.jai.Warp
039: * @see javax.media.jai.WarpOpImage
040: * @see javax.media.jai.operator.WarpDescriptor
041: * @see WarpRIF
042: *
043: */
044: final class WarpBilinearOpImage extends WarpOpImage {
045:
046: /** Color table representing source's IndexColorModel. */
047: private byte[][] ctable = null;
048:
049: /**
050: * Constructs a WarpBilinearOpImage.
051: *
052: * @param source The source image.
053: * @param extender A BorderExtender, or null.
054: * @param layout The destination image layout.
055: * @param warp An object defining the warp algorithm.
056: * @param interp An object describing the interpolation method.
057: */
058: public WarpBilinearOpImage(RenderedImage source,
059: BorderExtender extender, Map config, ImageLayout layout,
060: Warp warp, Interpolation interp, double[] backgroundValues) {
061: super (source, layout, config, false, extender, interp, warp,
062: backgroundValues);
063:
064: /*
065: * If the source has IndexColorModel, get the RGB color table.
066: * Note, in this case, the source should have an integral data type.
067: * And dest always has data type byte.
068: */
069: ColorModel srcColorModel = source.getColorModel();
070: if (srcColorModel instanceof IndexColorModel) {
071: IndexColorModel icm = (IndexColorModel) srcColorModel;
072: ctable = new byte[3][icm.getMapSize()];
073: icm.getReds(ctable[0]);
074: icm.getGreens(ctable[1]);
075: icm.getBlues(ctable[2]);
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;
117: if (extender != null) {
118: Rectangle bounds = new Rectangle(src.getMinX(), src
119: .getMinY(), src.getWidth() + 1, src.getHeight() + 1);
120: iter = RandomIterFactory.create(src.getExtendedData(bounds,
121: extender), bounds);
122: } else {
123: iter = RandomIterFactory.create(src, src.getBounds());
124: }
125:
126: int minX = src.getMinX();
127: int maxX = src.getMaxX() - (extender != null ? 0 : 1); // Right padding
128: int minY = src.getMinY();
129: int maxY = src.getMaxY() - (extender != null ? 0 : 1); // Bottom padding
130:
131: int dstWidth = dst.getWidth();
132: int dstHeight = dst.getHeight();
133: int dstBands = dst.getNumBands();
134:
135: int lineStride = dst.getScanlineStride();
136: int pixelStride = dst.getPixelStride();
137: int[] bandOffsets = dst.getBandOffsets();
138: byte[][] data = dst.getByteDataArrays();
139:
140: float[] warpData = new float[2 * dstWidth];
141:
142: int lineOffset = 0;
143:
144: byte[] backgroundByte = new byte[dstBands];
145: for (int i = 0; i < dstBands; i++)
146: backgroundByte[i] = (byte) backgroundValues[i];
147:
148: if (ctable == null) { // source does not have IndexColorModel
149: for (int h = 0; h < dstHeight; h++) {
150: int pixelOffset = lineOffset;
151: lineOffset += lineStride;
152:
153: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
154: warpData);
155: int count = 0;
156: for (int w = 0; w < dstWidth; w++) {
157: float sx = warpData[count++];
158: float sy = warpData[count++];
159:
160: int xint = floor(sx);
161: int yint = floor(sy);
162: float xfrac = sx - xint;
163: float yfrac = sy - yint;
164:
165: if (xint < minX || xint >= maxX || yint < minY
166: || yint >= maxY) {
167: /* Fill with a background color. */
168: if (setBackground) {
169: for (int b = 0; b < dstBands; b++) {
170: data[b][pixelOffset + bandOffsets[b]] = backgroundByte[b];
171: }
172: }
173: } else {
174: for (int b = 0; b < dstBands; b++) {
175: int s00 = iter.getSample(xint, yint, b) & 0xFF;
176: int s01 = iter.getSample(xint + 1, yint, b) & 0xFF;
177: int s10 = iter.getSample(xint, yint + 1, b) & 0xFF;
178: int s11 = iter.getSample(xint + 1,
179: yint + 1, b) & 0xFF;
180:
181: float s0 = (s01 - s00) * xfrac + s00;
182: float s1 = (s11 - s10) * xfrac + s10;
183: float s = (s1 - s0) * yfrac + s0;
184:
185: data[b][pixelOffset + bandOffsets[b]] = (byte) s;
186: }
187: }
188:
189: pixelOffset += pixelStride;
190: }
191: }
192: } else { // source has IndexColorModel
193: for (int h = 0; h < dstHeight; h++) {
194: int pixelOffset = lineOffset;
195: lineOffset += lineStride;
196:
197: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
198: warpData);
199: int count = 0;
200: for (int w = 0; w < dstWidth; w++) {
201: float sx = warpData[count++];
202: float sy = warpData[count++];
203:
204: int xint = floor(sx);
205: int yint = floor(sy);
206: float xfrac = sx - xint;
207: float yfrac = sy - yint;
208:
209: if (xint < minX || xint >= maxX || yint < minY
210: || yint >= maxY) {
211: /* Fill with a background color. */
212: if (setBackground) {
213: for (int b = 0; b < dstBands; b++) {
214: data[b][pixelOffset + bandOffsets[b]] = backgroundByte[b];
215: }
216: }
217: } else {
218: for (int b = 0; b < dstBands; b++) {
219: byte[] t = ctable[b];
220:
221: int s00 = t[iter.getSample(xint, yint, 0) & 0xFF] & 0xFF;
222: int s01 = t[iter.getSample(xint + 1, yint,
223: 0) & 0xFF] & 0xFF;
224: int s10 = t[iter.getSample(xint, yint + 1,
225: 0) & 0xFF] & 0xFF;
226: int s11 = t[iter.getSample(xint + 1,
227: yint + 1, 0) & 0xFF] & 0xFF;
228:
229: float s0 = (s01 - s00) * xfrac + s00;
230: float s1 = (s11 - s10) * xfrac + s10;
231: float s = (s1 - s0) * yfrac + s0;
232:
233: data[b][pixelOffset + bandOffsets[b]] = (byte) s;
234: }
235: }
236:
237: pixelOffset += pixelStride;
238: }
239: }
240: }
241: }
242:
243: private void computeRectUShort(PlanarImage src, RasterAccessor dst) {
244: RandomIter iter;
245: if (extender != null) {
246: Rectangle bounds = new Rectangle(src.getMinX(), src
247: .getMinY(), src.getWidth() + 1, src.getHeight() + 1);
248: iter = RandomIterFactory.create(src.getExtendedData(bounds,
249: extender), bounds);
250: } else {
251: iter = RandomIterFactory.create(src, src.getBounds());
252: }
253:
254: int minX = src.getMinX();
255: int maxX = src.getMaxX() - (extender != null ? 0 : 1); // Right padding
256: int minY = src.getMinY();
257: int maxY = src.getMaxY() - (extender != null ? 0 : 1); // Bottom padding
258:
259: int dstWidth = dst.getWidth();
260: int dstHeight = dst.getHeight();
261: int dstBands = dst.getNumBands();
262:
263: int lineStride = dst.getScanlineStride();
264: int pixelStride = dst.getPixelStride();
265: int[] bandOffsets = dst.getBandOffsets();
266: short[][] data = dst.getShortDataArrays();
267:
268: float[] warpData = new float[2 * dstWidth];
269:
270: int lineOffset = 0;
271:
272: short[] backgroundUShort = new short[dstBands];
273: for (int i = 0; i < dstBands; i++)
274: backgroundUShort[i] = (short) backgroundValues[i];
275:
276: for (int h = 0; h < dstHeight; h++) {
277: int pixelOffset = lineOffset;
278: lineOffset += lineStride;
279:
280: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
281: warpData);
282: int count = 0;
283: for (int w = 0; w < dstWidth; w++) {
284: float sx = warpData[count++];
285: float sy = warpData[count++];
286:
287: int xint = floor(sx);
288: int yint = floor(sy);
289: float xfrac = sx - xint;
290: float yfrac = sy - yint;
291:
292: if (xint < minX || xint >= maxX || yint < minY
293: || yint >= maxY) {
294: /* Fill with a background color. */
295: if (setBackground) {
296: for (int b = 0; b < dstBands; b++) {
297: data[b][pixelOffset + bandOffsets[b]] = backgroundUShort[b];
298: }
299: }
300: } else {
301: for (int b = 0; b < dstBands; b++) {
302: int s00 = iter.getSample(xint, yint, b) & 0xFFFF;
303: int s01 = iter.getSample(xint + 1, yint, b) & 0xFFFF;
304: int s10 = iter.getSample(xint, yint + 1, b) & 0xFFFF;
305: int s11 = iter.getSample(xint + 1, yint + 1, b) & 0xFFFF;
306:
307: float s0 = (s01 - s00) * xfrac + s00;
308: float s1 = (s11 - s10) * xfrac + s10;
309: float s = (s1 - s0) * yfrac + s0;
310:
311: data[b][pixelOffset + bandOffsets[b]] = (short) s;
312: }
313: }
314:
315: pixelOffset += pixelStride;
316: }
317: }
318: }
319:
320: private void computeRectShort(PlanarImage src, RasterAccessor dst) {
321: RandomIter iter;
322: if (extender != null) {
323: Rectangle bounds = new Rectangle(src.getMinX(), src
324: .getMinY(), src.getWidth() + 1, src.getHeight() + 1);
325: iter = RandomIterFactory.create(src.getExtendedData(bounds,
326: extender), bounds);
327: } else {
328: iter = RandomIterFactory.create(src, src.getBounds());
329: }
330:
331: int minX = src.getMinX();
332: int maxX = src.getMaxX() - (extender != null ? 0 : 1); // Right padding
333: int minY = src.getMinY();
334: int maxY = src.getMaxY() - (extender != null ? 0 : 1); // Bottom padding
335:
336: int dstWidth = dst.getWidth();
337: int dstHeight = dst.getHeight();
338: int dstBands = dst.getNumBands();
339:
340: int lineStride = dst.getScanlineStride();
341: int pixelStride = dst.getPixelStride();
342: int[] bandOffsets = dst.getBandOffsets();
343: short[][] data = dst.getShortDataArrays();
344:
345: float[] warpData = new float[2 * dstWidth];
346:
347: int lineOffset = 0;
348:
349: short[] backgroundShort = new short[dstBands];
350: for (int i = 0; i < dstBands; i++)
351: backgroundShort[i] = (short) backgroundValues[i];
352:
353: for (int h = 0; h < dstHeight; h++) {
354: int pixelOffset = lineOffset;
355: lineOffset += lineStride;
356:
357: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
358: warpData);
359: int count = 0;
360: for (int w = 0; w < dstWidth; w++) {
361: float sx = warpData[count++];
362: float sy = warpData[count++];
363:
364: int xint = floor(sx);
365: int yint = floor(sy);
366: float xfrac = sx - xint;
367: float yfrac = sy - yint;
368:
369: if (xint < minX || xint >= maxX || yint < minY
370: || yint >= maxY) {
371: /* Fill with a background color. */
372: if (setBackground) {
373: for (int b = 0; b < dstBands; b++) {
374: data[b][pixelOffset + bandOffsets[b]] = backgroundShort[b];
375: }
376: }
377: } else {
378: for (int b = 0; b < dstBands; b++) {
379: int s00 = iter.getSample(xint, yint, b);
380: int s01 = iter.getSample(xint + 1, yint, b);
381: int s10 = iter.getSample(xint, yint + 1, b);
382: int s11 = iter.getSample(xint + 1, yint + 1, b);
383:
384: float s0 = (s01 - s00) * xfrac + s00;
385: float s1 = (s11 - s10) * xfrac + s10;
386: float s = (s1 - s0) * yfrac + s0;
387:
388: data[b][pixelOffset + bandOffsets[b]] = (short) s;
389: }
390: }
391:
392: pixelOffset += pixelStride;
393: }
394: }
395: }
396:
397: private void computeRectInt(PlanarImage src, RasterAccessor dst) {
398: RandomIter iter;
399: if (extender != null) {
400: Rectangle bounds = new Rectangle(src.getMinX(), src
401: .getMinY(), src.getWidth() + 1, src.getHeight() + 1);
402: iter = RandomIterFactory.create(src.getExtendedData(bounds,
403: extender), bounds);
404: } else {
405: iter = RandomIterFactory.create(src, src.getBounds());
406: }
407:
408: int minX = src.getMinX();
409: int maxX = src.getMaxX() - (extender != null ? 0 : 1); // Right padding
410: int minY = src.getMinY();
411: int maxY = src.getMaxY() - (extender != null ? 0 : 1); // Bottom padding
412:
413: int dstWidth = dst.getWidth();
414: int dstHeight = dst.getHeight();
415: int dstBands = dst.getNumBands();
416:
417: int lineStride = dst.getScanlineStride();
418: int pixelStride = dst.getPixelStride();
419: int[] bandOffsets = dst.getBandOffsets();
420: int[][] data = dst.getIntDataArrays();
421:
422: float[] warpData = new float[2 * dstWidth];
423:
424: int lineOffset = 0;
425:
426: int[] backgroundInt = new int[dstBands];
427: for (int i = 0; i < dstBands; i++)
428: backgroundInt[i] = (int) backgroundValues[i];
429:
430: for (int h = 0; h < dstHeight; h++) {
431: int pixelOffset = lineOffset;
432: lineOffset += lineStride;
433:
434: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
435: warpData);
436: int count = 0;
437: for (int w = 0; w < dstWidth; w++) {
438: float sx = warpData[count++];
439: float sy = warpData[count++];
440:
441: int xint = floor(sx);
442: int yint = floor(sy);
443: float xfrac = sx - xint;
444: float yfrac = sy - yint;
445:
446: if (xint < minX || xint >= maxX || yint < minY
447: || yint >= maxY) {
448: /* Fill with a background color. */
449: if (setBackground) {
450: for (int b = 0; b < dstBands; b++) {
451: data[b][pixelOffset + bandOffsets[b]] = backgroundInt[b];
452: }
453: }
454: } else {
455: for (int b = 0; b < dstBands; b++) {
456: int s00 = iter.getSample(xint, yint, b);
457: int s01 = iter.getSample(xint + 1, yint, b);
458: int s10 = iter.getSample(xint, yint + 1, b);
459: int s11 = iter.getSample(xint + 1, yint + 1, b);
460:
461: float s0 = (s01 - s00) * xfrac + s00;
462: float s1 = (s11 - s10) * xfrac + s10;
463: float s = (s1 - s0) * yfrac + s0;
464:
465: data[b][pixelOffset + bandOffsets[b]] = (int) s;
466: }
467: }
468:
469: pixelOffset += pixelStride;
470: }
471: }
472: }
473:
474: private void computeRectFloat(PlanarImage src, RasterAccessor dst) {
475: RandomIter iter;
476: if (extender != null) {
477: Rectangle bounds = new Rectangle(src.getMinX(), src
478: .getMinY(), src.getWidth() + 1, src.getHeight() + 1);
479: iter = RandomIterFactory.create(src.getExtendedData(bounds,
480: extender), bounds);
481: } else {
482: iter = RandomIterFactory.create(src, src.getBounds());
483: }
484:
485: int minX = src.getMinX();
486: int maxX = src.getMaxX() - (extender != null ? 0 : 1); // Right padding
487: int minY = src.getMinY();
488: int maxY = src.getMaxY() - (extender != null ? 0 : 1); // Bottom padding
489:
490: int dstWidth = dst.getWidth();
491: int dstHeight = dst.getHeight();
492: int dstBands = dst.getNumBands();
493:
494: int lineStride = dst.getScanlineStride();
495: int pixelStride = dst.getPixelStride();
496: int[] bandOffsets = dst.getBandOffsets();
497: float[][] data = dst.getFloatDataArrays();
498:
499: float[] warpData = new float[2 * dstWidth];
500:
501: int lineOffset = 0;
502:
503: float[] backgroundFloat = new float[dstBands];
504: for (int i = 0; i < dstBands; i++)
505: backgroundFloat[i] = (float) backgroundValues[i];
506:
507: for (int h = 0; h < dstHeight; h++) {
508: int pixelOffset = lineOffset;
509: lineOffset += lineStride;
510:
511: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
512: warpData);
513: int count = 0;
514: for (int w = 0; w < dstWidth; w++) {
515: float sx = warpData[count++];
516: float sy = warpData[count++];
517:
518: int xint = floor(sx);
519: int yint = floor(sy);
520: float xfrac = sx - xint;
521: float yfrac = sy - yint;
522:
523: if (xint < minX || xint >= maxX || yint < minY
524: || yint >= maxY) {
525: /* Fill with a background color. */
526: if (setBackground) {
527: for (int b = 0; b < dstBands; b++) {
528: data[b][pixelOffset + bandOffsets[b]] = backgroundFloat[b];
529: }
530: }
531: } else {
532: for (int b = 0; b < dstBands; b++) {
533: float s00 = iter.getSampleFloat(xint, yint, b);
534: float s01 = iter.getSampleFloat(xint + 1, yint,
535: b);
536: float s10 = iter.getSampleFloat(xint, yint + 1,
537: b);
538: float s11 = iter.getSampleFloat(xint + 1,
539: yint + 1, b);
540:
541: float s0 = (s01 - s00) * xfrac + s00;
542: float s1 = (s11 - s10) * xfrac + s10;
543: float s = (s1 - s0) * yfrac + s0;
544:
545: data[b][pixelOffset + bandOffsets[b]] = s;
546: }
547: }
548:
549: pixelOffset += pixelStride;
550: }
551: }
552: }
553:
554: private void computeRectDouble(PlanarImage src, RasterAccessor dst) {
555: RandomIter iter;
556: if (extender != null) {
557: Rectangle bounds = new Rectangle(src.getMinX(), src
558: .getMinY(), src.getWidth() + 1, src.getHeight() + 1);
559: iter = RandomIterFactory.create(src.getExtendedData(bounds,
560: extender), bounds);
561: } else {
562: iter = RandomIterFactory.create(src, src.getBounds());
563: }
564:
565: int minX = src.getMinX();
566: int maxX = src.getMaxX() - (extender != null ? 0 : 1); // Right padding
567: int minY = src.getMinY();
568: int maxY = src.getMaxY() - (extender != null ? 0 : 1); // Bottom padding
569:
570: int dstWidth = dst.getWidth();
571: int dstHeight = dst.getHeight();
572: int dstBands = dst.getNumBands();
573:
574: int lineStride = dst.getScanlineStride();
575: int pixelStride = dst.getPixelStride();
576: int[] bandOffsets = dst.getBandOffsets();
577: double[][] data = dst.getDoubleDataArrays();
578:
579: float[] warpData = new float[2 * dstWidth];
580:
581: int lineOffset = 0;
582:
583: for (int h = 0; h < dstHeight; h++) {
584: int pixelOffset = lineOffset;
585: lineOffset += lineStride;
586:
587: warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1,
588: warpData);
589: int count = 0;
590: for (int w = 0; w < dstWidth; w++) {
591: float sx = warpData[count++];
592: float sy = warpData[count++];
593:
594: int xint = floor(sx);
595: int yint = floor(sy);
596: float xfrac = sx - xint;
597: float yfrac = sy - yint;
598:
599: if (xint < minX || xint >= maxX || yint < minY
600: || yint >= maxY) {
601: /* Fill with a background color. */
602: if (setBackground) {
603: for (int b = 0; b < dstBands; b++) {
604: data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b];
605: }
606: }
607: } else {
608: for (int b = 0; b < dstBands; b++) {
609: double s00 = iter
610: .getSampleDouble(xint, yint, b);
611: double s01 = iter.getSampleDouble(xint + 1,
612: yint, b);
613: double s10 = iter.getSampleDouble(xint,
614: yint + 1, b);
615: double s11 = iter.getSampleDouble(xint + 1,
616: yint + 1, b);
617:
618: double s0 = (s01 - s00) * xfrac + s00;
619: double s1 = (s11 - s10) * xfrac + s10;
620: double s = (s1 - s0) * yfrac + s0;
621:
622: data[b][pixelOffset + bandOffsets[b]] = s;
623: }
624: }
625:
626: pixelOffset += pixelStride;
627: }
628: }
629: }
630:
631: /** Returns the "floor" value of a float. */
632: private static final int floor(float f) {
633: return f >= 0 ? (int) f : (int) f - 1;
634: }
635: }
|