根据图片模板生成图片
- 背景
- 流程简介
- 代码实现
背景
根据提供的证书模板生成对应证书,证书内容有,姓名,身份证号,证书名称,证书编号,发证日期
根据用户达成的条件自动生成证书图片。
证书模板如下(原图):
流程简介
根据模板生成图片的流程如下
- 读取 图片模板
- 确定 需要替换内容的坐标
- 确定需要替换的内容
- 生成图片并保存
下面分别按上述步骤介绍方法
- 读取图片模板
//将图片链接转化为可操作的 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网站,将图片托进来也可以清楚的获取需要替换的内容坐标
https://ps.gaoding.com/#/
注意:画布是坐标原点在左上角
所以姓名所在的位置坐标应该是 (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();}
}
内容替换后: