如何使用Java调整图片大小?

131

我需要调整PNG、JPEG和GIF文件的大小。如何使用Java完成这个任务?


14
既然您要求一个库,真正的答案在这里:https://dev59.com/inVC5IYBdhLWcg3wlyQo#4528136。它比已接受的答案中的代码更容易使用 ;) - Artur Gajowy
我对库的部分持不同意见:Graphics2D是awt库的一部分,而且它是开源的。至于最后一部分(开源),我不是100%确定,但是谁会查看awt代码呢? - Burkhard
19个回答

186

顺便提一下,我刚刚发布了一个名为imgscalr的Java简单图片缩放库(Apache 2许可证,托管在GitHub上),可以在Maven central上获得。

该库实现了几种不同的图像缩放方法(包括Chris Campbell的增量方法和一些小的增强功能),如果您要求它,它将为您选择最优的方法,或者为您提供最快或最好看的方法。

使用非常简单,只需要一堆静态方法。最简单的用法是:

BufferedImage scaledImage = Scalr.resize(myImage, 200);

所有操作都保持图像的原始比例,因此在这种情况下,您要求imgscalr在200像素宽和200像素高的范围内调整图像大小,并且默认情况下,它会自动选择最佳外观和最快的方法,因为没有指定。我意识到这看起来像是自我推销(确实如此),但我花了很多时间在谷歌上搜索这个完全相同的主题,并不断得出不同的结果/方法/想法/建议,并决定坐下来编写一个简单的实现,以解决80-85%的用例,其中您拥有一张图片并且可能需要缩略图 - 要么尽可能快,要么尽可能好看(对于那些尝试过的人,您会注意到即使使用BICUBIC插值将Graphics.drawImage绘制到足够小的图像中,它仍然看起来很糟糕)。

1
Riyad,我喜欢使用Scalr。我很好奇你是怎么选择一个只包含静态方法的API的? 我写了一个类似的API,更接近于一个构建器. 比如new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer()。不过我也喜欢你的方式,觉得更简单易懂。 - Amir Raminfar
4
Amir,建造者模式同样非常适合这些类型的库,但我选择了静态方法的方式,因为我认为对于新用户来说更容易理解,并且从我最初预期imgscalr的使用模式(仅使用单个调整大小方法)中并不需要一个持有状态的实例(即建造者实例)。因此,我节省了对象实例化并采用了静态方法。我在尽可能避免imgscalr内部的对象创建方面采取了坚定立场。这两种方法都很好用。 - Riyad Kalla
6
感谢将此发布到中央 Maven 存储库!+1 - Grilse
3
BufferedImage是J2SE JDK中的一个类(Java2D框架的一部分),用于表示原始未压缩的像素数据。它在Android上不可用,Android提供了自己的类来处理图像数据。 - Riyad Kalla
1
感谢提供API。将一个24x7的基础图像转换为256x256,代码如下:img=Scalr.resize(img,Mode.FIT_EXACT,256,256); - math_law
显示剩余6条评论

90

加载完图片后,您可以尝试:

BufferedImage createResizedCopy(Image originalImage, 
            int scaledWidth, int scaledHeight, 
            boolean preserveAlpha)
    {
        System.out.println("resizing...");
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha) {
            g.setComposite(AlphaComposite.Src);
        }
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null); 
        g.dispose();
        return scaledBI;
    }

9
我发现这种技术生成的图像质量不够高,无法满足我的需求。 - morgancodes
1
Image.getScaledInstance(width,height,hints)也可以吗? - codeplay
1
保留Alpha通道的检查是否针对图像类型是错误的? - Thilo
我同意 @morgancodes 的看法。与例如 OS X 预览相比,在将图像调整为相同尺寸时其质量要差得多。我会尝试一些开源库,看看它们是否表现更好。 - Thilo
1
将尝试一些开源库,看看它们是否表现更好。从@RiyadKalla的回答中+1 imgscalr。 - Thilo
显示剩余2条评论

56

Thumbnailator是一个开源的Java图片缩放库,具有流畅的接口,并在MIT许可证下发布。

我编写该库是因为在Java中制作高质量的缩略图可能会令人惊讶地困难,而且生成的代码可能会相当混乱。使用Thumbnailator,可以使用简单的流畅API表达相当复杂的任务。

一个简单示例

对于一个简单的示例,可以通过一条语句将图像取出并调整大小为100 x 100(保留原始图像的纵横比),并保存到文件中:

Thumbnails.of("path/to/image")
    .size(100, 100)
    .toFile("path/to/thumbnail");

一个高级示例

使用Thumbnailator的流畅接口可以简化复杂的调整大小任务。

