在Node.js中实现PDF鼠标手绘签名功能求助
实现鼠标绘制手写签名嵌入PDF(Node.js + PDF-Lib)
要实现终端用户手写签名嵌入PDF,核心是把用户绘制的签名转为图像,再将图像插入到PDF的签名字段位置。以下是具体实现步骤:
1. 前端实现签名绘制与导出
首先需要在前端用Canvas让用户绘制签名,然后导出为PNG图片(Base64格式)传给后端:
<!-- 前端签名画布 --> <canvas id="signatureCanvas" width="300" height="100" style="border:1px solid #ccc;"></canvas> <button onclick="exportSignature()">确认签名并提交</button> <script> const canvas = document.getElementById('signatureCanvas'); const ctx = canvas.getContext('2d'); let isDrawing = false; // 手写绘制逻辑 canvas.addEventListener('mousedown', (e) => { isDrawing = true; ctx.beginPath(); ctx.moveTo(e.offsetX, e.offsetY); ctx.lineWidth = 2; ctx.strokeStyle = '#000'; }); canvas.addEventListener('mousemove', (e) => { if (isDrawing) { ctx.lineTo(e.offsetX, e.offsetY); ctx.stroke(); } }); canvas.addEventListener('mouseup', () => isDrawing = false); canvas.addEventListener('mouseleave', () => isDrawing = false); // 导出签名为Base64并发送后端 function exportSignature() { const signatureBase64 = canvas.toDataURL('image/png'); fetch('/embed-signature', { method: 'POST', body: JSON.stringify({ signature: signatureBase64, targetPdf: 'pdf24_merged.pdf' }), headers: { 'Content-Type': 'application/json' } }); } </script>
2. 后端用PDF-Lib嵌入签名图像
后端接收前端传来的签名图片,将其嵌入到PDF的签名字段对应位置。原代码使用的是TextField,我们需要先获取该字段的坐标和尺寸,再在对应位置插入图像:
const { PDFDocument } = require('pdf-lib'); const fs = require('fs').promises; const path = require('path'); const express = require('express'); const app = express(); app.use(express.json()); async function embedSignatureToPdf(pdfPath, signatureBase64) { // 加载目标PDF const pdfBuffer = await fs.readFile(path.join(__dirname, pdfPath)); const pdfDoc = await PDFDocument.load(pdfBuffer); // 获取签名字段 const form = pdfDoc.getForm(); const signatureField = form.getTextField('Datum und Unterschrift'); // 获取字段的位置与尺寸(PDF坐标系:原点在页面左下角,单位为点) const [fieldX, fieldY, fieldWidth, fieldHeight] = signatureField.getRectangle(); // 解码Base64签名图片 const signatureBytes = Buffer.from(signatureBase64.split(',')[1], 'base64'); const signatureImage = await pdfDoc.embedPng(signatureBytes); // 获取签名所在页面(默认第一页,可根据实际调整) const targetPage = pdfDoc.getPage(0); // 转换Canvas坐标系到PDF坐标系,绘制图像适配字段尺寸 targetPage.drawImage(signatureImage, { x: fieldX, y: targetPage.getHeight() - fieldY - fieldHeight, width: fieldWidth, height: fieldHeight, }); // 隐藏原文本字段(避免重叠) signatureField.setVisibility(false); // 保存签名后的PDF const signedPdfBuffer = await pdfDoc.save(); await fs.writeFile(path.join(__dirname, 'signed_document.pdf'), signedPdfBuffer); } // 处理前端提交的签名请求 app.post('/embed-signature', async (req, res) => { const { signature, targetPdf } = req.body; try { await embedSignatureToPdf(targetPdf, signature); res.send('签名已成功嵌入PDF'); } catch (err) { res.status(500).send(`处理失败:${err.message}`); } }); app.listen(3000, () => console.log('服务运行在3000端口'));
关键注意点
- 坐标系转换:PDF原点在页面左下角,而Canvas原点在左上角,因此绘制图像时需要用
页面高度 - 字段Y坐标 - 字段高度来修正Y轴位置。 - 签名适配:如果用户绘制的签名比例与字段不符,可以在
drawImage中添加scale参数或调整宽高,避免签名拉伸变形。 - 字段定位:如果签名字段不在第一页,需要修改
getPage(0)为对应页码。
内容的提问来源于stack exchange,提问作者Muhammad Muneeb Waqas
相关产品推荐
相关产品推荐

