如何缩放 BufferedImage
按照javadocs,我尝试缩放 BufferedImage ,但没有成功,这是我的代码:
BufferedImage image = MatrixToImageWriter.getBufferedImage(encoded);
Graphics2D grph = image.createGraphics();
grph.scale(2.0, 2.0);
grph.dispose();
我不明白为什么它不起作用,有什么帮助吗?
Following the javadocs, I have tried to scale a BufferedImage
without success here is my code:
BufferedImage image = MatrixToImageWriter.getBufferedImage(encoded);
Graphics2D grph = image.createGraphics();
grph.scale(2.0, 2.0);
grph.dispose();
I can't understand why it is not working, any help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
AffineTransformOp
提供了选择插值类型的额外灵活性。显示的片段说明了重采样,而不是裁剪;此相关答案解决了问题; 此处检查了一些相关示例。
AffineTransformOp
offers the additional flexibility of choosing the interpolation type.The fragment shown illustrates resampling, not cropping; this related answer addresses the issue; some related examples are examined here.
不幸的是, getScaledInstance() 的性能即使没有问题,也非常差。
另一种方法是创建一个新的 BufferedImage,并在新的 BufferedImage 上绘制原始图像的缩放版本。
newWidth,newHeight 表示新的 BufferedImage 大小,必须正确计算。
在因子缩放的情况下:
编辑:找到说明性能问题的文章: Image.getScaledInstance() 的危险
Unfortunately the performance of getScaledInstance() is very poor if not problematic.
The alternative approach is to create a new BufferedImage and and draw a scaled version of the original on the new one.
newWidth,newHeight indicate the new BufferedImage size and have to be properly calculated.
In case of factor scaling:
EDIT: Found the article illustrating the performance issue: The Perils of Image.getScaledInstance()
使用 imgscalr – Java 图像缩放库:
https://github.com/rkalla/imgscalr
Using imgscalr – Java Image Scaling Library:
https://github.com/rkalla/imgscalr
要缩放图像,您需要创建一个新图像并在其中绘制。一种方法是使用
AffineTransferOp
的filter()
方法,如建议的在这里。这允许您选择插值技术。另一种方法是简单地将原始图像绘制到新图像中,使用缩放操作来进行缩放。此方法非常相似,但它也说明了如何在最终图像中绘制任何您想要的内容。 (我在两种方法开始有所不同的地方放置了一个空行。)
附录:结果
为了说明差异,我比较了以下五种方法的结果。以下是按比例放大和缩小的结果以及性能数据。 (每次运行的性能都会有所不同,因此这些数字仅作为粗略指导。)顶部图像是原始图像。我将其缩放为两倍大小和一半大小。
正如您所看到的,
scaleBilinear()
中使用的AffineTransformOp.filter()
比Graphics2D.drawImage()
的标准绘图方法更快> 在scale2()
中。此外,双三次插值是最慢的,但在扩展图像时给出最佳结果。 (就性能而言,它只能与scaleBilinear()
和scaleNearest() 进行比较。
)双线性似乎更适合缩小图像,尽管这是一个艰难的选择。而 NearestNeighbor 是最快的,但结果也最差。双线性似乎是速度和质量之间的最佳折衷方案。在questionable()
方法中调用的Image.getScaledInstance()
性能非常差,并且返回与 NearestNeighbor 相同的低质量。 (仅给出扩展图像时的性能数据。)To scale an image, you need to create a new image and draw into it. One way is to use the
filter()
method of anAffineTransferOp
, as suggested here. This allows you to choose the interpolation technique.Another way is to simply draw the original image into the new image, using a scaling operation to do the scaling. This method is very similar, but it also illustrates how you can draw anything you want in the final image. (I put in a blank line where the two methods start to differ.)
Addendum: Results
To illustrate the differences, I compared the results of the five methods below. Here is what the results look like, scaled both up and down, along with performance data. (Performance varies from one run to the next, so take these numbers only as rough guidelines.) The top image is the original. I scale it double-size and half-size.
As you can see,
AffineTransformOp.filter()
, used inscaleBilinear()
, is faster than the standard drawing method ofGraphics2D.drawImage()
inscale2()
. Also BiCubic interpolation is the slowest, but gives the best results when expanding the image. (For performance, it should only be compared withscaleBilinear()
andscaleNearest().
) Bilinear seems to be better for shrinking the image, although it's a tough call. And NearestNeighbor is the fastest, with the worst results. Bilinear seems to be the best compromise between speed and quality. TheImage.getScaledInstance()
, called in thequestionable()
method, performed very poorly, and returned the same low quality as NearestNeighbor. (Performance numbers are only given for expanding the image.)正如 @Bozho 所说,您可能想使用 getScaledInstance。
要了解
grph.scale(2.0, 2.0)
的工作原理,您可以查看以下代码:给定 duke.png:
它会生成 duke_double_size.png:
As @Bozho says, you probably want to use
getScaledInstance
.To understand how
grph.scale(2.0, 2.0)
works however, you could have a look at this code:Given duke.png:
it produces duke_double_size.png:
如果您不介意使用外部库,Thumbnailator 可以执行
BufferedImage
。Thumbnailator 将负责处理 Java 2D 处理(例如使用
Graphics2D
并设置适当的 渲染提示),以便可以使用简单流畅的 API 调用来调整图像大小:虽然 Thumbnailator,顾名思义,是针对缩小图像的,但它也可以使用双线性来放大图像在其默认缩放器实现中进行插值。
免责声明:我是 Thumbnailator 库的维护者。
If you do not mind using an external library, Thumbnailator can perform scaling of
BufferedImage
s.Thumbnailator will take care of handling the Java 2D processing (such as using
Graphics2D
and setting appropriate rendering hints) so that a simple fluent API call can be used to resize images:Although Thumbnailator, as its name implies, is geared toward shrinking images, it will do a decent job enlarging images as well, using bilinear interpolation in its default resizer implementation.
Disclaimer: I am the maintainer of the Thumbnailator library.
scale(..)
的工作方式有点不同。您可以使用 bufferedImage.getScaledInstance(..)scale(..)
works a bit differently. You can usebufferedImage.getScaledInstance(..)
由trashgod提供的最高评价的答案有一些小问题,所以我将发布一个改进的版本(由于声誉点不足,我不能这样做作为对他的解决方案的评论)。
改进:
after
图像具有正确的尺寸来容纳缩放图像after
图像与编码图像具有相同的图像类型(否则转换将失败)The top-rated answer by trashgod has some minor problems, so I'll post an improved version (due to insufficient reputation points I can't do this as a comment to his solution).
Improvements:
after
image has the right dimensions to hold the scaled imageafter
image has the same image type as the encoded image (the transformation will fail otherwise)