我需要调整 PNG、JPEG 和 GIF 文件的大小。如何使用 Java 做到这一点?
17 回答
FWIW 我刚刚发布了(Apache 2,托管在 GitHub 上)一个简单的 Java 图像缩放库,称为imgscalr(可在Maven central上获得)。
该库实现了几种不同的图像缩放方法(包括 Chris Campbell 的增量方法,并进行了一些小的改进),如果您要求,它会为您选择最优化的方法,或者为您提供最快或最好看的方法(如果您要求)。
用法非常简单,只是一堆静态方法。最简单的用例是:
BufferedImage scaledImage = Scalr.resize(myImage, 200);
所有操作都保持图像的原始比例,因此在这种情况下,您要求 imgscalr 在 200 像素宽和 200 像素高的范围内调整图像大小,默认情况下,它会自动选择最好看和最快的方法,因为它是'未指定。
我一开始就意识到这看起来像是自我推销(确实如此),但我花了相当多的时间在谷歌上搜索这个完全相同的主题,并不断提出不同的结果/方法/想法/建议,并决定坐下来写一篇简单的实现可以解决 80-85% 的用例,在这些用例中,您有一张图片并且可能想要一个缩略图——要么尽可能快,要么尽可能好看(对于那些尝试过的人,你会注意到即使使用 BICUBIC 插值对足够小的图像进行 Graphics.drawImage,它仍然看起来像垃圾)。
加载图像后,您可以尝试:
BufferedImage createResizedCopy(Image originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
System.out.println("resizing...");
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
Thumbnailator是一个用于 Java 的开源图像大小调整库,具有流畅的界面,在MIT 许可下分发。
我编写这个库是因为在 Java 中制作高质量的缩略图非常困难,而且生成的代码可能非常混乱。借助 Thumbnailator,可以使用简单流畅的 API 表达相当复杂的任务。
一个简单的例子
举个简单的例子,拍摄一张图像并将其调整为 100 x 100(保留原始图像的纵横比),然后将其保存到文件中,可以在单个语句中实现:
Thumbnails.of("path/to/image")
.size(100, 100)
.toFile("path/to/thumbnail");
一个高级的例子
Thumbnailator 的流畅界面简化了复杂的调整大小任务。
假设我们要执行以下操作:
- 获取目录中的图像,然后,
- 使用原始图像的纵横比将它们调整为 100 x 100,
- 将它们全部保存为质量设置为 的 JPEG
0.85
, - 文件名取自原始文件名
thumbnail.
并附加到开头
翻译成 Thumbnailator,我们可以通过以下方式执行上述操作:
Thumbnails.of(new File("path/to/directory").listFiles())
.size(100, 100)
.outputFormat("JPEG")
.outputQuality(0.85)
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
关于图像质量和速度的说明
该库还使用Chet Haase 和 Romain Guy 在Filthy Rich Clients中强调的渐进式双线性缩放方法,以生成高质量的缩略图,同时确保可接受的运行时性能。
你不需要图书馆来做到这一点。您可以使用 Java 本身来完成。
Chris Campbell 有一篇关于缩放图像的出色而详细的文章 - 请参阅这篇文章。
Chet Haase 和 Romain Guy 在他们的书《 Filthy Rich Clients》中也有关于图像缩放的详细且内容丰富的文章。
Java Advanced Imaging现在是开源的,并提供您需要的操作。
如果您正在处理大图像或想要一个漂亮的结果,那么在 java 中这不是一项简单的任务。简单地通过 Graphics2D 进行重新缩放操作不会创建高质量的缩略图。你可以使用 JAI 来做,但是它需要比你想象的更多的工作才能得到看起来不错的东西,而且 JAI 有一个讨厌的习惯,就是用 OutOfMemory 错误来炸毁我们的 JVM。
如果您可以摆脱它,我建议使用 ImageMagick 作为外部可执行文件。它使用简单,并且可以正确完成工作,因此您不必这样做。
如果可以选择在您的机器上安装 imagemagick,我推荐im4java。它是命令行界面上的一个非常薄的抽象层,但它的工作做得很好。
Java API 不为图像和降级图像质量提供标准缩放功能。
因此,我尝试使用 JavaCV 中的 cvResize ,但它似乎会导致问题。
我找到了一个很好的图像缩放库:只需在 pom.xml 中添加“java-image-scaling”的依赖项。
<dependency>
<groupId>com.mortennobel</groupId>
<artifactId>java-image-scaling</artifactId>
<version>0.8.6</version>
</dependency>
在 Maven 存储库中,您将获得最新版本。
前任。在你的 java 程序中
ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
您可以尝试使用带有im4java的GraphicsMagick 图像处理系统作为 Java 的命令行接口。
GraphicsMagick 有很多优点,但只有一个优点:
- GM 用于处理世界上最大的照片网站(例如 Flickr 和 Etsy)上的数十亿个文件。
已经提到了 Image Magick。有一个名为 JMagick 的 JNI 前端项目。这不是一个特别稳定的项目(众所周知,Image Magick 本身会发生很大变化,甚至会破坏兼容性)。也就是说,我们在生产环境中使用 JMagick 和兼容版本的 Image Magick 以高吞吐量、低延迟率执行缩放有很好的经验。与我们之前尝试过的全 Java 图形库相比,速度要好得多。
您可以使用 Marvin(纯 Java 图像处理框架)进行此类操作: http: //marvinproject.sourceforge.net
缩放插件: http: //marvinproject.sourceforge.net/en/plugins/scale.html
只需使用 Burkhard 的答案,但在创建图形后添加这一行:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
您也可以将值设置为 BICUBIC,它会产生质量更好的图像,但操作成本更高。您可以设置其他渲染提示,但我发现插值会产生最显着的效果。请记住,如果您想放大很多,java 代码很可能会很慢。我发现较大的图像开始产生大约 300% 的缩放延迟,即使所有渲染提示都设置为优化速度而不是质量。
事实证明,编写高性能缩放器并非易事。我为一个开源项目做过一次:ImageScaler。
原则上,'java.awt.Image#getScaledInstance(int, int, int)' 也可以完成这项工作,但有一个讨厌的错误 - 请参阅我的链接了解详细信息。
我开发了一个解决方案,其中包含可用于处理 GIF 动画的免费类(AnimatedGifEncoder、GifDecoder 和 LWZEncoder)。
您可以下载 jgifcode jar 并运行 GifImageUtil 类。链接: http ://www.jgifcode.com
您可以使用以下流行产品:thumbnailator
如果您不想像上面我测试过的@Riyad Kalla 答案那样导入imgScalr也可以正常工作,那么您可以从Peter Walser 的答案@Peter Walser 中获取关于另一个问题的答案:
/**
* utility method to get an icon from the resources of this class
* @param name the name of the icon
* @return the icon, or null if the icon wasn't found.
*/
public Icon getIcon(String name) {
Icon icon = null;
URL url = null;
ImageIcon imgicon = null;
BufferedImage scaledImage = null;
try {
url = getClass().getResource(name);
icon = new ImageIcon(url);
if (icon == null) {
System.out.println("Couldn't find " + url);
}
BufferedImage bi = new BufferedImage(
icon.getIconWidth(),
icon.getIconHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
// paint the Icon to the BufferedImage.
icon.paintIcon(null, g, 0,0);
g.dispose();
bi = resizeImage(bi,30,30);
scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
imgicon = new ImageIcon(scaledImage);
} catch (Exception e) {
System.out.println("Couldn't find " + getClass().getName() + "/" + name);
e.printStackTrace();
}
return imgicon;
}
public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
float scaleX = (float) areaWidth / image.getWidth();
float scaleY = (float) areaHeight / image.getHeight();
float scale = Math.min(scaleX, scaleY);
int w = Math.round(image.getWidth() * scale);
int h = Math.round(image.getHeight() * scale);
int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
boolean scaleDown = scale < 1;
if (scaleDown) {
// multi-pass bilinear div 2
int currentW = image.getWidth();
int currentH = image.getHeight();
BufferedImage resized = image;
while (currentW > w || currentH > h) {
currentW = Math.max(w, currentW / 2);
currentH = Math.max(h, currentH / 2);
BufferedImage temp = new BufferedImage(currentW, currentH, type);
Graphics2D g2 = temp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(resized, 0, 0, currentW, currentH, null);
g2.dispose();
resized = temp;
}
return resized;
} else {
Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;
BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resized.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(image, 0, 0, w, h, null);
g2.dispose();
return resized;
}
}
试试下面的方法:
ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);