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


126

我需要调整PNG,JPEG和GIF文件的大小。如何使用Java做到这一点?


14
因为您要的是图书馆,所以真正的答案是在这里:stackoverflow.com/questions/244164/…。它比接受的答案中的代码更容易使用;)
Artur Gajowy

我在库部分上表示不同意:Graphics2D是awt库的一部分,它是开源的。对于最后一部分(开放源代码),我不确定100%,但是谁会看awt代码呢?
Burkhard,

Answers:


87

加载图像后,您可以尝试:

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)也可以吗?
2011年

1
(对于imageType),preserveAlpha是否检查错误的方法?
Thilo 2012年

我同意@morgancodes。调整为相同尺寸时,图像质量比例如OS X Preview差得多。将尝试一些开源库,看看它们是否性能更好。
Thilo 2012年

1
“将尝试一些开源库,看看它们是否表现更好。” +1来自@RiyadKalla的答案为imgscalr。
Thilo 2012年

182

我刚刚发布了FWIW(Apache 2,托管在GitHub上)一个简单的Java图像缩放库,名为imgscalr(在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()。我也喜欢您的方式,我认为这很简单。
阿米尔·拉明法

4
阿米尔,建造者模式奇妙的作品为这些类型的图书馆为好,我刚好去与静态方法的方法,因为我认为这是一个头发容易按照新的用户和使用模式,我从imgscalr预期(原仅单个调整大小的方法)无法从实例保持状态(构建器实例)中受益。因此,我保存了对象实例化并使用了静态方法。我在所有可以避免的地方都坚决反对在imgscalr内部创建对象。两种方法都很好用。
Riyad Kalla

5
+1使它在中央Maven存储库中可用!
Grilse 2012年

这个BufferedImage类是什么,为什么android studio找不到它?@Riyad Kalla
Milad

3
@ xe4me BufferedImage是J2SE JDK(Java2D框架的一部分)中的一个类,用于表示原始的未压缩像素数据。它在Android上不可用,Android提供了自己的类来处理图像数据。
Riyad Kalla

54

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

有关图像质量和速度的注意事项

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


1
coobird,使用API​​确实很棒。非常简单易用。
里亚德·卡拉

@LordT:很高兴您发现Thumbnailator易于使用:)
coobird 2011年

如何使用500x400原始图像创建80x80缩略图?我没有看到任何选择。谢谢!
特里2012年

“ .outputFormat(“ JPEG”)“在文档中的任何位置均未写入。
文森特·坎廷

@Vincent的可以使用的方法的完整列表是在Thumbnailator API文档- thumbnailator.googlecode.com/hg/javadoc/net/coobird/...
coobird

12

您不需要库即可执行此操作。您可以使用Java本身来实现。

克里斯·坎贝尔(Chris Campbell)在缩放图像方面有出色而详尽的文章 -请参阅本文

Chet Haase和Romain Guy在其著作《肮脏的富客户》(Filthy Rich Clients)中也有详尽而翔实的图像缩放文章。


7
克里斯的文章正是促使我首先编写imgscalr的原因。以及诸如此类的问题(以及诸如此类的答案)。很多人一遍又一遍地问如何从图像中获得漂亮的缩略图。有很多方法可以做到,克里斯的方法并不总是最好的方法,它取决于您要尝试做的事情以及减少的幅度。imgscalr解决了所有这些问题,它是1类。
里亚德·卡拉

2
+1,我同意,Filthy Rich客户是与“有效Java”相当的最好的Java书籍之一,但是我使用ImgScalr是因为我很懒。
肖恩·维德


9

如果您要处理大图像或想要漂亮的结果,那么在Java中这并不是一件简单的任务。通过Graphics2D通过重新缩放操作来简单地完成操作不会创建高质量的缩略图。您可以使用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(github.com/mortennobel/java-image-scaling.git)上获得,到目前为止,它的版本是8.7。您需要在pom.xml中进行修复(您将源和目标更改为至少1.6,因为较新的Maven不再支持1.5)。
Cromax

2

您可以尝试使用带有im4java的GraphicsMagick图像处理系统作为Java的命令行界面。

