如何将多个 HTML 文件解析为单个 PDF?

How to parse multiple HTML files into a single PDF?

我想使用 iText 将一系列 html 文件转换为 PDF。

例如:如果有这些文件:

现在我想创建一个 PDF 文件,其中 page1.html 是第一页,page2.html 是第二页,依此类推...

我知道如何将单个 HTML 文件转换为 PDF,但我不知道如何将此操作产生的这些不同 PDF 合并为一个 PDF。

在我们开始之前:我不是 C# 开发人员,所以我不能给你一个 C# 的例子。我写的所有 iText 示例都是用 Java 编写的。幸运的是,iText 和 iTextSharp 始终保持同步。在这个问题的上下文中,您可以放心,适用于 iText 的任何内容也适用于 iTextSharp,但您必须进行特定于 C# 的小改动。据我从 C# 开发人员那里听到的,这通常并不难实现。

关于答案: 有两个答案,答案 #2 通常比答案 #1 好,但我给出了两个选项,因为可能在特定情况下答案#1 更好。

测试数据: 我创建了 3 个简单的 HTML 文件,每个文件都包含一些关于美国某个州的信息:

我们将使用 XML Worker 来解析这三个文件,结果我们想要一个 PDF 文件。

答案 #1: 请参阅 ParseMultipleHtmlFiles1 for the full code sample and multiple_html_pages1.pdf 以获取生成的 PDF。

您说您已经成功将一个 HTML 文件转换为一个 PDF 文件。假设您是这样做的:

public byte[] parseHtml(String html) throws DocumentException, IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // step 1
    Document document = new Document();
    // step 2
    PdfWriter writer = PdfWriter.getInstance(document, baos);
    // step 3
    document.open();
    // step 4
    XMLWorkerHelper.getInstance().parseXHtml(writer, document,
            new FileInputStream(html));
    // step 5
    document.close();
    // return the bytes of the PDF
    return baos.toByteArray();
}

这不是解析 HTML 文件的最有效方法(网站上还有其他示例),但它是最简单的方法。

如您所见,此方法将 HTML 解析为 PDF 文件,并 returns 以 byte[] 的形式解析该 PDF 文件。因为我们想要创建一个 PDF,所以我们可以将这个字节数组提供给一个 PdfCopy 实例,这样我们就可以连接多个文档。

假设我们有三个文档:

public static final String[] HTML = {
    "resources/xml/page1.html",
    "resources/xml/page2.html",
    "resources/xml/page3.html"
};

我们可以遍历这三个文档,将它们一个一个地解析为 byte[],用 PDF 字节创建一个 PdfReader 实例,然后将文档添加到 PdfCopy使用 addDocument() 方法的实例:

public void createPdf(String file) throws IOException, DocumentException {
    Document document = new Document();
    PdfCopy copy = new PdfCopy(document, new FileOutputStream(file));
    document.open();
    PdfReader reader;
    for (String html : HTML) {
        reader = new PdfReader(parseHtml(html));
        copy.addDocument(reader);
        reader.close();
    }
    document.close();
} 

这解决了您的问题,但为什么我认为这不是最佳解决方案?

假设您需要使用需要嵌入的特殊字体。在这种情况下,每个单独的 PDF 文件都将包含该字体的一个子集。不同的文件需要不同的字体子集,PdfCopy(也不是 PdfSmartCopy)可以合并字体子集。这可能会导致 PDF 文件膨胀,其中包含太多相同字体的字体子集。

我们如何解决这个问题?这在答案 #2 中有解释。

答案 #2: 请参阅 ParseMultipleHtmlFiles2 for the full code sample and multiple_html_pages2.pdf 以获取生成的 PDF。您已经看到文件大小的差异:4.61 KB 与 5.05 KB(我们甚至没有引入嵌入式字体)。

在这种情况下,我们不会像在答案 #1 中的 parseHtml() 方法中那样将 HTML 解析为 PDF 文件。相反,我们使用 parseToElementList() 方法将 HTML 解析为 iText ElementList。此方法需要两个 String。一个包含 HTML 代码,另一个包含 CSS 值。

我们使用实用程序方法将 HTML 文件读入 String。至于 CSS 值,我们可以将 null 传递给 parseToElementList(),但在这种情况下,默认样式将被忽略。您会注意到,如果您不通过 XML Worker 附带的 default.css,我们在 HTML 中引入的 <h1> 标签将看起来完全不同。

长话短说,这是代码:

public void createPdf(String file) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter.getInstance(document, new FileOutputStream(file));
    document.open();
    String css = readCSS();
    for (String htmlfile : HTML) {
        String html = Utilities.readFileToString(htmlfile);
        ElementList list = XMLWorkerHelper.parseToElementList(html, css);
        for (Element e : list) {
            document.add(e);
        }
        document.newPage();
    }
    document.close();
}

我们创建了一个 Document 和一个 PdfWriter 实例。我们将不同的HTML个文件一个一个解析成ElementList个,我们把所有的元素都添加到Document.

如你所愿,每解析一个新的HTML文件,我就引入一个document.newPage()。如果您删除此行,则可以在一个页面上添加三个 HTML 页(如果您选择答案 #1,则不可能)。