1:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49:
50:
56: public class AffineTransformOp implements BufferedImageOp, RasterOp
57: {
58: public static final int TYPE_NEAREST_NEIGHBOR = 1;
59:
60: public static final int TYPE_BILINEAR = 2;
61:
62:
65: public static final int TYPE_BICUBIC = 3;
66:
67: private AffineTransform transform;
68: private RenderingHints hints;
69:
70:
78: public AffineTransformOp (AffineTransform xform, int interpolationType)
79: {
80: this.transform = xform;
81: if (xform.getDeterminant() == 0)
82: throw new ImagingOpException(null);
83:
84: switch (interpolationType)
85: {
86: case TYPE_BILINEAR:
87: hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION,
88: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
89: break;
90: case TYPE_BICUBIC:
91: hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION,
92: RenderingHints.VALUE_INTERPOLATION_BICUBIC);
93: break;
94: default:
95: hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION,
96: RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
97: }
98: }
99:
100:
106: public AffineTransformOp (AffineTransform xform, RenderingHints hints)
107: {
108: this.transform = xform;
109: this.hints = hints;
110: if (xform.getDeterminant() == 0)
111: throw new ImagingOpException(null);
112: }
113:
114:
125: public BufferedImage createCompatibleDestImage (BufferedImage src,
126: ColorModel destCM)
127: {
128:
129:
130:
131: if (destCM == null)
132: destCM = src.getColorModel ();
133:
134: return new BufferedImage (destCM,
135: createCompatibleDestRaster (src.getRaster ()),
136: src.isAlphaPremultiplied (),
137: null);
138:
139: }
140:
141:
149: public WritableRaster createCompatibleDestRaster (Raster src)
150: {
151: Rectangle rect = (Rectangle) getBounds2D (src);
152:
153:
154:
155:
156: if (rect.getWidth () == 0 || rect.getHeight () == 0)
157: throw new RasterFormatException("width or height is 0");
158:
159: return src.createCompatibleWritableRaster ((int) rect.getWidth (),
160: (int) rect.getHeight ());
161: }
162:
163:
171: public final BufferedImage filter (BufferedImage src, BufferedImage dst)
172: {
173:
174: if (dst == src)
175: throw new IllegalArgumentException ("src image cannot be the same as the dst image");
176:
177:
178:
179:
180: if (dst == null)
181: dst = createCompatibleDestImage(src, src.getColorModel ());
182:
183:
184:
185:
186:
187: Graphics2D gr = (Graphics2D) dst.createGraphics ();
188: gr.setRenderingHints (hints);
189: gr.drawImage (src, transform, null);
190: return dst;
191:
192: }
193:
194:
202: public final WritableRaster filter (Raster src, WritableRaster dst)
203: {
204: if (dst == src)
205: throw new IllegalArgumentException("src image cannot be the same as"
206: + " the dst image");
207:
208: if (dst == null)
209: dst = createCompatibleDestRaster(src);
210:
211: if (src.getNumBands() != dst.getNumBands())
212: throw new IllegalArgumentException("src and dst must have same number"
213: + " of bands");
214:
215: double[] dpts = new double[dst.getWidth() * 2];
216: double[] pts = new double[dst.getWidth() * 2];
217: for (int x = 0; x < dst.getWidth(); x++)
218: {
219: dpts[2 * x] = x + dst.getMinX();
220: dpts[2 * x + 1] = x;
221: }
222: Rectangle srcbounds = src.getBounds();
223: if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
224: {
225: for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
226: {
227: try {
228: transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
229: } catch (NoninvertibleTransformException e) {
230:
231: e.printStackTrace();
232: }
233:
234: for (int x = 0; x < dst.getWidth(); x++)
235: {
236: if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
237: continue;
238: dst.setDataElements(x + dst.getMinX(), y,
239: src.getDataElements((int)pts[2 * x],
240: (int)pts[2 * x + 1],
241: null));
242: }
243: }
244: }
245: else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
246: {
247: double[] tmp = new double[4 * src.getNumBands()];
248: for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
249: {
250: try {
251: transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
252: } catch (NoninvertibleTransformException e) {
253:
254: e.printStackTrace();
255: }
256:
257: for (int x = 0; x < dst.getWidth(); x++)
258: {
259: if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
260: continue;
261: int xx = (int)pts[2 * x];
262: int yy = (int)pts[2 * x + 1];
263: double dx = (pts[2 * x] - xx);
264: double dy = (pts[2 * x + 1] - yy);
265:
266:
267: if (xx == src.getMinX() + src.getWidth() - 1 ||
268: yy == src.getMinY() + src.getHeight() - 1)
269: {
270:
271: Arrays.fill(tmp, 0);
272: src.getPixel(xx, yy, tmp);
273: }
274: else
275: {
276:
277: src.getPixels(xx, yy, 2, 2, tmp);
278: for (int b = 0; b < src.getNumBands(); b++)
279: tmp[b] = dx * dy * tmp[b]
280: + (1 - dx) * dy * tmp[b + src.getNumBands()]
281: + dx * (1 - dy) * tmp[b + 2 * src.getNumBands()]
282: + (1 - dx) * (1 - dy) * tmp[b + 3 * src.getNumBands()];
283: }
284: dst.setPixel(x, y, tmp);
285: }
286: }
287: }
288: else
289: {
290:
291: throw new UnsupportedOperationException("not implemented yet");
292: }
293:
294: return dst;
295: }
296:
297:
304: public final Rectangle2D getBounds2D (BufferedImage src)
305: {
306: return getBounds2D (src.getRaster());
307: }
308:
309:
315: public final Rectangle2D getBounds2D (Raster src)
316: {
317:
318:
319:
320:
321: double x2 = (double) src.getWidth () + src.getMinX ();
322: double y2 = (double) src.getHeight () + src.getMinY ();
323: Point2D p2 = getPoint2D (new Point2D.Double (x2,y2), null);
324:
325: Rectangle2D rect = new Rectangle (0, 0, (int) p2.getX (), (int) p2.getY ());
326: return rect.getBounds ();
327: }
328:
329:
334: public final int getInterpolationType ()
335: {
336: if(hints.containsValue (RenderingHints.VALUE_INTERPOLATION_BILINEAR))
337: return TYPE_BILINEAR;
338: else
339: return TYPE_NEAREST_NEIGHBOR;
340: }
341:
342:
350: public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt)
351: {
352: return transform.transform (srcPt, dstPt);
353: }
354:
355:
360: public final RenderingHints getRenderingHints ()
361: {
362: return hints;
363: }
364:
365:
371: public final AffineTransform getTransform ()
372: {
373: return transform;
374: }
375: }