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

时间:2015-01-07 07:49:02

标签: itextsharp

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

例如:如果有这些文件:

  • page1.html
  • page2.html
  • page3.html
  • ...

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

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

1 个答案:

答案 0 :(得分:7)

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

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

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

我们将使用XML Worker来解析这三个文件,因此我们需要一个PDF文件。

回答#1:请参阅ParseMultipleHtmlFiles1获取完整的代码示例,并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文件,并以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;有关生成的PDF,请参阅multiple_html_pages2.pdf。您已经看到文件大小的差异:4.61 KB与5.05 KB(我们甚至没有引入嵌入字体)。

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

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

长话短说,这就是代码:

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,则不可能这样做。)