如何提高g.drawImage()方法的性能以调整图像大小
image-processing
java
5
0

我有一个应用程序,用户可以上传相册中的图片,但是自然需要调整上传图片的大小,因此也可以使用大拇指,并且所显示的图片也适合页面(例如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();

而且效果还不错。我唯一的问题是g.drawImage()方法似乎非常慢,我无法想象用户足够耐心等待20 * 10秒〜3分钟的20张图片的上传。实际上,在我的计算机上,为单张图片进行3种不同的尺寸调整大约需要40秒。

这还不够好,我正在寻找更快的解决方案。我想知道是否有人可以通过调用Shell脚本,命令告诉我有关Java或Java更好的一个信息,无论您知道什么黑客,它都必须更快,其他所有内容这次都无关紧要。

参考资料:
Stack Overflow
收藏
评论
共 9 个回答
高赞 时间 活跃

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

ImageMagick是用于AFAIK图像编辑的最佳,最灵活的工具。

Java语言有两个接口:

  • JMagick-是ImageMagick的JNI接口。请参阅项目Wiki以获取更多信息。
  • im4java-是ImageMagick的命令行界面。它不像JMagick那样基于JNI。

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

收藏
评论

我使用与以下类似的代码缩放图像,删除了保留长宽比的部分。性能绝对优于每张图像10s,但我不记得有任何确切数字。要在缩小时存档更好的质量,如果原始图像的大小是所需缩略图的两倍以上,则应分几步进行缩放,每一步都应将前一张图像的大小缩放到其一半左右。

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()));
}
收藏
评论

旧问题,但万一有人遇到这个问题:我分析了您的代码,最大的瓶颈是致电:

Image.getScaledInstance()

众所周知,该呼叫非常缓慢。请通过阅读以下文件来说服:

Image.getScaledInstance()的风险

显着提高性能的最简单/最佳解决方案是替换该调用。您可以使用dpineda的答案中的方法(请参见上面的答案/代码):

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

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

收藏
评论

问题的重点是关于Java缩放图像的性能。其他答案显示了不同的方法,没有进一步评估它们。我也对此感到很好奇,因此我尝试编写了一个小型性能测试。但是,难以可靠明智客观 测试图像缩放性能。有太多影响因素需要考虑:

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

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

  • 输入的是简单的“平均”照片(尤其是Wikipedia上的“每日图像” ,大小为2560x1706像素)

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

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

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

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

  • 目标图像大小在10000(因此将图像放大 )的宽度和100(因此将图像缩小到缩略图的尺寸)之间变化。

测试已在带有3.7 GHz的Win64 / AMD K10和带有-Xmx4000m -server 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在他的(著名的)有关Image.getScaledInstance()的危险的文章中指出的那样(该问题已经在其他答案中链接了), Image#getScaledInstance方法有些破损,令人痛苦的是大多数配置的性能都较差。另外,它的缺点是没有关于插值类型的这种细粒度控制。 在以下性能比较中应考虑到这一点 :生成的图像的质量可能有所不同,此处不予考虑。例如,当图像大小增加时, getScaledInstance的“区域平均”方法不会产生良好的图像质量。

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

可以看出,在几乎所有情况下,与其他方法相比, getScaledInstance性能都较差(并且在少数情况下,其表现似乎更好的原因可以由向上扩展时的较低质量来解释)。

基于AffineTransformOp的方法似乎平均表现最佳,唯一值得注意的例外是TYPE_INT_RGB图像的NEAREST_NEIGHBOR缩放比例,其中基于Graphics的方法似乎始终更快。

最重要的是:使用AffineTransformOp的方法(如JörnHorstmann回答)似乎是在大多数应用程序案例中提供最佳性能的方法。

收藏
评论

在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;
}
收藏
评论

您真的需要使用Image.SCALE_SMOOTH提供的质量吗?如果没有,则可以尝试使用Image.SCALE_FAST 。如果您想坚持使用Java提供的某些内容,可能会发现本文很有帮助。

收藏
评论

您可以使用ImageMagick 创建缩略图

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

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

收藏
评论

好吧,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;
}
收藏
评论

这对我有用:

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添加了白色背景

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号