在一些教学系统中,经常会用到一些证书自定义生成,提供一个模板,写入不同姓名、获得的奖项、描述等,本篇文章就是处理这类需求的。
<!-- cmyk格式图片转换 -->
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
</dependency>
@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;
}
@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);
}
String getCertificatePreviewPicture(CertificateParam certificateParam);
@Override
public String getCertificatePreviewPicture(CertificateParam certificateParam) {
return Base64.getEncoder().encodeToString(CertificatePictureUtil.getCertificatePictureByte(certificateParam));
}
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安装字体库(具体教程网上很多),安装好字体库后一定记得记得重启项目。