原创

Java5分钟制作海报

一、需求背景

​ 我们经常在多终端应用开发中会遇到这样的需求:用户在浏览商品时觉得不错,希望分享给朋友。此时终端(安卓、苹果、H5等)生成一张精美的商品海报,通过微信或者其他途径分享给他人。也可能会遇到需求:制作个人名片打印出来或者分享给他人。效果大概是这样的: 在这里插入图片描述 也可能是这样 在这里插入图片描述 (上面的图都是我从网上临时找的,只做参考学习,避免广告已经做了部分处理。) 刚开始设计这个需求的时候,我们是在前端来完成的,即由安卓、IOS、H5、微信几个端的开发者自主实现功能。各端完成开发后发布到全网,很快就发现一些用户机型上出现了兼容性的问题(C端安卓机型有很多版本)。用户手机安卓版本从5.N到最新的版本、从ip6到最新款,最大跨度超10年,这种兼容性问题对我们来说无法预料。曾尝试使用的dom-to-image和html2canvas效果都不太理想,解决了白屏、跨域问题又遇到低版本不支持标签的问题…。一通折腾,最后我们决定在服务端将海报图片生成好,在终端直接显示图片。

二、用JAVA生成海报

从上面的三张海报,我选《美女》图,作为今天演示效果。(在做此演示时并没有使用之前项目上的图,我也是首次照着图在开发)。 首先将海报分别为3类,背景图、其他图、文字、二维码。 如: 1-底图纯白,2-商品介绍图,3-头像 素材,4-“严选”字样的图素材,5-带色的二维码,6-标题、价格等文字,实际开发中根据视觉和美工给的图即可。 先上我完成的最终效果: 在这里插入图片描述 简单做一下,大概和视觉图差不多了, 虽然有点糙但足以表达到效果。

2.1 Easy Poster 易海报生成器

​ 在开发海报过程中,我也找了不少资料,花费了较多时间,后来发现了Easy Poster的设计还是不错的。所以在开发结束以后,我对代码进行了重新整理完善:修复了一些问题,并增加了二维码功能,成为开箱即用的海报生成工具。 接下来,我将介绍一下如何用来快速的制作海报。 创建一个新的海报,只需要3步即可完成 修改pom.xml添加依赖和打包过滤字体库。 创建海报对象及配置相关属性。 传入参数,生成海报

2.2修改pom.xml添加依赖和打包过滤字体库。

pom.xml
<properties>
 <maven.compiler.source>8</maven.compiler.source>
 <maven.compiler.target>8</maven.compiler.target>
 <lombok.version>1.16.18</lombok.version>
 <hutool-all.version>5.7.19</hutool-all.version>
 <zxing.version>3.4.1</zxing.version>
 <testng.version>6.8.8</testng.version>
 <slf4j.version>1.7.13</slf4j.version>
</properties>
<dependencies>
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>${lombok.version}</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 <version>${slf4j.version}</version>
 </dependency>
 <!-- 二维码生成 -->
 <dependency>
 <groupId>com.google.zxing</groupId>
 <artifactId>core</artifactId>
 <version>${zxing.version}</version>
 </dependency>
 <dependency>
 <groupId>cn.hutool</groupId>
 <artifactId>hutool-all</artifactId>
 <version>${hutool-all.version}</version>
 </dependency>
 <dependency>
 <groupId>org.testng</groupId>
 <artifactId>testng</artifactId>
 <version>${testng.version}</version>
 <scope>test</scope>
 </dependency>
</dependencies>
<!-- SpringBoot项目的maven项目引用的字体库font经过maven的filter,会破坏font文件的二进制文件格式 -->
<build>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-resources-plugin</artifactId>
 <configuration>
 <nonFilteredFileExtensions>
 <nonFilteredFileExtension>ttf</nonFilteredFileExtension>
 <nonFilteredFileExtension>woff</nonFilteredFileExtension>
 <nonFilteredFileExtension>woff2</nonFilteredFileExtension>
 </nonFilteredFileExtensions>
 </configuration>
 </plugin>
 </plugins>
</build>
*注意:我们海报用到了字体作为资源文件引入,在经过maven的filter,会破坏font文件的二进制文件格式 导致打包异常,此处要一定要注意。

2.3 创建海报对象及配置相关属性

CommodityPosterPojo.java
package com.naiqing.poster.demo;

