itextsharp 添加文字水印需在onendpage中先调用cb.savestate(),再设置旋转/透明度/字体,用cb.showtextaligned()居中绘制;图片水印须预加载为jpeg/png对象并缩放定位;pdfstamper构造时设true启用权限提升可锁定水印但触发加密警告;.net core下推荐改用itext7或启用wpf/winforms支持。

用 iTextSharp 添加文字水印时,PageStamp 和 ContentByte 的调用时机很关键
直接在 OnEndPage 里写水印,但没调用 cb.SaveState() 和 cb.RestoreState(),会导致后续内容(比如页眉页脚)被旋转或透明度污染。文字水印必须在页面内容绘制前叠加,且需独立坐标系。
- 先调用
cb.SaveState(),再设置旋转、字体、颜色、透明度 - 用
cb.BeginText()+cb.ShowTextAligned()写文字,别用ColumnText - 文字位置建议用
document.PageSize.Width / 2和document.PageSize.Height / 2居中,再手动平移避免裁剪 - 如果水印文字被原PDF内容盖住,说明你写在了
DirectContent而不是DirectContentUnder
iTextSharp v5 中图片水印必须预加载为 PdfTemplate 或 Jpeg 对象
不能直接传文件路径字符串给 cb.AddImage();否则会抛出 NullReferenceException 或静默失败。图片尺寸、DPI、色彩模式也会影响渲染效果——常见问题是 PNG 透明通道丢失或 JPG 拉伸变形。
- 用
Jpeg.GetInstance(imagePath)加载 JPG,Png.GetInstance(imagePath)加载 PNG(注意后者需启用 alpha 支持) - 缩放图片推荐用
img.ScaleAbsolute(200f, 100f),别依赖原始尺寸;太大易撑破页面,太小看不清 - 叠加前务必调用
img.SetAbsolutePosition(x, y),x/y 是左下角坐标,不是中心点 - 若 PDF 原始页面是 A4 但旋转了(如 landscape),要先读
page.PageSize.Rotate再算坐标
替换现有 PDF 时,PdfStamper 的构造参数决定水印是否可编辑
用 new PdfStamper(reader, output, '<p>用 <code>new PdfStamper(reader, output, '\0', true) 的第四个参数设为 true,才能启用“提升权限”模式,否则添加的水印图层可能被 Acrobat 识别为普通内容而允许删除。但这也意味着输出 PDF 会带修改密码保护标记(即使没设密码),部分下游系统会报“文档已加密”警告。
true,才能启用“提升权限”模式,否则添加的水印图层可能被 Acrobat 识别为普通内容而允许删除。但这也意味着输出 PDF 会带修改密码保护标记(即使没设密码),部分下游系统会报“文档已加密”警告。
- 不加权限提升:水印能被轻易删掉,适合内部草稿
- 加权限提升:水印图层锁定,但需确认接收方 PDF 阅读器兼容性(尤其国产阅读器常忽略该标志)
-
PdfStamper.FormFlattening = true可防止表单域遮挡水印,但会丢弃所有交互能力
.NET Core 项目里引用 iTextSharp 会遇到签名冲突和 GDI+ 依赖问题
iTextSharp v5.5.x 不支持 .NET Standard,强行 NuGet 安装后编译通过,运行时却在 PdfContentByte.ShowTextAligned() 报 System.TypeInitializationException —— 根源是其内部用了 System.Drawing.Common,而 .NET Core 3.1+ 默认不启用 GDI+。
- 方案一:降级用 iText7(
iText7.PdfCore),API 完全重写,但支持 .NET 6+,水印用Canvas+Div构建 - 方案二:保留 iTextSharp,项目文件加
<usewpf>true</usewpf>或<usewindowsforms>true</usewindowsforms> - 方案三:改用
QuestPDF生成带水印的新 PDF,而非修改旧文件——适合水印内容固定、无需保留原文档结构的场景
真正麻烦的不是加水印这一步,而是判断原 PDF 是否含加密、是否有 XFA 表单、是否用了非标准字体嵌入——这些都会让水印位置偏移或文字乱码。动手前先用 PdfReader.IsEncrypted 和 reader.Catalog.GetAsDict(PdfName.ACROFORM) 探查文档元信息。










