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

Jasper Report PDF不符合PDF/UA

桂坚
2023-03-14

我想让Jasper导出的PDF/UA兼容,但Jasper的限制阻止了我这么做。客户正在向我们施压,要求我们妥善完成这项工作。

PDF/UA有很多要求,包括但不限于显示标题和语言、嵌入字体以及向图像添加备用文本。到目前为止,我已经在Jaspersoft Studio中设置了所有508个PDF标记,设置了显示标题和语言的属性,嵌入了字体,并向图像添加了alt文本。我还通过Apache PDFBox将PDF/UA标识符附加到输出PDF中(即生成PDF之后)。我们正在使用Jaspersoft Studio v6。6.0与Jasper Reports Library v6结合使用。数据库为4.0和Oracle。据我所知,由于itext被降级回v2,Jasper在这方面的能力有限。1.7。js6,因为许可问题。

<jasperReport xlmns=...>
        ... // other properties
        <property name="net.sf.jasperreports.awt.ignore.missing.font" value="false"/>
        <property name="net.sf.jasperreports.export.xls.detect.cell.type" value="false"/>
        <property name="net.sf.jasperreports.export.xls.sheet.names.all" value="REPORT SHEET NAME"/>
        <property name="net.sjasperreports.default.pdf.font.name" value="Times-Roman"/>
        <property name="net.sf.jasperreports.export.xls.ignore.graphics" value="false"/>
        <property name="net.sf.jasperreports.default.pdf.embedded" value="true"/>
        <property name="net.sf.jasperreports.export.pdf.metadata.title" value="MY REPORT TITLE"/>
        <property name="net.sf.jasperreports.export.pdf.display.metadata.title" value="true"/>
        <property name="net.sf.jasperreports.export.pdf.tagged" value="true"/>
        <property name="net.sf.jasperreports.export.pdf.tag.language" value="EN-US"/>
        ... // parameters, stored proc call, headings, etc.
        <!-- Possible PDF 508 tags to be set on text fields -->
        <property name="net.sf.jasperreports.export.pdf.tag.table" value="start"/>
        <property name="net.sf.jasperreports.export.pdf.tag.th" value="full"/>
        <property name="net.sf.jasperreports.export.pdf.tag.tr" value="start">
        <property name="net.sf.jasperreports.export.pdf.tag.td" value="full">
        <property name="net.sf.jasperreports.export.pdf.tag.tr" value="end">
        <property name="net.sf.jasperreports.export.pdf.tag.table" value="start"/>
        ...
</jasperReport>
... // other imports
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.XMPSchema;
import org.apache.xmpbox.xml.XmpSerializer;
... // more imports

public class ReportResult {
   ... // other methods

    /*
     * @param pdf - The pdf instance created from BAOS
     * @param title - Document
     * @return BAOS containing metadata (UA-identifier, title)
     */
    private ByteArrayOutputStream appendXMPMetaData(PDDocument pdf, String title) throws TransformerException, IOException {
        XMPMetadata xmp = XMPMetadata.createXMPMetadata();
        xmp.createAndAddDublinCoreSchema();
        xmp.getDublinCoreSchema().setTitle(title);
        xmp.getDublinCoreSchema().setDescription(title);
        xmp.createAndAddPDFAExtensionSchemaWithDefaultNS();
        xmp.getPDFExtensionSchema().addNamespace("http://www.aiim.org/pdfa/ns/schema#", "pdfaSchema");
        xmp.getPDFExtensionSchema().addNamespace("http://www.aiim.org/pdfa/ns/property#", "pdfaProperty");
        xmp.getPDFExtensionSchema().addNamespace("http://www.aiim.org/pdfua/ns/id/", "pdfuaid");

        XMPSchema uaSchema = new XMPSchema(XMPMetadata.createXMPMetadata(),
                "pdfaSchema", "pdfaSchema", "pdfaSchema");
        uaSchema.setTextPropertyValue("schema", "PDF/UA Universal Accessibility Schema");
        uaSchema.setTextPropertyValue("namespaceURI", "http://www.aiim.org/pdfua/ns/id/");
        uaSchema.setTextPropertyValue("prefix", "pdfuaid");

        XMPSchema uaProp = new XMPSchema(XMPMetadata.createXMPMetadata(),"pdfaProperty", "pdfaProperty", "pdfaProperty");
        uaProp.setTextPropertyValue("name", "part");
        uaProp.setTextPropertyValue("valueType", "Integer");
        uaProp.setTextPropertyValue("category", "internal");
        uaProp.setTextPropertyValue("description", "Indicates, which part of ISO 14289 standard is followed");
        uaSchema.addUnqualifiedSequenceValue("property", uaProp);

        xmp.getPDFExtensionSchema().addBagValue("schemas", uaSchema);
        xmp.getPDFExtensionSchema().setPrefix("pdfuaid");
        xmp.getPDFExtensionSchema().setTextPropertyValue("part", "1");

        XmpSerializer serializer = new XmpSerializer();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        serializer.serialize(xmp, baos, true);

        PDMetadata metadata = new PDMetadata(pdf);
        metadata.importXMPMetadata(baos.toByteArray());
        pdf.getDocumentCatalog().setMetadata(metadata);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        pdf.save(byteArrayOutputStream);
        pdf.close();

        return byteArrayOutputStream;
    } 

