news 2026/1/12 11:21:31

用Java给图片添加水印:简单几行代码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Java给图片添加水印:简单几行代码实现

用Java给图片添加水印:简单几行代码实现

在日常开发中,图片水印是保护知识产权、标注来源的常用手段。Java通过 javax.imageio 和 java.awt 相关API,无需依赖第三方框架,仅用几行核心代码就能实现图片水印功能(支持文字水印/图片水印、自定义位置/透明度/旋转角度)。本文将带大家从基础实现到进阶优化,快速掌握实用的图片水印工具类。

一、核心原理

Java操作图片的核心是** BufferedImage (内存中的图片缓冲区)和 Graphics2D **(绘图上下文):

1. 通过 ImageIO.read() 读取原始图片,生成 BufferedImage 对象;
2. 调用 BufferedImage.createGraphics() 获取 Graphics2D ,用于绘制水印(文字/图片);
3. 配置水印的样式(字体、颜色、透明度、旋转角度等);
4. 将水印绘制到原始图片的指定位置;
5. 通过 ImageIO.write() 将处理后的图片写入磁盘或输出流。

二、基础实现:文字水印(最简单版本)

先实现一个极简版文字水印工具,支持自定义水印文字、位置、字体和颜色,核心代码仅10行左右:

1. 完整代码

java
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
* Java图片文字水印工具(基础版)
*/
public class ImageWatermarkDemo {
public static void main(String[] args) {
// 原始图片路径、输出图片路径、水印文字
String srcImagePath = "D:/test/original.jpg";
String destImagePath = "D:/test/watermarked.jpg";
String watermarkText = "CSDN-技术干货";

try {
// 1. 读取原始图片
BufferedImage srcImage = ImageIO.read(new File(srcImagePath));
// 2. 获取绘图上下文(Graphics2D)
Graphics2D g2d = srcImage.createGraphics();

// 3. 配置水印样式(字体、颜色、透明度)
g2d.setFont(new Font("微软雅黑", Font.BOLD, 36)); // 字体:微软雅黑,加粗,36号
g2d.setColor(new Color(255, 255, 255, 128)); // 颜色:白色,透明度128(0-255,值越小越透明)

// 4. 绘制水印(x=50,y=80为水印左上角坐标)
g2d.drawString(watermarkText, 50, 80);

// 5. 释放资源
g2d.dispose();

// 6. 保存处理后的图片(格式为JPG,支持PNG/GIF等)
ImageIO.write(srcImage, "jpg", new File(destImagePath));
System.out.println("水印添加成功!输出路径:" + destImagePath);
} catch (IOException e) {
System.err.println("水印添加失败:" + e.getMessage());
e.printStackTrace();
}
}
}


2. 关键参数说明

- 透明度控制: new Color(255,255,255,128) 中最后一个参数是Alpha通道(0=完全透明,255=完全不透明),建议设为100-150,避免遮挡原图;
- 字体配置: new Font(字体名称, 样式, 字号) ,样式支持 Font.BOLD (加粗)、 Font.ITALIC (斜体)、 Font.PLAIN (普通);
- 坐标设置: drawString(文字, x, y) 中 y 是文字基线的纵坐标(不是左上角),需根据字号调整,避免文字超出图片范围。

三、进阶实现:通用水印工具类(支持文字+图片水印)

实际开发中需要更灵活的功能,比如图片水印、平铺水印、旋转水印等。下面封装一个通用工具类,支持两种水印类型,且可自定义各项参数:

1. 工具类完整代码

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;

/**
* 通用图片水印工具类(支持文字水印/图片水印)
*/
public class WatermarkUtils {
// 水印类型枚举
public enum WatermarkType {
TEXT, IMAGE
}

/**
* 给图片添加水印
*
* @param srcImagePath 原始图片路径
* @param destImagePath 输出图片路径
* @param content 水印内容(文字水印=文字,图片水印=图片路径)
* @param type 水印类型(TEXT/IMAGE)
* @param font 文字水印字体(仅文字水印有效)
* @param color 文字水印颜色(仅文字水印有效)
* @param alpha 透明度(0-1,0=完全透明,1=完全不透明)
* @param rotate 旋转角度(0-360,顺时针为正)
* @param x 水印左上角x坐标
* @param y 水印左上角y坐标
* @param scale 水印缩放比例(图片水印有效,1=原尺寸)
* @throws IOException 图片读取/写入异常
*/
public static void addWatermark(String srcImagePath, String destImagePath,
String content, WatermarkType type, Font font,
Color color, float alpha, int rotate, int x, int y, float scale) throws IOException {
// 1. 读取原始图片
BufferedImage srcImage = ImageIO.read(new File(srcImagePath));
int srcWidth = srcImage.getWidth();
int srcHeight = srcImage.getHeight();

// 2. 创建图片缓冲区(与原图同尺寸、同类型)
BufferedImage destImage = new BufferedImage(srcWidth, srcHeight, srcImage.getType());
Graphics2D g2d = destImage.createGraphics();

// 3. 绘制原图到缓冲区
g2d.drawImage(srcImage, 0, 0, srcWidth, srcHeight, null);

// 4. 配置水印全局属性(透明度、抗锯齿)
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); // 透明度
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 抗锯齿(优化文字/图片边缘)

// 5. 根据水印类型绘制水印
if (type == WatermarkType.TEXT) {
// 文字水印
g2d.setFont(font);
g2d.setColor(color);
drawRotatedText(g2d, content, x, y, rotate); // 支持旋转
} else if (type == WatermarkType.IMAGE) {
// 图片水印
BufferedImage watermarkImage = ImageIO.read(new File(content));
int watermarkWidth = (int) (watermarkImage.getWidth() * scale);
int watermarkHeight = (int) (watermarkImage.getHeight() * scale);
drawRotatedImage(g2d, watermarkImage, x, y, rotate, watermarkWidth, watermarkHeight); // 支持旋转+缩放
}

// 6. 释放资源
g2d.dispose();

// 7. 保存图片(自动识别格式)
String format = destImagePath.substring(destImagePath.lastIndexOf(".") + 1);
ImageIO.write(destImage, format, new File(destImagePath));
}

