如何使用 HTML5 和 JavaScript 将签名插入 PDF 文档

电子签名是手写签名的数字形式,允许个人以电子方式签署文件。它已成为企业和组织简化签名流程的重要工具,只需单击几下即可在世界任何地方签署文件。在本文中,我们将探讨如何使用 HTML5、JavaScript 和 Dynamsoft 文档查看器将签名插入 PDF 文档。

演示视频:使用电子签名签署 PDF 文档

在线演示

https://yushulx.me/web-document-annotation/

先决条件

  • Dynamsoft Capture Vision 试用许可证:获得 30 天免费试用许可证,以解锁 Dynamsoft 产品的全部功能。
  • Dynamsoft 文档查看器:此 JavaScript SDK 可无缝查看 PDF、JPEG、PNG、TIFF 和 BMP 文件。它还具有 PDF 注释渲染和保存功能。下载链接:https://www.npmjs.com/package/dynamsoft-document-viewer。
  • 实现 Web PDF 编辑器的签名功能

    我们使用 Dynamsoft Document Viewer 构建的 Web 文档注释项目具有高度可扩展性。它目前包括 PDF 文档的条形码检测。在以下部分中,我们将逐步指导您完成向 PDF 文档添加电子签名的过程。

    步骤 1:获取源代码

  • 从 GitHub 存储库克隆源代码:git clone https://github.com/yushulx/web-twain-document-scan-management.git
  • 导航到 document_annotation 目录:cd web-twain-document-scan-management/examples/document_annotation
  • 在 Visual Studio Code 中打开项目。
  • 第 2 步:添加签名按钮

  • 在 main.css 中,为签名按钮添加一个 Material 图标: .icon-stylus::before { content: "edit"; } .icon-stylus { display: flex; font-size: 1.5em; }
  • 在main.js中定义签名按钮,并添加到工具栏中: const signatureButton = { type: Dynamsoft.DDV.Elements.Button, className: "material-icons icon-stylus", tooltip: "Sign the document", events: { click: "sign", } } const pcEditViewerUiConfig = { type: Dynamsoft.DDV.Elements.Layout, flexDirection: "column", className: "ddv-edit-viewer-desktop", children: [ { type: Dynamsoft.DDV.Elements.Layout, className: "ddv-edit-viewer-header-desktop", children: [ { type: Dynamsoft.DDV.Elements.Layout, children: [ Dynamsoft.DDV.Elements.ThumbnailSwitch, Dynamsoft.DDV.Elements.Zoom, Dynamsoft.DDV.Elements.FitMode, Dynamsoft.DDV.Elements.Crop, Dynamsoft.DDV.Elements.Filter, Dynamsoft.DDV.Elements.Undo, Dynamsoft.DDV.Elements.Redo, Dynamsoft.DDV.Elements.DeleteCurrent, Dynamsoft.DDV.Elements.DeleteAll, Dynamsoft.DDV.Elements.Pan, Dynamsoft.DDV.Elements.AnnotationSet, qrButton, checkButton, scanButton, clearButton, signatureButton, ], }, { 类型:Dynamsoft.DDV.Elements.Layout,子级:[ { 类型:Dynamsoft.DDV.Elements.Pagination,className:“ddv-edit-viewer-pagination-desktop”,}, loadButton,downloadButton,], }, ], }, Dynamsoft.DDV.Elements.MainView,], };
  • 添加签名按钮的点击事件处理程序:editViewer.on("sign", sign); function sign() { ... }
  • 步骤 3:创建用于签名输入的弹出对话框

    签名输入弹出对话框包含以下元素:

  • 用于绘制签名的画布元素。
  • 用于更改签名颜色的颜色选项。
  • 用于调整签名粗细的笔划滑块。
  • 用于定位签名的 X 和 Y 坐标。
  • 一个保存按钮,用于将签名插入 PDF 文档。
  • 取消按钮用于关闭对话框。
  • 用于擦除签名的重绘按钮。
  • **HTML 代码**

    Create New Signature

    Color Style:
    Stroke:
    Auto-generate signatures on all pages
    Signature input dialog

    **签名输入对话框的 JavaScript 代码**

  • 初始化画布和绘图上下文: let canvas = document.getElementById("signatureCanvas"); let ctx = canvas.getContext("2d"); let isDrawing = false; let color = "black"; let strokeWidth = 3; let drawingHistory = []; canvas.width = 500; canvas.height = 300;
  • 添加鼠标事件的事件监听器:canvas.addEventListener("mousedown", startDrawing); canvas.addEventListener("mousemove", draw); canvas.addEventListener("mouseup", stopDrawing); canvas.addEventListener("mouseout", stopDrawing);
  • 为颜色和描边选项添加事件监听器:document.getElementById("blue").addEventListener("click", () => { color = "blue"; redrawCanvas(); }); document.getElementById("red").addEventListener("click", () => { color = "red"; redrawCanvas(); }); document.getElementById("black").addEventListener("click", () => { color = "black"; redrawCanvas(); }); document.getElementById("strokeSlider").addEventListener("input", (e) => { strokeWidth = e.target.value; redrawCanvas(); });
  • 实现绘图函数: function startDrawing(event) { isDrawing = true; let currentPath = { color: color, strokeWidth: strokeWidth, points: [{ x: event.offsetX, y: event.offsetY }] }; drawingHistory.push(currentPath); } function draw(event) { if (isDrawing) { let currentPath = drawingHistory[drawingHistory.length - 1]; currentPath.points.push({ x: event.offsetX, y: event.offsetY }); redrawCanvas(); } } function stopDrawing() { isDrawing = false; } function redrawCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawingHistory.forEach(path => { ctx.beginPath(); ctx.moveTo(path.points[0].x, path.points[0].y); for (let i = 1; i < path.points.length; i++) { ctx.lineTo(path.points[i].x, path.points[i].y); } ctx.strokeStyle = color; ctx.lineWidth = strokeWidth; ctx.stroke(); }); } function clearCanvas() { drawingHistory = []; redrawCanvas(); } 所有路径都存储在 drawingHistory 数组中。redrawCanvas 函数遍历数组并在画布上重新绘制路径。
  • 为“确定”、“重绘”和“取消”按钮添加事件监听器: const signatureOKButton = document.getElementById('signatureOK'); const signatureRedrawButton = document.getElementById('signatureRedraw'); const signatureCancelButton = document.getElementById('signatureCancel'); signatureOKButton.addEventListener('click', async () => { ... }); signatureRedrawButton.addEventListener('click', async () => { drawingHistory = []; redrawCanvas(); }); signatureCancelButton.addEventListener('click', async () => { document.getElementById("signature-input").style.display = "none"; });
  • 步骤 4:将签名插入文档

    要将签名插入 PDF 文档:

  • 将画布转换为 blob:canvas.toBlob(async (blob) => { ... }, 'image/png');
  • 获取当前页面ID和页面数据:let currentPageId = currentDoc.pages[editViewer.getCurrentPageIndex()]; let pageData = await currentDoc.getPageData(currentPageId);
  • 使用签名图像创建新的印章注释: const applyToAllPages = document.getElementById("signatureAllPage").checked; const x = Number(document.getElementById("signatureX").value); const y = Number(document.getElementById("signatureY").value); const option = { stamp: blob, x: x > pageData.mediaBox.width - canvas.width ? pageData.mediaBox.width - canvas.width - 10 : x, y: y > pageData.mediaBox.height - canvas.height ? pageData.mediaBox.height - canvas.height - 10 : y, width: canvas.width, height: canvas.height, opacity: 1.0, flags: { print: false, noView: false, readOnly: false, } } 尝试 { if (applyToAllPages) { for (let i = 0; i < currentDoc.pages.length; i++) { let signatureAnnotation = await Dynamsoft.DDV.annotationManager.createAnnotation(currentDoc.pages[i], "stamp", option) signatureAnnotation['name'] = 'signature'; } } else { let signatureAnnotation = await Dynamsoft.DDV.annotationManager.createAnnotation(currentPageId, "stamp", option) signatureAnnotation['name'] = 'signature'; } } catch (e) { console.log(e); }
  • 源代码

    https://github.com/yushulx/web-twain-document-scan-management/tree/main/examples/document_annotation