BufferedImage getSubimage 以看似好的参数抛出异常
BufferedImage getSubimage throws exception with seemingly good arguments
Java 8 在这里。试图坚持 BufferedImage
API 而不是钻研 JavaFx 领域。
我有一张 768 像素宽、432 像素高的 JPG 图片。我想使用 BufferedImage#getSubimage(...)
.
从中心裁剪一个 centered 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 < 768 和 416 - 400 > 0。因此所有这些参数都应映射到图像内的有效 400x400 矩形,对吧?
这看起来很简单。高度为 432,您将左上角指定为 (182, 416)。接下来,您要求它向下移动 400 像素。所以你得到 432 < 416 + 400 这意味着你想要 select 的框架底部大于图像的高度。
绘制图像不同于绘制文本,其中上升从基线到较小的 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) 转换为 select 所需的细节矩形。
Java 8 在这里。试图坚持 BufferedImage
API 而不是钻研 JavaFx 领域。
我有一张 768 像素宽、432 像素高的 JPG 图片。我想使用 BufferedImage#getSubimage(...)
.
我有以下代码:
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 < 768 和 416 - 400 > 0。因此所有这些参数都应映射到图像内的有效 400x400 矩形,对吧?
这看起来很简单。高度为 432,您将左上角指定为 (182, 416)。接下来,您要求它向下移动 400 像素。所以你得到 432 < 416 + 400 这意味着你想要 select 的框架底部大于图像的高度。
绘制图像不同于绘制文本,其中上升从基线到较小的 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) 转换为 select 所需的细节矩形。