如何缩放BufferedImage

继javadoc之后,我试图缩放一个BufferedImage而没有成功,这里是我的代码:

 BufferedImage image = MatrixToImageWriter.getBufferedImage(encoded); Graphics2D grph = image.createGraphics(); grph.scale(2.0, 2.0); grph.dispose(); 

我不明白为什么它不工作,有什么帮助?

AffineTransformOp提供了select插值types的额外的灵活性。

 BufferedImage before = getBufferedImage(encoded); int w = before.getWidth(); int h = before.getHeight(); BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); AffineTransform at = new AffineTransform(); at.scale(2.0, 2.0); AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); after = scaleOp.filter(before, after); 

在这里和这里检查一些相关的例子。

不幸的是,如果没有问题,getScaledInstance()的性能非常差。

另一种方法是创build一个新的BufferedImage,并在新的上绘制一个原始的缩放版本。

 BufferedImage resized = new BufferedImage(newWidth, newHeight, original.getType()); Graphics2D g = resized.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(original, 0, 0, newWidth, newHeight, 0, 0, original.getWidth(), original.getHeight(), null); g.dispose(); 

newWidth,newHeight表示新的BufferedImage大小,必须正确计算。 在因素缩放的情况下:

 int newWidth = new Double(original.getWidth() * widthFactor).intValue(); int newHeight = new Double(original.getHeight() * heightFactor).intValue(); 

编辑 :find说明性能问题的文章: Image.getScaledInstance()的风险

正如@Bozho所说,你可能想要使用getScaledInstance

要了解grph.scale(2.0, 2.0)如何工作,可以看看这段代码:

 import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import javax.imageio.ImageIO; import javax.swing.ImageIcon; class Main { public static void main(String[] args) throws IOException { final int SCALE = 2; Image img = new ImageIcon("duke.png").getImage(); BufferedImage bi = new BufferedImage(SCALE * img.getWidth(null), SCALE * img.getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics2D grph = (Graphics2D) bi.getGraphics(); grph.scale(SCALE, SCALE); // everything drawn with grph from now on will get scaled. grph.drawImage(img, 0, 0, null); grph.dispose(); ImageIO.write(bi, "png", new File("duke_double_size.png")); } } 

鉴于duke.png
在这里输入图像描述

它产生duke_double_size.png
在这里输入图像描述

使用imgscalr – Java Image Scaling Library :

 BufferedImage image = Scalr.resize(originalImage, Scalr.Method.BALANCED, newWidth, newHeight); 

这对我来说足够快。

如果您不介意使用外部库, Thumbnailator可以执行BufferedImage的缩放。

Thumbnailator将负责处理Java 2D处理(例如使用Graphics2D和设置适当的渲染提示 ),以便可以使用简单stream畅的API调用来调整图像大小:

 BufferedImage image = Thumbnails.of(originalImage).scale(2.0).asBufferedImage(); 

虽然Thumbnailator,正如其名称所暗示的,是面向缩小的图像,但它会做一个体面的工作,以扩大图像以及使用双线性插值在其默认的resizer实现。


免责声明:我是Thumbnailator库的维护者。

scale(..)工作有点不同。 你可以使用bufferedImage.getScaledInstance(..)

要缩放图像,您需要创build一个新的图像并将其绘制。 一种方法是使用AffineTransferOpfilter()方法,如此处所示 。 这使您可以select插值技术。

 private static BufferedImage scale1(BufferedImage before, double scale) { int w = before.getWidth(); int h = before.getHeight(); // Create a new image of the proper size int w2 = (int) (w * scale); int h2 = (int) (h * scale); BufferedImage after = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_ARGB); AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale); AffineTransformOp scaleOp = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR); scaleOp.filter(before, after); return after; } 

另一种方法是简单地将原始图像绘制到新图像中,使用缩放操作来进行缩放。 这种方法非常相似,但它也说明了如何在最终图像中绘制任何你想要的东西。 (我在两个方法开始有所不同的空白行。)

 private static BufferedImage scale2(BufferedImage before, double scale) { int w = before.getWidth(); int h = before.getHeight(); // Create a new image of the proper size int w2 = (int) (w * scale); int h2 = (int) (h * scale); BufferedImage after = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_ARGB); AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale); AffineTransformOp scaleOp = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR); Graphics2D g2 = (Graphics2D) after.getGraphics(); // Here, you may draw anything you want into the new image, but we're // drawing a scaled version of the original image. g2.drawImage(before, scaleOp, 0, 0); g2.dispose(); return after; }