20.1 处理缩略图片

在项目开发中,我们总是会遇到一些情况,需要接受客户端上传的图片,而客户端上传的图片总是格式不一致,为了方便存储,我们需要对图片进行一些统一处理,如大小压缩,质量压缩,透明度处理,添加水印等等操作。
这时候我们就需要一个工具来帮助我们完成这些事情,而Thumbnailator就一个这样的工具。

官方地址 https://github.com/coobird/thumbnailator

Thumbnailator 是一个优秀的图片处理的Google开源Java类库,从API提供现有的图像文件和图像对象的类中简化了处理过程,两三行代码就能够从现有图片生成处理后的图片,且允许微调图片的生成方式,同时保持了需要写入的最低限度的代码量,处理效果远比Java API的好。Thumbnailator还支持对一个目录的所有图片进行批量处理操作。

20.1.1 基础开发说明

20.1.1.1 依赖项目

下面是 Thumbnailator 的依赖

  1. <dependency>
  2. <groupId>net.coobird</groupId>
  3. <artifactId>thumbnailator</artifactId>
  4. <version>0.4.14</version>
  5. </dependency>

20.1.1.2 核心类

  • Thumbnails

Thumbnails类提供流畅接口(Fluent Interface)来创建缩略图。这是使用Thumbnailator的主要入口点。通过使用Thumbnailator的流畅接口(Fluent Interface)可以编写类似于书面英语的缩略图生成代码。

  • Thumbnails.Builder

Thumbnailator的Builder接口用来设置生成缩略图的任务。使用Thumbnailator的时候,通常先调用某一个Thumbnails.of(...) 方法,然后连接上诸如size(int, int)) 和 outputQuality(double))这样的方法去设置生成缩率图的参数。最终结果应该是类似于英语的代码。

根据实践规则, 要总是从Thumbnails.of开始链接操作方法直到调用输出方法 (如toFile、asBufferedImage等) ,不应将它们分解为单个语句

调用某个 Thumbnails.of(...)方法会内部类的实例。在大多数情况下,不应通过将返回的实例存储在局部变量中来使用它。如下文 “非预期用途” 示例所示, 这样的代码更冗长、更少面向未来,因为未来Thumbnailator内部实现中的更改将来可能会破坏代码。

期望的用法:
以下示例代码演示了如何使用流畅接口从目录中的多个文件创建缩略图,将它们的大小调整为最大200像素乘以200像素,同时保留原稿的纵横比,然后将生成的缩略图保存为JPEG图像,文件名前面加上thumbnail。

  1. // Intended use - recommended!
  2. Thumbnails.of(directory.listFiles())
  3. .size(200, 200)
  4. .outputFormat("jpeg")
  5. .asFiles(Rename.PREFIX_DOT_THUMBNAIL);

上面的代码用英语来表示就是:
Make thumbnails of files in the directory, with a size of 200x200, with output format of JPEG, and save them as files while renamingthe files to be prefixed with a ‘thumbnail.’.”

不期望的用法:

  1. // Unintended use - not recommended!
  2. Builder<File> instance = Thumbnails.of("path/to/image");
  3. instance.size(200, 200);
  4. instance.asFiles("path/to/thumbnail");

20.1.2 常用方法

本节处理Thumbnailator常用处理缩率图的方法。多数方法一般在调用链上只能被执行一次,否则会发生 IllegalStateException 异常(具体的请参加官方文档)。

20.1.2.1 获得实例

在处理钱,首先要通过调用下面的某个方法获得Thumbnails.Builder类的实例

// Sets the height of the thumbnail. Thumbnails.Builder height(int height)

