PDF 版式固定、便于分发,但其内容一经生成便不易在正文中修改。对于合同、报表、公告等文档,通常需要在不影响正文阅读的前提下标识机密等级、版权归属或“草稿”“样例”等使用状态。文本水印是解决这一问题的常见手段:它以半透明的文字浮于内容之上,既能清楚传达信息,又不破坏原文的可读性。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接完成 PDF 的加载、绘制与保存,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。添加文本水印通常有两种形态:一种是在每页中央沿对角线放置一行水印文字,可通过页面画布的透明度与坐标系变换直接实现;另一种是让文字在整页重复平铺,可借助 PdfTilingBrush 平铺画刷完成。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
将单行文本水印添加到 PDF
单行文本水印会在每页中央生成一行斜向文字,适用于密级或版权标识。做法是:用中文字体的 PdfTrueTypeFont 搭配 MeasureString 测量文字尺寸并计算居中偏移,再逐页通过 SetTransparency、TranslateTransform、RotateTransform 设置透明度、旋转坐标系,最后用 DrawString 绘制水印文字。
function App() {
const addSingleLineTextWatermark = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将支持中文的 TrueType 字体载入 VFS
await window.spire.FetchFileToVFS('ARIAL UNICODE MS.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 将待加水印的 PDF 文件载入 VFS
const inputFileName = '财务报表.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 创建 TrueType 字体:粗体、40 号
let trueTypeFont = new pdfModule.PdfTrueTypeFont({
fontFamily: 'Arial Unicode MS',
size: 40,
style: pdfModule.PdfFontStyle.Bold,
unicode: true
});
// 创建水印笔刷并指定水印文本
let brush = pdfModule.PdfBrushes.get_DarkGray();
const text = '机密文档,不可外泄';
// 测量水印文本的尺寸
let textSize = trueTypeFont.MeasureString({ text: text });
// 计算两个偏移量,用于确定坐标系平移量,使水印沿对角线居中
let offset1 = (textSize.Width * Math.sqrt(2)) / 4;
let offset2 = (textSize.Height * Math.sqrt(2)) / 4;
let format = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Left });
// 遍历文档中的所有页面
for (let i = 0; i < doc.Pages.Count; i++) {
// 获取指定页面
let page = doc.Pages.get_Item(i);
// 设置页面透明度
page.Canvas.SetTransparency(0.8);
// 将坐标系平移到页面中央并补偿文本尺寸带来的偏移
page.Canvas.TranslateTransform(
page.Canvas.ClientSize.Width / 2 - offset1 - offset2,
page.Canvas.ClientSize.Height / 2 + offset1 - offset2
);
// 逆时针旋转坐标系 45 度
page.Canvas.RotateTransform({ angle: -45 });
// 在页面上绘制水印文本
page.Canvas.DrawString({ s: text, font: trueTypeFont, brush: brush, x: 0, y: 0, format: format });
}
// 定义输出文件名并保存文档
const outputFileName = '单行文本水印.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Single-line Text Watermark To PDF</h1>
<button onClick={addSingleLineTextWatermark}>
Generate
</button>
</div>
);
}
export default App;
添加单行文本水印后的 PDF 文档

