代码之家  ›  专栏  ›  技术社区  ›  Balázs Németh

如何提高G.DrawImage()方法调整图像大小的性能

  •  47
  • Balázs Németh  · 技术社区  · 15 年前

    我调整大小的方法如下:

    Image scaledImage = img.getScaledInstance((int)width, (int)height, Image.SCALE_SMOOTH);
    BufferedImage imageBuff = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_RGB);
    Graphics g = imageBuff.createGraphics();
    g.drawImage(scaledImage, 0, 0, new Color(0,0,0), null);
    g.dispose();
    

    它工作正常。我唯一的问题是 g.drawImage() 方法似乎非常慢,我只是无法想象用户有耐心等待20张图片上传20*10秒~3分钟。事实上,在我的电脑上,为一张图片调整3种不同的大小需要将近40秒。

    这还不够好,我正在寻找更快的解决方案。我想知道是否有人能告诉我一个更好的Java语言,或者调用shell脚本,命令,不管你知道什么,它必须更快,其他的一切都无关紧要。

    12 回复  |  直到 10 年前
        1
  •  11
  •   dogbane    15 年前

    你可以使用 ImageMagick create thumbnails .

    convert -define jpeg:size=500x180  hatching_orig.jpg  -auto-orient \
            -thumbnail 250x90   -unsharp 0x.5  thumbnail.gif
    

    从Java中使用它,您可以尝试 JMagick 它提供了一个Java(JNI)接口到IGIMAGEKIK。或者您可以直接使用 Runtime.exec ProcessBuilder .

        2
  •  26
  •   jontro    14 年前

    我正在使用类似下面的代码来缩放图像,我删除了处理保持纵横比的部分。每幅图像的性能肯定超过10秒,但我不记得确切的数字。如果原始图像的大小是所需缩略图的两倍以上,为了在缩小比例时存档更高的质量,应分几个步骤进行缩放,每个步骤都应将以前的图像缩放到其大小的一半左右。

    public static BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException {
        int imageWidth  = image.getWidth();
        int imageHeight = image.getHeight();
    
        double scaleX = (double)width/imageWidth;
        double scaleY = (double)height/imageHeight;
        AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
        AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);
    
        return bilinearScaleOp.filter(
            image,
            new BufferedImage(width, height, image.getType()));
    }
    
        3
  •  14
  •   Klarth    15 年前

    您真的需要使用image.scale“平滑”提供的质量吗?如果没有,可以尝试使用 Image.SCALE_FAST . 你可能会发现这个 article 如果你想坚持用Java提供的东西。

        4
  •  13
  •   johnstosh    14 年前

    我和雅各布想调整图像的大小,而不是缓冲图像。所以我们得到了这个代码:

    /**
     * we want the x and o to be resized when the JFrame is resized
     *
     * @param originalImage an x or an o. Use cross or oh fields.
     *
     * @param biggerWidth
     * @param biggerHeight
     */
    private Image resizeToBig(Image originalImage, int biggerWidth, int biggerHeight) {
        int type = BufferedImage.TYPE_INT_ARGB;
    
    
        BufferedImage resizedImage = new BufferedImage(biggerWidth, biggerHeight, type);
        Graphics2D g = resizedImage.createGraphics();
    
        g.setComposite(AlphaComposite.Src);
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
        g.drawImage(originalImage, 0, 0, biggerWidth, biggerHeight, this);
        g.dispose();
    
    
        return resizedImage;
    }
    
        5
  •  11
  •   Community Mohan Dere    9 年前

    问题的关键在于缩放图像的性能。 用Java语言 . 其他答案显示了不同的方法,但没有进一步评估。我对此也很好奇,所以我试着写一个小的性能测试。但是,测试图像缩放性能 可靠地 , 明智地 客观地 很难。要考虑的影响因素太多了:

    • 输入图像的大小
    • 输出图像的大小
    • 插值(即“质量”:最近邻、双线性、双三次)
    • 这个 BufferedImage.TYPE_* 输入图像的
    • 这个 BufferedImage.类型_* 输出图像的
    • JVM版本和操作系统
    • 最后: 方法 实际用于执行操作。

    我试图掩盖那些我认为最重要的事情。设置是:

    • 输入是一张简单的“普通”照片(尤其是, this "Image Of The Day" 来自维基百科,大小为2560x1706像素)

    • 测试主要的插值类型-即使用 RenderingHints 何处 INTERPOLATION 键被设置为值 NEAREST_NEIGHBOR , BILINEAR BICUBIC

    • 输入图像已转换为不同的类型:

      • BufferedImage.TYPE_INT_RGB :通常使用的类型,因为它“通常”显示最佳性能特征

      • BufferedImage.TYPE_3BTE_BGR :这是默认情况下用它读取的类型,当用它读取时 ImageIO

    • 目标图像的大小在10000宽之间变化(因此,缩放图像 向上的 )和100(因此,将图像缩小到缩略图大小)

    测试已经在Win64/AMD K10上运行,3.7 GHz和JDK 1.8U31,以及 -Xmx4000m -server .

    试验方法为:

    测试代码如下所示:

    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.MediaTracker;
    import java.awt.RenderingHints;
    import java.awt.geom.AffineTransform;
    import java.awt.image.AffineTransformOp;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;
    import java.util.function.Supplier;
    
    import javax.imageio.ImageIO;
    import javax.swing.JLabel;
    
    public class ImageScalingPerformance
    {
        private static int blackHole = 0;
    
        public static void main(String[] args) throws IOException
        {
            // Image with size 2560 x 1706, from https://upload.wikimedia.org/
            //   wikipedia/commons/4/41/Pitta_moluccensis_-_Kaeng_Krachan.jpg
            BufferedImage image = ImageIO.read(
                new File("Pitta_moluccensis_-_Kaeng_Krachan.jpg"));
    
            int types[] =
            {
                BufferedImage.TYPE_3BYTE_BGR,
                BufferedImage.TYPE_INT_RGB,
            };
            Object interpolationValues[] =
            {
                RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC,
            };
            int widths[] =
            {
                10000, 5000, 2500, 1000, 500, 100
            };
    
    
            System.out.printf("%10s%22s%6s%18s%10s\n",
                "Image type", "Interpolation", "Size", "Method", "Duration (ms)");
    
            for (int type : types)
            {
                BufferedImage currentImage = convert(image, type);
                for (Object interpolationValue : interpolationValues)
                {
                    for (int width : widths)
                    {
                        List<Supplier<Image>> tests = 
                            createTests(currentImage, interpolationValue, width);
    
                        for (Supplier<Image> test : tests)
                        {
                            double durationMs = computeMs(test);
    
                            System.out.printf("%10s%22s%6s%18s%10s\n",
                                stringForBufferedImageType(type),
                                stringForInterpolationValue(interpolationValue),
                                String.valueOf(width), 
                                String.valueOf(test),
                                String.format(Locale.ENGLISH, "%6.3f", durationMs));
                        }
                    }
                }
            }
            System.out.println(blackHole);
        }
    
        private static List<Supplier<Image>> createTests(
            BufferedImage image, Object interpolationValue, int width)
        {
            RenderingHints renderingHints = new RenderingHints(null);
            renderingHints.put(
                RenderingHints.KEY_INTERPOLATION, 
                interpolationValue);
            double scale = (double) width / image.getWidth();
            int height = (int)(scale * image.getHeight());
    
            Supplier<Image> s0 = new Supplier<Image>()
            {
                @Override
                public BufferedImage get()
                {
                    return scaleWithAffineTransformOp(
                        image, width, height, renderingHints);
                }
    
                @Override
                public String toString()
                {
                    return "AffineTransformOp";
                }
            };
    
            Supplier<Image> s1 = new Supplier<Image>()
            {
                @Override
                public Image get()
                {
                    return scaleWithGraphics(
                        image, width, height, renderingHints);
                }
    
                @Override
                public String toString()
                {
                    return "Graphics";
                }
            };
    
            Supplier<Image> s2 = new Supplier<Image>()
            {
                @Override
                public Image get()
                {
                    return scaleWithGetScaledInstance(
                        image, width, height, renderingHints);
                }
    
                @Override
                public String toString()
                {
                    return "GetScaledInstance";
                }
            };
    
            List<Supplier<Image>> tests = new ArrayList<Supplier<Image>>();
            tests.add(s0);
            tests.add(s1);
            tests.add(s2);
            return tests;
        }
    
        private static double computeMs(Supplier<Image> supplier)
        {
            int runs = 5;
            long before = System.nanoTime();
            for (int i=0; i<runs; i++)
            {
                Image image0 = supplier.get();
                blackHole += image0.hashCode();
            }
            long after = System.nanoTime();
            double durationMs = (after-before) / 1e6 / runs;
            return durationMs;
        }
    
        private static BufferedImage convert(BufferedImage image, int type)
        {
            BufferedImage newImage = new BufferedImage(
                image.getWidth(), image.getHeight(), type);
            Graphics2D g = newImage.createGraphics();
            g.drawImage(image, 0, 0, null);
            g.dispose();
            return newImage;
        }        
    
        private static BufferedImage scaleWithAffineTransformOp(
            BufferedImage image, int w, int h,
            RenderingHints renderingHints)
        {
            BufferedImage scaledImage = new BufferedImage(w, h, image.getType());
            double scaleX = (double) w / image.getWidth();
            double scaleY = (double) h / image.getHeight();
            AffineTransform affineTransform = 
                AffineTransform.getScaleInstance(scaleX, scaleY);
            AffineTransformOp affineTransformOp = new AffineTransformOp(
                affineTransform, renderingHints);
            return affineTransformOp.filter(
                image, scaledImage);
        }
    
        private static BufferedImage scaleWithGraphics(
            BufferedImage image, int w, int h,
            RenderingHints renderingHints) 
        {
            BufferedImage scaledImage = new BufferedImage(w, h, image.getType());
            Graphics2D g = scaledImage.createGraphics();
            g.setRenderingHints(renderingHints);
            g.drawImage(image, 0, 0, w, h, null);
            g.dispose();
            return scaledImage;
        }
    
        private static Image scaleWithGetScaledInstance(
            BufferedImage image, int w, int h,
            RenderingHints renderingHints)
        {
            int hint = Image.SCALE_REPLICATE;
            if (renderingHints.get(RenderingHints.KEY_ALPHA_INTERPOLATION) != 
                RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
            {
                hint = Image.SCALE_AREA_AVERAGING;
            }
            Image scaledImage = image.getScaledInstance(w, h, hint);
            MediaTracker mediaTracker = new MediaTracker(new JLabel());
            mediaTracker.addImage(scaledImage, 0);
            try
            {
                mediaTracker.waitForAll();
            }
            catch (InterruptedException e)
            {
                Thread.currentThread().interrupt();
            }
            return scaledImage;
        }
    
        private static String stringForBufferedImageType(int type)
        {
            switch (type)
            {
                case BufferedImage.TYPE_INT_RGB : return "INT_RGB";
                case BufferedImage.TYPE_INT_ARGB : return "INT_ARGB";
                case BufferedImage.TYPE_INT_ARGB_PRE : return "INT_ARGB_PRE";
                case BufferedImage.TYPE_INT_BGR : return "INT_BGR";
                case BufferedImage.TYPE_3BYTE_BGR : return "3BYTE_BGR";
                case BufferedImage.TYPE_4BYTE_ABGR : return "4BYTE_ABGR";
                case BufferedImage.TYPE_4BYTE_ABGR_PRE : return "4BYTE_ABGR_PRE";
                case BufferedImage.TYPE_USHORT_565_RGB : return "USHORT_565_RGB";
                case BufferedImage.TYPE_USHORT_555_RGB : return "USHORT_555_RGB";
                case BufferedImage.TYPE_BYTE_GRAY : return "BYTE_GRAY";
                case BufferedImage.TYPE_USHORT_GRAY : return "USHORT_GRAY";
                case BufferedImage.TYPE_BYTE_BINARY : return "BYTE_BINARY";
                case BufferedImage.TYPE_BYTE_INDEXED : return "BYTE_INDEXED";
            }
            return "CUSTOM";
        }
    
        private static String stringForInterpolationValue(Object value)
        {
            if (value == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
            {
                return "NEAREST/REPLICATE";
            }
            if (value == RenderingHints.VALUE_INTERPOLATION_BILINEAR)
            {
                return "BILINEAR/AREA_AVG";
            }
            if (value == RenderingHints.VALUE_INTERPOLATION_BICUBIC)
            {
                return "BICUBIC/AREA_AVG";
            }
            return "(unknown)";
        }
    
    
    }
    

    首先,关于 getScaledInstance :正如Chris Campbell在他(著名的)文章中指出的那样 The Perils of Image.getScaledInstance() (在其他答案中已链接到),该 图像获取缩放状态 方法有点破损,对于大多数配置来说,它的性能非常糟糕。此外,它还有一个缺点,即没有对插值类型进行如此精细的控制。 在以下性能比较中应考虑到这一点 : 质量 产生的图像可能不同,这里不考虑。例如,“面积平均”法 获取缩放状态 当图像大小为 增加 .

    (最严重的缺点是 图像获取缩放状态 是不是它只提供了一个 Image 而不是 BufferedImage 但如果图像只应该被绘制成 绘图 ,这可能不重要)

    我将在这里转储程序的输出以供参考,下面将详细介绍:

    Image type         Interpolation  Size            MethodDuration (ms)
     3BYTE_BGR     NEAREST/REPLICATE 10000 AffineTransformOp   197.287
     3BYTE_BGR     NEAREST/REPLICATE 10000          Graphics   184.427
     3BYTE_BGR     NEAREST/REPLICATE 10000 GetScaledInstance  1869.759
     3BYTE_BGR     NEAREST/REPLICATE  5000 AffineTransformOp    38.354
     3BYTE_BGR     NEAREST/REPLICATE  5000          Graphics    40.220
     3BYTE_BGR     NEAREST/REPLICATE  5000 GetScaledInstance  1088.448
     3BYTE_BGR     NEAREST/REPLICATE  2500 AffineTransformOp    10.153
     3BYTE_BGR     NEAREST/REPLICATE  2500          Graphics     9.461
     3BYTE_BGR     NEAREST/REPLICATE  2500 GetScaledInstance   613.030
     3BYTE_BGR     NEAREST/REPLICATE  1000 AffineTransformOp     2.137
     3BYTE_BGR     NEAREST/REPLICATE  1000          Graphics     1.956
     3BYTE_BGR     NEAREST/REPLICATE  1000 GetScaledInstance   464.989
     3BYTE_BGR     NEAREST/REPLICATE   500 AffineTransformOp     0.861
     3BYTE_BGR     NEAREST/REPLICATE   500          Graphics     0.750
     3BYTE_BGR     NEAREST/REPLICATE   500 GetScaledInstance   407.751
     3BYTE_BGR     NEAREST/REPLICATE   100 AffineTransformOp     0.206
     3BYTE_BGR     NEAREST/REPLICATE   100          Graphics     0.153
     3BYTE_BGR     NEAREST/REPLICATE   100 GetScaledInstance   385.863
     3BYTE_BGR     BILINEAR/AREA_AVG 10000 AffineTransformOp   830.097
     3BYTE_BGR     BILINEAR/AREA_AVG 10000          Graphics  1501.290
     3BYTE_BGR     BILINEAR/AREA_AVG 10000 GetScaledInstance  1627.934
     3BYTE_BGR     BILINEAR/AREA_AVG  5000 AffineTransformOp   207.816
     3BYTE_BGR     BILINEAR/AREA_AVG  5000          Graphics   376.789
     3BYTE_BGR     BILINEAR/AREA_AVG  5000 GetScaledInstance  1063.942
     3BYTE_BGR     BILINEAR/AREA_AVG  2500 AffineTransformOp    52.362
     3BYTE_BGR     BILINEAR/AREA_AVG  2500          Graphics    95.041
     3BYTE_BGR     BILINEAR/AREA_AVG  2500 GetScaledInstance   612.660
     3BYTE_BGR     BILINEAR/AREA_AVG  1000 AffineTransformOp     9.121
     3BYTE_BGR     BILINEAR/AREA_AVG  1000          Graphics    15.749
     3BYTE_BGR     BILINEAR/AREA_AVG  1000 GetScaledInstance   452.578
     3BYTE_BGR     BILINEAR/AREA_AVG   500 AffineTransformOp     2.593
     3BYTE_BGR     BILINEAR/AREA_AVG   500          Graphics     4.237
     3BYTE_BGR     BILINEAR/AREA_AVG   500 GetScaledInstance   407.661
     3BYTE_BGR     BILINEAR/AREA_AVG   100 AffineTransformOp     0.275
     3BYTE_BGR     BILINEAR/AREA_AVG   100          Graphics     0.297
     3BYTE_BGR     BILINEAR/AREA_AVG   100 GetScaledInstance   381.835
     3BYTE_BGR      BICUBIC/AREA_AVG 10000 AffineTransformOp  3015.943
     3BYTE_BGR      BICUBIC/AREA_AVG 10000          Graphics  5431.703
     3BYTE_BGR      BICUBIC/AREA_AVG 10000 GetScaledInstance  1654.424
     3BYTE_BGR      BICUBIC/AREA_AVG  5000 AffineTransformOp   756.136
     3BYTE_BGR      BICUBIC/AREA_AVG  5000          Graphics  1359.288
     3BYTE_BGR      BICUBIC/AREA_AVG  5000 GetScaledInstance  1063.467
     3BYTE_BGR      BICUBIC/AREA_AVG  2500 AffineTransformOp   189.953
     3BYTE_BGR      BICUBIC/AREA_AVG  2500          Graphics   341.039
     3BYTE_BGR      BICUBIC/AREA_AVG  2500 GetScaledInstance   615.807
     3BYTE_BGR      BICUBIC/AREA_AVG  1000 AffineTransformOp    31.351
     3BYTE_BGR      BICUBIC/AREA_AVG  1000          Graphics    55.914
     3BYTE_BGR      BICUBIC/AREA_AVG  1000 GetScaledInstance   451.808
     3BYTE_BGR      BICUBIC/AREA_AVG   500 AffineTransformOp     8.422
     3BYTE_BGR      BICUBIC/AREA_AVG   500          Graphics    15.028
     3BYTE_BGR      BICUBIC/AREA_AVG   500 GetScaledInstance   408.626
     3BYTE_BGR      BICUBIC/AREA_AVG   100 AffineTransformOp     0.703
     3BYTE_BGR      BICUBIC/AREA_AVG   100          Graphics     0.825
     3BYTE_BGR      BICUBIC/AREA_AVG   100 GetScaledInstance   382.610
       INT_RGB     NEAREST/REPLICATE 10000 AffineTransformOp   330.445
       INT_RGB     NEAREST/REPLICATE 10000          Graphics   114.656
       INT_RGB     NEAREST/REPLICATE 10000 GetScaledInstance  2784.542
       INT_RGB     NEAREST/REPLICATE  5000 AffineTransformOp    83.081
       INT_RGB     NEAREST/REPLICATE  5000          Graphics    29.148
       INT_RGB     NEAREST/REPLICATE  5000 GetScaledInstance  1117.136
       INT_RGB     NEAREST/REPLICATE  2500 AffineTransformOp    22.296
       INT_RGB     NEAREST/REPLICATE  2500          Graphics     7.735
       INT_RGB     NEAREST/REPLICATE  2500 GetScaledInstance   436.779
       INT_RGB     NEAREST/REPLICATE  1000 AffineTransformOp     3.859
       INT_RGB     NEAREST/REPLICATE  1000          Graphics     2.542
       INT_RGB     NEAREST/REPLICATE  1000 GetScaledInstance   205.863
       INT_RGB     NEAREST/REPLICATE   500 AffineTransformOp     1.413
       INT_RGB     NEAREST/REPLICATE   500          Graphics     0.963
       INT_RGB     NEAREST/REPLICATE   500 GetScaledInstance   156.537
       INT_RGB     NEAREST/REPLICATE   100 AffineTransformOp     0.160
       INT_RGB     NEAREST/REPLICATE   100          Graphics     0.074
       INT_RGB     NEAREST/REPLICATE   100 GetScaledInstance   126.159
       INT_RGB     BILINEAR/AREA_AVG 10000 AffineTransformOp  1019.438
       INT_RGB     BILINEAR/AREA_AVG 10000          Graphics  1230.621
       INT_RGB     BILINEAR/AREA_AVG 10000 GetScaledInstance  2721.918
       INT_RGB     BILINEAR/AREA_AVG  5000 AffineTransformOp   254.616
       INT_RGB     BILINEAR/AREA_AVG  5000          Graphics   308.374
       INT_RGB     BILINEAR/AREA_AVG  5000 GetScaledInstance  1269.898
       INT_RGB     BILINEAR/AREA_AVG  2500 AffineTransformOp    68.137
       INT_RGB     BILINEAR/AREA_AVG  2500          Graphics    80.163
       INT_RGB     BILINEAR/AREA_AVG  2500 GetScaledInstance   444.968
       INT_RGB     BILINEAR/AREA_AVG  1000 AffineTransformOp    13.093
       INT_RGB     BILINEAR/AREA_AVG  1000          Graphics    15.396
       INT_RGB     BILINEAR/AREA_AVG  1000 GetScaledInstance   211.929
       INT_RGB     BILINEAR/AREA_AVG   500 AffineTransformOp     3.238
       INT_RGB     BILINEAR/AREA_AVG   500          Graphics     3.689
       INT_RGB     BILINEAR/AREA_AVG   500 GetScaledInstance   159.688
       INT_RGB     BILINEAR/AREA_AVG   100 AffineTransformOp     0.329
       INT_RGB     BILINEAR/AREA_AVG   100          Graphics     0.277
       INT_RGB     BILINEAR/AREA_AVG   100 GetScaledInstance   127.905
       INT_RGB      BICUBIC/AREA_AVG 10000 AffineTransformOp  4211.287
       INT_RGB      BICUBIC/AREA_AVG 10000          Graphics  4712.587
       INT_RGB      BICUBIC/AREA_AVG 10000 GetScaledInstance  2830.749
       INT_RGB      BICUBIC/AREA_AVG  5000 AffineTransformOp  1069.088
       INT_RGB      BICUBIC/AREA_AVG  5000          Graphics  1182.285
       INT_RGB      BICUBIC/AREA_AVG  5000 GetScaledInstance  1155.663
       INT_RGB      BICUBIC/AREA_AVG  2500 AffineTransformOp   263.003
       INT_RGB      BICUBIC/AREA_AVG  2500          Graphics   297.663
       INT_RGB      BICUBIC/AREA_AVG  2500 GetScaledInstance   444.497
       INT_RGB      BICUBIC/AREA_AVG  1000 AffineTransformOp    42.841
       INT_RGB      BICUBIC/AREA_AVG  1000          Graphics    48.605
       INT_RGB      BICUBIC/AREA_AVG  1000 GetScaledInstance   209.261
       INT_RGB      BICUBIC/AREA_AVG   500 AffineTransformOp    11.004
       INT_RGB      BICUBIC/AREA_AVG   500          Graphics    12.407
       INT_RGB      BICUBIC/AREA_AVG   500 GetScaledInstance   156.794
       INT_RGB      BICUBIC/AREA_AVG   100 AffineTransformOp     0.817
       INT_RGB      BICUBIC/AREA_AVG   100          Graphics     0.790
       INT_RGB      BICUBIC/AREA_AVG   100 GetScaledInstance   128.700
    

    可以看出,几乎所有情况下, 获取缩放状态 与其他方法相比,它的性能较差(在某些情况下,它的性能似乎更好,这可以用扩展时的低质量来解释)。

    这个 仿射变换 基于方法似乎平均表现最好,唯一值得注意的例外是 最近的邻居 缩放 TYPE_INT_RGB 图像,其中 绘图 -基于的方法似乎总是更快。

    底线是:使用 仿射变换 ,就像在 由JRN Horstmann回答 似乎是为 应用程序案例。

        6
  •  6
  •   dpineda    11 年前

    这对我很有用:

    private BufferedImage getScaledImage(BufferedImage src, int w, int h){
        int original_width = src.getWidth();
        int original_height = src.getHeight();
        int bound_width = w;
        int bound_height = h;
        int new_width = original_width;
        int new_height = original_height;
    
        // first check if we need to scale width
        if (original_width > bound_width) {
            //scale width to fit
            new_width = bound_width;
            //scale height to maintain aspect ratio
            new_height = (new_width * original_height) / original_width;
        }
    
        // then check if we need to scale even with the new height
        if (new_height > bound_height) {
            //scale height to fit instead
            new_height = bound_height;
            //scale width to maintain aspect ratio
            new_width = (new_height * original_width) / original_height;
        }
    
        BufferedImage resizedImg = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = resizedImg.createGraphics();
        g2.setBackground(Color.WHITE);
        g2.clearRect(0,0,new_width, new_height);
        g2.drawImage(src, 0, 0, new_width, new_height, null);
        g2.dispose();
        return resizedImg;
    }
    

    我还为PNG添加了白色背景

        7
  •  5
  •   A. Ocannaille    10 年前

    在不破坏图像质量的情况下,缩放Java图像的最快方法是使用双线性缩放。双线性只有当你一次缩放50%的图像时才是好的,因为它的工作方式。 以下代码来自ChetHaase的“肮脏的富客户”。他在书中解释了多种技术,但这一种技术在质量权衡方面具有最高的性能。

    它支持所有类型的bufferedImages,因此不必担心兼容性。它还允许java2d硬件加速您的图像,因为计算是由java2d完成的。如果您不理解最后一部分,请不要担心。最重要的是这是最快的方法。

    public static BufferedImage getFasterScaledInstance(BufferedImage img, int targetWidth, int targetHeight, boolean progressiveBilinear)
    {
        int type = (img.getTransparency() == Transparency.OPAQUE) ? 
                BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = (BufferedImage) img;
        BufferedImage scratchImage = null;
        Graphics2D g2 = null;
        int w, h;
        int prevW = ret.getWidth();
        int prevH = ret.getHeight();
        if(progressiveBilinear) {
            w = img.getWidth();
            h = img.getHeight();
        }else{
            w = targetWidth;
            h = targetHeight;
        }
        do {
            if (progressiveBilinear && w > targetWidth) {
                w /= 2;
                if(w < targetWidth) {
                    w = targetWidth;
                }
            }
    
            if (progressiveBilinear && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }
    
            if(scratchImage == null) {
                scratchImage = new BufferedImage(w, h, type);
                g2 = scratchImage.createGraphics();
            }
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2.drawImage(ret, 0, 0, w, h, 0, 0, prevW, prevH, null);
            prevW = w;
            prevH = h;
            ret = scratchImage;
        } while (w != targetWidth || h != targetHeight);
    
        if (g2 != null) {
            g2.dispose();
        }
    
        if (targetWidth != ret.getWidth() || targetHeight != ret.getHeight()) {
            scratchImage = new BufferedImage(targetWidth, targetHeight, type);
            g2 = scratchImage.createGraphics();
            g2.drawImage(ret, 0, 0, null);
            g2.dispose();
            ret = scratchImage;
        }
        System.out.println("ret is "+ret);
        return ret;
    }
    
        8
  •  3
  •   Sam R. chikka.anddev    12 年前

    您将在调整大小的速度和生成的图片的质量之间进行权衡。 您可以尝试JDK的另一种缩放算法。

    用于图像编辑的最佳和最灵活的工具是 ImageMagick .

    Java语言有两种接口:

    • JMagick -是ImageMagick的JNI接口。查看项目 Wiki 以获取更多信息。
    • im4java -是ImageMagick的命令行接口。它不像jmagick那样基于jni。

    在直接使用命令行调用imagemagick之前,您应该首选im4java。

        9
  •  2
  •   Pierre eboakyegyau    10 年前

    老问题,但如果有人碰到这个问题:我分析了您的代码,您最大的瓶颈是调用:

    Image.getScaledInstance()
    

    众所周知,这个电话慢得可怕。请阅读本文件:

    The Perils of Image.getScaledInstance()

    实现显著性能改进的最简单/最佳解决方案是替换该调用。您可以使用dpineda答案中的方法(请参阅上面的答案/代码):

    private BufferedImage getScaledImage(BufferedImage src, int w, int h){
    

    我测试了他的方法,效果很好。在我的测试中,他的实现(避免了较慢的image.getscaledInstance())节省了80%的处理时间!

        10
  •  1
  •   leonbloy    15 年前

    通过调整渲染提示,可以获得一些性能改进(可能很小,可能可以忽略不计,可能以牺牲质量为代价)。例如。

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
                   RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    
        11
  •  0
  •   mdrg    15 年前

    如果您想要更快的东西,如果您可以放弃可移植性,那么您最好使用一些本机代码。

    <如果你想要一个纯Java的解决方案,你也可以尝试其他的解决方案,比如“http://oals/javas/1.42/DOCS/API/Java/Att/GraceCs2D.html”=“NoFoLoLy”> GraceS2D。Stase< /A>和 image.getscaledInstance。 我以前用过它们,但记不起哪一个性能更好或外观更好,抱歉。

    尝试一下,看看哪一个最适合你的需求。

    你也可以尝试其他的解决方案,比如 图形二维比例 图片.getscaledInstance . 我以前用过,但记不起哪一个性能更好或外观更好,对不起。

    试试看,看看哪一个最适合你的需要。

        12
  •  0
  •   Anthony O.    12 年前

    我用过 im4java 具有 GraphicsMagick 为了获得更快的结果(比ImageIO更快)。

    使用了这种代码:

    public static void createFilePreview(final File originalFile, final String originalFileMimeType, final File destinationPreviewFile, final Integer maxWidth, final Integer maxHeight) throws IOException, InterruptedException, IM4JavaException {
        runThumbnail(new ConvertCmd(), originalFile.getAbsolutePath(), originalFileMimeType, destinationPreviewFile.getAbsolutePath(), maxWidth, maxHeight);
    }
    
    public static void createFilePreview(final InputStream originalFileInputStream, final String originalFileMimeType, final File destinationPreviewFile, final Integer maxWidth, final Integer maxHeight) throws IOException, InterruptedException, IM4JavaException {
        final ConvertCmd cmd = new ConvertCmd();
    
        cmd.setInputProvider(new Pipe(originalFileInputStream, null));
    
        runThumbnail(cmd, "-", originalFileMimeType, destinationPreviewFile.getAbsolutePath(), maxWidth, maxHeight);
    }
    
    private static void runThumbnail(final ConvertCmd cmd, final String originalFile, final String originalFileMimeType, final String destinationPreviewFile, final Integer maxWidth, final Integer maxHeight) throws IOException, InterruptedException, IM4JavaException {
        final IMOperation operation = new IMOperation();
        // if it is a PDF, will add some optional parameters to get nicer results
        if (originalFileMimeType.startsWith("application/pdf")) {
            operation.define("pdf:use-trimbox=true");   // as it is said here http://www.prepressure.com/pdf/basics/page_boxes "The imposition programs and workflows that I know all use the TrimBox as the basis for positioning pages on a press sheet."
            operation.density(300, 300);    // augment the rendering from 75 (screen size) to 300 dpi in order to create big preview with good quality
        }
        operation.addImage("[0]");  // if it is a PDF or other multiple image source, will extract the first page / image, else it is ignored
        operation.autoOrient(); // Auto-orient the image if it contains some orientation information (typically JPEG with EXIF header)
        operation.thumbnail(maxWidth, maxHeight);
        operation.addImage();
    
        cmd.run(operation, originalFile, destinationPreviewFile);
    }