根据图片模板生成图片

  • 背景
  • 流程简介
  • 代码实现
  • 遇到的问题及解决方式
  • linux系统生成的图片中文字乱码


背景

根据提供的证书模板生成对应证书,证书内容有,姓名,身份证号,证书名称,证书编号,发证日期
根据用户达成的条件自动生成证书图片。

证书模板如下(原图):

java 根据视频生成缩略图 java图片生成视频_java 根据视频生成缩略图

流程简介

根据模板生成图片的流程如下

  1. 读取 图片模板
  2. 确定 需要替换内容的坐标
  3. 确定需要替换的内容
  4. 生成图片并保存

下面分别按上述步骤介绍方法

  1. 读取图片模板
//将图片链接转化为可操作的 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;
}
  1. 确定需要替换的内容坐标

如果有设计稿的话,直接在设计稿上可以清楚的看到内容坐标。

如果没有设计稿,下面推荐一个在线PS网站,将图片托进来也可以清楚的获取需要替换的内容坐标

https://ps.gaoding.com/#/

注意:画布是坐标原点在左上角

java 根据视频生成缩略图 java图片生成视频_开发语言_02


所以姓名所在的位置坐标应该是 (578,832)

  1. 确定需要替换的内容并替换
    确定好替换的内容,包括字体大小,颜色等
Graphics2D g = sourceImage.createGraphics();
g.setColor(Color.RED);//设置画笔颜色
g.setFont(new Font("宋体",Font.PLAIN,58));// 更改字体、样式和大小
//替换内容
g.drawString("张三", 578, 832);

注意:画图时是从左下脚开始画的,所以drawString方法填入的坐标点,是准备填入内容的的左下角的位置

如下图所示:

java 根据视频生成缩略图 java图片生成视频_中文字体_03


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();
    }
}

内容替换后:

java 根据视频生成缩略图 java图片生成视频_java 根据视频生成缩略图_04

遇到的问题及解决方式

linux系统生成的图片中文字乱码

linux系统默认没有中文字体,使用上述代码生成图片,会导致中文字符乱码

java 根据视频生成缩略图 java图片生成视频_开发语言_05


所以需要在生成图片的linux系统下,安装相应的中文字体

  1. 执行命令,查看系统存在的中文字体
fc-list :lang=zh

如果提示没有fc-list,执行命令安装 字体工具包
yum install -y fontconfig

  1. 找到需要的中文字体
    可以去官网下载,也可以在我们windows系统上copy一份
    WIN字体库目录:C:\Windows\Fonts
  2. java 根据视频生成缩略图 java图片生成视频_Image_06

  3. 安装字体
    将对应字体 复制到 linux 目录 /usr/share/fonts/chinese 下
    执行如下命令,刷新字体
fc-cache -f
  1. 再次查看中文字体,确认是否安装成功
fc-list :lang=zh

(我这里是只装了宋体 simsun.ttc )
**温馨提示:**字体装完后,记得重启程序,不然不生效哦!