Java 8在这里。尝试坚持使用BufferedImage API而不是深入研究JavaFx。

我有一个768像素宽,432像素高的JPG图像。我想使用BufferedImage#getSubimage(...)从其中心裁剪出居中的400x400像素正方形。

我有以下代码:

BufferedImage image = ImageIO.read(imageTempFile);

int dim = 400;
int xCropBuffer, yCropBuffer;
xCropBuffer = (image.getWidth() - dim) / 2;
yCropBuffer = (image.getHeight() - dim) / 2;

log.info("width = " + image.getWidth() + ", height = " + image.getHeight() + ", dim = " + dim + ", xCropBuffer = " + xCropBuffer + ", yCropBuffer = " + yCropBuffer);

image = image.getSubimage(xCropBuffer, yCropBuffer + dim, dim, dim);


在运行时,将引发以下异常:

java.awt.image.RasterFormatException: (y + height) is outside of Raster
    at sun.awt.image.ByteInterleavedRaster.createWritableChild(ByteInterleavedRaster.java:1248)
    at java.awt.image.BufferedImage.getSubimage(BufferedImage.java:1202)
    at java_awt_image_BufferedImage$getSubimage.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:149)
    at com.myapp.DefaultMediaService.uploadImage(DefaultMediaService.java:56)
    at com.myapp.MediaService$uploadImage.call(Unknown Source)


并且在抛出异常之前,日志会立即显示以下消息:

width = 768, height = 432, dim = 400, xCropBuffer = 184, yCropBuffer = 16


所以我要传递image.getSubimage(184, 416, 400, 400)参数...这行吗?!图片为768x432,因此(184,416)应该是其左上角的有效坐标,并且184 + 400 0。因此所有这些参数都应映射到图片内的有效400x400矩形, 对?

最佳答案

绘制图像与绘制文本不同,绘制图像的过程是从基线到较小的y坐标。图像由其左上角指定,并朝x和y的较大坐标延伸。因此,您不应为y坐标指定+ dim

BufferedImage oldImage = ImageIO.read(imageFile),
    newImage = oldImage.getSubimage(
        (oldImage.getWidth()-dim)/2, (oldImage.getHeight()-dim)/2, dim, dim);
ImageIO.write(newImage, "png", imageFile);


为了完整起见,由于您的上一个问题似乎有些困惑,因此,这里有一些替代方法可以实现相同的图像转换,可以将其用作其他图像操作的模板:


通过BufferedImageOp

BufferedImage oldImage = ImageIO.read(imageFile),
    newImage = new BufferedImage(dim, dim, oldImage.getType());
BufferedImageOp op = new AffineTransformOp(
    AffineTransform.getTranslateInstance(
        -(oldImage.getWidth()-dim)/2, -(oldImage.getHeight()-dim)/2),
    AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
op.filter(oldImage, newImage);
ImageIO.write(newImage, "png", imageFile);

通过Graphics

BufferedImage oldImage = ImageIO.read(imageFile),
    newImage = new BufferedImage(dim, dim, oldImage.getType());
Graphics2D gfx = newImage.createGraphics();
gfx.drawImage(oldImage,
              -(oldImage.getWidth()-dim)/2, -(oldImage.getHeight()-dim)/2, null);
gfx.dispose();
ImageIO.write(newImage, "png", imageFile);



在任何一种情况下,都通过使目标图像小于原始图像来隐含裁剪到所需大小。
然后,只需将源图像转换为(-x,-y)即可选择所需的细节矩形。

07-27 23:56