import com.quaint.poster.annotation.PosterBackground;
import com.quaint.poster.annotation.PosterBarCodeCss;
import com.quaint.poster.annotation.PosterFontCss;
import com.quaint.poster.annotation.PosterImageCss;
import com.quaint.poster.core.abst.AbstractDefaultPoster;
import com.quaint.poster.core.dto.PosterBarcode;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Tolerate;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 〈商品分享海报元素及相关参数定义〉<br>
 *
 * @author naiqing
 * @Date 2022/1/21
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
public class CommodityPoster2Pojo extends AbstractDefaultPoster {

 /**
 * 背景图
 */
 @PosterBackground(width = 540, height = 868)
 private BufferedImage backgroundImage;

 /**
 * 商品图
 */
 @PosterImageCss(position = {0, 0}, width = 540, height = 614)
 private BufferedImage commodityImage;

 /**
 * 严选图标
 */
 @PosterImageCss(position = {16, 625}, width = 50, height = 28)
 private BufferedImage yanxuanImage;
 /**
 * 商品标题
 */
 @PosterFontCss(position = {16, 625}, size = 22, canNewLine = {1, 482, 2}, style = Font.BOLD)
 private String commodityTitle;

 /**
 * 特权价
 */
 @PosterFontCss(position = {16, 706}, size = 20, color = {247,23,61})
 private String vipPrice;
 /**
 * 原价
 */
 @PosterFontCss(position = {16, 742}, size = 15, color = {51, 51, 51}, delLine = true)
 private String oldPrice;

 /**
 * 头像
 */
 @PosterImageCss(position = {10, 780}, width = 55, height = 55, circle = true)
 private BufferedImage headImage;

 /**
 * 昵称
 */
 @PosterFontCss(position = {77, 788}, color = {85,85,85}, name = "腾祥爱情体细简", style = Font.BOLD)
 private String nickName;
 /**
 * 昵称下的描述
 */
 @PosterFontCss(position = {75, 813}, size = 15, color = {104,104,104}, name = "腾祥爱情体细简")
 private String nickDesc;


 /**
 * 二维码
 */
 @PosterBarCodeCss(position = {376, 695}, width = 130, height = 130, foreColor = {17,125,124})
 private PosterBarcode qrCode;

 /**
 * 二维码字
 */
 @PosterFontCss(position = {386, 833}, size = 20, color = {104,104,104}, center = true)
 private String qrCodeText;

 @Tolerate
 public CommodityPoster2Pojo() {
 }
}


此处定义了海报全部的元素,通过注解:背景图片@PosterBackground、其他图片@PosterImageCss、字体 @PosterFontCss和二维码@PosterBarCodeCss,来配置位置、宽度等参数(更多参数可通过源码了解)。
@PosterBarCodeCss 二维码注解,只适用类PosterBarcodeDto
@PosterBackground 背景图片注解、@PosterImageCss,只适用类BufferedImage
@PosterFontCss文字注解,只适用类String

2.4如何快速得到x\y坐标和width\heigth尺寸

正常来说,视觉稿给到我们开发的时候,页面上都是可以快速得到每个元素的位置和尺寸,但此处因为是从网上找到整图,所以只能自己动手了。 此处我是通过ps打开图片,打开”窗口-信息“,可以查看到鼠标的坐标及圈选的尺寸,如下图可以快速得到各元素的位置: 在这里插入图片描述

2.5 传入参数,生成海报

1) 加载字体库 在此调用生成海报之前,我们要将用到的字体库放到项目中,比如说我这里用到了2个字体库:resources\fonts\simkai.ttf和resources\fonts\TTAiQingXiJ_0.ttf。 这里我要特别说明:如果不加载字体库在windows下也是可以直接使用的(会默认使用宋体),但是在将服务发布到服务器下Linux时所有中文都会乱码,因为Linux下并没有相应字体库。 2)生成海报 我用一个单元测试来实现海报生成调用示范,传入商品名称相关信息
package com.naiqing.poster.demo;

import com.quaint.poster.core.dto.PosterBarcode;
import com.quaint.poster.core.impl.PosterBarcodeImpl;
import lombok.SneakyThrows;
import org.testng.annotations.Test;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;

