创建PDF/A-3:嵌入式文件应包含有效的Params密钥

use*_*193 3 pdf itext

我试图用itextpdf-5.4.5和itext-pdfa-5.4.5创建一个PDF/A-3.当我设置PdfFileSpecification时,我得到以下异常:

com.itextpdf.text.pdf.PdfAConformanceException: Embedded file shall contain valid Params key.
Run Code Online (Sandbox Code Playgroud)

这是我创建PdfDictionary的部分:

PdfDictionary params = new PdfDictionary();
params.put(PdfName.MODDATE, new PdfDate());
PdfFileSpecification fileSpec = PdfFileSpecification.fileEmbedded(
writer, "./src/main/resources/com/itextpdf/invoice.xml", "invoice.xml", null, false, "text/xml", params);
Run Code Online (Sandbox Code Playgroud)

我找到了检查发生的方法,但我没有找到任何解决方案:

com.itextpdf.text.pdf.internal.PdfA3Checker.checkEmbeddedFile

protected void checkEmbeddedFile(PdfDictionary embeddedFile) {
    PdfDictionary params = getDirectDictionary(embeddedFile.get(PdfName.PARAMS));
    if (params == null) {
        throw new PdfAConformanceException(embeddedFile, MessageLocalization.getComposedMessage("embedded.file.shall.contain.valid.params.key"));
    }
Run Code Online (Sandbox Code Playgroud)

任何的想法?先感谢您!

mkl*_*mkl 5

一般来说

PDF/A-3对嵌入式文件有一些特殊要求,其中包括

嵌入文件的流字典应包含Params键,其值应为至少包含ModDate键的字典,其值应为源文件的最新修改日期.

(ISO 19000-3的附录E.1)

iText支持使用iText解释PDF/A-3如何从头开始创建符合PDF/A-3标准的PDF文件,他们还演示了如何以符合PDF/A-3标准的方式嵌入文件,其示例代码如下:

PdfDictionary parameters = new PdfDictionary();
parameters.put(PdfName.MODDATE, new PdfDate());
PdfFileSpecification fileSpec = PdfFileSpecification.fileEmbedded(
    writer, "./src/main/resources/com/itextpdf/invoice.xml",
    "invoice.xml", null, "application/xml", parameters, 0);
fileSpec.put(new PdfName("AFRelationship"), new PdfName("Data"));
writer.addFileAttachment("invoice.xml", fileSpec);
PdfArray array = new PdfArray();
array.add(fileSpec.getReference());
writer.getExtraCatalog().put(new PdfName("AF"), array);
Run Code Online (Sandbox Code Playgroud)

此示例还将相关文件条目(AF)添加到目录,这是另一个要求.

顺便说一句,严格来说,Params字典只在一个应该基础上,而不是必须.因此,这实际上是一个建议,并且可以存在有效的PDF/A-3文档,其中包含没有此条目的附件.

因为没有明显的理由为什么iText在创建PDF/A-3文件时不遵循这个建议会更好,但是它的检查的严格解释是可以的.

iText 5.4.5中的问题

最近发布了OP发现的检查.在将文件存储在PDF文件中时,已经触发了此检查.不幸的是,此时尚未分配params字典,仅保留了引用.因此,即使在编写字典后不久,检查也会失败.

来自PdfFileSpecification.java:

        stream.put(PdfName.TYPE, PdfName.EMBEDDEDFILE);
        stream.flateCompress(compressionLevel);
        PdfDictionary param = new PdfDictionary();
        if (fileParameter != null) {
            param.merge(fileParameter);
        }
        if (!param.contains(PdfName.MODDATE)) {
            param.put(PdfName.MODDATE, new PdfDate());
        }
        if (fileStore != null) {
            param.put(PdfName.SIZE, new PdfNumber(stream.getRawLength()));
            stream.put(PdfName.PARAMS, param);
        }
        else
            stream.put(PdfName.PARAMS, refFileLength);

        if (mimeType != null)
            stream.put(PdfName.SUBTYPE, new PdfName(mimeType));

        ref = writer.addToBody(stream).getIndirectReference();
Run Code Online (Sandbox Code Playgroud)

在此操作期间,检查发生(并且失败).

        if (fileStore == null) {
            stream.writeLength();
            param.put(PdfName.SIZE, new PdfNumber(stream.getRawLength()));
            writer.addToBody(param, refFileLength);
        }
Run Code Online (Sandbox Code Playgroud)

在这之后,直接在这里写下参数.

解决方法

PdfFileSpecification.fileEmbedded允许您将数据显示为byte[]文件系统中的文件而不是文件.正如您在上面的源代码中所看到的,处理在这种情况下有所不同:fileStore包含该byte[]参数.如果你fileStore在那里跟进使用,你会发现,对于null它的非值,params字典被写为直接对象,因此出现在测试中.

因此,如果您将文件作为byte[]实例提供,则可以将iText 5.4.5用于PDF/A-3文件附件.