Java根据模板图片自定义生成获奖证书图片

需求

在一些教学系统中,经常会用到一些证书自定义生成,提供一个模板,写入不同姓名、获得的奖项、描述等,本篇文章就是处理这类需求的。
在这里插入图片描述

代码

1、引入依赖

<!-- cmyk格式图片转换 -->
<dependency>
     <groupId>org.sejda.imageio</groupId>
     <artifactId>webp-imageio</artifactId>
     <version>0.1.6</version>
 </dependency>

2、实体类

@Data
public class CertificateParam {

    private Long id;

    /**
     * 证书图片
     */
    private String certificateImg;

    /**
     * 证书导入参数
     */
    private List<CertificateConfigParam> certificateConfigParams;
}
@Data
public class CertificateConfigParam {

    /**
     * 要绘制的内容
     **/
    private String context;
    /**
     * 位置:横坐标
     **/
    private Integer x;
    /**
     * 位置:纵坐标
     **/
    private Integer y;
    /**
     * 字体大小
     **/
    private Integer fontSize;
    /**
     * 字体
     **/
    private String font;
    /**
     * 字体颜色(RGB Color对象)
     **/
    private String color;
}

3、Controller

  @PostMapping("/getCertificatePreviewPicture")
    public String getCertificatePreviewPicture(@RequestBody CertificateParam certificateParam,HttpServletResponse response) {
        response.addHeader("request-type", "download");
        response.addHeader("Access-Control-Expose-Headers", "request-type");
        return bizCertificateService.getCertificatePreviewPicture(certificateParam);
    }

4、Service

String getCertificatePreviewPicture(CertificateParam certificateParam);

5、ServiceImpl

 @Override
    public String getCertificatePreviewPicture(CertificateParam certificateParam) {
        return Base64.getEncoder().encodeToString(CertificatePictureUtil.getCertificatePictureByte(certificateParam));
    }

6、Utils

public class CertificatePictureUtil {

    /**
     * @Description 根据传入的证书参数和证书模板参数去生成证书字节数据
     * @Date 15:52 2023/4/25
     * @Param [certificateParam, response]
     * @Return byte[]
     **/
    public static byte[] getCertificatePictureByte(CertificateParam certificateParam){
        try {

            //获取底图
            URL url = new URL(certificateParam.getCertificateImg());
            URLConnection resource = url.openConnection();

            InputStream inputStream = resource.getInputStream();
            //文件转化为图片
            Image srcImg = ImageIO.read(inputStream);
            //获取图片的宽、高
            int srcImgWidth = srcImg.getWidth(null);
            int srcImgHeight = srcImg.getHeight(null);
            // 设置画布大小
            BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = bufImg.createGraphics();
            g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
            // 证书中写字
            List<CertificateConfigParam> certificateConfigParams = certificateParam.getCertificateConfigParams();
            if(ObjectUtil.isNotEmpty(certificateConfigParams)){
                for (CertificateConfigParam certificateConfigParam : certificateConfigParams) {
                    setMark(g, certificateConfigParam.getContext(), srcImgWidth, srcImgHeight, certificateConfigParam.getX(), certificateConfigParam.getY(),certificateConfigParam.getFontSize(), certificateConfigParam.getFont(), certificateConfigParam.getColor());
                }
            } else {
                throw new RuntimeException("证书参数错误");
            }
            //画出内容
            g.dispose();

            // 下载证书
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(bufImg, "png", imOut);

            //关闭流
            bs.close();
            inputStream.close();
            imOut.close();

            return bs.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("证书生成失败");
        }
    }


    /**
     * 设置水印
     *
     * @param graphics2D   绘图对象
     * @param context      要绘制的内容
     * @param srcImgWidth  原图的宽度
     * @param srcImgHeight 原图的高度
     * @param x            位置:横坐标
     * @param y            位置:纵坐标
     * @param font         字体
     * @param fontSize     字体大小
     * @param color        字体颜色(RGB Color对象)
     */
    private static void setMark(Graphics2D graphics2D, String context, Integer srcImgWidth, Integer srcImgHeight, Integer x, Integer y,Integer fontSize, String font, String color) {
        // 获取图片相对500 * 708 的相对坐标,以及字体大小
        fontSize=(int) ((srcImgWidth / 500.00) * fontSize);
        x = (int) ((srcImgWidth / 500.00) * x);
        y = (int) ((srcImgHeight / 708.00) * y)+fontSize;

        // 设置字体
        graphics2D.setFont(new Font(font, Font.PLAIN, fontSize));
        // 设置颜色
        try {
            graphics2D.setColor(Color.decode(color));
        } catch (Exception e) {
            throw new RuntimeException("不存在该种颜色,请重新设置");
        }

        // 获取文本宽度
        int textWidth = graphics2D.getFontMetrics().stringWidth(context);

        // 写字
        graphics2D.drawString(new String(context.getBytes(StandardCharsets.UTF_8)), x - textWidth, y);

    }
}

注意事项:
代码在本地跑时,写入中文内容正常,但是部署到Linux环境出现乱码,解决办法:需要在Linux安装字体库(具体教程网上很多),安装好字体库后一定记得记得重启项目。