合并两个 pdf 时不再有链接和锚点

No more links and anchors when merging two pdfs

我们使用 iText 7.1.0 和 html2pdf 2.0.0 创建了一个应用程序来构建我们的 pdf。 在我们的第一次迭代中,我们向它发送一个 data-object,其中包括 header、body 和页脚的 html,此外还包括 meta-data,如标题等。

html-body 包括 2 个部分:details-part 和 table-part。

到目前为止一切正常,links 和锚点的样式和可点击,meta-data 设置正确(除此之外:我们的 header html,有一个徽标,但我们无法围绕它构建 link。

我们更改了应用程序的行为:现在我们将 data-object 中的 collection 放入应用程序(details-part 和 table-part 分开;每个 data-objects 包括 html 用于 header、body 和页脚,还有 meta-data)。我们遍历 collection,使用之前运行良好的相同方法并将两部分合并在一起。

现在 link 和锚点已设置样式但不再可点击。我们也看不到 meta-data。构建合并时我们有什么问题吗?

控制器:

public byte[] index(@RequestBody PDFDataModelCollection elements, Model model) throws IOException {

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(byteArrayOutputStream);
    try (PdfDocument resultDoc = new PdfDocument(writer)) {
        for (PDFDataModel pdfDataModel : elements.getElements()) {
            PdfReader reader = new PdfReader(new ByteArrayInputStream(creationService.createDatasheet(pdfDataModel)));
            try (PdfDocument sourceDoc = new PdfDocument(reader)) {
                int n = sourceDoc.getNumberOfPages();
                for (int i = 1; i <= n; i++) {
                    PdfPage page = sourceDoc.getPage(i).copyTo(resultDoc);
                    resultDoc.addPage(page);
                }
            }
        }
    }

    return byteArrayOutputStream.toByteArray();
}

方法 createDatasheet():

public byte[] createDatasheet(PDFDataModel pdfDataModel) throws IOException {

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    PdfWriter writer = new PdfWriter(byteArrayOutputStream);

    //Initialize PDF document
    PdfDocument pdfDoc = new PdfDocument(writer);

    try (
        Document document = new Document(pdfDoc)
    ) {
        document.setMargins(0, 0, 0, 0);

        //meta tags
        PDFMetaService.addPdfMetaTags(pdfDoc, pdfDataModel.getMetaModel());

        Header header = new Header(document, this.fontProvider, pdfDataModel.getHeader());

        pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, header);
        pdfDoc.addEventHandler(PdfDocumentEvent.INSERT_PAGE, header);

        Footer footer = new Footer(document, this.fontProvider, pdfDataModel.getFooter());
        pdfDoc.addEventHandler(PdfDocumentEvent.INSERT_PAGE, footer);

        //watermark
        PDFImageModel pdfImageModel = pdfDataModel.getImageModel();
        if (pdfImageModel != null) {
            Watermark watermark = new Watermark(document, pdfImageModel);
            pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, watermark);
        }

        //body
        for (IElement element : HtmlConverter.convertToElements(pdfDataModel.getBody(), this.props)) {
            document.add((IBlockElement) element);
        }

        footer.writeTotalNumberOnPages(pdfDoc);
    }

    return byteArrayOutputStream.toByteArray();
}

pdfDataModel.getMetaModel()、pdfDataModel.getHeader()、pdfDataModel.getBody()等返回setter/getter类; html 存储在那里。

任何建议都会有所帮助...

我们已将控制器更改为此,现在可以使用了:

@RequestMapping(value = "/pdf", method = RequestMethod.POST, produces = MediaType.APPLICATION_PDF_VALUE)
public byte[] index(@RequestBody PDFDataModelCollection pdfDataCollection, Model model) throws IOException {

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(byteArrayOutputStream);

    try (PdfDocument resultDoc = new PdfDocument(writer)) {
        LOGGER.debug("Parsing {} element(s) from PDFDataModelCollection.", pdfDataCollection.getElements().size());
        for (PDFDataModel pdfDataModel : pdfDataCollection.getElements()) {
            PdfReader reader = new PdfReader(new ByteArrayInputStream(creationService.createDatasheet(pdfDataModel)));
            PdfDocument sourceDoc = new PdfDocument(reader);
            sourceDoc.copyPagesTo(1, sourceDoc.getNumberOfPages(), resultDoc, resultDoc.getNumberOfPages()+1);
        }

        PDFMetaService.addPdfMetaTags(resultDoc, pdfDataCollection.getElements().get(1).getMetaModel());
    }

    return byteArrayOutputStream.toByteArray();
}