如何使用Java快速地给图片转码和生成缩略图(Thumbnailator和webp-imageio-core的使用)

文章简介

本文中介绍,如何使用Java优雅处理图片;包括:主流图片格式转码、图片压缩(缩略图生成)等。主要用到的外部工具包:

  • Google Thumbnailator
  • webp-imageio-core

本文同步博客图文( ´▽`):https://www.mintimate.cn/2021/01/19/JavaDealWithImage
同时,同步发布在腾讯云社区:https://cloud.tencent.com/developer/article/1779344

在线演示

搭建了一个在线演示地址:https://image.mintimate.cn/

视频教程

和以前一样,我们觉得有用、有必要录个视频的内容,我们还是会花时间做个视频:
B站视频:视频原链接,望投币嗷:https://www.bilibili.com/video/BV1nT4y1K7E6

腾讯云社区视频:视频链接地址,望点赞嗷:https://cloud.tencent.com/developer/video/10496

图片转码/生成缩略图

原理

本次博客使用的Thumbnailator包,实际上是封装好的类和方法,基于Java的Image I/O APIJava 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 2000
  • Write: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进行处理的。

如何安装

首先添加lib包,如果你是Maven工程,或者使用Maven管理的项目,添加依赖:


  net.coobird
  thumbnailator
  [0.4, 0.5)

上面的依赖项定义是获取0.4.x版本范围内的Thumbnailator的最新可用版本。如果需要特定版本的Thumbnailator,则将[0.4,0.5)替换为特定版本号,例如0.4.13
如何使用Java快速地给图片转码和生成缩略图(Thumbnailator和webp-imageio-core的使用)_第1张图片
另外,如果下载太慢,可以把Maven换成国内下载源(比如:阿里Maven镜像源)

如果你不是Maven工程,可以下载Thumbnailator的最新版本,如何手动添加lib包,最新版本Thumbnailator下载:https://github.com/coobird/thumbnailator/releases/latest

如何使用

Thumbnailator的使用十分简单,原本你需要使用Java的Image I/O APIBufferedImagesGraphics2D来处理图片,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"));

实操演示

我在我网站上使用上述包,搭建了一个在线演示地址:https://image.mintimate.cn/

功能:用户上传图片后,系统更具用户的选择的输出格式,转码图片。

扩展名判断

前端传送图片到后台,我们后台可以对文件扩展名进行判断:

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;
    }
}

这样,就可以成功转码图片了(运用恰当,还可以压缩图片( ;´Д`)):
如何使用Java快速地给图片转码和生成缩略图(Thumbnailator和webp-imageio-core的使用)_第2张图片
左边为原图,右边为转码后图片。这个是大小不变情况下,图片质量变为原来80%;主要文件大小变小,是Webp格式带来的。下文我们介绍一下Java转码Webp格式。

Java处理Webp格式

什么是Webp格式

根据Wiki百科:WebP(发音:weppy])是一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式,派生自影像编码格式,被认为是WebM多媒体格式的姊妹项目,是由Google在购买On2 Technologies后发展出来,以BSD授权条款发布。
而Webp具有的优势,显而易见:

  • 更优的图像数据压缩算法
  • 更小的图片体积
  • 肉眼识别无差异的图像质量
  • 无损和有损的压缩模式
  • Alpha 透明以及动画的特性
    简单地说,它可以像PNG格式一样,保存无损画质,并保持图片透明特性;同时,可以像JPG一样,压缩图片。Webp在同等情况下,文件体积比PNG小,甚至比JPG还小。

Java如何支持Webp格式

因为Webp,实际上是Google开发的,所以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

可以参考项目:https://github.com/scijava/native-lib-loader
当然,你也可以直接用大神整合好的lib包,比如:webp-imageio-core;下文就详解如何使用。

webp-imageio-core使用

因为webp-imageio-core并没有发布到Maven中央仓库,所以使用Maven骨架用户需要自己添加lib依赖
首先下载webp-imageio-core的jar发布包,下载地址:https://github.com/nintha/webp-imageio-core/releases
之后添加自定义:

  
    com.github.nintha  
    webp-imageio-core  
    {version}  
    system  
    ${pom.basedir}/libs/webp-imageio-core-{version}.jar  

比如:我的项目,添加本地lib:
如何使用Java快速地给图片转码和生成缩略图(Thumbnailator和webp-imageio-core的使用)_第3张图片
这个时候,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();
        }
}

最后

感兴趣可以关注B站:Mintimate;
如果想进一步处理图片,需要基于系统工具包了:
比如:ImageMagick
ImageMagick其实是真正全功能图片处理,但是Java调用前,系统需要预先安装ImageMagick,且Mac、Linux和Windows上调用方法有差异,有机会给大家介绍( ̀⌄ ́)

你可能感兴趣的:(#,Mintimate的博文,java,maven)