iTextPDF+Apache PDFBox®实现免费的html转PDF功能

       我们知道,iTextPDF是一个强大PDF操作库,其中PdfHTML模块可以实现一键html格式转PDF(属于扩展付费业务),iTextPDF社区版(免费)只能使用itextcore里面的功能模块,所以为了实现免费的html转PDF功能,我们就可以利用Apache PDFBox®实现html转PDF,利用iTextPDF实现PDF操作。

         通过组合使用 Apache PDFBox 和 iTextPDF,可以实现更加灵活且免费的 HTML 转 PDF 解决方案。Apache PDFBox 适用于简单的 PDF 生成,特别是我们不需要复杂布局或其他高级 PDF 操作时,而 iTextPDF 则可以在 PDF 创建完成后,进一步增强文档的功能和布局。这种方法可以让我们在不使用付费模块的情况下,依然高效地处理 PDF 文件。

知识储备:

iTextPDF:The Leading PDF Library for Developers | iText

iTextPDF社区版(免费)依赖下载网址:Installing iText Community for Java developers

itextcore模块

Kernel:这是 iText 的核心模块,包含所有基本的 PDF 操作功能,如创建、修改和读取 PDF 文件。几乎所有 PDF 操作都依赖于这个模块。

Layout:这个模块基于 Kernel 构建,提供更高级的布局功能,使开发人员可以创建更复杂的 PDF 文档,包含段落、表格、列表、图像等。

使用 Apache PDFBox 将 HTML 转换为 PDF

Apache PDFBox | A Java PDF LibraryApache PDFBox :Apache PDFBox | A Java PDF Library

        Apache PDFBox 是一个功能强大的开源库,专门用于创建、操作和读取 PDF 文档。虽然它不像 iTextPDF 的付费扩展那样直接支持将 HTML 转换为 PDF,但我们可以使用它来创建 PDF 文档,然后手动将 HTML 的各个部分(如段落、标题、列表等)映射为 PDF 中的相应组件。

        这里我们示例一个简单的 HTML 转 PDF 的实现,主要处理基础的 HTML 标签如 <p><h1><ul><li> 等:

public class HtmlToPdfUsingPdfBox {
    public static byte[] convertHtmlToPdf(String htmlContent) throws IOException {
        // 创建一个新的 PDF 文档
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage();
            document.addPage(page);

            // 加载字体(此处为中文字体)
            PDType0Font font = PDType0Font.load(document, new File("src/main/resources/fonts/NotoSansSC-VariableFont_wght.ttf"));

            // 使用 Jsoup 解析 HTML
            org.jsoup.nodes.Document htmlDoc = Jsoup.parse(htmlContent);
            Elements elements = htmlDoc.body().select("p, h1, h2, h3, ul, li");

            // 准备内容流
            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                contentStream.beginText();
                contentStream.setFont(font, 12);
                contentStream.setLeading(14.5f);  // 设置行高
                contentStream.newLineAtOffset(25, 750);

                // 将 HTML 内容写入 PDF
                for (Element element : elements) {
                    String text = element.text();

                    // 处理不同的 HTML 标签
                    if (element.tagName().equals("h1")) {
                        contentStream.setFont(font, 18);
                    } else if (element.tagName().equals("h2")) {
                        contentStream.setFont(font, 16);
                    } else if (element.tagName().equals("h3")) {
                        contentStream.setFont(font, 14);
                    } else {
                        contentStream.setFont(font, 12);
                    }

                    contentStream.showText(text);
                    contentStream.newLine();
                }

                contentStream.endText();
            }

            // 将 PDF 文档写入字节数组
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                document.save(outputStream);
                return outputStream.toByteArray();
            }
        }
    }
}