/**
 * 〈测试海报〉<br>
 *
 * @author naiqing
 * @Date 2022/1/22
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class CommodityPoster2Test {

 @SneakyThrows
 @Test
 public void testCreate() {
 //背景图,此处测试我是用的本地图,实际开发可换成网络获取图片(下面有示例)
 BufferedImage backgroundImage = ImageIO.read(new File("D:\\temp\\s_bg.jpg"));
 //商品主图
 BufferedImage commodityImage = ImageIO.read(new File("D:\\temp\\s_commodity.jpg"));
 //严选图标
 BufferedImage yanxuanImage = ImageIO.read(new File("D:\\temp\\s_yanxuan.jpg"));
 //头像
 BufferedImage headImage = ImageIO.read(new File("D:\\temp\\s_head.jpg"));
 //二维码logo
 BufferedImage qrLogo = headImage;
 //二维码内容
 String qrContent = "http://www.baidu.com";

 //全局默认字体(如果不将字体库资源引入,在windows下没问题,但linux没有默认的"宋体"会显示乱码)
 InputStream in1 = this.getClass().getResourceAsStream("/fonts/simkai.ttf");
 Font defaultFont = Font.createFont(Font.TRUETYPE_FONT, in1);
 //昵称显示的字体(此字体库是从网上下载的,非windows自带),使用时引用FontName字体名称即可(字体名称:双击字体库可以看到字体名称)
 InputStream in2 = this.getClass().getResourceAsStream("/fonts/TTAiQingXiJ_0.ttf");
 Font txin2 = Font.createFont(Font.TRUETYPE_FONT, in2);

 CommodityPoster2Pojo shareCommodityInfo = CommodityPoster2Pojo.builder()
 .backgroundImage(backgroundImage)
 .commodityImage(commodityImage)
 .yanxuanImage(yanxuanImage)
 .commodityTitle(" 雾中女孩2022冬季新款女装连帽拉链长袖棉服 WH88888")
 .vipPrice("特权价¥0.01")
 .oldPrice("售价¥268")
 .headImage(headImage)
 .nickName("叫我胡歌啊")
 .nickDesc("邀请好友享受内部优惠价")
 .qrCode(PosterBarcode.builder().content(qrContent).logo(qrLogo).build())
 .qrCodeText("微信扫一扫")
 .build();
 //创建海报生成器
 PosterBarcodeImpl<CommodityPoster2Pojo> poster = new PosterBarcodeImpl<>();
 //设置默认字体库 /安装用到的全部字体库(支持传多个)
 poster.defaultFont(defaultFont).installFonts(txin2,...);
 //生成海报
 BufferedImage image = poster.annotationDrawPoster(shareCommodityInfo).draw(null);
 ImageIO.write(image, "png", new File("D:\\temp\\out2.png"));
 }
}
可以看到用起来还是非常简单的,开箱即用!有了这个工具,5分钟可以搞一个海报出来!再也不需要去考虑APP端的不确定的兼容问题了,也不用兴师动众让安卓、苹果、H5等多端的开发者多人开发了。美滋滋~ 我上面的示例是使用的本地图,也可以使用图片链接。
//远程图片
 BufferedImage backgroundImage = ImageIO.read(new URL("https://img-blog.csdnimg.cn/8bf7094ae7b044f495035c8ea734dca8.png"));
如何使用自定义字体库? ​ 当我们在制作海报时,视觉给的效果图可能除了颜色、粗体要求以外,可能还会要求使用指定的字体。此时我们要拿到此字体库文件”*.ttf“并放到项目资源目录下,比如我的是resources\fonts\*.ttf。 ​ 第二步,是我们要得到此字体库的字体名称,在创建海报时配置@PosterFontCss 设置字体需要指定字体名称。双击此字体库文件,第一行就能看到字体名称,如下图: 如何将海报图片转成base64返回给前端
//将生成的海报图片以base64形式回写至终端
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ImageIO.write(image, "png", stream);
String asBase64 = "data:image/png;base64,"+Base64.encode(stream.toByteArray());
System.out.println(asBase64);

三、 用到的技术及相关源码

3.1 Easy Poster 易海报生成器

​ 以上的源码和示例代码均在gitee上,可直接下载。欢迎大家一起来修复完善此工具。 https://gitee.com/naiqing/easyposter 在此特别感谢框架Easy Poster 的作者,我是基于此框架,修复了一些问题后进行的二次开发。

3.3 二维码生成zxing

对于二维码的生成我是使用了谷歌的zxing,然后利用hutool-all来简化调用。
正文到此结束
Loading...