一、话不多说,直接上代码
1.1,水印类型枚举
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author: wangjing
* @createTime: 2023-12-05 15:01
* @version: 1.0.0
* @Description: 水印类型枚举
*/
@Getter
@AllArgsConstructor
@SuppressWarnings("AlibabaEnumConstantsMustHaveComment")
public enum WatermarkTypeEnum {
TEXT_WATERMARK(1, "文字水印"),
IMAGE_WATERMARK(2, "图片水印");
private final Integer code;
private final String msg;
public static WatermarkTypeEnum matchCode(Integer code) {
for (WatermarkTypeEnum watermarkTypeEnum : WatermarkTypeEnum.values()) {
if (code.equals(watermarkTypeEnum.getCode())) {
return watermarkTypeEnum;
}
}
return null;
}
}
1.2,图片水印位置类型枚举
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author: wangjing
* @createTime: 2023-12-05 15:01
* @version: 1.0.0
* @Description: 图片水印位置类型枚举
*/
@Getter
@AllArgsConstructor
@SuppressWarnings("AlibabaEnumConstantsMustHaveComment")
public enum ImageWatermarkPositionTypeEnum {
/**
* 九方位
*/
CENTER(1, "居中"),
LEFT_SIDE(2, "左侧"),
RIGHT_SIDE(3, "右侧"),
DIRECTLY_ABOVE(4, "正上方"),
DIRECTLY_BELOW(5, "正下方"),
UPPER_LEFT(6, "左上角"),
LOWER_LEFT(7, "左下角"),
UPPER_RIGHT(8, "右上方"),
LOWER_RIGHT(9, "右下方"),
/**
* 平铺
*/
TILE(10, "平铺水印"),
TILT_TILE(11, "倾斜平铺");
private final Integer code;
private final String msg;
public static ImageWatermarkPositionTypeEnum matchCode(Integer code) {
for (ImageWatermarkPositionTypeEnum imageWatermarkPositionTypeEnum : ImageWatermarkPositionTypeEnum.values()) {
if (code.equals(imageWatermarkPositionTypeEnum.getCode())) {
return imageWatermarkPositionTypeEnum;
}
}
return null;
}
}
1.3,图片水印处理类
import cn.piesat.space.watermark.enums.ImageWatermarkPositionTypeEnum;
import cn.piesat.space.watermark.enums.WatermarkTypeEnum;
import lombok.Data;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
/**
* @author: wangjing
* @createTime: 2023-12-05 15:01
* @version: 1.0.0
* @Description: 图片水印处理类
*/
public class ImageWatermarkUtil {
/**
* 水印信息对象
*/
@Data
static class WatermarkInfo {
BufferedImage watermarkBufferedImage;
Integer watermarkWidth;
Integer watermarkHeight;
}
/**
* 获取水印信息并对画布做基础配置
*
* @param graphics
* @param watermarkType
* @param watermark
* @param font
* @param color
* @return
*/
public static WatermarkInfo getWatermarkInfo(Graphics2D graphics, Integer watermarkType, String watermark,
Font font, Color color) {
WatermarkInfo watermarkInfo = new WatermarkInfo();
// 文字水印
if (WatermarkTypeEnum.TEXT_WATERMARK.getCode().equals(watermarkType)) {
// 设置字体
graphics.setFont(font);
// 设置颜色
graphics.setColor(color);
watermarkInfo.setWatermarkWidth(getWatermarkLength(watermark, graphics));
watermarkInfo.setWatermarkHeight(font.getSize());
} else {
// 图片水印BufferedImage对象
BufferedImage watermarkBufferedImage = readPicture(watermark);
watermarkInfo.setWatermarkBufferedImage(watermarkBufferedImage);
watermarkInfo.setWatermarkWidth(watermarkBufferedImage.getWidth());
watermarkInfo.setWatermarkHeight(watermarkBufferedImage.getHeight());
}
return watermarkInfo;
}
/**
* 添加水印
*
* @param bufferedImage 源文件
* @param font 字体
* @param color 颜色
* @param watermarkType 水印类型(具体见 WatermarkTypeEnum 枚举类)
* @param imageWatermarkPositionType 水印位置(具体见 ImageWatermarkPositionType)
* @param watermark 水印(文字或图片地址)
* @return
*/
public static BufferedImage addWatermark(BufferedImage bufferedImage, Font font, Color color, Integer watermarkType,
Integer imageWatermarkPositionType, String watermark) {
// 图片宽度
Integer imageWidth = bufferedImage.getWidth();
// 图片高度
Integer imageHeight = bufferedImage.getHeight();
// 创建画笔
Graphics2D graphics = bufferedImage.createGraphics();
WatermarkInfo watermarkInfo = getWatermarkInfo(graphics, watermarkType, watermark, font, color);
switch (ImageWatermarkPositionTypeEnum.matchCode(imageWatermarkPositionType)) {
// 居中
case CENTER:
centerCompute(graphics, imageWidth, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 左侧
case LEFT_SIDE:
leftSideCompute(graphics, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 右侧
case RIGHT_SIDE:
rightSideCompute(graphics, imageWidth, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 正上方
case DIRECTLY_ABOVE:
directlyAboveCompute(graphics, imageWidth, watermarkInfo, watermarkType, watermark);
break;
// 正下方
case DIRECTLY_BELOW:
directlyBelowCompute(graphics, imageWidth, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 左上角
case UPPER_LEFT:
upperLeftCompute(graphics, watermarkInfo, watermarkType, watermark);
break;
// 左下角
case LOWER_LEFT:
lowerLeftCompute(graphics, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 右上角
case UPPER_RIGHT:
upperRightCompute(graphics, imageWidth, watermarkInfo, watermarkType, watermark);
break;
// 右下角
case LOWER_RIGHT:
lowerRightCompute(graphics, imageWidth, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 右下角
case TILE:
tileDrawCompute(graphics, imageWidth, imageHeight, watermarkInfo, watermarkType, watermark);
break;
// 右下角
case TILT_TILE:
// 倾斜度
graphics.rotate(0.2);
tileDrawCompute(graphics, imageWidth, imageHeight, watermarkInfo, watermarkType, watermark);
break;
default: // 错误的操作类型
throw new RuntimeException("错误的操作类型");
}
graphics.dispose();
return bufferedImage;
}
/**
* 居中 配置
*
* @param graphics
* @param imageWidth
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void centerCompute(Graphics2D graphics, Integer imageWidth, Integer imageHeight,
WatermarkInfo watermarkInfo, Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = (imageWidth - watermarkInfo.getWatermarkWidth()) / 2;
Integer y = imageHeight / 2 + (watermarkInfo.getWatermarkHeight() / 2);
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 左侧 配置
*
* @param graphics
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void leftSideCompute(Graphics2D graphics, Integer imageHeight, WatermarkInfo watermarkInfo,
Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = 0;
Integer y = (imageHeight + watermarkInfo.getWatermarkHeight()) / 2;
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 右侧配置
*
* @param graphics
* @param imageWidth
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void rightSideCompute(Graphics2D graphics, Integer imageWidth, Integer imageHeight,
WatermarkInfo watermarkInfo, Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = imageWidth - watermarkInfo.getWatermarkWidth();
Integer y = (imageHeight + watermarkInfo.getWatermarkHeight()) / 2;
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 正上方配置
*
* @param graphics
* @param imageWidth
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void directlyAboveCompute(Graphics2D graphics, Integer imageWidth, WatermarkInfo watermarkInfo,
Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = (imageWidth - watermarkInfo.getWatermarkWidth()) / 2;
Integer y = watermarkInfo.getWatermarkHeight();
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 正下方
*
* @param graphics
* @param imageWidth
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void directlyBelowCompute(Graphics2D graphics, Integer imageWidth, Integer imageHeight,
WatermarkInfo watermarkInfo, Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = (imageWidth - watermarkInfo.getWatermarkWidth()) / 2;
Integer y = imageHeight;
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 左上角
*
* @param graphics
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void upperLeftCompute(Graphics2D graphics, WatermarkInfo watermarkInfo, Integer watermarkType,
String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = 0;
Integer y = watermarkInfo.getWatermarkHeight();
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 左下角
*
* @param graphics
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void lowerLeftCompute(Graphics2D graphics, Integer imageHeight, WatermarkInfo watermarkInfo,
Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = 0;
Integer y = imageHeight;
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 右上方
*
* @param graphics
* @param imageWidth
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void upperRightCompute(Graphics2D graphics, Integer imageWidth, WatermarkInfo watermarkInfo,
Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = imageWidth - watermarkInfo.getWatermarkWidth();
Integer y = watermarkInfo.getWatermarkHeight();
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 右下方
*
* @param graphics
* @param imageWidth
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void lowerRightCompute(Graphics2D graphics, Integer imageWidth, Integer imageHeight,
WatermarkInfo watermarkInfo, Integer watermarkType, String watermark) {
// 设置水印的坐标(为原图片中间位置)
Integer x = imageWidth - watermarkInfo.getWatermarkWidth();
Integer y = imageHeight;
drawTestOrImage(graphics, x, y, watermarkType, watermark, watermarkInfo);
}
/**
* 平铺
*
* @param graphics
* @param imageWidth
* @param imageHeight
* @param watermarkInfo
* @param watermarkType
* @param watermark
*/
public static void tileDrawCompute(Graphics2D graphics, Integer imageWidth, Integer imageHeight,
WatermarkInfo watermarkInfo, Integer watermarkType, String watermark) {
Integer watermarkHeight = watermarkInfo.getWatermarkHeight();
Integer watermarkWidth = watermarkInfo.getWatermarkWidth();
// 间隔
Integer split = watermarkHeight * 2;
// x,y可以绘制的数量,多加一个补充空白
int xCanNum = imageWidth / watermarkWidth + 1;
int yCanNum = imageHeight / watermarkHeight + 1;
for (int i = 1; i <= yCanNum; i++) {
int y = watermarkHeight * i + split * i;
for (int j = 0; j < xCanNum; j++) {
int x = watermarkWidth * j + split * j;
drawTestOrImage(graphics, x, y - (watermarkHeight + split) * j, watermarkType, watermark,
watermarkInfo);
}
}
}
/**
* 画文字水印或图片水印
*
* @param graphics
* @param x
* @param y
* @param watermarkType
* @param watermark
* @param watermarkInfo
*/
public static void drawTestOrImage(Graphics2D graphics, int x, int y, Integer watermarkType, String watermark,
WatermarkInfo watermarkInfo) {
// 文字水印
if (WatermarkTypeEnum.TEXT_WATERMARK.getCode().equals(watermarkType)) {
graphics.drawString(watermark, x, y);
} else {
// 图片水印
graphics.drawImage(watermarkInfo.getWatermarkBufferedImage(), x, y - watermarkInfo.getWatermarkHeight(), watermarkInfo.getWatermarkWidth(),
watermarkInfo.getWatermarkHeight(), null);
}
}
/**
* 获取水印文字的长度
*
* @param watermarkContent 文字水印内容
* @param graphics 图像类
* @return
*/
private static Integer getWatermarkLength(String watermarkContent, Graphics2D graphics) {
return graphics.getFontMetrics(graphics.getFont()).charsWidth(watermarkContent.toCharArray(), 0,
watermarkContent.length());
}
/**
* 将图片写入到指定位置
*
* @param bufImg
* @param tarImgPath
*/
public static void writeImage(BufferedImage bufImg, String tarImgPath) {
// 输出图片
try {
FileOutputStream outImgStream = new FileOutputStream(tarImgPath);
ImageIO.write(bufImg, "png", outImgStream);
outImgStream.flush();
outImgStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 读取图片
*
* @param path
* @return
*/
public static BufferedImage readPicture(String path) {
try {
// 尝试获取本地
return readLocalPicture(path);
} catch (Exception e) {
// 尝试获取网路
return readNetworkPicture(path);
}
}
/**
* 读取本地图片
*
* @param path
* @return
*/
public static BufferedImage readLocalPicture(String path) {
if (null == path) {
throw new RuntimeException("本地图片路径不能为空");
}
// 读取原图片信息 得到文件
File srcImgFile = new File(path);
try {
// 将文件对象转化为图片对象
return ImageIO.read(srcImgFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 读取网络图片
*
* @param path 网络图片地址
*/
public static BufferedImage readNetworkPicture(String path) {
if (null == path) {
throw new RuntimeException("网络图片路径不能为空");
}
try {
// 创建一个URL对象,获取网络图片的地址信息
URL url = new URL(path);
// 将URL对象输入流转化为图片对象 (url.openStream()方法,获得一个输入流)
BufferedImage bugImg = ImageIO.read(url.openStream());
if (null == bugImg) {
throw new RuntimeException("网络图片地址不正确");
}
return bugImg;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 文字类型测试
* @param args
*/
public static void main(String[] args) {
// 要处理的图片路径:
String localPath = "/Users/wangjing/Desktop/watermark/image/test1.jpg";
// 定义存储的地址
String tarImgPath = "/Users/wangjing/Desktop/watermark/image/";
// 文字水印内容
String textWatermark = "刘亦菲";
// 根据图片的背景设置水印颜色
Color color = new Color(255, 255, 255, 128);
// 设置字体 画笔字体样式为微软雅黑,加粗,文字大小为45pt
Font font = new Font("微软雅黑", Font.BOLD, 45);
for (int i = 1; i < 12; i++) {
BufferedImage bufferedImage = readPicture(localPath);
BufferedImage test = addWatermark(bufferedImage, font, color, WatermarkTypeEnum.TEXT_WATERMARK.getCode(),
i, textWatermark);
writeImage(test, tarImgPath + "watermark_text_" + i + ".jpg");
}
}
/**
* 图片水印测试
*
* @param args
*/
// public static void main(String[] args) {
//
// // 要处理的图片路径:
// String localPath = "https://vrar-obs-production.obs.cn-north-4.myhuaweicloud.com/survey/watermark/image.jpg";
//
// // 定义存储的地址
// String tarImgPath = "/Users/wangjing/Desktop/watermark/image/";
//
// // 图片水印内容
// String textWatermark = "https://vrar-obs-production.obs.cn-north-4.myhuaweicloud" +
// ".com/survey/watermark/watermark.png";
//
//
// for (int i = 1; i < 12; i++) {
// BufferedImage bufferedImage = readPicture(localPath);
// BufferedImage test = addWatermark(bufferedImage, null, null, WatermarkTypeEnum.IMAGE_WATERMARK.getCode(), i,
// textWatermark);
// writeImage(test, tarImgPath + "watermark_image_" + i + ".jpg");
// }
// }
}
二、看效果
2.1,原图
2.2,文字水印生成效果
2.3,水印图片
2.4,图片水印生成效果
注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!