package com.doumee.core.utils;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import javax.imageio.ImageIO;
|
import java.awt.*;
|
import java.awt.image.BufferedImage;
|
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayOutputStream;
|
import java.io.InputStream;
|
import java.text.SimpleDateFormat;
|
import java.util.Date;
|
|
/**
|
* 图片水印工具类
|
* 在图片左下角叠加时间 + 地址水印
|
*
|
* @author rk
|
* @date 2026/04/21
|
*/
|
@Slf4j
|
public class ImageWatermarkUtil {
|
|
/**
|
* 为图片添加水印(时间 + 地址 + 经纬度)
|
*
|
* @param imageInput 原图输入流
|
* @param timeText 时间文案(如 "2026-04-21 14:30:00")
|
* @param addressText 地址文案(如 "北京市海淀区xxx路")
|
* @param latitude 纬度
|
* @param longitude 经度
|
* @return 添加水印后的输入流,水印失败时返回原图
|
*/
|
public static InputStream addWatermark(InputStream imageInput, String timeText, String addressText,
|
Double latitude, Double longitude) {
|
try {
|
BufferedImage srcImage = ImageIO.read(imageInput);
|
if (srcImage == null) {
|
log.warn("水印: 无法读取图片,跳过水印处理");
|
imageInput.reset();
|
return imageInput;
|
}
|
|
int srcWidth = srcImage.getWidth();
|
int srcHeight = srcImage.getHeight();
|
|
// 字体大小按图片宽度自适应(约3%),最小16px
|
int fontSize = Math.max(16, srcWidth * 3 / 100);
|
int padding = fontSize;
|
int lineHeight = fontSize + fontSize / 3;
|
|
// 经纬度行
|
String locationText = "";
|
if (latitude != null && longitude != null) {
|
locationText = String.format("经度:%.6f 纬度:%.6f", longitude, latitude);
|
}
|
int lineCount = 2 + (locationText.isEmpty() ? 0 : 1);
|
|
// 计算水印区域背景高度
|
int bgHeight = lineHeight * lineCount + padding;
|
|
// 创建图片
|
BufferedImage destImage = new BufferedImage(srcWidth, srcHeight, BufferedImage.TYPE_INT_RGB);
|
Graphics2D g2d = destImage.createGraphics();
|
|
// 绘制原图
|
g2d.drawImage(srcImage, 0, 0, null);
|
|
// 绘制半透明背景(左下角)
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
|
g2d.setColor(Color.BLACK);
|
g2d.fillRect(0, srcHeight - bgHeight, srcWidth, bgHeight);
|
|
// 绘制水印文字
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.9f));
|
g2d.setColor(Color.WHITE);
|
Font font = new Font(Font.SANS_SERIF, Font.PLAIN, fontSize);
|
g2d.setFont(font);
|
|
// 开启抗锯齿
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
int textX = padding;
|
int textY = srcHeight - bgHeight + padding + fontSize;
|
FontMetrics fm = g2d.getFontMetrics();
|
int maxTextWidth = srcWidth - padding * 2;
|
|
// 第一行:时间
|
g2d.drawString(timeText, textX, textY);
|
|
// 第二行:地址(地址过长时截断)
|
String displayAddr = addressText;
|
while (fm.stringWidth(displayAddr) > maxTextWidth && displayAddr.length() > 0) {
|
displayAddr = displayAddr.substring(0, displayAddr.length() - 1);
|
}
|
g2d.drawString(displayAddr, textX, textY + lineHeight);
|
|
// 第三行:经纬度
|
if (!locationText.isEmpty()) {
|
g2d.drawString(locationText, textX, textY + lineHeight * 2);
|
}
|
|
g2d.dispose();
|
|
// 输出为字节流
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ImageIO.write(destImage, "jpg", baos);
|
return new ByteArrayInputStream(baos.toByteArray());
|
} catch (Exception e) {
|
log.error("添加水印失败,返回原图", e);
|
try {
|
imageInput.reset();
|
} catch (Exception ignored) {}
|
return imageInput;
|
}
|
}
|
}
|