/**
* 绘制旋转文字
*/
private static void drawRotatedText(Graphics2D g2d, String text, int x, int y, int rotate) {
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(rotate), x, y); // 以(x,y)为旋转中心
g2d.setTransform(transform);
g2d.drawString(text, x, y);
}

/**
* 绘制旋转+缩放图片
*/
private static void drawRotatedImage(Graphics2D g2d, BufferedImage image, int x, int y, int rotate, int width, int height) {
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(rotate), x + width / 2, y + height / 2); // 以图片中心为旋转中心
transform.scale(scale, scale); // 缩放
g2d.setTransform(transform);
g2d.drawImage(image, x, y, width, height, null);
}

// ------------------------------ 测试方法 ------------------------------
public static void main(String[] args) {
try {
// 测试1:添加文字水印(旋转45度,半透明)
addWatermark(
"D:/test/original.jpg",
"D:/test/text_watermark.jpg",
"原创内容,禁止转载",
WatermarkType.TEXT,
new Font("宋体", Font.BOLD + Font.ITALIC, 28),
new Color(0, 0, 0, 100), // 黑色半透明
0.5f,
45, // 旋转45度
100, // x坐标
200, // y坐标
1.0f // 文字水印无需缩放
);

// 测试2:添加图片水印(缩放0.5倍,不旋转)
addWatermark(
"D:/test/original.jpg",
"D:/test/image_watermark.jpg",
"D:/test/logo.png", // 水印图片路径
WatermarkType.IMAGE,
null, // 图片水印无需字体
null, // 图片水印无需颜色
0.6f, // 60%透明度
0, // 不旋转
50, // x坐标
50, // y坐标
0.5f // 缩放为原尺寸的50%
);

System.out.println("水印添加完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}


2. 核心功能亮点

- 双水印类型:支持文字水印(自定义字体/颜色/旋转)和图片水印(自定义缩放/透明度);
- 抗锯齿优化:通过 RenderingHints 开启抗锯齿,避免文字或图片边缘模糊;
- 灵活旋转:可指定旋转角度,文字水印以左上角为中心,图片水印以自身中心为中心旋转;
- 自动格式识别:根据输出路径后缀自动识别图片格式(JPG/PNG/GIF等)。

四、常用扩展场景

1. 平铺水印(全屏重复显示)

如果需要在图片上全屏平铺水印(比如版权声明),只需在工具类中添加循环绘制逻辑:

java
/**
* 平铺文字水印(全屏重复)
*/
public static void addTileTextWatermark(String srcPath, String destPath, String text, Font font, Color color, float alpha) throws IOException {
BufferedImage srcImage = ImageIO.read(new File(srcPath));
int srcWidth = srcImage.getWidth();
int srcHeight = srcImage.getHeight();
Graphics2D g2d = srcImage.createGraphics();

g2d.drawImage(srcImage, 0, 0, srcWidth, srcHeight, null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
g2d.setFont(font);
g2d.setColor(color);

// 计算文字宽度和高度,循环平铺
FontMetrics metrics = g2d.getFontMetrics();
int textWidth = metrics.stringWidth(text);
int textHeight = metrics.getHeight();

// 横向间隔:文字宽度+50,纵向间隔:文字高度+50
for (int x = 0; x < srcWidth; x += textWidth + 50) {
for (int y = textHeight; y < srcHeight; y += textHeight + 50) {
g2d.drawString(text, x, y);
}
}

g2d.dispose();
ImageIO.write(srcImage, "jpg", new File(destPath));
}


2. 处理大图片(避免内存溢出)

如果处理超大图片(比如几MB甚至几十MB),直接读取整个图片到内存可能导致OOM,可通过 ImageIO 的 ImageReadParam 分块读取,或使用 Thumbnails (谷歌开源工具)先压缩图片再添加水印:

xml
<!-- 引入Thumbnails依赖(Maven) -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.19</version>
</dependency>


java
// 大图片水印示例(先压缩再加水印)
public static void addWatermarkForLargeImage(String srcPath, String destPath, String text) throws IOException {
Thumbnails.of(srcPath)
.scale(1.0) // 不改变原图尺寸
.outputQuality(0.9) // 保持图片质量
.watermark(Positions.BOTTOM_RIGHT, // 水印位置:右下角
new TextOverlay(text, new Font("微软雅黑", Font.BOLD, 24), Color.WHITE, 0.5f),
0.5f) // 水印透明度
.toFile(destPath);
}


五、注意事项与避坑指南

1. 图片格式兼容:JPG格式不支持透明通道,若需保留水印透明度(比如PNG水印图片),建议输出为PNG格式;
2. 字体路径问题:Linux系统可能没有Windows默认字体(如“微软雅黑”),建议使用跨平台字体(如“宋体”“Arial”),或手动引入字体文件;
3. 坐标越界问题:添加水印前需判断 x+水印宽度 和 y+水印高度 是否超过原图尺寸,避免水印被截断;
4. 性能优化:处理大量图片时,可使用线程池异步处理,同时避免重复创建 Font 、 Color 等对象(缓存复用)。

六、总结

Java原生API实现图片水印简单高效,无需依赖第三方框架,核心是通过 BufferedImage 和 Graphics2D 操作图片缓冲区。本文提供的基础版代码适合快速上手,通用工具类支持文字/图片水印、旋转、缩放等常用功能,可直接集成到项目中。

如果需要更复杂的需求(如渐变水印、动态水印位置计算),可以基于本文工具类进一步扩展。建议收藏本文,遇到图片水印需求时直接复用代码!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/11 20:52:12

从千问灵光 App 看生成式 UI 技术的发展

本文由体验技术团队OpenTiny项目负责人莫春辉老师原创。 引言 2025 年 11 月 18 日&#xff0c;蚂蚁集团全模态通用 AI 助手——灵光 App 发布&#xff0c;上线两周用户已创建 330 万个闪应用。这一现象级数据的背后&#xff0c;不仅是开发效率的提升&#xff0c;更是人机交互…

作者头像 李华
网站建设 2026/1/7 3:50:03

普通程序员必看:该不该转型AI大模型?收藏这篇少走弯路

前言&#xff1a;AI浪潮下&#xff0c;程序员的转型焦虑与机遇 在程序员的日常交流中&#xff0c;"技术迭代"和"职业转型"永远是绕不开的话题。尤其是2023年以来&#xff0c;GPT-4、文心一言等大模型相继爆发&#xff0c;AI技术从实验室走向产业落地&#…

作者头像 李华
网站建设 2026/1/11 16:20:09

医疗挂号管理系统毕业论文+PPT(附源代码+演示视频)

文章目录医疗挂号管理系统一、项目简介&#xff08;源代码在文末&#xff09;1.运行视频2.&#x1f680; 项目技术栈3.✅ 环境要求说明4.包含的文件列表&#xff08;含论文&#xff09;数据库结构与测试用例系统功能结构后台运行截图项目部署源码下载医疗挂号管理系统 如需其他…

作者头像 李华
网站建设 2026/1/10 12:56:53

实用指南:文献怎么查——高效查找文献的方法与技巧

① WisPaper&#xff08;文献聚类 术语辅助&#xff09; 官网&#xff1a;https://www.wispaper.ai 帮助快速理解陌生领域的核心概念和研究主题。 ② Elicit 自动列出最相关论文和方法&#xff0c;为跨学科快速扫文献提供便利。 ③ Explainpaper 逐段解释论文内容&#xff0c…

作者头像 李华
网站建设 2026/1/11 13:28:42

文献检索网站有哪些:常用学术文献检索平台汇总与使用指南

① WisPaper&#xff08;文献聚类 术语辅助&#xff09; 官网&#xff1a;https://www.wispaper.ai 帮助快速理解陌生领域的核心概念和研究主题。 ② Elicit 自动列出最相关论文和方法&#xff0c;为跨学科快速扫文献提供便利。 ③ Explainpaper 逐段解释论文内容&#xff0c…

作者头像 李华
网站建设 2026/1/11 17:40:16

高可用架构下的 1688 API 接口开发与商品数据同步方案

在电商生态中&#xff0c;1688 作为核心的货源供应链平台&#xff0c;其 API 接口的稳定性和商品数据同步的时效性直接影响下游业务的运转。高可用架构下的 1688 API 开发与数据同步&#xff0c;需兼顾接口调用的可靠性、数据一致性、故障容错与性能优化。本文将从架构设计、接…

作者头像 李华