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

kyz*_*101 4 itextsharp

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

例如:如果有这些文件:

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

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

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

Bru*_*gie 7

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

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

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

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

答案#1:查看完整代码示例的ParseMultipleHtmlFiles1和生成的PDF的multiple_html_pages1.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();
}
Run Code Online (Sandbox Code Playgroud)

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

如您所见,此方法将HTML解析为PDF文件,并以a的形式返回该PDF文件byte[].由于我们要创建单个PDF,我们可以将此字节数组提供给PdfCopy实例,以便我们可以连接多个文档.

假设我们有三个文件:

public static final String[] HTML = {
    "resources/xml/page1.html",
    "resources/xml/page2.html",
    "resources/xml/page3.html"
};
Run Code Online (Sandbox Code Playgroud)

我们可以循环遍历这三个文档,将它们逐个解析为a byte[],创建一个PdfReader包含PDF字节的实例,并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();
} 
Run Code Online (Sandbox Code Playgroud)

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

假设您需要使用需要嵌入的特殊字体.在这种情况下,每个单独的PDF文件都将包含该字体的子集.不同的文件将需要不同的字体子集,并且PdfCopy(也PdfSmartCopy就此而言)可以合并字体子集.这可能导致臃肿的PDF文件具有相同字体的太多字体子集.

我们如何解决这个问题?这在答案#2中得到了解释.

答2:参见ParseMultipleHtmlFiles2为完整的代码示例和multiple_html_pages2.pdf为生成的PDF.您已经看到文件大小的差异:4.61 KB与5.05 KB(我们甚至没有引入嵌入字体).

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

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

长话短说,这是代码:

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();
}
Run Code Online (Sandbox Code Playgroud)

我们创建一个Document单个PdfWriter实例.我们将不同的HTML文件ElementList逐个解析为s,然后我们将所有元素添加到Document.

如果你想要一个新的页面,每次解析一个新的HTML文件时,我都会介绍一个document.newPage().如果删除此行,则可以在一个页面上添加三个HTML页面(如果您选择回答#1,则无法实现).