You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js使用PFX文件签名PDF后可视化签章不显示的问题求助

Node.js使用PFX文件签名PDF后可视化签章不显示的问题求助

最近接了个任务,需要用Node.js结合PFX文件给PDF做数字签名。现在签名功能已经跑通了,也能在PDF里找到指定标记位置添加签名占位符,但遇到了一个很棘手的问题:签名在视觉上完全没有显示出来。

具体情况是这样的:PDF里的签名位置是个空白框,鼠标悬停上去能看到签名有效性的提示,但框里啥都没有——既没有常见的✔对勾、✖叉号,也没有我设置的签名人名称、原因这些文字信息,完全不像官方/政府文档里那种一目了然的签章效果。点击这个空白框倒是能弹出签名有效性的对话框,证明签名是有效的,但视觉上就是一片空白,完全达不到需求里的效果。

我是通过在PDF中查找标记文本DigiSign来定位签名位置的,然后用pdf-lib添加占位符,再用@signpdf的工具完成签名。下面是我的完整代码,麻烦各位大佬帮忙看看哪里出了问题,怎么才能让可视化的签章正常显示出来?

const express = require('express');
const { PDFDocument, rgb, StandardFonts, PDFName, PDFNumber } = require('pdf-lib');
const signpdf = require('@signpdf/signpdf').default;
const { P12Signer } = require('@signpdf/signer-p12');
const { pdflibAddPlaceholder } = require('@signpdf/placeholder-pdf-lib');
const pdfjsLib = require('pdfjs-dist/legacy/build/pdf.mjs');

const app = express();
app.use(express.json({ limit: '50mb' }));

async function findMarkerCoords(pdfBuffer, marker) {
    const loadingTask = pdfjsLib.getDocument({ data: new Uint8Array(pdfBuffer) });
    const pdf = await loadingTask.promise;
    const numPages = pdf.numPages;

    for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
        const page = await pdf.getPage(pageIndex + 1);
        const textContent = await page.getTextContent();

        for (const item of textContent.items) {
            if (item.str && item.str.includes(marker)) {
                return { pageIndex, x: item.transform[4], y: item.transform[5] };
            }
        }
    }
    throw new Error(`Marker "${marker}" not found in any page.`);
}

app.post('/sign', async (req, res) => {
    try {
        const { pdf, pfx, password } = req.body;
        if (!pdf || !pfx || !password) {
            return res.status(400).json({ status: 'error', message: 'Missing pdf, pfx, or password.' });
        }

        const pdfBuffer = Buffer.from(pdf, 'base64');
        const pfxBuffer = Buffer.from(pfx, 'base64');
        const marker = 'DigiSign';

        // Get coordinates of the marker text
        const { pageIndex, x, y } = await findMarkerCoords(pdfBuffer, marker);

        // Load PDF with pdf-lib
        const pdfDoc = await PDFDocument.load(pdfBuffer);
        const pdfPage = pdfDoc.getPages()[pageIndex];
        const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
        const fontSize = 10;

        // Draw the signature appearance box
        const sigX = x;
        const sigY = y;
        const sigWidth = 180;
        const sigHeight = 60;

        const pages = pdfDoc.getPages();
        for (const page of pages) {
            const annots = page.node.Annots();
            if (annots) {
                const annotsArray = annots.asArray();
                for (const annotRef of annotsArray) {
                    const annot = pdfDoc.context.lookup(annotRef);
                    annot.set(PDFName.of('F'), PDFNumber.of(4));
                    annot.set(PDFName.of('Type'),PDFName.of('Annot'));
                    annot.set(PDFName.of('Subtype'),PDFName.of('Widget'));
                    annot.set(PDFName.of('FT'),PDFName.of('Sig'));
                    const rect = pdfDoc.context.obj([sigX,sigY,sigX + sigWidth , sigY + sigHeight]);
                    annot.set(PDFName.of('Rect'),rect);
                }
            }
        }

        // Add visible signature placeholder
        pdflibAddPlaceholder({
            pdfDoc : pdfDoc,
            pdfPage : pdfPage,
            reason: 'Signed for approval',
            contactInfo: 'xyz@gmail.com',
            name: 'Aditya Garg',
            location: 'India',
            signingTime: new Date(),
            signatureLength: 12000,
            widgetRect: [sigX, sigY, sigX + sigWidth, sigY + sigHeight],
        });

        // Make signature annotation visible
        const pdfWithPlaceholder = await pdfDoc.save({ useObjectStreams: false });
        const signer = new P12Signer(pfxBuffer, { passphrase: password });
        const signedPdf = await signpdf.sign(Buffer.from(pdfWithPlaceholder), signer);

        return res.json({ status: 'success', signedPdf: signedPdf.toString('base64') });
    } catch (err) {
        console.error('Signing failed:', err);
        return res.status(500).json({ status: 'error', message: err.message });
    }
});

app.listen(3000, () => {
    console.log('✅ Digital Signature Server running at http://localhost:3000');
});

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 13:03:03