如何提高g.drawImage()方法的性能来调整图像大小

Bal*_*eth 47 java image-processing

我有一个应用程序,用户可以在相册中上传图片,但自然上传的图像需要调整大小,因此也有拇指可用,所显示的图片也适合页面(例如800x600).我调整大小的方式是这样的:

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();
Run Code Online (Sandbox Code Playgroud)

它工作得很好.我唯一的问题是这个g.drawImage()方法看起来非常慢,而我无法想象用户要耐心等待上传20张图片20*10秒~3分钟.事实上,在我的电脑上,为单张照片制作3种不同的调整大小需要近40秒.

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

Jör*_*ann 26

我正在使用类似于以下的代码来缩放图像,我删除了处理保留纵横比的部分.性能绝对优于每张图像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()));
}
Run Code Online (Sandbox Code Playgroud)


Kla*_*rth 14

你真的需要使用Image.SCALE_SMOOTH提供的质量吗?如果不这样做,您可以尝试使用Image.SCALE_FAST.如果您想坚持使用Java提供的东西,您可能会发现本文很有帮助.


小智 13

好吧,Jacob和我想要调整Image的大小,而不是BufferedImage.所以我们最终得到了这段代码:

/**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 谁是雅各? (93认同)
  • 4年后,我们仍然不知道雅各是谁 (19认同)
  • 不,说真的,谁是雅各布? (7认同)
  • 好的,快到2019年了,还没有关于雅各布的信息:| (3认同)
  • 雅各被杀时你在哪里? (2认同)
  • 雅各布,我想相信你还活着! (2认同)

Mar*_*o13 13

问题的主要内容是关于Java中缩放图像的性能.其他答案显示了不同的方法,没有进一步评估.我对此也很好奇,所以我试着写一个小的性能测试.然而,难以可靠,合理客观测试图像缩放性能.有太多的影响因素需要考虑:

  • 输入图像的大小
  • 输出图像的大小
  • 插值(即"质量":最近邻,双线性,双三次)
  • BufferedImage.TYPE_*输入图像的
  • BufferedImage.TYPE_*输出图像的
  • JVM版本和操作系统
  • 最后:该方法,实际上是用于执行操作.

我试图涵盖那些我认为最重要的那些.设置是:

  • 输入是一张简单的"平均"照片(特别是维基百科的"今日形象",大小为2560x1706像素)

  • 主内插类型进行测试-即,通过使用RenderingHints其中INTERPOLATION键被设置为的值NEAREST_NEIGHBOR,BILINEARBICUBIC

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

    • BufferedImage.TYPE_INT_RGB:一种常用的类型,因为它"通常"显示最佳性能特征

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

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

测试已在具有3.7 GHz和JDK 1.8u31的Win64/AMD K10上运行-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)";
    }


}
Run Code Online (Sandbox Code Playgroud)

First, regarding getScaledInstance: As Chris Campbell has pointed out in his (famous) article about The Perils of Image.getScaledInstance() (which was already linked to in other answers), the Image#getScaledInstance method is somewhat broken, and has a distressingly bad performance for most configurations. Additionally, it has the disadvantage of not having such a fine-grained control about the interpolation type. This should be taken into account in the following performance comparison: The quality of the resulting images may differ, which is not considered here. For example, the "area averaging" method of getScaledInstance does not yield a good image quality when the image size is increased.

(最严重的缺点Image#getScaledInstance是恕我直言,它只提供一个Image,而不是一个BufferedImage,但如果图像只应该被绘成一个Graphics,这可能不重要)

我将在这里转储程序的输出以供参考,一些细节将在下面进行:

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
Run Code Online (Sandbox Code Playgroud)

可以看出,对于几乎所有情况,getScaledInstance与其他方法相比表现不佳(并且在扩展时可以通过较低质量来解释其似乎表现更好的少数情况).

AffineTransformOp基础的方法似乎表现最佳,平均,唯一明显的例外是一个NEAREST_NEIGHBOR缩放TYPE_INT_RGB图像,其中Graphics基的方法似乎是一致的更快.

底线是:AffineTransformOpJörnHorstmann答案中,使用的方法似乎是为大多数应用案例提供最佳性能的方法.


dog*_*ane 11

您可以使用的ImageMagick创建缩略图.

convert -define jpeg:size=500x180  hatching_orig.jpg  -auto-orient \
        -thumbnail 250x90   -unsharp 0x.5  thumbnail.gif
Run Code Online (Sandbox Code Playgroud)

要从Java中使用它,您可以尝试JMagick,它为ImageMagick提供Java(JNI)接口.或者您可以直接使用Runtime.exec或调用ImageMagick命令ProcessBuilder.


dpi*_*eda 6

这对我有用:

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;
}
Run Code Online (Sandbox Code Playgroud)

我还为png添加了白色背景


nem*_*emo 5

在不降低图像质量的情况下在Java中缩放图像的最快方法是使用双线性缩放.双线性是唯一好的,因为它的工作方式一次缩放50%的图像.以下代码来自Chet Haase的"肮脏富客户".他解释了本书中的多种技术,但这种技术在质量权衡方面具有最高的性能.

它支持所有类型的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;
}
Run Code Online (Sandbox Code Playgroud)