java - 如何将报告导出为 PDF/A-1a、PDF/A-1b?

标签 java jasper-reports pdf-generation export-to-pdf pdfa

在 jasper-report 中生成 PDF/A 包含许多陷阱,并且某些版本的 jasper-report 不支持。这就是为什么我决定通过这篇问题-答案帖子,指出将带有图表的简单报告导出为 PDF/A 所需的步骤和库版本

示例数据 (usersRep.csv)

+----------------+--------+
|      User      |  Rep   |
+----------------+--------+
| Jon Skeet      | 854503 |
| Darin Dimitrov | 652133 |
| BalusC         | 639753 |
| Hans Passant   | 616871 |
| Me             |   5640 |
+----------------+--------+

示例 jrxml (reputation.jrxml)

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reputation" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="a88bd694-4f90-41fc-84d0-002b90b2d73e">
    <queryString>
        <![CDATA[]]>
    </queryString>
    <field name="User" class="java.lang.String"/>
    <field name="Rep" class="java.lang.Long"/>
    <columnHeader>
        <band height="20" splitType="Stretch">
            <staticText>
                <reportElement x="0" y="0" width="100" height="20" uuid="9e7b5f50-5795-4c95-a122-f14f2e3f9366"/>
                <box leftPadding="3" bottomPadding="0" rightPadding="3">
                    <pen lineWidth="0.25"/>
                    <topPen lineWidth="0.25"/>
                    <leftPen lineWidth="0.25"/>
                    <bottomPen lineWidth="0.5" lineStyle="Double"/>
                    <rightPen lineWidth="0.25"/>
                </box>
                <textElement verticalAlignment="Middle">
                    <font fontName="SansSerif" isBold="true"/>
                </textElement>
                <text><![CDATA[User]]></text>
            </staticText>
            <staticText>
                <reportElement x="100" y="0" width="100" height="20" uuid="4a6f0a2a-d9b5-4e74-a9e8-0f965336f2bf"/>
                <box leftPadding="3" bottomPadding="0" rightPadding="3">
                    <pen lineWidth="0.25"/>
                    <topPen lineWidth="0.25"/>
                    <leftPen lineWidth="0.25"/>
                    <bottomPen lineWidth="0.5" lineStyle="Double"/>
                    <rightPen lineWidth="0.25"/>
                </box>
                <textElement textAlignment="Right" verticalAlignment="Middle">
                    <font fontName="SansSerif" isBold="true"/>
                </textElement>
                <text><![CDATA[Reputation]]></text>
            </staticText>
        </band>
    </columnHeader>
    <detail>
        <band height="20" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="100" height="20" uuid="8ff583b9-88dc-4726-85e1-16d79de78095"/>
                <box leftPadding="3" bottomPadding="0" rightPadding="3">
                    <pen lineWidth="0.25"/>
                    <topPen lineWidth="0.25"/>
                    <leftPen lineWidth="0.25"/>
                    <bottomPen lineWidth="0.25"/>
                    <rightPen lineWidth="0.25"/>
                </box>
                <textElement verticalAlignment="Middle">
                    <font fontName="SansSerif"/>
                </textElement>
                <textFieldExpression><![CDATA[$F{User}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="100" y="0" width="100" height="20" uuid="ebd33b2f-7297-41c2-9dc7-78ff472890c4"/>
                <box leftPadding="3" bottomPadding="0" rightPadding="3">
                    <pen lineWidth="0.25"/>
                    <topPen lineWidth="0.25"/>
                    <leftPen lineWidth="0.25"/>
                    <bottomPen lineWidth="0.25"/>
                    <rightPen lineWidth="0.25"/>
                </box>
                <textElement textAlignment="Right" verticalAlignment="Middle">
                    <font fontName="SansSerif"/>
                </textElement>
                <textFieldExpression><![CDATA[$F{Rep}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
    <pageFooter>
        <band height="140">
            <pieChart>
                <chart isShowLegend="false">
                    <reportElement x="225" y="-670" width="320" height="140" uuid="23bd26a6-04a4-406f-8a1a-5e1b260cb75d"/>
                    <chartTitle/>
                    <chartSubtitle/>
                    <chartLegend/>
                </chart>
                <pieDataset>
                    <keyExpression><![CDATA[$F{User}]]></keyExpression>
                    <valueExpression><![CDATA[$F{Rep}]]></valueExpression>
                </pieDataset>
                <piePlot>
                    <plot/>
                    <itemLabel/>
                </piePlot>
            </pieChart>
        </band>
    </pageFooter>
</jasperReport>

导出为 PDF 的 Java 代码 (reputation.pdf)

JasperReport report = JasperCompileManager.compileReport("reputation.jrxml");
JRCsvDataSource datasource = new JRCsvDataSource("usersRep.csv");
datasource.setFieldDelimiter(';');
datasource.setUseFirstRowAsHeader(true);

JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<String, Object>(),datasource);

JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("reputation.pdf"));
SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
configuration.setMetadataAuthor("Me and only me");
exporter.setConfiguration(configuration);
exporter.exportReport();

这会将报告导出为 pdf,我需要做什么才能生成 PDF/A-1a?

最佳答案

JasperReports 库 4.1.2.3 或更高版本 is needed (6.0.0 中不再支持,请参阅末尾的 NullPointerException)。

这些步骤是生成 PDF/A 所需的,可以通过 java 代码或通过将 jrxml property 设置为根标记(jasper-server 支持)来实现。我将展示这两种方法,但只需要一种方法

#设置 PDF/A 一致性

java

configuration.setPdfaConformance(PdfaConformanceEnum.PDFA_1A); // or PdfaConformanceEnum.PDFA_1B

jrxml

<property name="net.sf.jasperreports.export.pdfa.conformance" value="pdfa1a" />

#设置ICC Profile

to avoid JRPdfaIccProfileNotFoundException: The ICC profile is not available to the JVM

java

configuration.setIccProfilePath("srgb.icc");

jrxml

<property name="net.sf.jasperreports.export.pdfa.icc.profile.path" value="srgb.icc" />

#嵌入报告中使用的所有字体,使用 font-extensions

如果仍然有错误

com.lowagie.text.pdf.PdfXConformanceException: All the fonts must be embedded. This one isn't: Helvetica

在 jrxml 中包含默认样式,指示字体扩展中包含的 fontName,示例

<style name="default" isDefault="true" fontName="DejaVu Sans"/>

#删除透明对象和图层(可选内容组)它们是 not allowed

to avoid PdfXConformanceException: Transparency is not allowed

在示例中,图表元素必须是不透明,为了避免标签透明,您可以实现 JRChartCustomizer

public class NoTransparencyCustomizer implements JRChartCustomizer{
    @Override
    public void customize(JFreeChart chart, JRChart jrchart) {
        PiePlot plot = (PiePlot) chart.getPlot();
        plot.setLabelShadowPaint(Color.GRAY);       
    }
}

#设置标记和标记语言(PDF/A-1b 不需要)

java

configuration.setTagged(true);
configuration.setTagLanguage("en-us");

jrxml

<property name="net.sf.jasperreports.export.pdf.tagged" value="true" />
<property name="net.sf.jasperreports.export.pdf.tag.language" value="en-us"/>

#结果

这是实现上述内容的结果,将 fontName 切换为 DejaVu Sans 并使用捆绑的 jasperreports-fonts.jar 作为字体扩展。已在 pdf-tools 上验证成功适用于 PDF/A-1a 和 PDF/A-1b

Result

我没有小菜一碟

XMP属性与文档信息不同步

Validating file "reputation.pdf" for conformance level pdfa-1a
dc:description/*[0] :: Missing language qualifier.
dc:title/*[0] :: Missing language qualifier.
The XMP property 'dc:title' is not synchronized with the document information entry 'Title'.
The XMP property 'dc:description' is not synchronized with the document information entry 'Subject'.

此错误来自于在配置中设置元数据标题或主题时使用旧版 jasper-reports 库 <6.2.0。

configuration.setMetadataTitle("Title");
configuration.setMetadataSubject("Subject");

解决方案是删除这些或将 jasper-reports 更新到版本 6.2.0 或更高版本,请参阅 PDF/A_1A XMP Metadata validation fails if title and/or subject are set了解更多信息

停止支持 在 jasper 报告版本 6.0.0 中,总是抛出 com.itextpdf.text.pdf.internal.PdfA1Checker.checkPdfObject 处的 NullPointerException 。此问题已在 6.0.4 及更高版本中解决,请参阅 Jasper report tracker .

关于java - 如何将报告导出为 PDF/A-1a、PDF/A-1b?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34341527/

相关文章:

java - 在数组中查找重复项,用java中重复出现次数最多的数组填充第二个数组

r - 如何禁用 knitr 图中的透明度?

ruby-on-rails - 如何在 Ruby on Rails 中设置 prawn pdf 文件名?

Android 应用程序上的 Java 计时器

java - 在 HashMap 中选择性地随机生成键

java - 检查提供的语言环境是否存在

java - Netbeans 类路径问题的 JaseperReports 插件

formatting - 在 JasperReports 中打印何时(到达最后一个元素)表达式

jasper-reports - 贾斯珀报告 : How to conditionally set the textbox style?

pdf - poppler pdfunite 无法合并加密的 PDF 文件,如何去除加密? (无需密码即可打开)