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

如何通过PDFBox为签名部件添加打印属性控制印章打印可见性

解决Adobe Reader打印时隐藏PDF签名印章的问题

问题分析

你的代码尝试通过可选内容组(OCG)控制签名印章的打印状态,但存在几个关键问题导致无效:

  • 创建的OCG对象未注册到文档的可选内容属性字典中,Adobe Reader无法识别该OCG的规则
  • 签名的可视化图片未被关联到OCG,也没有实际绘制到页面
  • OCG的PrintState属性设置方式不符合PDF规范要求

修正后的代码实现

private InputStream createVisualSignatureTemplate(PDDocument srcDoc, PDRectangle rect, BufferedImage image, int pageNum, PDSignature signature) throws IOException {
    PDDocument doc = new PDDocument();
    PDPage page = new PDPage(srcDoc.getPage(pageNum).getMediaBox());
    doc.addPage(page);

    PDAcroForm acroForm = new PDAcroForm(doc);
    doc.getDocumentCatalog().setAcroForm(acroForm);

    // 1. 创建并注册可选内容组(OCG)用于控制打印状态
    PDOCProperties ocProperties = doc.getDocumentCatalog().getOCProperties();
    if (ocProperties == null) {
        ocProperties = new PDOCProperties(doc);
        doc.getDocumentCatalog().setOCProperties(ocProperties);
    }
    PDOptionalContentGroup ocg = new PDOptionalContentGroup(doc, "SignatureNoPrint");
    // 设置OCG的打印使用规则:打印时隐藏
    COSDictionary usage = new COSDictionary();
    COSDictionary printDict = new COSDictionary();
    printDict.setItem(COSName.getPDFName("PrintState"), COSName.OFF);
    usage.setItem(COSName.getPDFName("Print"), printDict);
    ocg.getCOSObject().setItem(COSName.getPDFName("Usage"), usage);
    // 将OCG添加到文档的OC属性中
    ocProperties.getOCGs().add(ocg);

    // 2. 创建签名字段和Widget注释
    PDSignatureField signatureField = new PDSignatureField(acroForm);
    PDAnnotationWidget widget = signatureField.getWidgets().get(0);
    // 将Widget注释关联到OCG,控制其打印可见性
    widget.setOptionalContentGroup(ocg);

    signatureField.setValue(signature);
    acroForm.getFields().add(signatureField);
    acroForm.setSignaturesExist(true);
    acroForm.setAppendOnly(true);

    widget.setRectangle(rect);
    widget.setPage(page);
    page.getAnnotations().add(widget);

    // 3. 创建签名可视化内容并关联OCG
    PDFormXObject form = new PDFormXObject(doc);
    form.setBBox(rect);
    PDResources resources = new PDResources();
    form.setResources(resources);

    // 将印章图片转为PDImageXObject
    ByteArrayOutputStream baosImage = new ByteArrayOutputStream();
    ImageIO.write(image, "PNG", baosImage);
    PDImageXObject signatureImage = PDImageXObject.createFromByteArray(doc, baosImage.toByteArray(), "Signature");

    // 在FormXObject中绘制图片
    try (PDPageContentStream cs = new PDPageContentStream(doc, form)) {
        float scaleX = rect.getWidth() / signatureImage.getWidth();
        float scaleY = rect.getHeight() / signatureImage.getHeight();
        cs.drawImage(signatureImage, 0, 0, signatureImage.getWidth() * scaleX, signatureImage.getHeight() * scaleY);
    }

    // 将FormXObject设置为Widget的外观
    PDAppearanceDictionary appearance = new PDAppearanceDictionary();
    PDAppearanceStream appearanceStream = new PDAppearanceStream(form);
    appearance.setNormalAppearance(appearanceStream);
    widget.setAppearance(appearance);

    // 保存文档
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    doc.save(baos);
    doc.close();
    return new ByteArrayInputStream(baos.toByteArray());
}

关键修正点说明

  • 注册OCG:必须将创建的OCG添加到文档的OCProperties字典中,否则阅读器无法识别该可选内容规则
  • 关联Widget到OCG:通过widget.setOptionalContentGroup(ocg)将注释和OCG绑定,确保打印时应用OCG的隐藏规则
  • 正确设置PrintState:严格按照PDF规范构造Usage下的Print字典,使用标准的COSName而非字符串键
  • 绘制可视化内容:补充了图片绘制代码,并将其设置为签名Widget的外观,确保印章正确显示且受OCG控制

验证方法

  • 生成修改后的PDF后,打开Adobe Reader,查看打印预览确认印章已隐藏
  • 若需临时开启印章打印,可通过「视图」→「显示/隐藏」→「可选内容」调整对应OCG的状态

内容的提问来源于stack exchange,提问作者Serendipity

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:01:02