1

我正在尝试将文件附加到现有的 PDF/A-3。

示例说明如何创建 PDF/A-3 并将内容附加到其中。

我的下一步是修改代码并使用 PdfAStamper 而不是文档。

所以这是我的结果代码。

private ByteArrayOutputStream append(byte[] content, InputStream inPdf) throws IOException, DocumentException {

  ByteArrayOutputStream result = new ByteArrayOutputStream(16000);
  PdfReader reader = new PdfReader(inPdf);
  PdfAStamper stamper = new PdfAStamper(reader, result, PdfAConformanceLevel.PDF_A_3B);

  stamper.createXmpMetadata();

  // Creating PDF/A-3 compliant attachment.
  PdfDictionary embeddedFileParams = new PdfDictionary();
  embeddedFileParams.put(PARAMS, new PdfName(ZF_NAME));
  embeddedFileParams.put(MODDATE, new PdfDate());
  PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(stamper.getWriter(), null,ZF_NAME, content , "text/xml", embeddedFileParams,0);
  fs.put(AFRELATIONSHIP, Alternative);
  stamper.addFileAttachment("file description",fs);

  stamper.close();
  reader.close();
  return result;
}

这是错误的堆栈跟踪。

    com.itextpdf.text.pdf.PdfAConformanceException: EF key of the file specification dictionary for an embedded file shall contain dictionary with valid F key.
    at com.itextpdf.text.pdf.internal.PdfA3Checker.checkFileSpec(PdfA3Checker.java:95)
    at com.itextpdf.text.pdf.internal.PdfAChecker.checkPdfAConformance(PdfAChecker.java:198)
    at com.itextpdf.text.pdf.internal.PdfAConformanceImp.checkPdfIsoConformance(PdfAConformanceImp.java:70)
    at com.itextpdf.text.pdf.PdfWriter.checkPdfIsoConformance(PdfWriter.java:3380)
    at com.itextpdf.text.pdf.PdfWriter.checkPdfIsoConformance(PdfWriter.java:3376)
    at com.itextpdf.text.pdf.PdfFileSpecification.toPdf(PdfFileSpecification.java:309)
    at com.itextpdf.text.pdf.PdfIndirectObject.writeTo(PdfIndirectObject.java:157)
    at com.itextpdf.text.pdf.PdfWriter$PdfBody.write(PdfWriter.java:424)
    at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:402)
    at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:381)
    at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:334)
    at com.itextpdf.text.pdf.PdfWriter.addToBody(PdfWriter.java:819)
    at com.itextpdf.text.pdf.PdfFileSpecification.getReference(PdfFileSpecification.java:256)
    at com.itextpdf.text.pdf.PdfDocument.addFileAttachment(PdfDocument.java:2253)
    at com.itextpdf.text.pdf.PdfWriter.addFileAttachment(PdfWriter.java:1714)
    at com.itextpdf.text.pdf.PdfStamper.addFileAttachment(PdfStamper.java:497)

现在,当我尝试分析 Stacktrace 并查看时,PdfFileSpecification.fileEmbedded 我看到创建了一个带有 F 和 UF 条目的 EF。

往里PdfA3Checker看,我发现那行PdfDictionary embeddedFile = getDirectDictionary(dict.get(PdfName.F));不是目录,而是 strem。

if (fileSpec.contains(PdfName.EF)) {
    PdfDictionary dict = getDirectDictionary(fileSpec.get(PdfName.EF));
    if (dict == null || !dict.contains(PdfName.F)) {
        throw new PdfAConformanceException(obj1, MessageLocalization.getComposedMessage("ef.key.of.file.specification.dictionary.shall.contain.dictionary.with.valid.f.key"));
    }

    PdfDictionary embeddedFile = getDirectDictionary(dict.get(PdfName.F));
    if (embeddedFile == null) {
        throw new PdfAConformanceException(obj1, MessageLocalization.getComposedMessage("ef.key.of.file.specification.dictionary.shall.contain.dictionary.with.valid.f.key"));
    }

    checkEmbeddedFile(embeddedFile);
}

这是 iText 中的错误还是我遗漏了什么?顺便说一句,我使用的是 iText 5.4.5。

更新 1

正如 Bruno an mkl所建议的,4.5.6-Snapshot 应该包含修复。我尝试了我的测试用例要点链接到针对当前主干的完整测试用例。但结果是同样的错误。

4

2 回答 2

3

您遇到了一个与创建 PDF/A-3 中的错误非常相似的错误:嵌入式文件应包含有效的参数键

问题(如您所见)在此代码中

PdfDictionary embeddedFile = getDirectDictionary(dict.get(PdfName.F));
if (embeddedFile == null) {
    throw new PdfAConformanceException(obj1, MessageLocalization.getComposedMessage("ef.key.of.file.specification.dictionary.shall.contain.dictionary.with.valid.f.key"));
}

在 PdfA3Checker.checkFileSpec(PdfWriter, int, Object); 即使dict包含名为F的流,getDirectDictionary(dict.get(PdfName.F))也不会返回它。但是,原因不是在这里寻找字典(流本质上是带有一些添加的字典),而是由以下PdfAChecker.getDirectObject方式调用的问题PdfAChecker.getDirectDictionary

protected PdfObject getDirectObject(PdfObject obj) {
    if (obj == null)
        return null;
    //use counter to prevent indirect reference cycling
    int count = 0;
    while (obj.type() == 0) {
        PdfObject tmp = cachedObjects.get(new RefKey((PdfIndirectReference)obj));
        if (tmp == null)
            break;
        obj = tmp;
        //10 - is max allowed reference chain
        if (count++ > 10)
            break;
    }
    return obj;
}

此方法仅查找缓存的对象(即 in cachedObjects),但在您的情况下(以及我的测试),此流已被写入文件并且不再位于缓存中,导致null返回...更正,参见 PPS : 已经写好了,但是一开始还没有缓存

PS:如果在 PDF 创建过程中添加 PDF/A-3 符合文件附件(使用 a PdfAWriter),但如果在 PDF 操作过程中添加(使用 a )则不行PdfAStamper;在这些用例中,缓存可能不同。

PPS:确实有区别:通过将添加的对象添加到缓存来PdfAWriter覆盖重载。不这样做,而且是从and派生的,而不是从.addToBodyPdfAStamperImpPdfStamperImpPdfWriterPdfAWriter

于 2014-02-10T09:54:56.707 回答
2

您确实遇到了 iText 5.4.5 中的错误。此处报告了此错误:创建 PDF/A-3:嵌入式文件应包含有效的参数键 它已在 iText 的 SVN 版本中修复。我们正在准备下一个版本的 iText(本周到期)。

于 2014-02-10T07:49:56.717 回答