    protected void getJasperPDFDoc(ReportConfig reportConfig) throws IOException, TransformerException {

        List<ReportParameter> reportParams = reportConfig.getReportParams();

        ... // cookies and printer config

        Map imagesMap = new HashMap();
        request.getSession(true).setAttribute("IMAGES_MAP", imagesMap);

        ByteArrayOutputStream bs = ReportAccess.Instance.getInstance().generateJasperReport(
                getCurrentUserId(), getCurrentUserName(), reportConfig, "PDF",
                 reportParams, getTmpImageUri(),
                 imagesMap, rptTemplateLoc);

        if (bs != null) {
            if (reportConfig.doPrint) {
                response.setContentType("text/html");
            } else {
                log.debug("Got PDF report data");
                String fileName = getReportFileName(reportConfig) + ".pdf";
                response.setContentType("application/pdf");
                String dispositionProperty = "attachment; filename=" + fileName;
                response.setHeader("Content-disposition", dispositionProperty);
            }

            PDDocument pdf = PDDocument.load(new ByteArrayInputStream(bs.toByteArray()));
            ByteArrayOutputStream baosWithMetaData = appendXMPMetaData(pdf, reportConfig.getDisplayName());

            response.setHeader("Content-length", Integer.toString(baosWithMetaData.size()));
            ServletOutputStream os = response.getOutputStream();
            baosWithMetaData.writeTo(os);

            os.flush();
            os.close();
        } else {
            displayError("PDF");
        }
     }

     ... // other methods
}
/* REPORT MANAGER CLASS */
private static void generatePDFDoc(JasperPrint jasperPrint, ByteArrayOutputStream f) {

        try {

            JasperPrint jr = moveTableOfContents(jasperPrint);
            JRPdfExporter exporter  = new JRPdfExporter();
            exporter.setExporterInput(new SimpleExporterInput(jr));
            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(f));

            //configuration
            SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
            configuration.setCompressed(true);
            configuration.setTagged(true);
            configuration.setTagLanguage("EN-US");

            //set configuration
            exporter.setConfiguration(configuration);

            //export to PDF
            exporter.exportReport();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

我注意到Adobe的飞行前检查程序和我们的客户报告的一些错误,如下所示:

  1. 存在非标准标签
  2. 圆形角色图
  3. 附加到每个页面左上角的未知定位单元格
  4. 在表编辑器视图中无法正确识别表

显示我的问题的图像。在此方面的任何帮助都将不胜感激。

共有1个答案

雍光远
2023-03-14

如果您想让事情变得更简单,但方式不同,可以选择PD4ML v4。页面上有一个简约示例:https://pd4ml.tech/pdf-ua/

它使用来自输入HTML/CSS的可用结构和元信息来生成有效的标记PDF/UA。

如果目标是仅通过PDF/UA文件格式验证(例如通过Adobe的预飞行检查器),只需选择常量即可。PDFUA作为输出格式。

pd4ml.writePDF(fos, Constants.PDFUA);

如果目标是生成符合马特宏峰协议的PDF(并通过PAC3https://www.access-for-all.ch/en/pdf-lab/pdf-accessibility-checker-pac.html的验证),很可能您还需要对齐输入超文本标记语言:添加TITLE、ALT和LANG属性,以确保表结构和标题层次结构一致等。

 类似资料:
  • 我想在另一个缩放的PDF页面中插入一个PDF页面。我想用iTextSharp做这个。 我有一个矢量绘图,可以导出为单页PDF文件。我想将此文件添加到其他PDF文档的页面中,就像我将图像添加到PDF文档一样。 这可能吗? 这样做的目的是在不损失质量的情况下保留放大的能力。 使用PDF矢量很难再现矢量绘图,因为它是一个极其复杂的绘图。 导出矢量绘图为高分辨率图像不是一个选项,因为我不得不在一个单独的P

  • 我目前正在评估一些html到pdf包。在使用以下方法时,大多数人似乎都能正确插入分页符:

  • 如果两个字符串具有相同的长度,并且两个字符串中对应的字符具有相同的忽略大小写,则将它们视为相同的忽略大小写。两个字符c1和c2被认为是相同的忽略情况,如果以下至少一个为真: 这两个字符是相同的(通过==运算符比较) 对每个字符应用character.touppercase(char)方法会产生相同的结果

  • 问题内容: 我在AppDelegate中,尝试传递对WatchKit扩展请求的答复。我不能使用枚举数组作为其值键入为AnyObject的Dictionary中的值。在操场上进行实验显示: 当然,可以通过将枚举转换为字符串或数字来解决此问题,但是为什么这在Swift中是类型错误? 问题答案: 为了与Objective-C兼容而存在。您只能将对象放入Objective- C可以解释的数组中。Swift

  • 我正在尝试合并我的应用程序中的两个pdf文件。但我的应用程序在创建组合文件引用的时候不断出现故障。(参见代码中的注释)。有人能给我指一下这里的正确方向吗?谢了。

  • 问题内容: 我试图在我快速编写的类上使用NSCoding协议,但是似乎无法弄清楚为什么当我实现所需的方法时,编译器会抱怨它“不符合协议NSCoding”: 这是一个错误还是我只是缺少一些东西? 问题答案: 如您在报告导航器中详细的编译器消息中所见,您的方法未正确声明: (在beta版本之间可能有所变化。)此外,该方法必须标记为: 在 Swift 3中 ,所需的方法是