AffineTransformOp.java [plain text]
package java.awt.image;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
public class AffineTransformOp implements BufferedImageOp, RasterOp
{
public static final int TYPE_NEAREST_NEIGHBOR = 1;
public static final int TYPE_BILINEAR = 2;
public static final int TYPE_BICUBIC = 3;
private AffineTransform transform;
private RenderingHints hints;
public AffineTransformOp (AffineTransform xform, int interpolationType)
{
this.transform = xform;
if (xform.getDeterminant() == 0)
throw new ImagingOpException(null);
switch (interpolationType)
{
case TYPE_BILINEAR:
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
break;
case TYPE_BICUBIC:
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
break;
default:
hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}
}
public AffineTransformOp (AffineTransform xform, RenderingHints hints)
{
this.transform = xform;
this.hints = hints;
if (xform.getDeterminant() == 0)
throw new ImagingOpException(null);
}
public BufferedImage createCompatibleDestImage (BufferedImage src,
ColorModel destCM)
{
if (destCM == null)
destCM = src.getColorModel ();
return new BufferedImage (destCM,
createCompatibleDestRaster (src.getRaster ()),
src.isAlphaPremultiplied (),
null);
}
public WritableRaster createCompatibleDestRaster (Raster src)
{
Rectangle rect = (Rectangle) getBounds2D (src);
if (rect.getWidth () == 0 || rect.getHeight () == 0)
throw new RasterFormatException("width or height is 0");
return src.createCompatibleWritableRaster ((int) rect.getWidth (),
(int) rect.getHeight ());
}
public final BufferedImage filter (BufferedImage src, BufferedImage dst)
{
if (dst == src)
throw new IllegalArgumentException ("src image cannot be the same as the dst image");
if (dst == null)
dst = createCompatibleDestImage(src, src.getColorModel ());
Graphics2D gr = (Graphics2D) dst.createGraphics ();
gr.setRenderingHints (hints);
gr.drawImage (src, transform, null);
return dst;
}
public final WritableRaster filter (Raster src, WritableRaster dst)
{
if (dst == src)
throw new IllegalArgumentException("src image cannot be the same as"
+ " the dst image");
if (dst == null)
dst = createCompatibleDestRaster(src);
if (src.getNumBands() != dst.getNumBands())
throw new IllegalArgumentException("src and dst must have same number"
+ " of bands");
double[] dpts = new double[dst.getWidth() * 2];
double[] pts = new double[dst.getWidth() * 2];
for (int x = 0; x < dst.getWidth(); x++)
{
dpts[2 * x] = x + dst.getMinX();
dpts[2 * x + 1] = x;
}
Rectangle srcbounds = src.getBounds();
if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
{
for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
{
try {
transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
for (int x = 0; x < dst.getWidth(); x++)
{
if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
continue;
dst.setDataElements(x + dst.getMinX(), y,
src.getDataElements((int)pts[2 * x],
(int)pts[2 * x + 1],
null));
}
}
}
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
{
double[] tmp = new double[4 * src.getNumBands()];
for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
{
try {
transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
for (int x = 0; x < dst.getWidth(); x++)
{
if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
continue;
int xx = (int)pts[2 * x];
int yy = (int)pts[2 * x + 1];
double dx = (pts[2 * x] - xx);
double dy = (pts[2 * x + 1] - yy);
if (xx == src.getMinX() + src.getWidth() - 1 ||
yy == src.getMinY() + src.getHeight() - 1)
{
Arrays.fill(tmp, 0);
src.getPixel(xx, yy, tmp);
}
else
{
src.getPixels(xx, yy, 2, 2, tmp);
for (int b = 0; b < src.getNumBands(); b++)
tmp[b] = dx * dy * tmp[b]
+ (1 - dx) * dy * tmp[b + src.getNumBands()]
+ dx * (1 - dy) * tmp[b + 2 * src.getNumBands()]
+ (1 - dx) * (1 - dy) * tmp[b + 3 * src.getNumBands()];
}
dst.setPixel(x, y, tmp);
}
}
}
else
{
throw new UnsupportedOperationException("not implemented yet");
}
return dst;
}
public final Rectangle2D getBounds2D (BufferedImage src)
{
return getBounds2D (src.getRaster());
}
public final Rectangle2D getBounds2D (Raster src)
{
double x2 = (double) src.getWidth () + src.getMinX ();
double y2 = (double) src.getHeight () + src.getMinY ();
Point2D p2 = getPoint2D (new Point2D.Double (x2,y2), null);
Rectangle2D rect = new Rectangle (0, 0, (int) p2.getX (), (int) p2.getY ());
return rect.getBounds ();
}
public final int getInterpolationType ()
{
if(hints.containsValue (RenderingHints.VALUE_INTERPOLATION_BILINEAR))
return TYPE_BILINEAR;
else
return TYPE_NEAREST_NEIGHBOR;
}
public Point2D getPoint2D (Point2D srcPt, Point2D dstPt)
{
return transform.transform (srcPt, dstPt);
}
public final RenderingHints getRenderingHints ()
{
return hints;
}
public final AffineTransform getTransform ()
{
return transform;
}
}