GraphicsMagick有很多优点,但有一个优点:

  • GM用于处理世界上最大的照片网站(例如Flickr和Etsy)上的数十亿个文件。

1

提到了Image Magick。有一个名为JMagick的JNI前端项目。这不是一个特别稳定的项目(众所周知,Image Magick本身会发生很大变化,甚至破坏兼容性)。也就是说,我们在生产环境中使用JMagick和兼容的Image Magick版本具有良好的经验,可以在高吞吐量,低延迟率下执行缩放。与我们之前尝试过的全Java图形库相比,速度要好得多。

http://www.jmagick.org/index.html


1

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

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

您也可以将值设置为BICUBIC,它将产生质量更好的图像,但操作成本更高。您还可以设置其他渲染提示,但是我发现插值会产生最显着的效果。请记住,如果您想放大很多,Java代码很可能会非常慢。我发现较大的图像甚至在所有渲染提示都设置为针对速度进行优化时也开始产生300%左右的缩放滞后。



1

事实证明,编写高性能的缩放器并不容易。我为一个开源项目ImageScaler做了一次。

原则上,“ java.awt.Image#getScaledInstance(int,int,int)”也可以完成这项工作,但是这样做有一个讨厌的错误-有关详细信息,请参阅我的链接。


0

我已经开发了一种可免费使用的类(AnimatedGifEncoder,GifDecoder和LWZEncoder)用于处理GIF动画的解决方案。
您可以下载jgifcode jar并运行GifImageUtil类。链接:http//www.jgifcode.com


1
如果您推荐的产品是附属产品,请在答案中提及。
汉斯·奥尔森

哇...是用来调整GIF动画图像大小的吗?它是免费的?哇...我现在应该尝试...
gumuruh 2012年

是的,这是我开发的。这是它的源代码github.com/rt29/jgifcode-现在在这里。我不再支持它。
Rohit Tiwari 2015年


0

如果您不想像上面测试过的@Riyad Kalla答案那样导入imgScalr,但我也可以很好地进行测试,尽管如此,您也可以在另一个问题上从Peter Walser答案 @Peter Walser 那里获取:

 /**
     * utility method to get an icon from the resources of this class
     * @param name the name of the icon
     * @return the icon, or null if the icon wasn't found.
     */
    public Icon getIcon(String name) {
        Icon icon = null;
        URL url = null;
        ImageIcon imgicon = null;
        BufferedImage scaledImage = null;
        try {
            url = getClass().getResource(name);

            icon = new ImageIcon(url);
            if (icon == null) {
                System.out.println("Couldn't find " + url);
            }

            BufferedImage bi = new BufferedImage(
                    icon.getIconWidth(),
                    icon.getIconHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = bi.createGraphics();
            // paint the Icon to the BufferedImage.
            icon.paintIcon(null, g, 0,0);
            g.dispose();

            bi = resizeImage(bi,30,30);
            scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
            imgicon = new ImageIcon(scaledImage);

        } catch (Exception e) {
            System.out.println("Couldn't find " + getClass().getName() + "/" + name);
            e.printStackTrace();
        }
        return imgicon;
    }

 public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
        float scaleX = (float) areaWidth / image.getWidth();
        float scaleY = (float) areaHeight / image.getHeight();
        float scale = Math.min(scaleX, scaleY);
        int w = Math.round(image.getWidth() * scale);
        int h = Math.round(image.getHeight() * scale);

        int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        boolean scaleDown = scale < 1;

        if (scaleDown) {
            // multi-pass bilinear div 2
            int currentW = image.getWidth();
            int currentH = image.getHeight();
            BufferedImage resized = image;
            while (currentW > w || currentH > h) {
                currentW = Math.max(w, currentW / 2);
                currentH = Math.max(h, currentH / 2);

                BufferedImage temp = new BufferedImage(currentW, currentH, type);
                Graphics2D g2 = temp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(resized, 0, 0, currentW, currentH, null);
                g2.dispose();
                resized = temp;
            }
            return resized;
        } else {
            Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;

            BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = resized.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(image, 0, 0, w, h, null);
            g2.dispose();
            return resized;
        }
    }

0

尝试以下方法:

ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.