001: /*
002: * $RCSfile: MlibWarpPolynomialTableOpImage.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.2 $
009: * $Date: 2005/12/15 18:35:49 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.mlib;
013:
014: import java.awt.Point;
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.BorderExtender;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.Interpolation;
023: import javax.media.jai.InterpolationTable;
024: import java.util.Map;
025: import javax.media.jai.RasterFactory;
026: import javax.media.jai.WarpOpImage;
027: import javax.media.jai.WarpPolynomial;
028:
029: import com.sun.medialib.mlib.*;
030: import com.sun.media.jai.util.ImageUtil;
031:
032: /**
033: * An <code>OpImage</code> implementing the polynomial "Warp" operation
034: * using MediaLib.
035: *
036: * <p> With warp operations, there is no forward mapping (from source to
037: * destination). JAI images are tiled, while mediaLib does not handle
038: * tiles and consider each tile an individual image. For each tile in
039: * destination, in order not to cobble the entire source image, the
040: * <code>computeTile</code> method in this class attemps to do a backward
041: * mapping on the tile region using the pixels along the perimeter of the
042: * rectangular region. The hope is that the mapped source rectangle
043: * should include all source pixels needed for this particular destination
044: * tile. However, with certain unusual warp points, an inner destination
045: * pixel may be mapped outside of the mapped perimeter pixels. In this
046: * case, this destination pixel is not filled, and left black.
047: *
048: * @see javax.media.jai.operator.WarpDescriptor
049: * @see javax.media.jai.InterpolationTable
050: * @see MlibWarpRIF
051: *
052: * @since 1.1
053: *
054: */
055: final class MlibWarpPolynomialTableOpImage extends WarpOpImage {
056:
057: /** The x and y coefficients. */
058: private double[] xCoeffs;
059: private double[] yCoeffs;
060:
061: /**
062: * converting from interpolation to mlib table for
063: * integral, float and double data type
064: */
065: private mediaLibImageInterpTable mlibInterpTableI;
066: private mediaLibImageInterpTable mlibInterpTableF;
067: private mediaLibImageInterpTable mlibInterpTableD;
068:
069: /** The pre and post scale factors. */
070: private double preScaleX;
071: private double preScaleY;
072: private double postScaleX;
073: private double postScaleY;
074:
075: /**
076: * Constructs a <code>MlibWarpPolynomialTableOpImage</code>.
077: *
078: * @param source The source image.
079: * @param layout The destination image layout.
080: * @param warp An object defining the warp algorithm.
081: * @param interp An object describing the interpolation method.
082: */
083: public MlibWarpPolynomialTableOpImage(RenderedImage source,
084: BorderExtender extender, Map config, ImageLayout layout,
085: WarpPolynomial warp, Interpolation interp,
086: double[] backgroundValues) {
087: super (source, layout, config, true, extender, interp, warp,
088: backgroundValues);
089:
090: mlibInterpTableI = null;
091: mlibInterpTableF = null;
092: mlibInterpTableD = null;
093:
094: float[] xc = warp.getXCoeffs();
095: float[] yc = warp.getYCoeffs();
096: int size = xc.length;
097:
098: xCoeffs = new double[size]; // X and Y coefficients as doubles
099: yCoeffs = new double[size];
100: for (int i = 0; i < size; i++) {
101: xCoeffs[i] = xc[i];
102: yCoeffs[i] = yc[i];
103: }
104:
105: preScaleX = warp.getPreScaleX(); // pre/post factors
106: preScaleY = warp.getPreScaleY();
107: postScaleX = warp.getPostScaleX();
108: postScaleY = warp.getPostScaleY();
109: }
110:
111: /**
112: * Returns the minimum bounding box of the region of the specified
113: * source to which a particular <code>Rectangle</code> of the
114: * destination will be mapped.
115: *
116: * @param destRect the <code>Rectangle</code> in destination coordinates.
117: * @param sourceIndex the index of the source image.
118: *
119: * @return a <code>Rectangle</code> indicating the source bounding box,
120: * or <code>null</code> if the bounding box is unknown.
121: *
122: * @throws IllegalArgumentException if <code>sourceIndex</code> is
123: * negative or greater than the index of the last source.
124: * @throws IllegalArgumentException if <code>destRect</code> is
125: * <code>null</code>.
126: */
127: protected Rectangle backwardMapRect(Rectangle destRect,
128: int sourceIndex) {
129: // Superclass method will throw documented exceptions if needed.
130: Rectangle wrect = super .backwardMapRect(destRect, sourceIndex);
131:
132: // "Dilate" the backwarp mapped rectangle to account for
133: // the lack of being able to know the floating point result of
134: // mapDestRect() and to mimic what is done in AffineOpImage.
135: // See bug 4518223 for more information.
136: wrect.setBounds(wrect.x - 1, wrect.y - 1, wrect.width + 2,
137: wrect.height + 2);
138:
139: return wrect;
140: }
141:
142: /**
143: * Computes a tile. A new <code>WritableRaster</code> is created to
144: * represent the requested tile. Its width and height equals to this
145: * image's tile width and tile height respectively. If the requested
146: * tile lies outside of the image's boundary, the created raster is
147: * returned with all of its pixels set to 0.
148: *
149: * <p> This method overrides the method in <code>WarpOpImage</code>
150: * and performs source cobbling when necessary. MediaLib is used to
151: * calculate the actual warping.
152: *
153: * @param tileX The X index of the tile.
154: * @param tileY The Y index of the tile.
155: *
156: * @return The tile as a <code>Raster</code>.
157: */
158: public Raster computeTile(int tileX, int tileY) {
159: /* The origin of the tile. */
160: Point org = new Point(tileXToX(tileX), tileYToY(tileY));
161:
162: /* Create a new WritableRaster to represent this tile. */
163: WritableRaster dest = createWritableRaster(sampleModel, org);
164:
165: /* Find the intersection between this tile and the writable bounds. */
166: Rectangle rect = new Rectangle(org.x, org.y, tileWidth,
167: tileHeight);
168: Rectangle destRect = rect.intersection(computableBounds);
169: Rectangle destRect1 = rect.intersection(getBounds());
170:
171: if (destRect.isEmpty()) {
172: if (setBackground) {
173: ImageUtil.fillBackground(dest, destRect1,
174: backgroundValues);
175: }
176: return dest; // tile completely outside of writable bounds
177: }
178:
179: /* Map destination rectangle to source space. */
180: Rectangle srcRect = backwardMapRect(destRect, 0).intersection(
181: getSourceImage(0).getBounds());
182:
183: if (srcRect.isEmpty()) {
184: if (setBackground) {
185: ImageUtil.fillBackground(dest, destRect1,
186: backgroundValues);
187: }
188: return dest; // outside of source bounds
189: }
190:
191: if (!destRect1.equals(destRect)) {
192: // beware that destRect1 contains destRect
193: ImageUtil.fillBordersWithBackgroundValues(destRect1,
194: destRect, dest, backgroundValues);
195: }
196:
197: /* Add the interpolation paddings. */
198: int l = interp == null ? 0 : interp.getLeftPadding();
199: int r = interp == null ? 0 : interp.getRightPadding();
200: int t = interp == null ? 0 : interp.getTopPadding();
201: int b = interp == null ? 0 : interp.getBottomPadding();
202:
203: srcRect = new Rectangle(srcRect.x - l, srcRect.y - t,
204: srcRect.width + l + r, srcRect.height + t + b);
205:
206: /* Cobble source into one Raster. */
207: Raster[] sources = new Raster[1];
208: sources[0] = getBorderExtender() != null ? getSourceImage(0)
209: .getExtendedData(srcRect, extender) : getSourceImage(0)
210: .getData(srcRect);
211:
212: computeRect(sources, dest, destRect);
213:
214: // Recycle the source tile
215: if (getSourceImage(0).overlapsMultipleTiles(srcRect)) {
216: recycleTile(sources[0]);
217: }
218:
219: return dest;
220: }
221:
222: /**
223: * Performs the "Warp" operation on a rectangular region of
224: * the same.
225: */
226: protected void computeRect(Raster[] sources, WritableRaster dest,
227: Rectangle destRect) {
228: Raster source = sources[0];
229:
230: /* Find the mediaLib data tag. */
231: int formatTag = MediaLibAccessor.findCompatibleTag(sources,
232: dest);
233:
234: MediaLibAccessor srcMA = new MediaLibAccessor(source, source
235: .getBounds(), formatTag);
236: MediaLibAccessor dstMA = new MediaLibAccessor(dest, destRect,
237: formatTag);
238:
239: mediaLibImage[] srcMLI = srcMA.getMediaLibImages();
240: mediaLibImage[] dstMLI = dstMA.getMediaLibImages();
241:
242: switch (dstMA.getDataType()) {
243: case DataBuffer.TYPE_BYTE:
244: case DataBuffer.TYPE_USHORT:
245: case DataBuffer.TYPE_SHORT:
246: case DataBuffer.TYPE_INT:
247: if (mlibInterpTableI == null) {
248: InterpolationTable jtable = (InterpolationTable) interp;
249: mlibInterpTableI = new mediaLibImageInterpTable(
250: Constants.MLIB_INT, jtable.getWidth(), jtable
251: .getHeight(), jtable.getLeftPadding(),
252: jtable.getTopPadding(), jtable
253: .getSubsampleBitsH(), jtable
254: .getSubsampleBitsV(), jtable
255: .getPrecisionBits(), jtable
256: .getHorizontalTableData(), jtable
257: .getVerticalTableData());
258:
259: }
260:
261: if (setBackground)
262: for (int i = 0; i < dstMLI.length; i++) {
263: Image.PolynomialWarpTable2(dstMLI[i], srcMLI[i],
264: xCoeffs, yCoeffs, destRect.x, destRect.y,
265: source.getMinX(), source.getMinY(),
266: preScaleX, preScaleY, postScaleX,
267: postScaleY, mlibInterpTableI,
268: Constants.MLIB_EDGE_DST_NO_WRITE,
269: intBackgroundValues);
270: }
271: else
272: for (int i = 0; i < dstMLI.length; i++) {
273: Image.PolynomialWarpTable(dstMLI[i], srcMLI[i],
274: xCoeffs, yCoeffs, destRect.x, destRect.y,
275: source.getMinX(), source.getMinY(),
276: preScaleX, preScaleY, postScaleX,
277: postScaleY, mlibInterpTableI,
278: Constants.MLIB_EDGE_DST_NO_WRITE);
279: MlibUtils.clampImage(dstMLI[i], getColorModel());
280: }
281: break;
282:
283: case DataBuffer.TYPE_FLOAT:
284: if (mlibInterpTableF == null) {
285: InterpolationTable jtable = (InterpolationTable) interp;
286: mlibInterpTableF = new mediaLibImageInterpTable(
287: Constants.MLIB_FLOAT, jtable.getWidth(), jtable
288: .getHeight(), jtable.getLeftPadding(),
289: jtable.getTopPadding(), jtable
290: .getSubsampleBitsH(), jtable
291: .getSubsampleBitsV(), jtable
292: .getPrecisionBits(), jtable
293: .getHorizontalTableDataFloat(), jtable
294: .getVerticalTableDataFloat());
295:
296: }
297:
298: if (setBackground)
299: for (int i = 0; i < dstMLI.length; i++) {
300: Image.PolynomialWarpTable2_Fp(dstMLI[i], srcMLI[i],
301: xCoeffs, yCoeffs, destRect.x, destRect.y,
302: source.getMinX(), source.getMinY(),
303: preScaleX, preScaleY, postScaleX,
304: postScaleY, mlibInterpTableD,
305: Constants.MLIB_EDGE_DST_NO_WRITE,
306: backgroundValues);
307: }
308: else
309: for (int i = 0; i < dstMLI.length; i++) {
310: Image.PolynomialWarpTable_Fp(dstMLI[i], srcMLI[i],
311: xCoeffs, yCoeffs, destRect.x, destRect.y,
312: source.getMinX(), source.getMinY(),
313: preScaleX, preScaleY, postScaleX,
314: postScaleY, mlibInterpTableD,
315: Constants.MLIB_EDGE_DST_NO_WRITE);
316: }
317: break;
318:
319: case DataBuffer.TYPE_DOUBLE:
320: if (mlibInterpTableD == null) {
321: InterpolationTable jtable = (InterpolationTable) interp;
322: mlibInterpTableD = new mediaLibImageInterpTable(
323: Constants.MLIB_DOUBLE, jtable.getWidth(),
324: jtable.getHeight(), jtable.getLeftPadding(),
325: jtable.getTopPadding(), jtable
326: .getSubsampleBitsH(), jtable
327: .getSubsampleBitsV(), jtable
328: .getPrecisionBits(), jtable
329: .getHorizontalTableDataDouble(), jtable
330: .getVerticalTableDataDouble());
331: }
332:
333: if (setBackground)
334: for (int i = 0; i < dstMLI.length; i++) {
335: Image.PolynomialWarpTable2_Fp(dstMLI[i], srcMLI[i],
336: xCoeffs, yCoeffs, destRect.x, destRect.y,
337: source.getMinX(), source.getMinY(),
338: preScaleX, preScaleY, postScaleX,
339: postScaleY, mlibInterpTableD,
340: Constants.MLIB_EDGE_DST_NO_WRITE,
341: backgroundValues);
342: }
343: else
344: for (int i = 0; i < dstMLI.length; i++) {
345: Image.PolynomialWarpTable_Fp(dstMLI[i], srcMLI[i],
346: xCoeffs, yCoeffs, destRect.x, destRect.y,
347: source.getMinX(), source.getMinY(),
348: preScaleX, preScaleY, postScaleX,
349: postScaleY, mlibInterpTableD,
350: Constants.MLIB_EDGE_DST_NO_WRITE);
351: }
352: break;
353:
354: default:
355: throw new RuntimeException(JaiI18N.getString("Generic2"));
356: }
357:
358: if (dstMA.isDataCopy()) {
359: dstMA.clampDataArrays();
360: dstMA.copyDataToRaster();
361: }
362: }
363: }
|