42 |
import java.awt.Rectangle; |
import java.awt.Rectangle; |
43 |
import java.awt.RenderingHints; |
import java.awt.RenderingHints; |
44 |
import java.awt.geom.AffineTransform; |
import java.awt.geom.AffineTransform; |
45 |
|
import java.awt.geom.NoninvertibleTransformException; |
46 |
import java.awt.geom.Point2D; |
import java.awt.geom.Point2D; |
47 |
import java.awt.geom.Rectangle2D; |
import java.awt.geom.Rectangle2D; |
48 |
|
import java.util.Arrays; |
49 |
|
|
50 |
/** |
/** |
51 |
* This class performs affine transformation between two images or |
* This class performs affine transformation between two images or |
58 |
{ |
{ |
59 |
public static final int TYPE_NEAREST_NEIGHBOR = 1; |
public static final int TYPE_NEAREST_NEIGHBOR = 1; |
60 |
public static final int TYPE_BILINEAR = 2; |
public static final int TYPE_BILINEAR = 2; |
61 |
|
public static final int TYPE_BICUBIC = 3; |
62 |
|
|
63 |
private AffineTransform transform; |
private AffineTransform transform; |
64 |
private RenderingHints hints; |
private RenderingHints hints; |
65 |
|
|
66 |
/** |
/** |
67 |
* Construct AffineTransformOp with the given xform and interpolationType. |
* Construct AffineTransformOp with the given xform and interpolationType. |
68 |
* Interpolation type can be either TYPE_BILINEAR or TYPE_NEAREST_NEIGHBOR. |
* Interpolation type can be TYPE_BILINEAR, TYPE_BICUBIC or |
69 |
|
* TYPE_NEAREST_NEIGHBOR. |
70 |
* |
* |
71 |
* @param xform AffineTransform that will applied to the source image |
* @param xform AffineTransform that will applied to the source image |
72 |
* @param interpolationType type of interpolation used |
* @param interpolationType type of interpolation used |
74 |
public AffineTransformOp (AffineTransform xform, int interpolationType) |
public AffineTransformOp (AffineTransform xform, int interpolationType) |
75 |
{ |
{ |
76 |
this.transform = xform; |
this.transform = xform; |
77 |
|
if (xform.getDeterminant() == 0) |
78 |
|
throw new ImagingOpException(null); |
79 |
|
|
80 |
if (interpolationType == 0) |
switch (interpolationType) |
81 |
|
{ |
82 |
|
case TYPE_BILINEAR: |
83 |
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, |
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, |
84 |
RenderingHints.VALUE_INTERPOLATION_BILINEAR); |
RenderingHints.VALUE_INTERPOLATION_BILINEAR); |
85 |
|
break; |
86 |
else |
case TYPE_BICUBIC: |
87 |
|
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, |
88 |
|
RenderingHints.VALUE_INTERPOLATION_BICUBIC); |
89 |
|
break; |
90 |
|
default: |
91 |
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, |
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, |
92 |
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); |
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); |
93 |
|
} |
94 |
} |
} |
95 |
|
|
96 |
/** |
/** |
103 |
{ |
{ |
104 |
this.transform = xform; |
this.transform = xform; |
105 |
this.hints = hints; |
this.hints = hints; |
106 |
|
if (xform.getDeterminant() == 0) |
107 |
|
throw new ImagingOpException(null); |
108 |
} |
} |
109 |
|
|
110 |
/** |
/** |
197 |
*/ |
*/ |
198 |
public WritableRaster filter (Raster src, WritableRaster dst) |
public WritableRaster filter (Raster src, WritableRaster dst) |
199 |
{ |
{ |
200 |
throw new UnsupportedOperationException ("not implemented yet"); |
if (dst == src) |
201 |
|
throw new IllegalArgumentException("src image cannot be the same as" |
202 |
|
+ " the dst image"); |
203 |
|
|
204 |
|
if (dst == null) |
205 |
|
dst = createCompatibleDestRaster(src); |
206 |
|
|
207 |
|
if (src.getNumBands() != dst.getNumBands()) |
208 |
|
throw new IllegalArgumentException("src and dst must have same number" |
209 |
|
+ " of bands"); |
210 |
|
|
211 |
|
double[] dpts = new double[dst.getWidth() * 2]; |
212 |
|
double[] pts = new double[dst.getWidth() * 2]; |
213 |
|
for (int x = 0; x < dst.getWidth(); x++) |
214 |
|
{ |
215 |
|
dpts[2 * x] = x + dst.getMinX(); |
216 |
|
dpts[2 * x + 1] = x; |
217 |
|
} |
218 |
|
Rectangle srcbounds = src.getBounds(); |
219 |
|
if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) |
220 |
|
{ |
221 |
|
for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++) |
222 |
|
{ |
223 |
|
try { |
224 |
|
transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2); |
225 |
|
} catch (NoninvertibleTransformException e) { |
226 |
|
// Can't happen since the constructor traps this |
227 |
|
e.printStackTrace(); |
228 |
|
} |
229 |
|
|
230 |
|
for (int x = 0; x < dst.getWidth(); x++) |
231 |
|
{ |
232 |
|
if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1])) |
233 |
|
continue; |
234 |
|
dst.setDataElements(x + dst.getMinX(), y, |
235 |
|
src.getDataElements((int)pts[2 * x], |
236 |
|
(int)pts[2 * x + 1], |
237 |
|
null)); |
238 |
|
} |
239 |
|
} |
240 |
|
} |
241 |
|
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) |
242 |
|
{ |
243 |
|
double[] tmp = new double[4 * src.getNumBands()]; |
244 |
|
for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++) |
245 |
|
{ |
246 |
|
try { |
247 |
|
transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2); |
248 |
|
} catch (NoninvertibleTransformException e) { |
249 |
|
// Can't happen since the constructor traps this |
250 |
|
e.printStackTrace(); |
251 |
|
} |
252 |
|
|
253 |
|
for (int x = 0; x < dst.getWidth(); x++) |
254 |
|
{ |
255 |
|
if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1])) |
256 |
|
continue; |
257 |
|
int xx = (int)pts[2 * x]; |
258 |
|
int yy = (int)pts[2 * x + 1]; |
259 |
|
double dx = (pts[2 * x] - xx); |
260 |
|
double dy = (pts[2 * x + 1] - yy); |
261 |
|
|
262 |
|
// TODO write this more intelligently |
263 |
|
if (xx == src.getMinX() + src.getWidth() - 1 || |
264 |
|
yy == src.getMinY() + src.getHeight() - 1) |
265 |
|
{ |
266 |
|
// bottom or right edge |
267 |
|
Arrays.fill(tmp, 0); |
268 |
|
src.getPixel(xx, yy, tmp); |
269 |
|
} |
270 |
|
else |
271 |
|
{ |
272 |
|
// Normal case |
273 |
|
src.getPixels(xx, yy, 2, 2, tmp); |
274 |
|
for (int b = 0; b < src.getNumBands(); b++) |
275 |
|
tmp[b] = dx * dy * tmp[b] |
276 |
|
+ (1 - dx) * dy * tmp[b + src.getNumBands()] |
277 |
|
+ dx * (1 - dy) * tmp[b + 2 * src.getNumBands()] |
278 |
|
+ (1 - dx) * (1 - dy) * tmp[b + 3 * src.getNumBands()]; |
279 |
|
} |
280 |
|
dst.setPixel(x, y, tmp); |
281 |
|
} |
282 |
|
} |
283 |
|
} |
284 |
|
else |
285 |
|
{ |
286 |
|
// Bicubic |
287 |
|
throw new UnsupportedOperationException("not implemented yet"); |
288 |
|
} |
289 |
|
|
290 |
|
return dst; |
291 |
} |
} |
292 |
|
|
293 |
/** |
/** |