本文目录导读:

我来为您提供一个完整的Java图片水印案例,包括文字水印和图片水印两种实现方式。
基础工具类实现
ImageWatermarkUtil.java
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 图片水印工具类
*/
public class ImageWatermarkUtil {
/**
* 添加文字水印
* @param sourcePath 源图片路径
* @param targetPath 目标图片路径
* @param watermarkText 水印文字
* @param fontStyle 字体样式
* @param fontSize 字体大小
* @param color 水印颜色
* @param alpha 透明度(0.0-1.0)
* @param x 水印x坐标
* @param y 水印y坐标
*/
public static void addTextWatermark(String sourcePath, String targetPath,
String watermarkText, int fontStyle,
int fontSize, Color color,
float alpha, int x, int y) {
try {
// 读取原图片
Image image = ImageIO.read(new File(sourcePath));
int width = image.getWidth(null);
int height = image.getHeight(null);
// 创建BufferedImage
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
// 绘制原图
g2d.drawImage(image, 0, 0, null);
// 设置水印透明度
AlphaComposite alphaComposite = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
g2d.setComposite(alphaComposite);
// 设置字体和颜色
g2d.setFont(new Font("微软雅黑", fontStyle, fontSize));
g2d.setColor(color);
// 绘制文字水印
g2d.drawString(watermarkText, x, y);
// 释放资源
g2d.dispose();
// 输出图片
ImageIO.write(bufferedImage, getExtension(targetPath), new File(targetPath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 添加文字水印(居中对角线平铺)
*/
public static void addTextWatermarkTile(String sourcePath, String targetPath,
String watermarkText, int fontStyle,
int fontSize, Color color, float alpha) {
try {
Image image = ImageIO.read(new File(sourcePath));
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
g2d.drawImage(image, 0, 0, null);
// 设置透明度
AlphaComposite alphaComposite = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
g2d.setComposite(alphaComposite);
g2d.setFont(new Font("微软雅黑", fontStyle, fontSize));
g2d.setColor(color);
// 计算字体尺寸
FontMetrics fontMetrics = g2d.getFontMetrics();
int textWidth = fontMetrics.stringWidth(watermarkText);
int textHeight = fontMetrics.getHeight();
// 平铺水印
for (int posX = -textWidth; posX < width; posX += textWidth * 2) {
for (int posY = -textHeight; posY < height; posY += textHeight * 2) {
g2d.drawString(watermarkText, posX, posY);
}
}
g2d.dispose();
ImageIO.write(bufferedImage, getExtension(targetPath), new File(targetPath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 添加图片水印
* @param sourcePath 源图片路径
* @param watermarkPath 水印图片路径
* @param targetPath 目标图片路径
* @param alpha 透明度
* @param x 水印x坐标
* @param y 水印y坐标
* @param scale 水印缩放比例(1.0为原尺寸)
*/
public static void addImageWatermark(String sourcePath, String watermarkPath,
String targetPath, float alpha,
int x, int y, double scale) {
try {
// 读取原图和水印图
BufferedImage sourceImage = ImageIO.read(new File(sourcePath));
BufferedImage watermarkImage = ImageIO.read(new File(watermarkPath));
int width = sourceImage.getWidth(null);
int height = sourceImage.getHeight(null);
// 缩放水印
int watermarkWidth = (int)(watermarkImage.getWidth() * scale);
int watermarkHeight = (int)(watermarkImage.getHeight() * scale);
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
// 绘制原图
g2d.drawImage(sourceImage, 0, 0, null);
// 设置透明度
AlphaComposite alphaComposite = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
g2d.setComposite(alphaComposite);
// 绘制水印图片
g2d.drawImage(watermarkImage, x, y, watermarkWidth, watermarkHeight, null);
g2d.dispose();
ImageIO.write(bufferedImage, getExtension(targetPath), new File(targetPath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 添加图片水印(默认位置:右下角)
*/
public static void addImageWatermarkBottomRight(String sourcePath,
String watermarkPath,
String targetPath, float alpha) {
try {
BufferedImage sourceImage = ImageIO.read(new File(sourcePath));
BufferedImage watermarkImage = ImageIO.read(new File(watermarkPath));
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
int watermarkWidth = watermarkImage.getWidth();
int watermarkHeight = watermarkImage.getHeight();
// 计算右下角位置,留10px边距
int x = width - watermarkWidth - 10;
int y = height - watermarkHeight - 10;
addImageWatermark(sourcePath, watermarkPath, targetPath, alpha, x, y, 1.0);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取文件扩展名
*/
private static String getExtension(String path) {
int lastIndexOfDot = path.lastIndexOf(".");
return path.substring(lastIndexOfDot + 1);
}
}
增强版水印服务
WatermarkService.java
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
/**
* 水印服务类 - 更丰富的功能
*/
public class WatermarkService {
/**
* 添加旋转文字水印
*/
public static void addRotatedTextWatermark(String sourcePath, String targetPath,
String text, float alpha, boolean tile) {
try {
BufferedImage sourceImage = ImageIO.read(new File(sourcePath));
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
BufferedImage watermarkImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) watermarkImage.getGraphics();
// 设置字体
g2d.setFont(new Font("楷体", Font.BOLD, 30));
g2d.setColor(new Color(255, 255, 255));
// 旋转45度
g2d.rotate(Math.toRadians(-45), width / 2.0, height / 2.0);
if (tile) {
// 平铺模式
FontMetrics fontMetrics = g2d.getFontMetrics();
int textWidth = fontMetrics.stringWidth(text);
int textHeight = fontMetrics.getHeight();
for (int x = -textWidth; x < width * 1.5; x += textWidth * 2 + 50) {
for (int y = -textHeight; y < height * 1.5; y += textHeight * 2 + 50) {
g2d.drawString(text, x, y);
}
}
} else {
// 单个水印,居中
FontMetrics fontMetrics = g2d.getFontMetrics();
int textWidth = fontMetrics.stringWidth(text);
int x = (width - textWidth) / 2;
int y = height / 2;
g2d.drawString(text, x, y);
}
g2d.dispose();
// 合并图片
BufferedImage result = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D resultG2d = result.createGraphics();
resultG2d.drawImage(sourceImage, 0, 0, null);
// 设置透明度
AlphaComposite alphaComposite = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
resultG2d.setComposite(alphaComposite);
resultG2d.drawImage(watermarkImage, 0, 0, null);
resultG2d.dispose();
ImageIO.write(result, "jpg", new File(targetPath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 添加斜角平铺水印(类似平铺瓷砖效果)
*/
public static void addTileWatermark(String sourcePath, String targetPath,
String text, Color color, float alpha) {
try {
BufferedImage sourceImage = ImageIO.read(new File(sourcePath));
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
BufferedImage result = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(sourceImage, 0, 0, null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
// 创建小块水印
int tileSize = 150;
BufferedImage tile = createTextTile(text, tileSize, color);
for (int x = 0; x < width; x += tileSize) {
for (int y = 0; y < height; y += tileSize) {
g2d.drawImage(tile, x, y, null);
}
}
g2d.dispose();
ImageIO.write(result, "jpg", new File(targetPath));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建文字小方块
*/
private static BufferedImage createTextTile(String text, int size, Color color) {
BufferedImage tile = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = tile.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setFont(new Font("宋体", Font.PLAIN, 20));
g2d.setColor(color);
// 在方块中心绘制文字
FontMetrics fm = g2d.getFontMetrics();
int textWidth = fm.stringWidth(text);
int textHeight = fm.getHeight();
// 绘制两行文字和简单边框
g2d.drawString(text, (size - textWidth) / 2, (size - textHeight) / 2);
g2d.drawRect(5, 5, size - 10, size - 10);
g2d.dispose();
return tile;
}
/**
* 批量添加水印
*/
public static void batchAddWatermark(String sourceDir, String targetDir,
String watermarkText, float alpha) {
File dir = new File(sourceDir);
File target = new File(targetDir);
if (!target.exists()) {
target.mkdirs();
}
File[] files = dir.listFiles((d, name) ->
name.endsWith(".jpg") ||
name.endsWith(".jpeg") ||
name.endsWith(".png") ||
name.endsWith(".bmp"));
if (files != null) {
for (File file : files) {
String fileName = file.getName();
String targetPath = targetDir + File.separator + fileName;
try {
// 添加文字水印
addTextWatermarkCenter(file.getAbsolutePath(), targetPath,
watermarkText, alpha);
System.out.println("处理完成: " + fileName);
} catch (Exception e) {
System.err.println("处理失败: " + fileName + " - " + e.getMessage());
}
}
}
}
private static void addTextWatermarkCenter(String sourcePath, String targetPath,
String text, float alpha) {
try {
BufferedImage source = ImageIO.read(new File(sourcePath));
int width = source.getWidth();
int height = source.getHeight();
BufferedImage result = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, 0, 0, null);
// 半透明水印
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
// 多行文字水印
g2d.setFont(new Font("微软雅黑", Font.PLAIN, Math.max(20, width / 20)));
g2d.setColor(Color.WHITE);
// 居中绘制
FontMetrics fm = g2d.getFontMetrics();
int textWidth = fm.stringWidth(text);
int x = (width - textWidth) / 2;
int y = height / 2;
// 添加文字阴影效果
g2d.setColor(new Color(0, 0, 0, 100));
g2d.drawString(text, x + 2, y + 2);
// 主文字
g2d.setColor(new Color(255, 255, 255, 150));
g2d.drawString(text, x, y);
g2d.dispose();
ImageIO.write(result, "jpg", new File(targetPath));
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试类
WatermarkTest.java
import java.awt.*;
/**
* 水印测试类
*/
public class WatermarkTest {
public static void main(String[] args) {
String sourcePath = "D:/test/source.jpg";
String targetPath = "D:/test/result.jpg";
String watermarkPath = "D:/test/logo.png";
// 1. 添加文字水印
ImageWatermarkUtil.addTextWatermark(
sourcePath,
targetPath,
"© 2024 版权所有",
Font.BOLD,
30,
new Color(255, 255, 0),
0.5f,
100,
100
);
// 2. 添加平铺文字水印
ImageWatermarkUtil.addTextWatermarkTile(
sourcePath,
"D:/test/result_tile.jpg",
"PROTECTED",
Font.PLAIN,
20,
Color.WHITE,
0.1f
);
// 3. 添加图片水印
ImageWatermarkUtil.addImageWatermark(
sourcePath,
watermarkPath,
"D:/test/result_logo.jpg",
0.5f,
50,
50,
0.5
);
// 4. 添加右下角图片水印
ImageWatermarkUtil.addImageWatermarkBottomRight(
sourcePath,
watermarkPath,
"D:/test/result_logo_br.jpg",
0.3f
);
// 5. 使用高级功能
WatermarkService.addRotatedTextWatermark(
sourcePath,
"D:/test/result_rotated.jpg",
"CONFIDENTIAL",
0.3f,
true
);
// 6. 批量处理
// WatermarkService.batchAddWatermark(
// "D:/test/images",
// "D:/test/watermarked",
// "SAMPLE",
// 0.3f
// );
System.out.println("所有水印处理完成!");
}
}
Web应用集成示例
WatermarkController.java (Spring Boot)
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* 水印API接口
*/
@RestController
@RequestMapping("/api/watermark")
public class WatermarkController {
/**
* 上传图片并添加文字水印
*/
@PostMapping("/text")
public ResponseEntity<byte[]> addTextWatermark(
@RequestParam("file") MultipartFile file,
@RequestParam("text") String text,
@RequestParam(value = "alpha", defaultValue = "0.5") float alpha) {
try {
// 读取上传的图片
BufferedImage sourceImage = ImageIO.read(file.getInputStream());
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
// 创建画布
BufferedImage result = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = result.createGraphics();
// 绘制原图
g2d.drawImage(sourceImage, 0, 0, null);
// 设置水印
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2d.setFont(new Font("微软雅黑", Font.BOLD, Math.max(20, width / 15)));
// 计算位置(底部居中)
FontMetrics fm = g2d.getFontMetrics();
int textWidth = fm.stringWidth(text);
int x = (width - textWidth) / 2;
int y = height - 50;
// 添加阴影效果
g2d.setColor(new Color(0, 0, 0, 100));
g2d.drawString(text, x + 2, y + 2);
// 主文字
g2d.setColor(Color.WHITE);
g2d.drawString(text, x, y);
g2d.dispose();
// 输出图片
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(result, "jpg", baos);
return ResponseEntity.ok()
.header("Content-Type", "image/jpeg")
.body(baos.toByteArray());
} catch (IOException e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 上传图片并添加图片水印
*/
@PostMapping("/image")
public ResponseEntity<byte[]> addImageWatermark(
@RequestParam("file") MultipartFile file,
@RequestParam("watermark") MultipartFile watermark,
@RequestParam(value = "alpha", defaultValue = "0.5") float alpha) {
try {
// 读取两张图片
BufferedImage sourceImage = ImageIO.read(file.getInputStream());
BufferedImage watermarkImage = ImageIO.read(watermark.getInputStream());
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
// 创建结果图片
BufferedImage result = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = result.createGraphics();
// 绘制原图
g2d.drawImage(sourceImage, 0, 0, null);
// 绘制水印(右下角)
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
int watermarkWidth = watermarkImage.getWidth();
int watermarkHeight = watermarkImage.getHeight();
int x = width - watermarkWidth - 20;
int y = height - watermarkHeight - 20;
g2d.drawImage(watermarkImage, x, y, null);
g2d.dispose();
// 输出
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(result, "jpg", baos);
return ResponseEntity.ok()
.header("Content-Type", "image/jpeg")
.body(baos.toByteArray());
} catch (IOException e) {
return ResponseEntity.badRequest().build();
}
}
}
使用说明与注意事项
依赖配置 (pom.xml)
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 图片处理(可选,用于更高级的图片处理) -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.20</version>
</dependency>
</dependencies>
注意事项
- 性能优化:处理大图片时建议先压缩再加水印
- 中文支持:确保系统有对应中文字体
- 内存管理:及时释放Graphics对象
- 色彩模式:处理PNG透明图片时使用ARGB模式
- 文件名处理:避免中文路径导致的编码问题
这些示例代码覆盖了常见的水印使用场景,您可以根据实际需求进行调整和扩展。