如何缩放BufferedImage

时间:2010-11-18 14:59:59

标签: java image image-processing bufferedimage image-scaling

在javadocs之后,我试图扩展BufferedImage但没有成功,这是我的代码:

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

我无法理解为什么它不起作用,有什么帮助?

7 个答案:

答案 0 :(得分:60)

AffineTransformOp提供了选择插值类型的额外灵活性。

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);

显示的片段说明了resampling,而不是cropping;这个相关的answer解决了issue;我们会检查一些相关的例子here

答案 1 :(得分:32)

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

另一种方法是创建一个新的BufferedImage,并在新的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();

编辑:找到说明性能问题的文章:The Perils of Image.getScaledInstance()

答案 2 :(得分:11)

正如@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
enter image description here

它产生 duke_double_size.png
enter image description here

答案 3 :(得分:9)

使用imgscalr – Java Image Scaling Library

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

这对我来说足够快。

答案 4 :(得分:6)

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

Thumbnailator将负责处理Java 2D处理(例如使用Graphics2D并设置适当的rendering hints),以便可以使用简单的流畅API调用来调整图像大小:

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

虽然Thumbnailator,正如其名称所暗示的那样,是为了缩小图像,但它在放大图像方面也会做得不错,在默认的缩放器实现中使用双线性插值。


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

答案 5 :(得分:3)

scale(..)的工作方式略有不同。您可以使用bufferedImage.getScaledInstance(..)

答案 6 :(得分:2)

要缩放图像,您需要创建一个新图像并绘制到其中。一种方法是使用filter()的{​​{1}}方法,如建议here。这允许您选择插值技术。

AffineTransferOp

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

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; } 中使用的AffineTransformOp.filter()scaleBilinear()Graphics2D.drawImage()的标准绘图方法更快。 BiCubic插值也是最慢的,但在扩展图像时会产生最佳效果。 (为了表现,它应该只与scale2()scaleBilinear()进行比较)Bilinear似乎更适合缩小图像,尽管这是一个艰难的调用。而NearestNeighbor是最快的,效果最差。双线性似乎是速度和质量之间的最佳折衷。在scaleNearest().方法中调用的Image.getScaledInstance()表现非常糟糕,并返回与NearestNeighbor相同的低质量。 (性能数字仅用于扩展图像。)

enter image description here

questionable()