131

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

4

17 回答 17

184

FWIW 我刚刚发布了(Apache 2,托管在 GitHub 上)一个简单的 Java 图像缩放库,称为imgscalr(可在Maven central上获得)。

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

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

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

所有操作都保持图像的原始比例,因此在这种情况下,您要求 imgscalr 在 200 像素宽和 200 像素高的范围内调整图像大小,默认情况下,它会自动选择最好看和最快的方法,因为它是'未指定。

我一开始就意识到这看起来像是自我推销(确实如此),但我花了相当多的时间在谷歌上搜索这个完全相同的主题,并不断提出不同的结果/方法/想法/建议,并决定坐下来写一篇简单的实现可以解决 80-85% 的用例,在这些用例中,您有一张图片并且可能想要一个缩略图——要么尽可能快,要么尽可能好看(对于那些尝试过的人,你会注意到即使使用 BICUBIC 插值对足够小的图像进行 Graphics.drawImage,它仍然看起来像垃圾)。

于 2010-12-24T20:01:22.830 回答
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;
    }
于 2008-10-28T17:50:25.030 回答
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);

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

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

于 2011-02-19T14:46:06.387 回答
13

你不需要图书馆来做到这一点。您可以使用 Java 本身来完成。

Chris Campbell 有一篇关于缩放图像的出色而详细的文章 - 请参阅这篇文章

Chet Haase 和 Romain Guy 在他们的书《 Filthy Rich Clients》中也有关于图像缩放的详细且内容丰富的文章。

于 2009-02-10T18:41:37.507 回答
10

Java Advanced Imaging现在是开源的,并提供您需要的操作。

于 2008-10-28T18:24:04.153 回答
9

如果您正在处理大图像或想要一个漂亮的结果,那么在 java 中这不是一项简单的任务。简单地通过 Graphics2D 进行重新缩放操作不会创建高质量的缩略图。你可以使用 JAI 来做,但是它需要比你想象的更多的工作才能得到看起来不错的东西,而且 JAI 有一个讨厌的习惯,就是用 OutOfMemory 错误来炸毁我们的 JVM。

如果您可以摆脱它,我建议使用 ImageMagick 作为外部可执行文件。它使用简单,并且可以正确完成工作,因此您不必这样做。

于 2009-02-10T18:25:32.320 回答
4

如果可以选择在您的机器上安装 imagemagick,我推荐im4java。它是命令行界面上的一个非常薄的抽象层,但它的工作做得很好。

于 2009-07-29T18:51:19.783 回答
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);
于 2013-04-18T07:04:21.860 回答
2

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

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

  • GM 用于处理世界上最大的照片网站(例如 Flickr 和 Etsy)上的数十亿个文件。
于 2011-04-11T17:12:35.457 回答
1

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

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

于 2011-09-02T17:52:55.760 回答
1

您可以使用 Marvin(纯 Java 图像处理框架)进行此类操作: http: //marvinproject.sourceforge.net

缩放插件: http: //marvinproject.sourceforge.net/en/plugins/scale.html

于 2012-03-12T01:31:07.070 回答
1

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

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

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

于 2016-08-04T18:52:21.397 回答
1

事实证明,编写高性能缩放器并非易事。我为一个开源项目做过一次:ImageScaler

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

于 2018-01-15T14:55:37.183 回答
0

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

于 2012-02-26T13:58:49.903 回答
0

您可以使用以下流行产品:thumbnailator

于 2014-12-04T08:14:46.390 回答
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;
        }
    }
于 2016-05-14T15:35:42.540 回答
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);
于 2019-12-15T22:30:20.727 回答