「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
文章简介
有时候,我们项目需求,需要对业务图片生成小的缩略图,或者是对图片格式进行转码,大家会使用什么方法呢?
直接使用对象存储,把业务需求交给第三方?还是用javaScript对图片进行操作?
有没有试过后端直接处理呢?
本文中介绍,如何使用Java优雅处理图片;包括:主流图片格式转码、图片压缩(缩略图生成)、图片附带水印等。主要用到的外部工具包:
- Thumbnailator:老牌缩略图生成工具。
- webp-imageio-core:让Java支持Webp的读写。
如果你想支持更多图片,可以扩展Java图片IO流,这个以后再说……
视频教程
简单录制了一个视频,有需要可以转至b站:
6分钟学会使用Java“硬核”压缩和转码图片--图片转码和缩略图生成
图片转码/生成缩略图
原理
本次使用的Thumbnailator包,实际上是封装好的类和方法,基于Java的Image I/O API、Java 2D API等API接口实现。
所以,因为基于Java Image I/O API,所以支持的图片格式有限,但是已经满足绝大多数情况。 一般支持的格式如下:
Read:JPEG 2000, JPG, tiff, bmp, PCX, gif, WBMP, PNG, RAW, JPEG, PNM, tif, TIFF, wbmp, jpeg, jbig2, jpg, JPEG2000, BMP, pcx, GIF, png, raw, JBIG2, pnm, TIF, jpeg2000, jpeg 2000Write:JPEG 2000, JPG, tiff, bmp, PCX, gif, WBMP, PNG, RAW, JPEG, PNM, tif, TIFF, wbmp, jpeg, jpg, JPEG2000, BMP, pcx, GIF, png, raw, pnm, TIF, jpeg2000, jpeg 2000
很多文章作者,介绍这个包,居然还说支持Apple的
HEIC格式,这个是肯定不支持使用Thumbnailator进行处理的。除非能直接写一个转码器。但是这样,我觉得还不如调用ImageMagick。这个以后有机会给大家分享。
如何安装
首先添加lib包,如果你是Maven工程,或者使用Maven管理的项目,添加依赖:
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>[0.4, 0.5)</version>
</dependency>
复制代码 上面的依赖项定义是获取0.4.x版本范围内的Thumbnailator的最新可用版本。如果需要特定版本的Thumbnailator,则将[0.4,0.5)替换为特定版本号,例如0.4.13
另外,如果下载太慢,可以把Maven换成国内下载源(比如:阿里Maven镜像源)
如果你不是Maven工程,可以下载Thumbnailator的最新版本,如何手动添加lib包,最新版本Thumbnailator下载:github.com/coobird/thu…
如何使用
Thumbnailator的使用十分简单,原本你需要使用Java的Image I/O API、BufferedImages和Graphics2D来处理图片,Thumbnailator直接封装上述操作。简单的使用演示:
Thumbnails.of(new File("path/to/directory").listFiles())
.size(640, 480)
.outputFormat("jpg")
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
复制代码 - 原图片地址:
path/to/directory - 输出图片大小:
640*480 - 输出图片格式:
jpg - IO流输出地址(输出图片):
Rename.PREFIX_DOT_THUMBNAIL
图片转码
演示代码:
Thumbnails.of(originalImage).scale(scale)
.outputFormat("jpg")
.outputQuality(compression)
.toFile(thumbnailImage);
复制代码 其中:
scale是图片尺寸等比缩放,为float类型。outputFormat是输出图片的类型,注意:默认不支持webp,如果需要使用webp,需要提前安装webp-imageio-core,可以看看下文如何使Java支持Webp。outputQuality是输出图片的质量,即:清晰度/分辨率。
使用原图片生成缩略图
演示代码:
Thumbnails.of(new File("original.jpg"))
.size(160, 160)
.toFile(new File("thumbnail.jpg"));
复制代码 其中,原图片文件,可以使用字符串String来代替地址:
Thumbnails.of("original.jpg")
.size(160, 160)
.toFile("thumbnail.jpg");
复制代码 通常,缩略图输出体积已经很小,但是还是可以使用.outputQualit来降低图片质量(分辨率)。
旋转图片
很简单;添加.rotate即可。如:
Thumbnails.of(new File("original.jpg"))
.rotate(90)
.toFile(new File("image-with-watermark.jpg"));
复制代码 添加水印
添加水印也十分简单,添加.watermark即可:
Thumbnails.of(new File("original.jpg"))
.watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File("watermark.png")), 0.5f)
.toFile(new File("image-with-watermark.jpg"));
复制代码 实操演示
我在我网站上使用上述包,搭建了一个在线演示地址:tool.mintimate.cn/processIMG
功能:用户上传图片后,系统更具用户的选择的输出格式,转码图片。
扩展名判断
前端传送图片到后台,我们后台可以对文件扩展名进行判断:
String thumbnailImageName=originalImage.getName(); //缩略图输出名
String thumbnailImagePath; //缩略图输出地址
switch (format){
case "JPG":
thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/"
+ thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".jpg";
break;
case "PNG":
thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/"
+ thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".png";
break;
case "WEBP":
thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/"
+ thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".webp";
break;
case "BMP":
thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/"
+ thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".bmp";
break;
default:
thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/" + thumbnailImageName;
break;
}
复制代码 创建空白缩略图文件
虽然Thumbnailator可以直接自动根据String创建对应文件对象,但是为了更方便我们自己控制,我们手动创建:
File thumbnailImage = new File(thumbnailImagePath);
// 判断路径是否存在,如果不存在则创建
if (!thumbnailImage.getParentFile().exists()) {
thumbnailImage.getParentFile().mkdirs();
}
复制代码 转码图片
try {
switch (format){
case "JPG":
Thumbnails.of(originalImage).scale(scale)
.addFilter(new ThumbnailsImgFilter())
.outputFormat("jpg")
.outputQuality(compression)
.toFile(thumbnailImage);
break;
case "PNG":
Thumbnails.of(originalImage).scale(scale)
.outputFormat("png")
.outputQuality(compression)
.toFile(thumbnailImage);
break;
case "WEBP":
Thumbnails.of(originalImage).scale(scale)
.imageType(ThumbnailParameter.DEFAULT_IMAGE_TYPE)
.outputFormat("webp")
.outputQuality(compression)
.toFile(thumbnailImage);
break;
case "BMP":
Thumbnails.of(originalImage).scale(scale)
.addFilter(new ThumbnailsImgFilter())
.outputFormat("bmp")
.outputQuality(compression)
.toFile(thumbnailImage);
break;
default:
Thumbnails.of(originalImage).scale(scale)
.imageType(ThumbnailParameter.DEFAULT_IMAGE_TYPE)
.outputQuality(compression)
.toFile(thumbnailImage);
break;
}
} catch (IOException e) {
e.printStackTrace();
}
复制代码 因为,我是使用Springboot快速构建,我其实是创建了一个配置规则addFilter,可以使PNG透明图片转为JPG时,透明背景渲染为白色。(单纯为了好看……)。实现细节:
import net.coobird.thumbnailator.filters.ImageFilter;
import java.awt.*;
import java.awt.image.BufferedImage;
public class ThumbnailsImgFilter implements ImageFilter {
@Override
public BufferedImage apply(BufferedImage bufferedImage) {
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D graphic = newImage.createGraphics();
graphic.setColor(Color.white);//背景设置为白色
graphic.fillRect(0, 0, w, h);
graphic.drawRenderedImage(bufferedImage, null);
graphic.dispose();
return newImage;
}
}
复制代码 这样,就可以成功转码图片了(运用恰当,还可以压缩图片( ;´Д`)):
左边为原图,右边为转码后图片。这个是大小不变情况下,图片质量变为原来80%;主要文件大小变小,是Webp格式带来的。下文我们介绍一下Java转码Webp格式。
Java处理Webp格式
什么是Webp格式
根据Wiki百科:WebP(发音:weppy])是一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式,派生自影像编码格式,被认为是WebM多媒体格式的姊妹项目,是由Google在购买On2 Technologies后发展出来,以BSD授权条款发布。 而Webp具有的优势,显而易见:
- 更优的图像数据压缩算法
- 更小的图片体积
- 肉眼识别无差异的图像质量
- 无损和有损的压缩模式
- Alpha 透明以及动画的特性
简单地说,它可以像PNG格式一样,保存无损画质,并保持图片透明特性;同时,可以像JPG一样,压缩图片。Webp在同等情况下,文件体积比PNG小,甚至比JPG还小。
支持Webp格式
因为Webp,实际上是Google开发的,所以Java IO流设计之初就不支持Webp格式。
让Java IO流支持Webp的方法很多,这里介绍一种方法,有机会接受更多方法~
根据系统的不同,需要安装对应的依赖包:
/natives
/linux_32
libxxx[-vvv].so
/linux_64
libxxx[-vvv].so
/osx_32
libxxx[-vvv].dylib
/osx_64
libxxx[-vvv].dylib
/osx_arm64
libxxx[-vvv].dylib
/windows_32
xxx[-vvv].dll
/windows_64
xxx[-vvv].dll
/aix_32
libxxx[-vvv].so
libxxx[-vvv].a
/aix_64
libxxx[-vvv].so
libxxx[-vvv].a
复制代码 可以参考项目:github.com/scijava/nat… 当然,你也可以直接用大神整合好的lib包,比如:webp-imageio-core;下文就详解如何使用。
webp-imageio-core使用
因为webp-imageio-core并没有发布到Maven中央仓库,所以使用Maven骨架用户需要自己添加lib依赖 首先下载webp-imageio-core的jar发布包,下载地址:github.com/nintha/webp… 之后添加自定义<dependency>:
<dependency>
<groupId>com.github.nintha</groupId>
<artifactId>webp-imageio-core</artifactId>
<version>{version}</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/webp-imageio-core-{version}.jar</systemPath>
</dependency>
复制代码 比如:我的项目,添加本地lib:
这个时候,Java就已经支持处理Webp格式图片了。
实操使用
最简单的使用……其实是再加入上文所提到的Thumbnailator依赖包,便可以使用Thumbnailator直接处理图片IO流。 单独使用,我们可以用最传统的方法处理: 图片转WEBP:
public static void main(String args[]){
String srcFile = System.getProperty("user.dir") + "/file/Input/"+"Input.png" //原图地址
String webpFile = System.getProperty("user.dir") + "/file/Output/"+"Output.png" //输出地址
encodingToWebp(srcFile, webpFile);
}
public static void encodingToWebp(String srcFile, String webpFile) {
encodingToWebp(new File(srcFile),new File(webpFile) );
}
/**
* @param: srcFile
* @param: webpFile
* @description: 将文件编码为WEBP格式
* @author: Mintimate
*/
public static void encodingToWebp(File srcFile, File webpFile) {
try {
// Obtain an image to encode from somewhere
BufferedImage image = ImageIO.read(srcFile);
// Obtain a WebP ImageWriter instance
ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
// Configure encoding parameters
WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType(writeParam.getCompressionTypes()[WebPWriteParam.LOSSLESS_COMPRESSION]);
// Configure the output on the ImageWriter
writer.setOutput(new FileImageOutputStream(webpFile));
// Encode
writer.write(null, new IIOImage(image, null, null), writeParam);
//释放reader
writer.dispose();
//关闭文件流
fileImageOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码 最后
到此,使用Thumbnailator就可以优雅地处理图片了。
但是你会发现,有些情况图片处理(jpeg图片处理时)会偏红,处理方法很简单,可以用BufferedImage去写图片和读图片,这样就不会出现图片偏红或偏粉的失真情况。
有机会接受其他Java图片IO扩展包,让Java项目支持更多图片格式。

京公网安备 11010502036488号