杰瑞科技汇

iText生成PDF时如何解决中文乱码问题?

目录

  1. 环境搭建
    • 添加 Maven 依赖
    • 了解 iText 5 和 iText 7 的区别
  2. 核心概念
    • Document (文档)
    • PdfWriter (写入器)
    • PdfReader / PdfStamper (读取器/印章)
    • Element (元素) 和 Paragraph, Chunk, Phrase
    • PdfPTable (表格)
  3. 基础代码示例
    • 示例 1:创建一个包含文本、列表、标题的简单 PDF
    • 示例 2:在 PDF 中添加图片
    • 示例 3:创建一个表格
  4. 高级用法
    • 设置页面大小和边距
    • 添加页眉和页脚
    • 水印
    • 处理中文字体 (非常重要!)
  5. 总结与最佳实践

环境搭建

Maven 依赖

推荐使用 Maven 来管理项目依赖。

iText生成PDF时如何解决中文乱码问题?-图1
(图片来源网络,侵删)

iText 7 (推荐使用)

iText 7 是目前的主流版本,架构更现代化,功能更强大。

<dependencies>
    <!-- iText 7 Core -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext7-core</artifactId>
        <version>7.2.5</version> <!-- 使用最新稳定版 -->
        <type>pom</type>
    </dependency>
    <!-- 如果需要 HTML 转 PDF,可以添加这个 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>html2pdf</artifactId>
        <version>4.0.3</version>
    </dependency>
    <!-- 如果需要签名,可以添加这个 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>sign</artifactId>
        <version>7.2.5</version>
    </dependency>
</dependencies>

iText 5 (旧版)

很多老项目仍在使用 iText 5,如果你需要维护旧代码,可以使用这个版本。

<dependencies>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>5.5.13.3</version>
    </dependency>
    <!-- 需要单独添加亚洲字体支持包 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-asian</artifactId>
        <version>5.2.0</version>
    </dependency>
</dependencies>

重要提示:iText 5 使用 AGPL 许可证,用于商业项目可能需要购买商业许可,iText 7 使用更宽松的 AGPLv3 许可证,对于商业应用更友好。


核心概念

iText 7 中的核心类

  • PdfDocument: 代表一个 PDF 文档对象,它包含了所有页面和内容,这是你操作 PDF 的核心。
  • PdfWriter: 负责将 PdfDocument 写入到一个输出流(如文件)中,它是一个写入器。
  • Document: 这是一个高级的抽象层,用于简化向 PdfDocument 添加内容的过程,它处理了分页、边距等底层细节,你先创建 PdfWriter,然后用它来创建 Document,最后用 Document 来添加内容。
  • Element: 所有可以放入 Document 的内容(如段落、图片、列表)都是 Element 的子类。
    • Paragraph: 段落,可以包含文本、图片等。
    • Chunk: 文本块,是 Paragraph 的最小组成部分,可以设置字体、颜色等样式。
    • Phrase: 短语,由一个或多个 Chunk 组成。
    • Image: 图片。
    • Table: 表格,iText 7 中是 Table,iText 5 中是 PdfPTable

iText 5 中的核心类

  • Document: 代表一个文档,与 iText 7 的 Document 类似,是高级抽象。
  • PdfWriter: 写入器,将 Document 写入文件。
  • PdfPTable: 表格。
  • Paragraph: 段落。
  • Chunk: 文本块。
  • Image: 图片。

基础代码示例 (使用 iText 7)

示例 1:创建一个包含文本、列表、标题的简单 PDF

这个例子演示了如何创建一个 PDF 并添加基本文本元素。

