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

时间:2010-10-19 11:14:41

标签: 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();

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

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

12 个答案:

答案 0 :(得分: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()));
}

答案 1 :(得分:14)

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

答案 2 :(得分: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;
}

答案 3 :(得分:11)

您可以ImageMagick使用create thumbnails

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命令。

答案 4 :(得分:11)

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

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

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

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

  • 测试主要插值类型 - 即使用RenderingHintsINTERPOLATION键设置为值NEAREST_NEIGHBORBILINEAR和{{1} }}

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

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

    • BufferedImage.TYPE_INT_RGB:这是默认情况下读取的类型,只需使用BufferedImage.TYPE_3BTE_BGR

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

测试已在具有3.7 GHz的Win64 / AMD K10和带有ImageIO的JDK 1.8u31上运行。

测试方法是:

测试代码如下所示:

Image#getScaledInstance

首先,关于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)"; } } :正如克里斯·坎贝尔在他的(着名)文章中指出的那样The Perils of Image.getScaledInstance()(已经与其他答案相关联),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缩放NEAREST_NEIGHBOR图片,其中基于TYPE_INT_RGB的方法似乎一直更快。

底线是:使用Graphics的方法,如answer by Jörn Horstmann,似乎是为大多数应用案例提供最佳性能的方法。

答案 5 :(得分: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;
}

我也为png添加了白色背景

答案 6 :(得分: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;
}

答案 7 :(得分:3)

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

最佳且最灵活的图像编辑工具AFAIK是ImageMagick

Java语言有两个接口:

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

在使用命令行直接调用ImageMagick之前,您应该更喜欢im4java。

答案 8 :(得分:2)

旧问题,但万一其他人遇到此问题:我描述了您的代码,您最大的瓶颈是呼叫:

Image.getScaledInstance()

众所周知,这个电话非常缓慢。请阅读本文件以确信:

The Perils of Image.getScaledInstance()

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

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

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

答案 9 :(得分:1)

通过调整渲染提示,可以获得性能方面的一些改进(可能很小,也许可以忽略不计,可能以牺牲质量为代价)。 E.g。

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

答案 10 :(得分:0)

如果你想要快速的东西,你可能会更好地使用一些本机代码,如果你可以放弃可移植性。

但是如果你想要一个纯Java解决方案,你也可以尝试其他一些解决方案,比如Graphics2D.scaleImage.getScaledInstance。 我过去曾经使用它们,但不记得哪个有更好的性能或更好看的结果,抱歉。

尝试一下,看看哪一种最适合您的需求。

答案 11 :(得分:0)

我将im4javaGraphicsMagick一起使用,以获得更快的结果(比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);
}