// Sets the width of the thumbnail. Thumbnails.Builder width(int width)

  1. 默认情况下,会在保持当前长宽比例的前提下按照如下的选择缩小(不放大):
  2. - 若图片横比width小,高比height小,不变
  3. - 若图片横比width小,高比height大,高缩小到height,图片比例不变
  4. - 若图片横比width大,高比height小,横缩小到width,图片比例不变
  5. - 若图片横比width大,高比height大,图片按比例缩小,横为width或高为height
  6. 特殊情况下,可以使用下面的方法强制指定目标图标的尺寸或忽略长宽比例:
  7. ```java
  8. // Sets the size of the thumbnail.
  9. Thumbnails.Builder<T> forceSize(int width, int height)
  10. // Sets whether or not to keep the aspect ratio of the original image for the thumbnail.
  11. Thumbnails.Builder<T> keepAspectRatio(boolean keep)

下面是实际使用的范例:

  1. Thumbnails.of("images/a_1280x1024.jpg")
  2. .size(200, 300)
  3. .toFile("thumbnails/a_200x300.jpg");
  4. Thumbnails.of("images/a_1280x1024.jpg")
  5. .size(2560, 2048)
  6. .toFile("thumbnails/a_2560x2048.jpg");
  7. Thumbnails.of("images/a_1280x1024.jpg")
  8. .size(200,200)
  9. .keepAspectRatio(false)
  10. .toFile("thumbnails/a_200x200.jpg");

20.1.2.3 按比例缩放

下面的方法可以把图片按照指定的比例进行缩小

  1. // Sets the scaling factor of the thumbnail.
  2. Thumbnails.Builder<T> scale(double scale)
  3. // Sets the scaling factor for the width and height of the thumbnail.
  4. Thumbnails.Builder<T> scale(double scaleWidth, double scaleHeight)
  5. // Sets the resizing scaling mode to use when creating the thumbnail.
  6. Thumbnails.Builder<T> scalingMode(ScalingMode config)

ScalingMode是一个定义缩放算法的枚举类型,它有下面三个值

  • ScalingMode.BICUBIC 使用双三插值
  • ScalingMode.BILINEAR 使用双线性插值
  • ScalingMode.PROGRESSIVE_BILINEAR 使用进度双线性插值

下面是实际使用的范例:

  1. Thumbnails.of("images/a_1280x1024.jpg")
  2. .scale(0.25f)
  3. .toFile("thumbnails/a_025.jpg");
  4. Thumbnails.of("images/a_1280x1024.jpg")
  5. .scale(1.10f)
  6. .toFile("thumbnails/a_110.jpg");

20.1.2.4 旋转图片

下面的方法可以旋转图片

  1. // Sets the amount of rotation to apply to the thumbnail.
  2. Thumbnails.Builder<T> rotate(double angle)

缩略图将按指定的角度顺时针旋转。可以多次调用此方法以应用多次旋转。如果要应用多个旋转,将按照调用此方法的顺序应用旋转。

下面是实际使用的范例:

  1. //rotate(角度),正数:顺时针负数:逆时针
  2. Thumbnails.of("images/a_1280x1024.jpg")
  3. .size(1280,1024)
  4. .rotate(90)
  5. .toFile("thumbnails/a_rotate+90.jpg");
  6. Thumbnails.of("images/a_1280x1024.jpg")
  7. .size(1280,1024)
  8. .rotate(-90)
  9. .toFile("thumbnails/a_rotate-90.jpg");

20.1.2.5 裁剪部分图片

下面的方法指定要从中创建缩略图的源区域。

  1. Thumbnails.Builder<T> sourceRegion(int x, int y, int width, int height)
  2. Thumbnails.Builder<T> sourceRegion(Position position, int width, int height)
  3. Thumbnails.Builder<T> sourceRegion(Position position, Size size)
  4. Thumbnails.Builder<T> sourceRegion(Rectangle region)
  5. Thumbnails.Builder<T> sourceRegion(Region sourceRegion)

下面是实际使用的范例:

  1. //图片中心400*400的区域
  2. Thumbnails.of("images/a380_1280x1024.jpg")
  3. .sourceRegion(Positions.CENTER,400,400)
  4. .size(200,200)
  5. .keepAspectRatio(false)
  6. .toFile("thumbnails/a_region_center.jpg");
  7. //图片右下400*400的区域
  8. Thumbnails.of("images/a_1280x1024.jpg")
  9. .sourceRegion(Positions.BOTTOM_RIGHT,400,400)
  10. .size(200,200)
  11. .keepAspectRatio(false)
  12. .toFile("thumbnails/a_region_bootom_right.jpg");
  13. //指定坐标
  14. Thumbnails.of("images/a_1280x1024.jpg")
  15. .sourceRegion(600,500,400,400)
  16. .size(200,200)
  17. .keepAspectRatio(false)
  18. .toFile("thumbnails/a_region_coord.jpg");

20.1.2.6 附加水印

下面的方法可以给生成的缩率图加上水印

// Sets the image of the watermark to apply on the thumbnail. 
Thumbnails.Builder<T> watermark(BufferedImage image)

// Sets the image and opacity of the watermark to apply on the thumbnail.
Thumbnails.Builder<T> watermark(BufferedImage image, float opacity)

// Sets the image and opacity and position of the watermark to apply on the thumbnail.
Thumbnails.Builder<T> watermark(Position position, BufferedImage image, float opacity)

// Sets the image, opacity, position and insets for the watermark to apply on to the thumbnail.
Thumbnails.Builder<T> watermark(Position position, BufferedImage image, float opacity, int insets) 

// Sets the watermark to apply on the thumbnail.          
Thumbnails.Builder<T> watermark(Watermark w)

下面是实际使用的范例:

//watermark(位置,水印图,透明度) 
Thumbnails.of("images/a_1280x1024.jpg") 
  .size(1280,1024) 
  .watermark(Positions.BOTTOM_RIGHT,ImageIO.read(newFile("images/watermark.png")),0.5f) 
  .outputQuality(0.8f) 
  .toFile("thumbnails/a_watermark_bottom_right.jpg"); 

Thumbnails.of("images/a_1280x1024.jpg") 
  .size(1280,1024) 
  .watermark(Positions.CENTER,ImageIO.read(newFile("images/watermark.png")),0.5f) 
  .outputQuality(0.8f) 
  .toFile("thumbnails/a_watermark_center.jpg");

20.1.2.7 设置输出规则

下面的的方法可以设置渲染模式、输出文件格式、输出质量、是否允许覆盖、是否保留Exif信息等

// Sets the rendering mode when performing the resizing operation to generate the thumbnail.
Thumbnails.Builder<T> rendering(Rendering config) 

// Sets the compression format to use when writing the thumbnail.
Thumbnails.Builder<T> outputFormat(String format) 

// Sets the output quality of the compression algorithm used to compress the thumbnail when it is written to an external destination such as a file or output stream.
Thumbnails.Builder<T> outputQuality(double quality) 

// Sets the output quality of the compression algorithm used to compress the thumbnail when it is written to an external destination such as a file or output stream.          
Thumbnails.Builder<T> outputQuality(float quality) 

// Specifies whether or not to overwrite files which already exist if they have been specified as destination files.
Thumbnails.Builder<T> allowOverwrite(boolean allowOverwrite) 

// Sets whether or not to use the Exif metadata when orienting the thumbnail.
Thumbnails.Builder<T> useExifOrientation(boolean useExifOrientation) 

// Sets the compression format to use the same format as the original image.
Thumbnails.Builder<T> useOriginalFormat()

rendering的参数是关于渲染方式的枚举类型,它的取值及含义如下:

  • Rendering.DEFAULT 默认方式
  • Rendering.QUALITY 质量优先
  • Rendering.SPEED 速度优先

Thumbnailator支持所有javax.imageio.ImageIO支持的格式,可以通过下面的代码获得这些格式的内容

String[] formatNames = ImageIO.getWriterFormatNames();

System.out.println(Arrays.toString(formatNames));

对于Java 11来说,上面代码输出的结果为 [JPG, jpg, tiff, bmp, BMP, gif, GIF, WBMP, png, PNG, JPEG, tif, TIF, TIFF, jpeg, wbmp]

图片的质量参数是一个 0.0d1.0d 之间的数值,0.0d 代表最低质量,1.0d 代表最高质量。

下面是实际使用的范例:

Thumbnails.of("images/a_1280x1024.jpg") 
  .size(1280,1024) 
  .outputFormat("png") 
  .toFile("thumbnails/a_1280x1024.png"); 

Thumbnails.of("images/a_1280x1024.jpg") 
  .size(1280,1024) 
  .outputFormat("gif") 
  .toFile("thumbnails/a_1280x1024.gif");

20.1.2.8 图片处理算法

下面的方法可以对差值、抗锯齿、抖动等算法进行设置

// Sets the alpha interpolation mode when performing the resizing operation to generate the thumbnail.
Thumbnails.Builder<T> alphaInterpolation(AlphaInterpolation config)

// Sets the antialiasing mode when performing the resizing operation to generate the thumbnail.
Thumbnails.Builder<T> antialiasing(Antialiasing config)

// Sets the dithering mode when performing the resizing operation to generate the thumbnail.
Thumbnails.Builder<T> dithering(Dithering config)

20.1.2.9 输出结果图片

下面的方法用来指定输出结果的目标。目标可以是File对象、具体的文件路径或者一个输出流(用来通过HTTPresponse推给客户端)


// Create a thumbnail and writes it to a File.
void toFile(File outFile)

//Create a thumbnail and writes it to a File.
void toFile(String outFilepath)

// Creates thumbnails and stores them to files in the directory specified by the given File object, and using the Rename function to determine the filenames.
void toFiles(File destinationDir, Rename rename)

// Creates the thumbnails and stores them to the files.
void toFiles(Iterable<File> iterable)

// Creates thumbnails and stores them to files using the Rename function to determine the filenames.
void toFiles(Rename rename)

// Create a thumbnail and writes it to a OutputStream.
void toOutputStream(OutputStream os)

// Creates the thumbnails and writes them to OutputStreams provided by the Iterable.
void toOutputStreams(Iterable<? extends OutputStream> iterable)

前面的示例均直接输出到指定文件,下面是其它方法的范例:

//输出到 OutputStreamos
Thumbnails.of("images/a380_1280x1024.jpg") 
  .size(1280,1024) 
  .toOutputStream(response.getOutputStream());

//asBufferedImage()返回BufferedImage 
BufferedImagethumbnail=Thumbnails.of("images/a380_1280x1024.jpg") 
  .size(1280,1024) 
  .asBufferedImage(); 
ImageIO.write(thumbnail,"jpg",newFile("c:/a380_1280x1024_BufferedImage.jpg"));

20.1.3 对整个目录进行操作

Thumbnailator 可以操作指定文件夹下所有图片生成缩略图:

Thumbnails.of(new File("path/to/directory")
  .listFiles())         
  .size(640, 480)         
  .outputFormat("jpg")         
  .toFiles(Rename.PREFIX_DOT_THUMBNAIL);

20.1.4 简单功能测试

下面测试代码有两个方法,一个列出当前支持的全部图片格式,另外一个方法是从一个 jpg 图片生成 png 格式的缩略图:

package com.longser.union.cloud.thumbnailator;

import net.coobird.thumbnailator.Thumbnails;
import org.junit.jupiter.api.Test;

import javax.imageio.ImageIO;
import java.io.IOException;
import java.util.Arrays;

public class ThumbnailatorTest {

    @Test
    public void getFormatList() {
        String[] formatNames = ImageIO.getWriterFormatNames();
        System.out.println(Arrays.toString(formatNames));
    }

    @Test
    public void test() throws IOException {
        Thumbnails.of("src/main/resources/static/007.jpg")
                .size(490,326)
                .outputFormat("png")
                .toFile("src/main/resources/static/t_007.png");
    }

}

getFormatList 方法执行的结果可以看到,支持的格式很是很丰富的

[JPG, jpg, tiff, bmp, BMP, gif, GIF, WBMP, png, PNG, JPEG, tif, TIF, TIFF, jpeg, wbmp]

20.1.5 其他问题

有时候Thumbnailator可能会报错 heap 不足,此时可以指定 jvm 启动参数大一些:

-Xms1G

若PNG、GIF 格式图片中含有透明背景,Thumbnailator会把背景处理成黑色,这是 Thumbnailator 的一个 bug,可以通过指定 imageType 的方式来解决

Thumbnails.of("a.png")
    .imageType(BufferedImage.TYPE_INT_ARGB)
    .size(300, 200)
    .outputFormat("png")
    .toFile(destFile);

最后,我们要明白Thumbnailator如其名字一样,它主要设计用途是生成图片的缩率图(或者说减小图片尺寸)。他并不具备图文叠加、色彩处理等图片处理功能。

20.2 处理图片合成

基于营销或传播的目的,后端开发有时会遇到处理图片合成的需求。图片合成本身并不是什么高深的技术,但用底层 API 去搞确实繁琐。为简化开发,图处理图片合成可以使用一个小型项目 ImageCombiner

ImageCombiner是一个专门用于Java服务端图片合成的工具,没有很复杂的功能,简单实用,从实际业务场景出发,提供简单的接口,几行代码即可实现图片拼合(当然用于合成水印也可以),素材上支持图片、文本、矩形三种,支持定位、缩放、旋转、圆角、透明度、颜色、字体、字号、删除线、居中绘制、文本自动换行等特性,足够覆盖图片合成的日常需求。

下面是它的效果
image.png
ImageCombiner使用起来相当简单,主要的类只用一个,new一个ImageCombiner对象,指定背景图片和输出格式,然后加入各种素材元素,设置元素的位置、大小和效果(如圆角、颜色、透明度等),调用combine()方法即可。combine()方法直接返回BufferedImage对象,也可以调用getCombinedImageStream()获得流,方便上传oss等后续操作,或者调用save()方法保存到本地,调试的时候比较方便。[

](https://github.com/coobird/thumbnailator)
更详细的内容这里不再赘述,请去项目网站阅读:http://dromara.gitee.io/image-combiner/

版权说明:本文由北京朗思云网科技股份有限公司原创,向互联网开放全部内容但保留所有权力。