通过 使用 zxing 生成二维码 我们可以实现简单二维码的生成, 但是二维码显示却过于单调, 本文变讲述如何利用 thumbnailator 为我们的二维码添加 LOGO
thumbnailator 是一个缩略图工具类库, 但它除了能缩略图片外, 还提供裁剪, 旋转, 水印等功能, 此次我们便借助它的水印 API 实现以上需求
项目环境
- jdk1.8
- thumbnailator
1 | <dependency> |
操作步骤
生成
- 准备一张二维码图片, 一张 logo 图片
1
2String qrCodeFilePath = "src/qrCode.jpg";
String logoFilePath = "src/logo.jpg";
根据文件路径生成一个图片构造对象(
Thumbnails.of()
方法还可以接收BufferedImage
,InputStream
,URL
,String
的可变参数类型)1
Thumbnails.Builder<File> builder = Thumbnails.of(new File(qrCodeFilePath));
创建一个水印对象, 水印对象需要三个参数
Position position
,BufferedImage watermarkImg
,float opacity
, 其中Position
是水印的坐标,BufferedImage
是水印图片,opacity
是不透明度, 值为 [0-1] 之间, 1 代表不透明.1
2
3BufferedImage bufferedImage = ImageIO.read(new File(logoFilePath));
//Positions 实现了 Position 并提供九个坐标, 分别是 上左, 上中, 上右, 中左, 中中, 中右, 下左, 下中, 下右 我们使用正中的位置
Watermark watermark = new Watermark(Positions.CENTER, bufferedImage, 1F);为二维码设置水印, 并设置缩略比例为 1(即不压缩), 输出到一个新文件中(
outputFormat()
为指定输出格式, 如: jpg,png)1
builder.watermark(watermark).scale(1F).toFile(new File("src/logoQrCode.png"));
生成后的二维码
使用
通过以上方法我们能够简单的为二维码添加 LOGO, 但是实际使用时远没有这样简单, 有以下几个问题
logo 图片的尺寸可能并不固定, 可能有大有小, 这样就会导致 logo 在二维码中太小或太大
这时我们可以在创建BufferedImage
时将原图压缩 / 放大至指定尺寸, 也可以使用二维码的尺寸乘以一定比例1
2//forceSize(int width, int height) 指将图片强制压缩为指定宽高, 如不强制, 可使用 size(int width, int height)
BufferedImage bufferedImage = Thumbnails.of(new File(logoFilePath)).forceSize(120, 120).asBufferedImage();图片显示, logo 图片可能不是一个图片文件, 同时生成好之后的图片希望直接输出在页面上
Thumbnails.of()
可以接收BufferedImage
,InputStream
,URL
,String
,File
的可变 ( 批量处理需要 ) 参数类型ImageIO.read()
可以接收File
,ImageInputStream
,InputStream
,URL
参数类型
以下为 SpringMVC 动态生成带 LOGO 二维码示例,QRCodeUtil.toBufferedImage()
具体实现请看 生成二维码之 Java (Google zxing) 篇1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* @param content 二维码内容
* @param logoUrl logo 链接
*/
"/qrcode") (value =
public void qrcode(String content, String logoUrl, @RequestParam(defaultValue = "300") int width, @RequestParam(defaultValue = "300") int height,HttpServletResponse response) {
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
// 根据 QRCodeUtil.toBufferedImage() 返回的 BufferedImage 创建图片构件对象
Thumbnails.Builder<BufferedImage> builder = Thumbnails.of(QRCodeUtil.toBufferedImage(content, width, height));
// 将 logo 的尺寸设置为二维码的 30% 大小, 可以自己根据需求调节
BufferedImage logoImage = Thumbnails.of(new URL(logoUrl)).forceSize((int) (width * 0.3), (int) (height * 0.3)).asBufferedImage();
// 设置水印位置(居中), 水印图片 BufferedImage, 不透明度(1F 代表不透明)
builder.watermark(Positions.CENTER, logoImage, 1F).scale(1F);
// 此处需指定图片格式, 否者报 Output format not specified 错误
builder.outputFormat("png").toOutputStream(outputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}1
2
3
4
5
6
7
8
9
10/**
* 返回一个 BufferedImage 对象
* @param content 二维码内容
* @param width 宽
* @param height 高
*/
public static BufferedImage toBufferedImage(String content, int width, int height) throws WriterException, IOException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
return MatrixToImageWriter.toBufferedImage(bitMatrix);
}
拓展思考
以上案例可知 thumbnailator 水印功能的强大. 然而除了实现以上案例外, 我们也可以根据水印功能实现另外一种需求.
比如公司现在有一个推广需求, 让用户为我们的产品进行宣传, 达到多少次就进行奖励. 传统的实现方式是一段文字再配上一个专属链接. 但是此方式往往太过单调, 枯燥. 这个时候如果我们让设计提供一张内容丰富, 带有二维码的宣传图片, 然后根据专属链接生成二维码与宣传图片进行组合. 这时用户就有了一张自己的专属宣传图片. 此时通过直接宣传专属图片往往会比文字加链接有着更好的效果.
注: 此功能在图片合成时需要对二维码的位置进行定位, 此时可使用 Position
的实现类 Coordinate
完成
使用如下:1
2
3//Coordinate 存在一个 Coordinate(int x, int y) 构造函数, x 为水印距离底图左边的像素, y 为上边
BufferedImage bufferedImage = ImageIO.read(new File(logoFilePath));
Watermark watermark = new Watermark(new Coordinate(100, 100), bufferedImage, 1F);