将多行文本水印添加到 PDF
当需要让水印铺满整页时,可使用多行文本水印。做法是:用 PdfTilingBrush 按页面尺寸划分平铺单元,在单元内以 SetTransparency、RotateTransform 调整透明度与角度并用 DrawString 绘制文字,最后以 DrawRectangle 将画刷填充整页即可。
function App() {
const addMultilineTextWatermark = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将支持中文的 TrueType 字体载入 VFS
await window.spire.FetchFileToVFS('ARIAL UNICODE MS.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 将待加水印的 PDF 文件载入 VFS
const inputFileName = '财务报表.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 获取文档的第一页
let page = doc.Pages.get_Item(0);
// 创建平铺画刷:以页面的一半宽度、三分之一高度作为平铺单元
let size = new pdfModule.SizeF({
width: page.Canvas.ClientSize.Width / 2,
height: page.Canvas.ClientSize.Height / 3
});
let brush = new pdfModule.PdfTilingBrush({ size: size });
// 设置水印透明度为 30%
brush.Graphics.SetTransparency(0.3);
// 保存画刷当前状态,并将坐标系平移、旋转,使水印呈斜向排列
brush.Graphics.Save();
brush.Graphics.TranslateTransform(brush.Size.Width / 2, brush.Size.Height / 2);
brush.Graphics.RotateTransform({ angle: -45 });
// 绘制平铺水印
let format = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Center });
// 创建 TrueType 字体:粗体、25 号
let trueTypeFont = new pdfModule.PdfTrueTypeFont({
fontFamily: 'Arial Unicode MS',
size: 25,
style: pdfModule.PdfFontStyle.Bold,
unicode: true
});
// 绘制水印
brush.Graphics.DrawString({
s: "机密文档",
font: trueTypeFont,
brush: pdfModule.PdfBrushes.get_DarkRed(),
x: 0,
y: -18,
format: format
});
// 恢复画刷之前的状态,并还原为不透明
brush.Graphics.Restore();
brush.Graphics.SetTransparency({ alpha: 1 });
// 用平铺画刷填充整页矩形,使水印文字平铺覆盖整个页面
let rect = new pdfModule.RectangleF({
location: new pdfModule.PointF(0, 0),
size: page.Canvas.ClientSize
});
page.Canvas.DrawRectangle({ brush: brush, rectangle: rect });
// 定义输出文件名并保存文档
const outputFileName = '多行文本水印.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Multiline Text Watermark To PDF</h1>
<button onClick={addMultilineTextWatermark}>
Generate
</button>
</div>
);
}
export default App;
添加多行文本水印后的 PDF 文档

常见问题
如何设置水印文字的字体、字号与颜色
原因:DrawString 需要显式指定绘制文本所用的字体与画刷。
解决:英文字符可使用 PdfFont 配合内置的 PdfFontFamily(如 Helvetica),通过 PdfBrushes 的静态颜色属性指定水印颜色;需要中文等多语言文字或加粗等样式时,应先将对应的 TrueType 字体载入 VFS,再使用 PdfTrueTypeFont:
// 将中文字体载入 VFS
await window.spire.FetchFileToVFS('SIMSUN.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建中文字体与水印画刷
let font = new pdfModule.PdfTrueTypeFont({
fontFamily: '宋体',
size: 24,
style: pdfModule.PdfFontStyle.Regular,
unicode: true
});
let brush = new pdfModule.PdfSolidBrush({
pdfRGBColor: new pdfModule.PdfRGBColor({ color: pdfModule.Color.get_DarkRed() })
});
// 在页面上绘制中文水印(示例中绘制于页面画布)
page.Canvas.DrawString({ s: '机密文件', font: font, brush: brush, x: 0, y: 0, format: format });
如何给 PDF 的每一页都添加水印
原因:单行文本水印示例中已通过页面循环将水印应用到每一页,而多行文本水印示例仅通过 doc.Pages.get_Item(0) 作用于第一页。
解决:需要让多行水印也覆盖整篇文档时,将平铺画刷的创建与页面填充放入页面循环即可:
for (let i = 0; i < doc.Pages.Count; i++) {
let page = doc.Pages.get_Item(i);
// 创建平铺画刷并设置透明度、旋转与文字
let size = new pdfModule.SizeF({
width: page.Canvas.ClientSize.Width / 2,
height: page.Canvas.ClientSize.Height / 3
});
let brush = new pdfModule.PdfTilingBrush({ size: size });
// …… 设置透明度、旋转并绘制水印文字 ……
// 用平铺画刷填充当前页面
page.Canvas.DrawRectangle({
brush: brush,
rectangle: new pdfModule.RectangleF({ location: new pdfModule.PointF(0, 0), size: page.Canvas.ClientSize })
});
}
如何控制水印的透明度与旋转角度
原因:透明度过高或过低会影响水印的观感,旋转角度决定水印文字的方向。
解决:通过 SetTransparency 设置透明度,取值范围为 0(完全透明)到 1(不透明);通过 RotateTransform 控制坐标系旋转角度,负值表示逆时针旋转。单行示例将透明度设为 0.8、旋转 -45 度,多行平铺示例在平铺画刷的图形上下文中做了相同设置:
// 单行水印:设置页面透明度并旋转页面画布
page.Canvas.SetTransparency(0.8);
page.Canvas.RotateTransform({ angle: -45 });
// 多行平铺水印:在平铺画刷的图形上下文中设置透明度并旋转
brush.Graphics.SetTransparency(0.3);
brush.Graphics.RotateTransform({ angle: -45 });
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







