当前位置: 首页 > 知识库问答 >
问题:

PDFBox 1.8.10:填写并签署文件,再次填写失败

栾钟展
2023-03-14
    Exception in thread "main" java.lang.NullPointerException
        at org.apache.pdfbox.pdmodel.interactive.form.PDAppearance.calculateFontSize(PDAppearance.java:930)
        at org.apache.pdfbox.pdmodel.interactive.form.PDAppearance.setAppearanceValue(PDAppearance.java:359)
        at org.apache.pdfbox.pdmodel.interactive.form.PDVariableText.setValue(PDVariableText.java:131)
        at com.c10n.scalibur.ehealthdemo.examples.PdfEditor.fill(PdfEditor.java:100)
        at com.c10n.scalibur.ehealthdemo.examples.SignPdf_ProfileLayer.start(SignPdf_ProfileLayer.java:66)
        at com.c10n.scalibur.ehealthdemo.examples.SignPdf_ProfileLayer.main(SignPdf_ProfileLayer.java:28)

我在失败的填充运行中所做的:

    File curentDocument new File("doc_v2_fillsigned.pdf);
    File newDocument = new File("doc_v2_fillsigned_filled.pdf);

    String fieldName ="New Emergency Contact";
    String value="test";
    PDDocument doc = null;

    try(FileOutputStream fos = new FileOutputStream(newDocument)){

        try(FileInputStream fis = new FileInputStream(currentDocument);){
            int c;
            while ((c = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, c);
            }
        }

        doc = PDDocument.load(currentDocument);
        PDDocumentCatalog catalog = doc.getDocumentCatalog();

        catalog.getCOSObject().setNeedToBeUpdate(true);
        catalog.getPages().getCOSObject().setNeedToBeUpdate(true);

        PDAcroForm form = catalog.getAcroForm();

        form.getCOSObject().setNeedToBeUpdate(true);
        form.getDefaultResources().getCOSObject().setNeedToBeUpdate(true);

        PDField field = form.getField(fieldName);
        field.setValue(value); // here the exception occurs.

        // What should happen afterwards:
        field.getCOSObject().setNeedToBeUpdate(true);
        field.getAcroForm().getCOSObject().setNeedToBeUpdate(true);

        ((COSDictionary) field.getDictionary().getDictionaryObject("AP")).getDictionaryObject("N").setNeedToBeUpdate(true);

        try(FileInputStream fis = new FileInputStream(newDocument)){
            doc.saveIncremental(fis, fos);
        }
    }finally{
        if(null != doc){
            doc.close();
            doc=null;
        }
    }

文件:

同样,任何帮助解决这个问题都是欢迎的!

更新:

mkl在评论中要求创建fillsigned PDF的代码。到目前为止,我了解到,只有签名就足够了,让上面的填充代码在之后失败。下面是签名代码中的一些例外:

@Override
public byte[] sign(InputStream data) throws SignatureException, IOException {
    CMSTypedDataInputStream input = new CMSTypedDataInputStream(data);
    try {

        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(certData);

        X509Certificate signCert = (X509Certificate)certFactory.generateCertificate(in);

        ContentSigner signer = new MyContentSigner(profile);

        SignerInfoGenerator i = new JcaSignerInfoGeneratorBuilder(
                new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())

        .build(signer,signCert);

        Store<?> certStore = new JcaCertStore(Collections.singletonList(signCert));

        CMSSignedDataGenerator cmsGen = new CMSSignedDataGenerator();

        cmsGen.addCertificates(certStore);
        cmsGen.addSignerInfoGenerator(i);

        CMSSignedData signedData = cmsGen.generate(input);

        byte[] result =signedData.getEncoded(); 
        return result;
    } catch (Exception e) {
        e.printStackTrace();
        throw new SignatureException(e);
    }
}
public void sign(SignatureInterface signer, String signatureFieldName, int pageNumber, String location, String reason, boolean lock) throws IOException, SignatureException{
    PDSignature signature = new PDSignature();
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); // for visible sigs!

    signature.setLocation(location);
    signature.setReason(reason);

    signature.setSignDate(Calendar.getInstance());

    SignatureOptions options = makeSignatureVisible(signature,signatureFieldName, pageNumber, lock );

    doc.addSignature(signature, signer, options);
}
SignatureOptions makeSignatureVisible( PDSignature signature, String fieldName, int pageNumber, boolean lock) throws IOException{
    PDDocumentCatalog catalog = doc.getDocumentCatalog();

    catalog.getCOSObject().setNeedToBeUpdate(true);
    catalog.getPages().getCOSObject().setNeedToBeUpdate(true);

    PDAcroForm form = catalog.getAcroForm();

    form.getCOSObject().setNeedToBeUpdate(true);
    form.getDefaultResources().getCOSObject().setNeedToBeUpdate(true);

    PDSignatureField field = (PDSignatureField) form.getField(fieldName);

    field.setSignature(signature);      
    field.setReadonly(lock);

    FileInputStream image = new FileInputStream("MUniverse_Signature.jpg");

    PDVisibleSignDesigner visibleSig =  new PDVisibleSignDesigner(newDocument.getName(), image, 1);

    PDRectangle area = getFieldArea(field);

    float max_width = area.getWidth();
    float max_height = area.getHeight();

    float scale = 1;

    if(max_height < visibleSig.getHeight()){
        scale = max_height / visibleSig.getHeight();
        System.out.println("scale: "+scale);
    }

    if(max_width < scale*visibleSig.getWidth()){
        scale = max_width / visibleSig.getWidth();
        System.out.println("scale: "+scale);
    }

    float zoom = ((scale-1)*100);

    visibleSig.zoom(zoom);

    PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(pageNumber);
    visibleSig.coordinates(area.getLowerLeftX(),page.getMediaBox().getHeight()-area.getUpperRightY());
    visibleSig.signatureFieldName(fieldName);

    PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();

    signatureProperties.signerName("name").signerLocation("location").signatureReason("Security")
    .visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();

    SignatureOptions options = new SignatureOptions();
    options.setVisualSignature(signatureProperties);

    return options;
}

问候,

丹尼尔

共有1个答案

贺景胜
2023-03-14

基于此,我简单地将PDFBox示例CreateVisibleSigNature应用到OP的原始doc_v2.pdf文件中。实际上,这已经删除了字体默认资源字典。

因此,这显然看起来像是PDFBox错误。

在PDFBox Jira上环顾四周,实际上已经可以发现这方面的问题:

    null
  • PrepleNonVisualSignatural清除AcroForm DR(AcroForm.setDefaultResources(null)),如果存在其他表单字段,则该

这主要与非视觉签名有关,因此它是手头问题的附属部分。因此,DR似乎在与PDFBox的签名中迷失了方向

因此,这是一个已知的问题。我不确定PDFBox开发是否在优先级时考虑了问题投票,但如果你对这个问题的解决感兴趣,投票不会有什么坏处...;)

 类似资料:
  • 当我使用以下参数(无论是通过来自服务器的HTTPS POST还是通过DocuSign API Explorer)时,日期就会被创建信封的日期预先填充,并且在签名者打开信封进行签名时,日期就会显示为这样的日期。 我在使用沙箱环境。有窃听器吗?这可能和时区有关吗?

  • 问题内容: 我从我的android应用程序中的新功能开始,这将有助于填写某些PDF表格。 我发现最好的解决方案是使用iText库。 我可以读取文件,也可以从文档中读取AcroFields,但是是否有可能发现特定字段标记为必填项? 我试图在API文档和Internet上找到此选项,但是没有什么可以帮助解决此问题。 问题答案: 请查看我的书的 13.3.4节,标题为“ AcroForms重新访问”。清

  • 问题内容: 我确实使用MultipartEntity将文件发送到服务器,它在superglobal 中正确显示 但是我还需要填写POST正文以通过以下方式读取 我怎样才能做到这一点? 当前的摘要如下: MultipartEntity是HttpMime 4.1.2 API 文档的一部分 问题答案: 只需添加一些到您的。 您可以使用该对象来提供值。 这是一个如何使用它的示例: 这是PHP脚本的输出:

  • 我正在尝试用java做一个MVC应用程序,我想有一个带有JTable的窗口。 显然,这是一个可以显示多列列表框的组件,我想用实现相同接口的不同类的实例来填充它。 我现在唯一能做的就是用Object[][]和一个列名字符串数组初始化我的JTable。 但这感觉不对。每当包含原始对象列表的模型发生变化时,我必须重新加载JTable中的所有内容。。。 是否有一种方法可以简单地将Vector绑定到JTab

  • 问题内容: 这个问题已经在这里有了答案 : MySQL如何填充范围内的缺失日期? (5个答案) 2年前关闭。 我有这个查询,我想用一些值(例如零…)填充缺失的日期。 结果如下: 如何用零值填充缺失的日期?有人有主意吗? 我需要这些数据来进行 图表 预览。 问题答案: 通常,您可以使用以下方法在MySQL中生成一系列N个整数: 请注意,您联接的表(someTable)必须至少具有N行。 上面的-1是

  • 问题内容: 我有一个收藏。 产品浏览 我有一个查询,用于获取特定产品的每日视图。 询问 当前结果 问题 问题是,这种聚合不会在有视图的几天内返回。这会导致数据显示不正确: 结果应该看起来像 PS:最好输入开始和结束日期以基于此范围输出结果 问题答案: 您需要几个额外的步骤来返回默认值。首先,你需要使用与设置为收集所有结果中的一个文件内。然后,您可以将$ map 与一组天作为输入。在其中,您可以使用