代码总体概述

  1. 创建一个 PDF 文档。
  2. 使用 Jsoup 库解析 HTML 内容,并选择 HTML 文档中一些常用标签(如 <p><h1><h2> 等)。
  3. 通过 PDFBox 创建 PDF 页,并将解析出的 HTML 内容按顺序写入 PDF。
  4. 最终将生成的 PDF 写入字节数组,以便返回 PDF 文件数据。

  • public class HtmlToPdfUsingPdfBox
  • 定义了一个包含将 HTML 转换为 PDF 的类。
  • public static byte[] convertHtmlToPdf(String htmlContent) throws IOException
  • 这个方法是 static,表示可以在不实例化类的情况下调用。方法接收一个 htmlContent 参数,这是 HTML 文本内容,并返回一个 byte[](字节数组),表示生成的 PDF 文件内容。如果处理过程中有文件 I/O 错误,会抛出 IOException
  • PDDocument document = new PDDocument()
  • 创建了一个新的 PDF 文档对象。PDDocument 是 PDFBox 用于表示 PDF 文档的类。通过 try-with-resources 确保文档在使用完毕后自动关闭。
  • PDPage page = new PDPage()
  • 创建一个新的空白 PDF 页。
  • document.addPage(page):将创建的页面添加到文档中。
  • PDType0Font font = PDType0Font.load(document, new File(...))
  • 加载一个自定义字体(此处为 Noto Sans SC 字体),以确保生成的 PDF 支持中文字符的显示。PDType0Font 是 PDFBox 中支持 Unicode 字符集的字体类。字体文件是一个外部文件,通过 new File() 进行加载。
  • org.jsoup.nodes.Document htmlDoc = Jsoup.parse(htmlContent)
  • 使用 Jsoup 库将传入的 HTML 字符串解析为 Jsoup 的 Document 对象。Jsoup 是一个 Java 库,用于处理和操作 HTML。
  • Elements elements = htmlDoc.body().select("p, h1, h2, h3, ul, li")
  • 从 HTML 文档中选择所有的 <p><h1><h2><h3><ul><li> 标签,并存储在 elements 集合中。这个集合中的元素是将要写入 PDF 的内容。
  • PDPageContentStream contentStream = new PDPageContentStream(document, page)
  • 创建一个 PDPageContentStream 对象,用于向页面中写入内容。它提供方法来写文本、绘制图形和插入图像。
  • contentStream.beginText()
  • 启动一个文本流,表示接下来会向 PDF 页面写入文本。
  • contentStream.setFont(font, 12)
  • 设置字体,字体大小为12。
  • contentStream.setLeading(14.5f)
  • 设置文本的行高,确保多行文本之间有足够的间距,行距为14.5个点。
  • contentStream.newLineAtOffset(25, 750)
  • 设置文本的起始位置,即从页面左侧 25 点、页面顶部 750 点处开始写入。
  • for (Element element : elements)
  • 遍历 HTML 文档中的元素(<p><h1><h2> 等)。
  • String text = element.text()
  • 提取元素的文本内容。
  • if (element.tagName().equals(...))
  • 根据元素的标签类型,设置不同的字体大小。标题标签 <h1> 对应较大的字体,<h2><h3> 依次减小,普通段落 <p> 使用默认字体大小 12。
  • contentStream.showText(text)
  • 将提取的文本写入到 PDF 文档中。
  • contentStream.newLine()
  • 每写一段文本后换行,准备写入下一行。
  • contentStream.endText()
  • 结束文本流。所有文本写入操作完成后调用此方法。
  • ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
  • 创建一个字节输出流,用于将生成的 PDF 内容保存为字节数组。
  • document.save(outputStream)
  • 将 PDF 文档保存到字节流中。
  • return outputStream.toByteArray()
  • 返回生成的 PDF 的字节数组,这可以用于生成 PDF 文件或通过网络发送。
  • 结束 try-with-resources 块
  • PDDocument 自动关闭,确保资源被正确释放。

        通过上面的代码,我们可以将 HTML 文本的基本内容转换为 PDF 文档。然而,Apache PDFBox 主要适用于基本的 PDF 创建和编辑任务,而在某些复杂的场景下(如页面布局、表格、图片插入等),我们可以结合 iTextPDF 提供的功能来增强 PDF 的处理能力。

假设你需要将 PDF 文档生成后进一步处理,比如给 PDF 增加页眉、页脚、电子签名等高级功能,你可以用 iTextPDF 进行二次处理。以下是一个简单的例子:

public class PdfEnhancementUsingItext {

    public static byte[] addFooterToPdf(byte[] pdfBytes) throws IOException {
        // 创建 iTextPDF 读取器
        PdfReader reader = new PdfReader(new ByteArrayInputStream(pdfBytes));
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        PdfWriter writer = new PdfWriter(byteArrayOutputStream);

        // 读取 PDF 文档
        PdfDocument pdfDocument = new PdfDocument(reader, writer);
        Document document = new Document(pdfDocument);

        // 添加页脚
        for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
            pdfDocument.getPage(i).setIgnorePageRotationForContent(true);
            document.showTextAligned(new Paragraph("页脚文本 - 第 " + i + " 页"),
                    297.5f, 20, i, TextAlignment.CENTER, VerticalAlignment.BOTTOM, 0);
        }

        // 关闭文档
        document.close();

        return byteArrayOutputStream.toByteArray();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值