假设我们想要执行以下操作:

  1. 获取目录中的图像,并且
  2. 将它们调整为100 x 100,保持原始图像的纵横比,
  3. 将它们全部保存为JPEG格式,质量设置为0.85,
  4. 其中文件名是从原始文件名中取出并添加了thumbnail.前缀的

使用Thumbnailator,我们可以通过以下方式完成上述操作:

Thumbnails.of(new File("path/to/directory").listFiles())
    .size(100, 100)
    .outputFormat("JPEG")
    .outputQuality(0.85)
    .toFiles(Rename.PREFIX_DOT_THUMBNAIL);

关于图片质量和速度的说明

该库还使用了在Filthy Rich Clients一书中由Chet Haase和Romain Guy强调的渐进双线性缩放方法,以生成高质量的缩略图,同时确保可接受的运行时性能。


1
coobird,API做得非常好。非常直观易用。 - Riyad Kalla
文档中没有写明".outputFormat("JPEG")"。 - Vincent Cantin
@Vincent 可以使用的完整方法列表在Thumbnailator API文档中--http://thumbnailator.googlecode.com/hg/javadoc/net/coobird/thumbnailator/Thumbnails.Builder.html。 - coobird
我也对此有着积极的体验。它支持流,非常适合我的SSH客户端。 - Sridhar Sarnobat
@terry,你可以执行以下操作:Thumbnails.of(..).size(80,80).crop(Positions.CENTER).toFile( ... )。这将首先将宽度或高度调整为80,然后从中心进行裁剪。 - Wim Deblauwe
显示剩余4条评论

13

你不需要使用库来做这件事,Java本身就可以实现。

Chris Campbell在图像缩放方面有一篇非常出色而详细的文章 - 请参见此文章

Chet Haase和Romain Guy在他们的书Filthy Rich Clients中也有一篇详细且非常有用的关于图像缩放的文章。


7
Chris的文章正是激励我创作imgscalr的原因;还有像这样的问题(以及你提供的答案),许多人反复问如何从图像获取好看的缩略图。有许多方法可以做到这一点,Chris的方法并不总是最佳选择,这取决于你尝试做什么和缩小比例的大小。imgscalr解决了所有这些问题,而且只需要1个类。 - Riyad Kalla
2
+1,我同意。《Filthy Rich Clients》是最好的Java书籍之一,与“Effective Java”不相上下。但是因为我太懒了,所以我使用ImgScalr。 - Shawn Vader
@RiyadKalla,你所说的库在哪里?你的网站无法访问:http://ww1.thebuzzmedia.com/。 - TheRealChx101

10

9
如果你需要处理大图像或想要一个漂亮的结果,那么在Java中这并不是一项简单的任务。仅通过Graphics2D的rescale操作来创建高质量的缩略图是不够的。虽然可以使用JAI来实现,但需要投入比你想象更多的工作才能获得好看的结果,并且JAI可能会出现OutOfMemory错误,导致JVM崩溃。
如果可以使用外部可执行文件,我建议使用ImageMagick。它简单易用,可以胜任任务,并且不需要做额外的工作。

4
如果您的计算机安装了ImageMagick,则我建议使用im4java。它是一个非常薄的抽象层,可在命令行界面上运行,并且可以很好地完成其工作。

3

Java API没有提供标准的图像缩放和降低图像质量的功能。

因此,我尝试使用JavaCV中的cvResize,但它似乎会引起问题。

我找到了一个很好的图像缩放库:只需在您的pom.xml中添加"java-image-scaling"的依赖即可。

<dependency>
    <groupId>com.mortennobel</groupId>
    <artifactId>java-image-scaling</artifactId>
    <version>0.8.6</version>
</dependency>

在Maven仓库中,你可以获取到最新版本的内容。
例如,在你的Java程序中:
ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);

它也可以在GitHub上找到(https://github.com/mortennobel/java-image-scaling.git),目前版本为8.7。虽然pom.xml需要进行一些小修复(将源和目标更改为至少1.6,因为较新的Maven不再支持1.5)。 - Cromax

2
你可以尝试使用GraphicsMagick图像处理系统,并使用im4java作为Java的命令行接口。GraphicsMagick有很多优点,其中一个就是:
  • GM用于处理全球最大的照片网站(例如Flickr和Etsy)的数十亿个文件。

1

只需使用Burkhard的答案,但在创建图形后添加此行:

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

你也可以将值设置为BICUBIC,它会生成更好质量的图像,但是操作成本更高。还有其他渲染提示可以设置,但我发现插值产生了最显著的效果。 请记住,如果你想要大幅度缩放,Java代码很可能会非常慢。我发现即使将所有渲染提示设置为优化速度而不是质量,较大的图像开始在300%缩放时产生延迟。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接