package com.cajc.common.utils;
import com.cajctech.common.exception.CajctechException;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* @author 图片水印工具类
*/
public class WatermarkUtils {
// 水印透明度
private static final float alpha = 1f;
// 水印文字大小
public static final int FONT_SIZE = 60; // 适中的大小
// 水印文字字体
private static final Font font = new Font("宋体", Font.PLAIN, FONT_SIZE);
// 水印文字颜色
private static final Color color = Color.white;
// 水印之间的间隔
private static final int XMOVE = 100; // 增加水平间距
// 水印之间的间隔
private static final int YMOVE = 100; // 增加垂直间距
// 错开的距离
private static final int OFFSET_X = 120; // 每行错开的水平距离
// 固定的水印文字
public static final String FIXED_WATERMARK_TEXT = "水印";
/**
* 获取文本长度。汉字为1:1,英文和数字为2:1
*/
private static int getTextLength(String text) {
int length = text.length();
for (int i = 0; i < text.length(); i++) {
String s = String.valueOf(text.charAt(i));
if (s.getBytes().length > 1) {
length++;
}
}
length = length % 2 == 0 ? length / 2 : length / 2 + 1;
return length;
}
/**
* 给图片添加固定水印文字,默认旋转角度为-15度,并返回带有水印的 MultipartFile 对象
*
* @param multipartFile 源图片的MultipartFile对象
* @return 带有水印的 MultipartFile 对象
*/
public static MultipartFile addFixedWatermark(MultipartFile multipartFile) {
// String logoText = "水印"; // 固定水印文本
int degree = -15; // 默认旋转角度
try (InputStream inputStream = multipartFile.getInputStream()) {
// 读取原始图像
BufferedImage srcImg = ImageIO.read(inputStream);
if (srcImg == null) {
throw new CajctechException("无法读取图像");
}
int width = srcImg.getWidth(); // 原图宽度
int height = srcImg.getHeight(); // 原图高度
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();
// 设置图像处理选项
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(srcImg, 0, 0, null);
// 设置水印旋转
g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
// 设置水印属性
g.setColor(color);
g.setFont(font);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
// 循环添加水印
int x = -width / 2;
int y = -height / 2;
int markWidth = FONT_SIZE * getTextLength(FIXED_WATERMARK_TEXT); // 字体长度
int markHeight = FONT_SIZE; // 字体高度
while (x < width * 1.5) {
y = -height / 2;
while (y < height * 1.5) {
int offsetY = (int) (Math.random() * 40) - 20;
g.drawString(FIXED_WATERMARK_TEXT, x, y + offsetY);
y += markHeight + YMOVE;
}
x += markWidth + XMOVE;
}
g.dispose();
// 将带有水印的图像写入字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(buffImg, "JPG", outputStream);
byte[] watermarkedImageBytes = outputStream.toByteArray();
// 创建并返回带有水印的 MultipartFile 对象
return new MockMultipartFile(
multipartFile.getName(),
multipartFile.getOriginalFilename(),
multipartFile.getContentType(),
watermarkedImageBytes
);
} catch (Exception e) {
e.printStackTrace();
throw new CajctechException("添加水印失败");
}
}
public static void main(String[] args) {
try {
// 设置输入和输出路径
String inputImagePath = "D:\\photo\\20241030164805.jpg";
String outputImagePath = "D:\\photo\\20241030164805.jpg";
Path path = Paths.get(inputImagePath);
byte[] fileContent = Files.readAllBytes(path);
MultipartFile multipartFile = new MockMultipartFile(
"file",
new File(inputImagePath).getName(),
"image/jpeg",
fileContent
);
MultipartFile watermarkedMultipartFile = WatermarkUtils.addFixedWatermark(multipartFile);
saveToFile(watermarkedMultipartFile.getBytes(), outputImagePath);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void saveToFile(byte[] bytes, String filePath) throws IOException {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
fos.write(bytes);
}
}
}