在C#开发过程中,为PDF文档添加文字水印是一项非常常见的需求。无论是保护版权、标注文档状态,还是防止内容被随意使用,水印都是一种实用且有效的方案。而通过代码实现批量处理,不仅能大幅提升效率,还能获得更精准的控制效果,远胜于手动使用专业软件逐一操作。

本文重点介绍如何借助 Free Spire.PDF for .NET 这个开源免费库,通过C#代码实现两种常见的文字水印效果——平铺背景水印(也称平铺水印)和局部单处水印(固定位置水印)。同时,水印透明度、旋转角度等常用配置也会一并覆盖,让你拿来就能直接用。
一、准备工作
1.1 安装 Free Spire.PDF
该库通过NuGet安装最为便捷。在Visual Studio中,右键项目 → 管理NuGet程序包 → 搜索“FreeSpire.PDF”,选择最新稳定版安装即可。当然,使用包管理器控制台运行一条命令也同样方便:
Install-Package FreeSpire.PDF
注意:这是一个免费社区版,唯一的限制是单次处理不能超过10页。如果原始PDF超出10页,超出部分不会报错,但会被悄悄截断。因此,该库更适合小文档或开发测试阶段使用。
1.2 引入命名空间
在代码文件头部添加以下引用:
using Spire.Pdf; using Spire.Pdf.Graphics; using System.Drawing;
二、使用 PdfTilingBrush 绘制平铺文字水印
PdfTilingBrush 是 Free Spire.PDF 提供的一个平铺画刷工具。核心思路很简单:设定一个平铺单元的尺寸(tileWidth 和 tileHeight),水印就会在页面上像贴瓷砖一样重复出现,形成网格状或阵列状的背景效果。这种玩法特别适合制作“文件密级”“内部资料”等全页背景水印。
下面是完整的平铺水印实现代码:
using Spire.Pdf;
using Spire.Pdf.Graphics;
using System.Drawing;
namespace TextWatermarkDemo
{
class Program
{
static void Main(string[] args)
{
// 加载PDF文档
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("sample.pdf");
// 设置单个水印单元的尺寸(控制水印间距,可根据需求调整)
float tileWidth = 260f;
float tileHeight = 260f;
// 创建平铺画刷,覆盖页面区域
PdfTilingBrush brush = new PdfTilingBrush(
new SizeF(tileWidth, tileHeight));
// 设置水印透明度(0.0 完全透明,1.0 完全不透明)
brush.Graphics.SetTransparency(0.3f);
// 保存图形状态
brush.Graphics.Sa ve();
// 平移并旋转画布,使水印呈倾斜效果
brush.Graphics.TranslateTransform(brush.Size.Width / 2, brush.Size.Height / 2);
brush.Graphics.RotateTransform(-45); // 逆时针旋转45度
// 创建字体
PdfTrueTypeFont font = new PdfTrueTypeFont("微软雅黑", 24f, PdfFontStyle.Regular, true);
// 绘制水印文字
string watermarkText = "内部文档 · 禁止外传";
brush.Graphics.DrawString(
watermarkText,
font,
PdfBrushes.Gray,
0,
0,
new PdfStringFormat(PdfTextAlignment.Center, PdfVerticalAlignment.Middle));
brush.Graphics.Restore();
brush.Graphics.SetTransparency(1f);
// 为每一页应用平铺画刷
foreach (PdfPageBase page in pdf.Pages)
{
page.Canvas.DrawRectangle(brush, new RectangleF(0, 0, page.Canvas.ClientSize.Width, page.Canvas.ClientSize.Height));
// 保存生成带水印的PDF
pdf.Sa veToFile("output.pdf");
}
}
}
}
代码要点:
tileWidth和tileHeight决定了水印单元的尺寸,也就是水印重复排列的间距。实际生成时,PDF页面会被这个尺寸的单元格自动铺满,每个单元格里都包含旋转后的水印文字。PdfTilingBrush创建一个指定尺寸的画刷。当用它绘制一个较大的矩形(比如整个页面)时,会自动以画刷尺寸为单元进行平铺填充。- 水印透明度通过
SetTransparency(0.3f)控制,取值范围0.0到1.0,数值越小越透明。 - 在平移和旋转操作中,
TranslateTransform将水印的原点移到单元格中心,RotateTransform让水印倾斜,避免死板的正向平铺感。 - 字体构造比较直接:
new PdfTrueTypeFont("微软雅黑", 24f, PdfFontStyle.Regular, true)直接指定字体名称、字号、样式以及是否嵌入,支持中文显示,简洁明了。 - 页面绘制部分,对每一页调用
page.Canvas.DrawRectangle,将平铺画刷铺满整个页面区域,水印就覆盖全页并重复平铺了。
三、添加单处局部文本水印
如果需求没那么复杂——比如只想在页面某个角落、页眉或页脚放置一个水印,而非糊满全屏——那操作更简单,直接在页面画布的指定坐标处绘制文字即可。这种方式适合添加版权信息、公司名称、页码等。
using Spire.Pdf;
using Spire.Pdf.Graphics;
using System.Drawing;
namespace TextWatermarkDemo
{
class Program
{
static void Main(string[] args)
{
// 加载PDF文档
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("sample.pdf");
foreach (PdfPageBase page in pdf.Pages)
{
PdfBrush brush = new PdfSolidBrush(Color.FromArgb(60, Color.DarkBlue));
PdfFont font = new PdfFont(PdfFontFamily.TimesRoman, 22f);
string waterText = "© 2026 Copyright";
// 在页面右下角绘制水印,预留边距
float x = page.ActualSize.Width - 220;
float y = page.ActualSize.Height - 40;
page.Canvas.DrawString(waterText, font, brush, x, y);
// 保存生成带水印的PDF
pdf.Sa veToFile("simple_watermark.pdf");
}
}
}
}
关键参数说明:
Color.FromArgb(60, Color.DarkBlue)创建了一个带透明度的颜色,第一个参数60表示Alpha通道(0~255),数值越小越透明。PdfFontFamily.TimesRoman是内置PDF字体族,无需嵌入字体,生成的文件体积较小。但缺点是该字体只支持英文及基本字符,不支持中文。page.ActualSize.Width/Height用于获取页面的实际宽高,方便计算相对位置,非常实用。page.Canvas.DrawString在指定的(x, y)坐标处绘制水印文字,坐标原点位于页面左上角,务必注意。
位置调整技巧:
- 右下角:
x = pageWidth - textWidth - margin,y = pageHeight - margin - 左下角:
x = margin,y = pageHeight - margin - 居中:
x = (pageWidth - textWidth) / 2,y = (pageHeight - textHeight) / 2
如果需要精确测量文字宽度,可以使用 font.MeasureString 方法获取 SizeF 尺寸。
四、实际应用建议与注意事项
4.1 选择合适的水印方式
不同场景应选择不同的水印方案。这里简单梳理一下:
- 文档密级标识、草稿状态、内部文件(全页背景警示) → 平铺背景水印(平铺水印)
- 版权声明、公司名称、页码、简单的"Confidential"水印 → 局部单处水印(固定位置水印)
- 需要水印倾斜且重复布满整页,但不希望过于遮挡正文 → 平铺背景水印 + 低透明度
4.2 平铺水印的间距与密度调优
- 单元格尺寸:建议
tileWidth和tileHeight设置在200~400像素之间。如果尺寸太小,文字容易重叠,绘制性能也会受影响;尺寸太大,水印显得稀疏,背景警示作用会减弱。 - 文字字号:平铺水印中的字号通常选择18~28磅。字号必须明显小于单元格尺寸,否则文字会相互挤压。
- 旋转角度:-45° 或 -30° 是比较常用的倾斜角度,既美观又不容易与正文内容混淆。
4.3 局部水印的坐标与原点
- 坐标系原点:页面左上角为 (0,0),X轴向右为正,Y轴向下为正。务必牢记这个方向。
- 底部位置:Y坐标接近
page.ActualSize.Height。例如放在底部边距40磅处,y = pageHeight - 40。 - 顶部位置:Y坐标设置较小(比如20磅)。
- 绘制文字前,建议先用
MeasureString测量文字尺寸,避免超出页面边界。
4.4 字体与中文支持
- 平铺水印:使用
PdfTrueTypeFont("字体名", 字号, 样式, true),最后一个参数true表示将字体嵌入PDF,确保中文在任何设备上都能正常显示。 - 局部水印:如果使用
PdfFontFamily内置字体族(如TimesRoman、Helvetica),它们不支持中文。要显示中文,必须同样使用PdfTrueTypeFont并嵌入中文字体。 - 字体名称:在Windows系统上,常用中文字体有“微软雅黑”、“宋体”、“黑体”等。
4.5 常见问题排查
实际开发中可能会遇到一些坑,这里列出几个常见问题及解决方法:
- 水印不显示或极淡:透明度设置过低(例如
0.1f)。可先调至0.5f测试,也可能是颜色与背景过于接近,尝试使用深色。 - 平铺水印没有平铺,只显示一个:
PdfTilingBrush的尺寸等于或大于页面尺寸。缩小tileWidth/tileHeight即可。 - 局部水印位置不对:多半是忽略了坐标系原点在左上角、Y轴向下为正。顶部用较小Y值,底部用较大Y值,牢记这一规则。
- 中文显示为乱码或方框:使用了不支持中文的
PdfFontFamily,或者未设置字体嵌入。改用PdfTrueTypeFont并确保参数为true。 - 保存后水印丢失:检查
Sa veToFile之前是否意外关闭了PdfDocument。确保绘制循环完成后再保存。
五、总结
本文详细介绍了使用C#为PDF添加文字水印的两种主流方式——平铺背景水印(平铺水印)和局部单处水印(固定位置水印)。两种方法均提供了可直接运行的完整代码示例,并对关键参数、中文支持、间距调整等常见问题做了说明。需要提醒的是,免费版有10页限制,且平铺水印中必须正确设置字体嵌入才能支持中文显示。
在实际开发中,根据业务需求选择合适的方式即可。多留意坐标原点与方向、透明度调节以及内存管理。希望这些内容能帮助你快速为自己的C#项目集成稳定可靠的PDF文字水印功能。
