根据图片模板生成图片
背景
根据提供的证书模板生成对应证书,证书内容有,姓名,身份证号,证书名称,证书编号,发证日期
根据用户达成的条件自动生成证书图片。
证书模板如下(原图):
流程简介
根据模板生成图片的流程如下
- 读取 图片模板
- 确定 需要替换内容的坐标
- 确定需要替换的内容
- 生成图片并保存
下面分别按上述步骤介绍方法
- 读取图片模板
//将图片链接转化为可操作的 Image对象
private BufferedImage readImageFromUrl(String template) {
try {
URL url = new URL(template);
return ImageIO.read(url);
} catch (IOException e) {
}
return null;
}
//将本地图片转化为可操作的 Image对象
private BufferedImage readImageFromPath(String template) {
try(FileInputStream input = new FileInputStream(new File(template))) {
return ImageIO.read(input);
} catch (IOException e) {
}
return null;
}
- 确定需要替换的内容坐标
如果有设计稿的话,直接在设计稿上可以清楚的看到内容坐标。
如果没有设计稿,下面推荐一个在线PS网站,将图片托进来也可以清楚的获取需要替换的内容坐标
注意:画布是坐标原点在左上角
所以姓名所在的位置坐标应该是 (578,832)
- 确定需要替换的内容并替换
确定好替换的内容,包括字体大小,颜色等
Graphics2D g = sourceImage.createGraphics();
g.setColor(Color.RED);//设置画笔颜色
g.setFont(new Font("宋体",Font.PLAIN,58));// 更改字体、样式和大小
//替换内容
g.drawString("张三", 578, 832);
注意:画图时是从左下脚开始画的,所以drawString方法填入的坐标点,是准备填入内容的的左下角的位置
如下图所示:
4. 生成新的图片
将Image对象转为文件
//图片生成到本地
File outputImageFile = new File("output_image.jpg"); // 输出图片文件路径
ImageIO.write(modifiedImage, "jpg", outputImageFile);
//或者写入输出流,然后上传到服务器
try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){
ImageIO.write(newImage,ext,outputStream);
}catch (IOException e){
}
代码实现
这里做了简单的代码抽象
抽象一些辅助类:用来存储模板信息,替换位置,以及字体,内容等
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PicWithParams {
//模板地址
private String picTemplate;
//替换的参数列表
private List<PicParams> paramsList;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
class PicParams {
/*字体*/
private Font font;
/*画笔颜色*/
private Color color;
/*正文*/
private String content;
/*x坐标*/
private Integer xPoint;
/*y坐标*/
private Integer yPoint;
/*位置*/
private TextAlign textAlign;
}
enum TextAlign {
/*居中*/
CENTER,
/*左对齐*/
LEFT,
/*右对齐*/
RIGHT
;
}
核心处理类
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class ProduceImageService {
private static String FONT_NAME = "宋体";
public void drawImage(PicWithParams picWithParams) {
BufferedImage templateImage = readImageFromPath(picWithParams.getPicTemplate());
BufferedImage newImage = drawImageWithParams(templateImage, picWithParams.getParamsList());
storeImage(newImage);
}
private void storeImage(BufferedImage newImage) {
File outputImageFile = new File("output.jpg"); // 输出图片文件路径
try {
ImageIO.write(newImage, "jpg", outputImageFile);
} catch (IOException e) {
}
System.out.println("Generated image saved to: " + outputImageFile.getAbsolutePath());
}
private BufferedImage drawImageWithParams(BufferedImage sourceImage, List<PicParams> paramsList) {
if(null == sourceImage){
throw new IllegalArgumentException("参数异常");
}
Graphics2D g = sourceImage.createGraphics();
try {
for (PicParams param : paramsList) {
g.setColor(param.getColor());
g.setFont(param.getFont());
FontMetrics metrics = g.getFontMetrics();
switch (param.getTextAlign()){
case LEFT:
g.drawString(param.getContent(), param.getXPoint(), param.getYPoint());
break;
case RIGHT:
g.drawString(param.getContent(), param.getXPoint() - metrics.stringWidth(param.getContent()), param.getYPoint());
break;
case CENTER:
default:
g.drawString(param.getContent(), param.getXPoint() - metrics.stringWidth(param.getContent()) / 2, param.getYPoint());
}
}
} finally {
g.dispose();
}
return sourceImage;
}
private BufferedImage readImageFromUrl(String template) {
try {
URL url = new URL(template);
return ImageIO.read(url);
} catch (IOException e) {
}
return null;
}
private BufferedImage readImageFromPath(String template) {
try(FileInputStream input = new FileInputStream(new File(template))) {
return ImageIO.read(input);
} catch (IOException e) {
}
return null;
}
public static void main(String[] args) {
ProduceImageService ImageService = new ProduceImageService();
PicWithParams picWithParams = ImageService.getParams();
ImageService.drawImage(picWithParams);
}
private PicWithParams getParams() {
List<PicParams> picParams = new ArrayList<>();
picParams.add(PicParams.builder()
.content("张三")
.xPoint(578)
.yPoint(832)
.color(Color.black)
.textAlign(TextAlign.CENTER)
.font(new Font(FONT_NAME,Font.PLAIN,58)).build());
picParams.add(PicParams.builder()
.content("353638199905022815")
.xPoint(1300)
.yPoint(832)
.color(Color.black)
.textAlign(TextAlign.CENTER)
.font(new Font(FONT_NAME,Font.PLAIN,54)).build());
picParams.add(PicParams.builder()
.content("架构师认证")
.xPoint(1000)
.yPoint(900+53)
.color(Color.black)
.textAlign(TextAlign.CENTER)
.font(new Font(FONT_NAME,Font.PLAIN,54)).build());
picParams.add(PicParams.builder()
.content("RJ12345678900001")
.xPoint(410)
.yPoint(1164+25)
.color(Color.black)
.textAlign(TextAlign.LEFT)
.font(new Font(FONT_NAME,Font.PLAIN,33)).build());
picParams.add(PicParams.builder()
.content("2024年2月11日")
.xPoint(1385)
.yPoint(1164+30)
.color(Color.black)
.textAlign(TextAlign.LEFT)
.font(new Font(FONT_NAME,Font.PLAIN,33)).build());
return PicWithParams.builder().picTemplate("证书.jpg").paramsList(picParams).build();
}
}
内容替换后:
遇到的问题及解决方式
linux系统生成的图片中文字乱码
linux系统默认没有中文字体,使用上述代码生成图片,会导致中文字符乱码
所以需要在生成图片的linux系统下,安装相应的中文字体
- 执行命令,查看系统存在的中文字体
fc-list :lang=zh
如果提示没有fc-list,执行命令安装 字体工具包
yum install -y fontconfig
-
找到需要的中文字体
可以去官网下载,也可以在我们windows系统上copy一份
WIN字体库目录:C:\Windows\Fonts
-
安装字体
将对应字体 复制到 linux 目录 /usr/share/fonts/chinese 下
执行如下命令,刷新字体
fc-cache -f
- 再次查看中文字体,确认是否安装成功
fc-list :lang=zh
(我这里是只装了宋体 simsun.ttc )
**温馨提示:**字体装完后,记得重启程序,不然不生效哦!