如何修复 PDFBox 设置的 PDF/A 元数据(使用 Docx4j 和 XDocReport)
How to fix PDF/A metadata set by PDFBox (working with Docx4j and XDocReport)
为了达到可访问性级别 PDF/A-1A,我正在使用 PDFBox v2.0.13 在 PDF 上设置 XMP 元数据。在设置元数据之前,我将文件从 .docx 转换为 pdf。我尝试了两种方法来进行转换:一种使用 XDocReport v.2.0.1,另一种使用 Docx4j v.6.1.0.
在Javaclass中我有以下代码:
PDDocumentInformation info = pdf.getDocumentInformation();
info.setTitle("Apache PDFBox");
info.setSubject("Apache PDFBox adding meta-data to PDF document");
info.setCreator("MyCreator");
...
DublinCoreSchema dcSchema = metadata.createAndAddDublinCoreSchema();
dcSchema.setTitle(info.getTitle());
dcSchema.setDescription(info.getSubject());
dcSchema.addCreator(info.getCreator());
使用 XDocReport 进行转换我得到以下元数据:
</rdf:Description>
<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about="">
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Apache PDFBox</rdf:li>
</rdf:Alt>
</dc:title>
<dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">Apache PDFBox adding meta-data to PDF document</rdf:li>
</rdf:Alt>
</dc:description>
<dc:creator>
<rdf:Seq>
<rdf:li>MyCreator</rdf:li>
</rdf:Seq>
</dc:creator>
</rdf:Description>
我得到了以下元数据,而不是使用 Docx4j 进行转换:
<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about="">
<dc:title>
<rdf:Alt>
<rdf:li lang="x-default">Apache PDFBox</rdf:li>
</rdf:Alt>
</dc:title>
<dc:description>
<rdf:Alt>
<rdf:li lang="x-default">Apache PDFBox adding meta-data to PDF document</rdf:li>
</rdf:Alt>
</dc:description>
<dc:creator>
<rdf:Seq>
<rdf:li>MyCreator</rdf:li>
</rdf:Seq>
</dc:creator>
</rdf:Description>
由于为 "title" 和 "description" 生成的元数据不同,使用 XDocReport 结果生成的最终 pdf PDF/A-1A 可访问,而使用 Docx4j 生成的则不可访问。
可访问性检查是使用 VeraPDF 进行的。
由于 Docx4j 生成的 PDF 更具可读性,有没有办法修复最终 pdf 中的元数据?
docx4j 的 export-FO 使用 Apache FOP (v2.3) 创建 PDF。
因此 export-FO 与 FOP v2.3 具有相同的制作 PDF/A-1A 的能力:https://xmlgraphics.apache.org/fop/2.3/pdfa.html
所以我尝试了:
FOUserAgent foUserAgent = FORendererApacheFOP.getFOUserAgent(foSettings);
foUserAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-1b");
// nb PDF/A-1a, PDF/A-2a and PDF/A-3a require accessibility to be enabled
但它抱怨:
For PDF/A-1b, all fonts, even the base 14 fonts, have to be embedded! Offending font: /Times-Roman
org.apache.fop.pdf.PDFConformanceException: For PDF/A-1b, all fonts, even the base 14 fonts, have to be embedded! Offending font: /Times-Roman
at org.apache.fop.pdf.PDFFont.validate(PDFFont.java:170)
因此您需要考虑嵌入 base 14 字体。
作为旁注,我在使用 export-FO 创建的简单 PDF 上尝试了 PDFBox 的 ExtractMetadata 示例。不幸的是,它报告:
An error ouccred when parsing the meta data: Invalid array definition, expecting Alt and found com.sun.org.apache.xerces.internal.dom.DeferredTextImpl [prefix=dc; name=title]
作为所有这些的替代方案,您可以考虑我们的商业 PDF 转换器。可以产生 PDF/A-2b: https://converter-eval.plutext.com/pdf_archive.html
当 xmpbox 与某些其他库一起使用时,这是一个已知问题,例如离岸价。
问题出在变压器上。
XmpSerializer.java中的代码:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
应该return一个com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl
class。 (试一试)
Java文档:
https://docs.oracle.com/javase/7/docs/api/javax/xml/transform/TransformerFactory.html#newInstance()
"The Services API will look for a classname in the file META-INF/services/javax.xml.transform.TransformerFactory in jars available to the runtime."
您可以通过设置系统属性:
强制默认实现
System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
然而,这可能会弄乱其他库中的某些内容。
另一种解决方案是复制 XmpSerializer 的源代码,并像这样更改 newInstance 调用:
Transformer transformer = TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null).newTransformer();
为了达到可访问性级别 PDF/A-1A,我正在使用 PDFBox v2.0.13 在 PDF 上设置 XMP 元数据。在设置元数据之前,我将文件从 .docx 转换为 pdf。我尝试了两种方法来进行转换:一种使用 XDocReport v.2.0.1,另一种使用 Docx4j v.6.1.0.
在Javaclass中我有以下代码:
PDDocumentInformation info = pdf.getDocumentInformation();
info.setTitle("Apache PDFBox");
info.setSubject("Apache PDFBox adding meta-data to PDF document");
info.setCreator("MyCreator");
...
DublinCoreSchema dcSchema = metadata.createAndAddDublinCoreSchema();
dcSchema.setTitle(info.getTitle());
dcSchema.setDescription(info.getSubject());
dcSchema.addCreator(info.getCreator());
使用 XDocReport 进行转换我得到以下元数据:
</rdf:Description>
<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about="">
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Apache PDFBox</rdf:li>
</rdf:Alt>
</dc:title>
<dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">Apache PDFBox adding meta-data to PDF document</rdf:li>
</rdf:Alt>
</dc:description>
<dc:creator>
<rdf:Seq>
<rdf:li>MyCreator</rdf:li>
</rdf:Seq>
</dc:creator>
</rdf:Description>
我得到了以下元数据,而不是使用 Docx4j 进行转换:
<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about="">
<dc:title>
<rdf:Alt>
<rdf:li lang="x-default">Apache PDFBox</rdf:li>
</rdf:Alt>
</dc:title>
<dc:description>
<rdf:Alt>
<rdf:li lang="x-default">Apache PDFBox adding meta-data to PDF document</rdf:li>
</rdf:Alt>
</dc:description>
<dc:creator>
<rdf:Seq>
<rdf:li>MyCreator</rdf:li>
</rdf:Seq>
</dc:creator>
</rdf:Description>
由于为 "title" 和 "description" 生成的元数据不同,使用 XDocReport 结果生成的最终 pdf PDF/A-1A 可访问,而使用 Docx4j 生成的则不可访问。
可访问性检查是使用 VeraPDF 进行的。
由于 Docx4j 生成的 PDF 更具可读性,有没有办法修复最终 pdf 中的元数据?
docx4j 的 export-FO 使用 Apache FOP (v2.3) 创建 PDF。
因此 export-FO 与 FOP v2.3 具有相同的制作 PDF/A-1A 的能力:https://xmlgraphics.apache.org/fop/2.3/pdfa.html
所以我尝试了:
FOUserAgent foUserAgent = FORendererApacheFOP.getFOUserAgent(foSettings);
foUserAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-1b");
// nb PDF/A-1a, PDF/A-2a and PDF/A-3a require accessibility to be enabled
但它抱怨:
For PDF/A-1b, all fonts, even the base 14 fonts, have to be embedded! Offending font: /Times-Roman
org.apache.fop.pdf.PDFConformanceException: For PDF/A-1b, all fonts, even the base 14 fonts, have to be embedded! Offending font: /Times-Roman
at org.apache.fop.pdf.PDFFont.validate(PDFFont.java:170)
因此您需要考虑嵌入 base 14 字体。
作为旁注,我在使用 export-FO 创建的简单 PDF 上尝试了 PDFBox 的 ExtractMetadata 示例。不幸的是,它报告:
An error ouccred when parsing the meta data: Invalid array definition, expecting Alt and found com.sun.org.apache.xerces.internal.dom.DeferredTextImpl [prefix=dc; name=title]
作为所有这些的替代方案,您可以考虑我们的商业 PDF 转换器。可以产生 PDF/A-2b: https://converter-eval.plutext.com/pdf_archive.html
当 xmpbox 与某些其他库一起使用时,这是一个已知问题,例如离岸价。
问题出在变压器上。
XmpSerializer.java中的代码:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
应该return一个com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl
class。 (试一试)
Java文档: https://docs.oracle.com/javase/7/docs/api/javax/xml/transform/TransformerFactory.html#newInstance()
"The Services API will look for a classname in the file META-INF/services/javax.xml.transform.TransformerFactory in jars available to the runtime."
您可以通过设置系统属性:
强制默认实现System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
然而,这可能会弄乱其他库中的某些内容。
另一种解决方案是复制 XmpSerializer 的源代码,并像这样更改 newInstance 调用:
Transformer transformer = TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null).newTransformer();