本文详解如何在 pdf.js 的 canvas 渲染流程中正确插入自定义文本(如水印、页眉、调试标记等),重点解决因渲染覆盖导致文本不可见的常见问题,并提供可立即运行的完整示例与关键注意事项。
本文详解如何在 pdf.js 的 canvas 渲染流程中正确插入自定义文本(如水印、页眉、调试标记等),重点解决因渲染覆盖导致文本不可见的常见问题,并提供可立即运行的完整示例与关键注意事项。
在使用 pdf.js 渲染 PDF 时,开发者常希望通过
你的代码中:
gcc.fillText("Hello World", canvas.width/2, canvas.height/2);
page.render({canvasContext: gcc, viewport: viewport}); // ← 此行清空并重绘 Canvas!
page.render() 内部会调用 clearRect(0, 0, width, height) 并执行 PDF 图形指令,因此前置绘制的文本必然被擦除。
✅ 正确做法是:在 page.render() 完成后,再执行文本绘制,即利用其返回的 RenderTask 的 promise 链式回调:
function renderPage(pageNumber, canvas) {
thePdf.getPage(pageNumber).then(function(page) {
const viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
const ctx = canvas.getContext('2d');
// Step 1: 执行 PDF 渲染
const renderTask = page.render({
canvasContext: ctx,
viewport: viewport
});
// Step 2: 渲染完成后,再绘制自定义文本(确保不被覆盖)
renderTask.promise.then(function() {
ctx.font = "30px 'Comic Sans MS', sans-serif";
ctx.fillStyle = "rgba(0, 128, 0, 0.8)"; // 半透明绿色,避免遮挡内容
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(`Page ${pageNumber}`, canvas.width / 2, canvas.height / 2);
}).catch(console.error);
});
}
? 关键要点说明:
- 渲染与绘制必须分阶段:PDF 内容由 page.render() 生成;自定义图形/文本必须在其 promise 解析后追加。
- 字体与样式建议:优先使用 Web 安全字体(如 'Helvetica', sans-serif),避免依赖本地字体(Comic Sans MS 在多数服务器环境不可用);使用 rgba() 控制透明度,提升可读性。
- 坐标系注意:page.getViewport() 返回的 height/width 是逻辑像素尺寸,与 Canvas 的 height/width 属性一致,可直接用于定位。
-
性能提示:若需为每页添加相同水印(如“DRAFT”),建议复用 ctx 绘制逻辑;若涉及复杂 SVG 或多层文本,可考虑在 renderTask.promise 后叠加绝对定位的 层(需同步 Canvas 尺寸与 CSS transform),但 Canvas 原生绘制更轻量、更可控。
? 进阶技巧:如需动态文本(如当前时间、用户 ID),可在 renderTask.promise.then() 中实时生成字符串;若需抗锯齿文本,可启用 ctx.imageSmoothingEnabled = true(对文字效果有限,主要影响缩放图像)。
总结:pdf.js 的 Canvas 渲染是单向覆写流程,任何前置绘制都会失效。牢记“先渲染 PDF,后叠加文本”的原则,并依托 renderTask.promise 实现可靠时机控制——这是实现页眉、水印、调试标注等增强功能的核心范式。









