因项目需求,需要在图片上添加上用户二维码及用户相关的信息
1、二维码生成。
public static BufferedImage getBufferedImage(String content) throws WriterException {
//com.google.zxing.EncodeHintType:编码提示类型,枚举类型
Map<EncodeHintType, Object> hints = new HashMap();
//EncodeHintType.CHARACTER_SET:设置字符编码类型
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
//EncodeHintType.ERROR_CORRECTION:设置误差校正
//ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
//不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
hints.put(EncodeHintType.MARGIN, 1);
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
for (int x = 0; x < CODE_WIDTH; x++) {
for (int y = 0; y < CODE_HEIGHT; y++) {
bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
}
}
return bufferedImage;
}
2、图片处理
图片数据位置类:
@Data
public class ImageInfo {
private Object data; //数据
private float x; // 坐标:x
private float y; // 坐标:y
private float w; // 坐标:w
private float h; // 坐标:h
private Font font; // 字体
private Color color; // 顏色
public ImageInfo (Object data, float x, float y, Font font, Color color) {
this.data = data;
this.x = x;
this.y = y;
this.font = font;
this.color = color;
}
public ImageInfo (Object data, float x, float y, float w, float h) {
this.data = data;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
}
底图上要添加的文字图片类
@Data
@AllArgsConstructor
public class ImageHandle {
//文字
private List<ImageInfo> textList;
// 图片
private List<ImageInfo> imageList;
}
处理图片
public static Map<String, String> createUserInvationPoster(User user) {
try {
// 生成二维码
BufferedImage qrCode = QRCodeUtil.getBufferedImage(user.getInvationUrl());
List<ImageInfo> imageList = new ArrayList<>();
imageList.add(new ImageInfo(qrCode, 642, 1396F, 144F, 144F));
// font
Font font1 = new Font("Source Han Sans SC Heavy", Font.PLAIN, 40);
List<ImageInfo> textList = new ArrayList<>();
List<ImageInfo> textListCn = new ArrayList<>();
// 生成两张海报图片,en,cn
textListCn.add(new ImageInfo("邀請碼:" + user.getInvationCode(), 126F, 1476F, font1, Color.white));
textList.add(new ImageInfo("InvationCode:" + user.getInvationCode(), 126F, 1476F, font1, Color.white));
// /xxx/pic/ + "image/hb/"
String dirStr = savepath + package_name + System.getProperty("file.separator");
String userHbPath = package_name + System.getProperty("file.separator") + user.getUserId() + "_hb.jpg";
String userHbPathCn = package_name + System.getProperty("file.separator") + user.getUserId() + "_hb_cn.jpg";
handleImage(new ImageHandle(textList, imageList),
new File(dirStr + "base_imag_en.jpg"),
userHbPath);
handleImage(new ImageHandle(textListCn, imageList),
new File(dirStr + "base_imag_cn.jpg"),
userHbPathCn);
return Map.of("en", userHbPath, "cn", userHbPathCn);
} catch (Exception e) {
LogConfig.errorLog.error("createUserInvationPoster error", e);
return null;
}
}
/**
* 图片处理(输出到文件中)
* @param imageHandle 处理的数据
* @param saveFilePath 处理后图片保存的路径
*/
public static void handleImage(ImageHandle imageHandle, File sourceFile, String saveFilePath) throws IOException {
synchronized (FLAG) {
PictureSynthesis.sourceFile = sourceFile;
// 构建叠加层
BufferedImage buffImg = watermark(imageHandle);
// 输出水印图片
generateWaterFile(buffImg, saveFilePath);
}
}
/**
* 构建叠加层
* 图像处理的原点坐标在:左上角
* @param imageHandle 处理的数据
* @throws IOException io异常
* @return BufferedImage 生成水印并返回java.awt.image.BufferedImage
*/
private static BufferedImage watermark(ImageHandle imageHandle) throws IOException {
// 获取底图
LogConfig.log.info("sourceFile:{}", sourceFile);
BufferedImage buffImg = ImageIO.read(sourceFile);
// 创建Graphics2D对象,用在底图对象上绘图
Graphics2D g2d = buffImg.createGraphics();
// 处理文字
if (imageHandle.getTextList() != null && imageHandle.getTextList().size() > 0){
for (ImageInfo pp : imageHandle.getTextList()){
g2d.setColor(pp.getColor() == null ? Color.BLACK : pp.getColor());
g2d.setFont( pp.getFont() == null ? FONT : pp.getFont());
g2d.drawString(pp.getData().toString(), pp.getX(), pp.getY());
}
}
// 处理图片
if (imageHandle.getImageList() != null && imageHandle.getImageList().size() > 0){
for (ImageInfo pp : imageHandle.getImageList()){
BufferedImage image = (BufferedImage) pp.getData();
// 获取层图的宽度
int width = pp.getW() <= 0 ? image.getWidth() : (int) pp.getW();
// 获取层图的高度
int height = pp.getH() <= 0 ? image.getHeight() : (int) pp.getH();
// 在图形和图像中实现混合和透明效果
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, PELLUCIDITY));
// 绘制
g2d.drawImage(image, (int)pp.getX(), (int)pp.getY(), width, height, null);
}
}
// 释放图形上下文使用的系统资源
g2d.dispose();
return buffImg;
}
/**
* 输出水印图片
* @param buffImg 图像加水印之后的BufferedImage对象
* @param savePath 图像加水印之后的保存路径
*/
private static void generateWaterFile(BufferedImage buffImg, String savePath) {
int temp = savePath.lastIndexOf(".") + 1;
try {
ImageIO.write(buffImg, savePath.substring(temp), new File(savepath + savePath));
} catch (IOException e1) {
e1.printStackTrace();
}
}