feat(image): 添加水印四边偏移支持

- 在 WatermarkInfo 中新增 offsetTop、offsetBottom、offsetLeft 和 offsetRight 字段
- 在 PrinterDefaultWatermarkOperator 中实现四边偏移逻辑,默认值为 0
- 根据图片方向设置不同的偏移值,横图左偏移 40 像素,竖图下偏移 30 像素
- 调整二维码和文字位置计算方式以应用偏移量
- 优化水印处理流程,确保偏移参数正确传递和使用
This commit is contained in:
2025-11-18 16:24:15 +08:00
parent 6e84a5fd43
commit 208202ba41
3 changed files with 29 additions and 6 deletions

View File

@@ -23,6 +23,16 @@ public class WatermarkInfo {
private String dtFormat;
private String datetimeLine;
/**
* 四边偏移(像素值),正数表示向内偏移
* 例如: offsetLeft=40 表示左边界向右收缩40像素,所有左对齐元素随之向右移动
* null 表示使用默认值(通常为0)
*/
private Integer offsetTop;
private Integer offsetBottom;
private Integer offsetLeft;
private Integer offsetRight;
public String getDatetimeLine() {
if (datetimeLine == null) {
datetimeLine = DateUtil.format(datetime, dtFormat);

View File

@@ -56,8 +56,20 @@ public class PrinterDefaultWatermarkOperator implements IOperator {
public static Color datetimeColor = Color.white;
public static double TEXT_RIGHT_MARGIN_RATIO = 0.05; // 文字距离右边缘的图片宽度比例
// 默认四边偏移值(像素),当 WatermarkInfo 中未提供时使用
public static int DEFAULT_OFFSET_TOP = 0;
public static int DEFAULT_OFFSET_BOTTOM = 0;
public static int DEFAULT_OFFSET_LEFT = 0;
public static int DEFAULT_OFFSET_RIGHT = 0;
@Override
public File process(WatermarkInfo info) throws ImageWatermarkException {
// 获取四边偏移值,优先使用传入的值,否则使用默认值
int offsetTop = info.getOffsetTop() != null ? info.getOffsetTop() : DEFAULT_OFFSET_TOP;
int offsetBottom = info.getOffsetBottom() != null ? info.getOffsetBottom() : DEFAULT_OFFSET_BOTTOM;
int offsetLeft = info.getOffsetLeft() != null ? info.getOffsetLeft() : DEFAULT_OFFSET_LEFT;
int offsetRight = info.getOffsetRight() != null ? info.getOffsetRight() : DEFAULT_OFFSET_RIGHT;
BufferedImage baseImage;
BufferedImage qrcodeImage;
BufferedImage faceImage = null;
@@ -92,9 +104,9 @@ public class PrinterDefaultWatermarkOperator implements IOperator {
int scenicLineWidth = scenicFontMetrics.stringWidth(info.getScenicLine());
int datetimeLineWidth = datetimeFontMetrics.stringWidth(info.getDatetimeLine());
// 二维码放置在左下角,距离左边缘图片宽度的5%
int qrcodeOffsetX = (int) (newImage.getWidth() * QRCODE_LEFT_MARGIN_RATIO);
int qrcodeOffsetY = EXTRA_BORDER_PX + baseImage.getHeight() - OFFSET_Y - newQrcodeHeight;
// 二维码放置在左下角,距离左边缘图片宽度的5%,再加上左侧偏移
int qrcodeOffsetX = (int) (newImage.getWidth() * QRCODE_LEFT_MARGIN_RATIO) + offsetLeft;
int qrcodeOffsetY = EXTRA_BORDER_PX + baseImage.getHeight() - OFFSET_Y - newQrcodeHeight - offsetBottom;
Shape originalClip = g2d.getClip();
// 创建比二维码大10像素的白色圆形背景
@@ -165,8 +177,8 @@ public class PrinterDefaultWatermarkOperator implements IOperator {
// 计算第一行文字的Y坐标(基线位置),使两行文字整体垂直居中于二维码
int textStartY = qrcodeCenter - totalTextHeight / 2 + scenicFontMetrics.getAscent();
// 文字右对齐,放置在右下角,距离右边缘图片宽度的5%
int textRightX = newImage.getWidth() - (int) (newImage.getWidth() * TEXT_RIGHT_MARGIN_RATIO);
// 文字右对齐,放置在右下角,距离右边缘图片宽度的5%,再减去右侧偏移
int textRightX = newImage.getWidth() - (int) (newImage.getWidth() * TEXT_RIGHT_MARGIN_RATIO) - offsetRight;
g2d.setFont(scenicFont);
g2d.setColor(scenicColor);

View File

@@ -790,6 +790,7 @@ public class PrinterServiceImpl implements PrinterService {
try {
HttpUtil.downloadFile(item.getCropUrl(), originalFile);
WatermarkInfo watermarkInfo = new WatermarkInfo();
// 判断图片方向并处理旋转
boolean isLandscape = false;
@@ -807,10 +808,10 @@ public class PrinterServiceImpl implements PrinterService {
rotatedOriginalFile = new File("print_" + processId + "_rotated.jpg");
ImageUtils.rotateImage90(originalFile, rotatedOriginalFile);
log.info("竖图已旋转为横图,照片ID: {}", item.getId());
watermarkInfo.setOffsetLeft(40);
}
// 处理水印
WatermarkInfo watermarkInfo = new WatermarkInfo();
watermarkInfo.setScenicLine(scenicConfig.getString("print_watermark_scenic_text", ""));
watermarkInfo.setOriginalFile(needRotation ? rotatedOriginalFile : originalFile);
watermarkInfo.setWatermarkedFile(watermarkedFile);