自适应文字长度水印
import cn.hutool.core.io.IoUtil;
import com.shinkeer.common.utils.DateUtils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;
import java.util.stream.IntStream;
/**
* @program: 工具箱
* @description 水印
* @date 2023/6/6
*/
public class ImgWatermarkUtil {
public static void main(String[] args) throws Exception {
//imgWatermarkLocal(""D:\\公司文件\\图片.png","D:\\公司文件\\图片1.png","这是水印");
InputStream inputStream = new FileInputStream("D:\\公司文件\\图片1.png");
InputStream inputStreamFile = imgWatermarkInt(inputStream, "yph", "这是水印BXCVVBADSSF","png");
saveFile(inputStreamFile,"D:\\公司文件\\图片" + DateUtils.dateTimeNow() + ".png");
}
public static void testFile(InputStream inputStream) throws Exception {
InputStream inputStreamFile = imgWatermarkInt(inputStream, "这是水印", "png");
saveFile(inputStreamFile,"D:\\公司文件\\图片" + DateUtils.dateTimeNow() + ".png");
}
/**
* 保存本地
* @param inputStream 输入流
* @param filePath 保存地址
* @throws IOException
*/
public static void saveFile(InputStream inputStream, String filePath) throws IOException {
try (OutputStream outputStream = new FileOutputStream(filePath)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
/**
* 给图片添加水印
*
* @param inputFile 原文件路径+名称
* @param outputFile 添加水印后输出文件保存的路径+名称
* @param waterMarkName 添加水印的内容
*/
public static void imgWatermarkLocal(String inputFile, String outputFile, String waterMarkName) {
try {
BufferedImage img = ImageIO.read(new File(inputFile));
int width = img.getWidth();
int height = img.getHeight();
int fontSize = (width + height) / 80;
Graphics2D g = img.createGraphics();
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
g.rotate(0.2);
// 间隔
int split = fontSize * 2;
// 文字占用的宽度
int xWidth = getStrWidth(waterMarkName, fontSize);
// x,y可以绘制的数量,多加一个补充空白
int xCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;
for (int i = 1; i <= yCanNum; i++) {
int y = fontSize * i + split * i;
for (int j = 0; j < xCanNum; j++) {
int x = xWidth * j + split * j;
g.drawString(waterMarkName, x, y - (fontSize + split) * j);
}
}
g.dispose();
ImageIO.write(img, "png", new File(outputFile));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 图片加水印
*
* @param inputStream 输入流
* @param waterMarkName 添加水印的内容
* @return OutputStream 输出流
*/
public static OutputStream imgWatermarkOut(InputStream inputStream, String waterMarkName) {
try {
BufferedImage img = ImageIO.read(inputStream);
int width = img.getWidth();
int height = img.getHeight();
int fontSize = (width + height) / 80;
Graphics2D g = img.createGraphics();
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
g.rotate(0.2);
// 间隔
int split = fontSize * 2;
// 文字占用的宽度
int xWidth = getStrWidth(waterMarkName, fontSize);
// x,y可以绘制的数量,多加一个补充空白
int xCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;
for (int i = 1; i <= yCanNum; i++) {
int y = fontSize * i + split * i;
for (int j = 0; j < xCanNum; j++) {
int x = xWidth * j + split * j;
g.drawString(waterMarkName, x, y - (fontSize + split) * j);
}
}
g.dispose();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(img, "png", outputStream);
return outputStream;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 图片加水印
*
* @param inputStream 输入流
* @param waterMarkName 添加水印的内容
* @param fileSuffix 扩展名
* @return InputStream 新的输入流
*/
public static InputStream imgWatermarkInt(InputStream inputStream, String waterMarkName, String fileSuffix) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
BufferedImage originalImage = ImageIO.read(inputStream);
int width = originalImage.getWidth();
int height = originalImage.getHeight();
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Invalid image size.");
}
if (waterMarkName == null || waterMarkName.trim().isEmpty()) {
throw new IllegalArgumentException("Watermark name cannot be empty.");
}
// 创建新的BufferedImage对象,并复制原始图像
BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());
Graphics2D g = newImage.createGraphics();
g.drawImage(originalImage, 0, 0, null);
int fontSize = (width + height) / 80;
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
g.rotate(0.2);
// 间隔
int split = fontSize * 2;
// 文字占用的宽度
int xWidth = getStrWidth(waterMarkName, fontSize);
// x,y可以绘制的数量,多加一个补充空白
int xCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;
for (int i = 1; i <= yCanNum; i++) {
int y = fontSize * i + split * i;
for (int j = 0; j < xCanNum; j++) {
int x = xWidth * j + split * j;
g.drawString(waterMarkName, x, y - (fontSize + split) * j);
}
}
g.dispose();
// 将新的BufferedImage对象写入ByteArrayOutputStream中
ImageIO.write(newImage, fileSuffix, outputStream);
// 返回新的InputStream对象
return new ByteArrayInputStream(outputStream.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 图片加水印
*
* @param inputStream 输入流
* @param waterMarkNameOne 添加水印的内容
* @param waterMarkNameTwo 添加水印的内容
* @param fileSuffix 扩展名
* @return InputStream 输入流
*/
public static InputStream imgWatermarkInt(InputStream inputStream, String waterMarkNameOne, String waterMarkNameTwo, String fileSuffix) {
try {
BufferedImage img = ImageIO.read(inputStream);
int width = img.getWidth();
int height = img.getHeight();
int fontSize = (width + height) / 80;
// 间隔
int split = fontSize * 2;
// 文字占用的宽度
int xWidth1 = getStrWidth(waterMarkNameOne, fontSize);
int xWidth2 = getStrWidth(waterMarkNameTwo, fontSize);
int xWidth = Math.max(xWidth1,xWidth2);
// x,y可以绘制的数量,多加一个补充空白
int xCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;
for (int i = 1; i <= yCanNum; i++) {
int y = fontSize * i + split * i;
String waterMarkName = "";
for (int j = 0; j < xCanNum; j++) {
Graphics2D g = img.createGraphics();
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
g.rotate(0.2);
int x = xWidth * j + split * j;
//随机水印
if (j % 2 == 0) {
waterMarkName = waterMarkNameOne;
} else {
waterMarkName = waterMarkNameTwo;
}
g.drawString(waterMarkName, x, y - (fontSize + split) * j);
g.dispose();
}
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(img, fileSuffix, outputStream);
return new ByteArrayInputStream(outputStream.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取字符串占用的宽度
* <br>
*
* @param str 字符串
* @param fontSize 文字大小
* @return 字符串占用的宽度
*/
public static int getStrWidth(String str, int fontSize) {
char[] chars = str.toCharArray();
int fontSize2 = fontSize / 2;
int width = 0;
for (char c : chars) {
int len = String.valueOf(c).getBytes().length;
// 汉字为3,其余1
// 可能还有一些特殊字符占用2等等,统统计为汉字
if (len != 1) {
width += fontSize;
} else {
width += fontSize2;
}
}
return width == 0 ? 1 : width;
}
/**
* 图片加水印
*
* @param inputStream 输入流
* @param waterMarkName 添加水印的内容
* @param fileSuffix 扩展名
* @return InputStream 新的输入流
*/
public static InputStream imgWatermarkInt2(InputStream inputStream, String waterMarkName, String fileSuffix) {
try (InputStream in = inputStream; ByteArrayOutputStream out = new ByteArrayOutputStream()) {
BufferedImage originalImage = ImageIO.read(in);
int width = originalImage.getWidth();
int height = originalImage.getHeight();
if(width <= 0 || height <= 0){
throw new IllegalArgumentException("Invalid image size.");
}
if(waterMarkName == null || waterMarkName.trim().isEmpty()){
throw new IllegalArgumentException("Watermark name cannot be empty.");
}
// 创建新的BufferedImage对象,并复制原始图像
BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());
Graphics2D g = newImage.createGraphics();
g.drawImage(originalImage, 0, 0, null);
int fontSize = (width + height) / 80;
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
g.rotate(0.2);
// 间隔
int split = fontSize * 2;
// 文字占用的宽度
int xWidth = getStrWidth(waterMarkName, fontSize);
// x,y可以绘制的数量,多加一个补充空白
int xCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;
// 使用流式API进行操作
IntStream.range(1, yCanNum + 1)
.forEach(i -> {
int y = fontSize * i + split * i;
IntStream.range(0, xCanNum)
.forEach(j -> {
int x = xWidth * j + split * j;
g.drawString(waterMarkName, x, y - (fontSize + split) * j);
});
});
g.dispose();
// 将新的BufferedImage对象写入ByteArrayOutputStream中
ImageIO.write(newImage, fileSuffix, out);
// 返回新的InputStream对象
return new ByteArrayInputStream(out.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}