iText生成PDF时如何解决中文乱码问题?-图2
(图片来源网络,侵删)
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
import java.io.FileNotFoundException;
import java.io.IOException;
public class HelloWorld {
    public static void main(String[] args) {
        // PDF 输出文件路径
        String dest = "hello_world.pdf";
        try {
            // 1. 创建 PdfWriter 写入器
            PdfWriter writer = new PdfWriter(dest);
            // 2. 创建 PdfDocument 文档对象
            PdfDocument pdf = new PdfDocument(writer);
            // 3. 创建 Document 高级布局文档对象
            // 可以设置页面大小和边距
            Document document = new Document(pdf, new com.itextpdf.kernel.geom.PageSize(com.itextpdf.kernel.geom.PageSize.A4));
            document.setMargins(20, 20, 20, 20); // 设置边距
            // 4. 添加内容
            // 添加一个标题
            // 注意:iText 7 默认不支持中文,这里先用英文演示
            document.add(new Paragraph("Hello World!").setFontSize(18).setBold().setTextAlignment(TextAlignment.CENTER));
            // 添加一个段落
            document.add(new Paragraph("This is a simple PDF generated using iText 7 in Java.")
                    .setFontSize(12)
                    .setMarginTop(10));
            // 添加一个列表
            List list = new List()
                    .setSymbolIndent(12) // 设置列表项缩进
                    .setListSymbol("•"); // 设置列表符号
            list.add(new ListItem("First item of the list."));
            list.add(new ListItem("Second item of the list."));
            list.add(new ListItem("Third item of the list."));
            document.add(list.setMarginTop(10));
            // 5. 关闭文档
            document.close();
            System.out.println("PDF created successfully at: " + dest);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

示例 2:在 PDF 中添加图片

// ... (前面的代码相同,直到创建 Document)
// 5. 添加图片
String imagePath = "path/to/your/image.png"; // 替换为你的图片路径
Image img = new Image(ImageDataFactory.create(imagePath));
// 设置图片宽度,高度自适应
img.setWidth(UnitValue.createPercentValue(50)); // 宽度为页面宽度的50%
img.setMarginTop(10);
document.add(img);
// 6. 关闭文档
document.close();

示例 3:创建一个表格

Table 是 iText 中非常常用的功能。

// ... (前面的代码相同,直到创建 Document)
// 6. 创建一个表格
// 参数是列数
Table table = new Table(3); // 3列表格
table.setWidth(UnitValue.createPercentValue(100)); // 表格宽度为100%
// 添加表头
table.addHeaderCell(new Cell().add(new Paragraph("ID")));
table.addHeaderCell(new Cell().add(new Paragraph("Product")));
table.addHeaderCell(new Cell().add(new Paragraph("Price")));
// 添加表格内容
table.addCell(new Cell().add(new Paragraph("001")));
table.addCell(new Cell().add(new Paragraph("Apple")));
table.addCell(new Cell().add(new Paragraph("¥5.00")));
table.addCell(new Cell().add(new Paragraph("002")));
table.addCell(new Cell().add(new Paragraph("Banana")));
table.addCell(new Cell().add(new Paragraph("¥3.50")));
table.addCell(new Cell().add(new Paragraph("003")));
table.addCell(new Cell().add(new Paragraph("Orange")));
table.addCell(new Cell().add(new Paragraph("¥4.80")));
document.add(table.setMarginTop(20));
// 7. 关闭文档
document.close();

高级用法

设置页面大小和边距

可以在创建 Document 时指定页面大小和边距。

// 创建一个自定义大小的页面 (500x800 点)
com.itextpdf.kernel.geom.PageSize pageSize = new com.itextpdf.kernel.geom.PageSize(500, 800);
Document document = new Document(pdf, pageSize);
document.setMargins(36, 54, 72, 108); // 左, 右, 上, 下 边距

添加页眉和页脚

iText 7 提供了 EventHandler 接口来实现页眉页脚,最简单的方式是使用 HeaderFooter

// 创建一个页脚
Text footerText = new Text("Page ")
        .setFontColor(com.itextpdf.kernel.color.Color.GRAY)
        .setFontSize(8);
PageNumber pageNumber = new PageNumber().setFontColor(com.itextpdf.kernel.color.Color.GRAY).setFontSize(8);
Paragraph footer = new Paragraph(footerText).add(pageNumber).setTextAlignment(TextAlignment.RIGHT);
// 将页脚应用到文档
document.setFooter(footer);
// 创建一个页眉
Text headerText = new Text("My Document")
        .setFontColor(com.itextpdf.kernel.color.Color.BLUE)
        .setFontSize(10);
Paragraph header = new Paragraph(headerText).setTextAlignment(TextAlignment.CENTER);
document.setHeader(header);

水印

水印通常是在现有 PDF 上添加的,这需要使用 PdfReader 读取现有 PDF,然后用 PdfStamper 修改。

// 假设我们有一个源 PDF
String src = "source.pdf";
String dest = "watermarked.pdf";
PdfReader reader = new PdfReader(src);
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdfDoc = new PdfDocument(reader, writer);
// 获取第一页
PdfPage page = pdfDoc.getFirstPage();
// 获取页面内容流
PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
// 设置水印样式
canvas.setColor(com.itextpdf.kernel.color.Color.LIGHT_GRAY)
     .setFillColor(com.itextpdf.kernel.color.Color.LIGHT_GRAY)
     .setFontAndSize(PdfFontFactory.createFont(), 48);
// 在页面中央绘制文本
canvas.beginText()
      .moveText(page.getPageSize().getWidth() / 2 - 100, page.getPageSize().getHeight() / 2)
      .showText("DRAFT")
      .endText();
canvas.release();
pdfDoc.close();

处理中文字体 (非常重要!)

iText 7 默认不包含任何 CJK (Chinese, Japanese, Korean) 字体,要显示中文,你必须提供中文字体文件(如 .ttf.otf)。

import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
// ... 在 main 方法中 ...
// 加载中文字体
// 请确保你的项目中有 'simhei.ttf' (黑体) 或 'simsun.ttc' (宋体) 等字体文件
// 可以从 Windows 的 C:\Windows\Fonts 目录复制,或从网上下载
PdfFont font = PdfFontFactory.createFont("simhei.ttf", PdfEncodings.IDENTITY_H, true);
// 创建一个使用中文字体的段落
String chineseText = "这是一个使用 iText 7 生成的中文字符串。";
Paragraph p = new Paragraph(chineseText).setFont(font).setFontSize(12);
// 将段落添加到文档
document.add(p);
// ... 关闭文档

注意

  1. 字体文件版权:确保你有权使用所选字体。
  2. 字体路径:字体文件可以放在项目资源目录下,然后通过 ClassLoaderInputStream 加载,以避免硬编码路径。
  3. IDENTITY_H:这是处理 CJK 字体的标准编码。

总结与最佳实践

  1. 选择版本:新项目请务必使用 iText 7,它更现代、功能更强、许可更友好。
  2. 理解核心流程Writer -> PdfDocument -> Document -> Elements -> close(),这个流程是基础。
  3. 字体是关键:处理非英文字符(尤其是中文)时,字体是最大的挑战,务必提前准备好字体文件。
  4. 资源管理:所有 PdfDocument, Document, PdfReader, PdfWriter 等对象在使用完毕后都要 close(),以释放资源。
  5. 查阅官方文档:iText 的官方文档非常详细,https://itextpdf.com/en/resources/documentation/overview-itext-7 是你最好的朋友。
  6. 分页处理Document 对象会自动处理分页,当你添加的内容超出当前页面剩余空间时,它会自动创建新的一页,你无需手动干预。
  7. 复杂布局:对于非常复杂的布局(如多列、绝对定位),可以考虑使用 iText 7 的 Layout API 或者先设计 HTML,然后用 html2pdf 模块转换。

希望这份指南能帮助你顺利地使用 iText 在 Java 中生成 PDF 文档!

分享:
扫描分享到社交APP
上一篇
下一篇