13

我有一个用 Java(Spring、Hibernate/JPA、Struts2)编写的 Web 应用程序,用户可以在其中上传图像并将它们存储在文件系统中。我想缩放这些图像,使它们具有一致的大小以在网站上显示。哪些库或内置函数将提供最佳结果?在做出决定时,我将考虑以下标准(按此顺序):

  • 免费/开源(必要)
  • 易于实施
  • 结果质量
  • 表现
  • 可执行文件的大小
4

7 回答 7

10

我真的建议给 imgscalr 看看。

它是在 Apache 2 许可下发布的,托管在GitHub 上,已经部署在少数 Web 应用程序中,有一个非常简单但经过迂腐记录的 API,有代码可以解决 JDK 中的 2 个主要图像错误,你可以透明地告诉你只有在缩放操作或可怕的结果后突然开始出现“黑色”图像时才会注意到,为您提供 Java 中可用的最佳外观结果,可通过 Maven 和 ZIP 获得,并且只是一个类.

基本使用如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 320);

这是最简单的调用,库将对质量做出最佳猜测,尊重您的图像比例,并将结果置于 320x320 边界框内。注意,边界框只是使用的最大 W/H,因为您的图像比例得到尊重,所以生成的图像仍然会尊重它,比如 320x200。

如果您想覆盖自动模式并强制它为您提供最好看的结果,甚至对结果应用非常温和的抗锯齿过滤器以使其看起来更好(尤其适用于缩略图),该调用将如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

这些都只是示例,API 很广泛,涵盖了从超级简单的用例到非常专业的所有内容。您甚至可以传入自己的 BufferedImageOp 以应用于图像(并且该库会自动为您修复 6 年的 BufferedImageOp JDK 错误!)

在 Java 中成功缩放图像比该库为您所做的要多得多,例如,在对图像进行操作时,始终将图像保持为受支持最好的 RGB 或 ARGB 图像类型之一。如果用于任何图像操作的图像类型得不到很好的支持,Java2D 图像处理管道在幕后就会退回到劣质的软件管道。

如果这一切听起来让人头疼,那就是……这就是我编写库并将其开源的原因,这样人们就可以调整图像大小并继续他们的生活而无需担心。

希望有帮助。

于 2011-07-05T16:41:22.147 回答
4

查看Java Image I/O API以读取/写入图像。然后使用AffineTransform调整大小。

此外,这是一个使用 java.awt.Image 的完整示例。

于 2009-05-03T08:30:40.803 回答
4

还要查看java-image-scaling库。它创建了比 ImageIO 质量更好的图像。

于 2010-05-08T09:31:05.150 回答
1

图像编辑的最佳工具是ImageMagick,它是开源的。

Java 语言有两个接口:

JMagick使用 JNI 接口到 ImageMagick

im4java什么是 ImageMagick 的命令行界面

于 2011-04-11T14:18:41.880 回答
1

发现这更快:

public static BufferedImage getScaledInstance(final BufferedImage img, final int targetWidth, final int targetHeight,
                                              final Object hint) {
    final int type = BufferedImage.TYPE_INT_RGB;
    int drawHeight = targetHeight;
    int drawWidth = targetWidth;
    final int imageWidth = img.getWidth();
    final int imageHeight = img.getHeight();
    if ((imageWidth <= targetWidth) && (imageHeight <= targetHeight)) {
        logger.info("Image " + imageWidth + "/" + imageHeight + " within desired scale");
        return img;
    }
    final double sar = ((double) imageWidth) / ((double) imageHeight);
    if (sar != 0) {
        final double tar = ((double) targetWidth) / ((double) targetHeight);
        if ((Math.abs(tar - sar) > .001) && (tar != 0)) {
            final boolean isSoureWider = sar > (targetWidth / targetHeight);
            if (isSoureWider) {
                drawHeight = (int) (targetWidth / sar);
            }
            else {
                drawWidth = (int) (targetHeight * sar);
            }
        }
    }
    logger.info("Scaling image from " + imageWidth + "/" + imageHeight + " to " + drawWidth + "/" + drawHeight);
    final BufferedImage result = new BufferedImage(drawWidth, drawHeight, type);
    try {
        final Graphics2D g2 = result.createGraphics();
        try {
            if (hint != null) {
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            }
            g2.drawImage(img, 0, 0, drawWidth, drawHeight, null);
        }
        finally {
            g2.dispose();
        }
        return result;
    }
    finally {
        result.flush();
    }
}
于 2015-07-17T13:13:29.803 回答
1

我知道这是一个非常古老的问题,但我使用标准 Java API 得到了自己的解决方案

import java.awt.*;
import java.awt.event.*;
import javax.imageio.*
import java.awt.image.*;

BufferedImage im, bi, bi2;
Graphics2D gfx;
int imWidth, imHeight, dstWidth, dstHeight;
int DESIRED_WIDTH = 500, DESIRED_HEIGHT = 500;

im = ImageIO.read(new File(filePath));
imWidth = im.getWidth(null);
imHeight = im.getHeight(null);

dstWidth = DESIRED_WIDTH;
dstHeight = (dstWidth * imHeight) / imWidth;

bi = new BufferedImage(dstWidth, dstHeight, im.getType());

gfx = bi.createGraphics();
gfx.drawImage(im, 0, 0, dstWidth, dstHeight, 0, 0, imWidth, imHeight, null);

bi2 = new BufferedImage(DESIRED_WIDTH, DESIRED_HEIGHT, im.getType());
gfx = bi2.createGraphics();

gfx.drawImage(bi, 0, 0, DESIRED_WIDTH, DESIRED_HEIGHT, null);

ImageIO.write(bi2, "jpg", new File(filePath));

我相信它可以改进和适应。

于 2017-07-29T10:39:23.927 回答
0

我尝试将 imgscalr 与标准 Java 1.6 进行比较,但我不能说它更好。

我试过的是

BufferedImage bufferedScaled = Scalr.resize(sourceImage, Method.QUALITY, 8000, height);

  Image scaled = sourceImage.getScaledInstance(-1, height, Image.SCALE_SMOOTH);
  BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null),  scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
  bufferedScaled.getGraphics().drawImage(scaled, 0, 0, null);

大约 5 分钟的测试让我觉得第二件事(纯 Java 1.6)会产生更好的结果。

于 2013-04-02T18:08:45.727 回答