1. 引言

为PDF文档添加页眉页脚能显著提升可读性和专业度,这在报告、发票或演示文稿等场景中尤为实用。例如,每页页眉可包含发布日期,页脚则显示页码或公司名称。

本文将探讨如何使用Java中的iText库为PDF添加页眉页脚。

2. 问题背景

创建PDF文档时,通常需要通过统一的页眉页脚来提升专业性和可读性。但实现这一需求可能颇具挑战性,特别是当需要根据页码等动态信息渲染内容时。

iText是广泛使用的开源PDF库,专用于Java中的PDF生成与操作。它通过事件处理机制提供强大的内容定制能力,允许开发者在PDF生成过程中自定义文档外观。

3. 实现页眉页脚处理器

我们将创建一个名为HeaderFooterEventHandler的处理器类,实现IEventHandler接口。

该接口是定义页眉页脚渲染逻辑的核心,核心功能需在handleEvent()方法中实现

3.1. 基础配置

首先设置HeaderFooterEventHandler类并实现handleEvent()方法,以获取PDF文档和页面信息:

public class HeaderFooterEventHandler implements IEventHandler {
    @Override
    public void handleEvent(Event event) {
        if (event instanceof PdfDocumentEvent docEvent) {
            PdfDocument pdfDoc = docEvent.getDocument();
            PdfPage page = docEvent.getPage();
            int pageNumber = pdfDoc.getPageNumber(page);

            //后续实现
        }
    }
}

通过instanceof检查确保只处理PDF页面生成相关事件。获取当前页面后,即可基于这些数据渲染页眉页脚。

3.2. 绘制页眉

创建PdfCanvas对象用于在PDF页面上绘制文本:

PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);

PdfCanvas提供强大的渲染定制能力。接下来开始绘制页眉:

canvas.beginText();
try {
    canvas.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 12);
} catch (Exception e) {
    e.printStackTrace();
}

使用beginText()启动文本块,设置12号Helvetica字体。⚠️ 若字体创建失败(如字体不可用),iText会自动回退到系统默认字体。

定位并渲染页眉文本:

canvas.moveText(36, page.getPageSize().getTop() - 20);
canvas.showText("Header text - Page " + pageNumber);
canvas.endText();

将页眉定位在距左边缘36像素、页面顶部20像素处,showText()方法会打印包含当前页码的页眉内容。

3.3. 绘制页脚

采用类似方式绘制页脚:

canvas.beginText();
canvas.moveText(36, 20);
canvas.showText("Footer text - Page " + pageNumber);
canvas.endText();

canvas.release();

页脚定位在距左边缘36像素、页面底部20像素处。**与页眉不同,页脚直接基于页面底部定位,无需调用getTop()**。

iText默认坐标系原点(0,0)位于页面左下角,因此定位从底部向上计算。最后释放canvas关联资源。

4. 为PDF添加页眉页脚

现在将HeaderFooterEventHandler集成到PDF生成流程,并使用PDFBox验证输出结果。

4.1. 通过事件处理器修改PDF

创建PDF文档并注册事件处理器,确保每页生成时自动添加页眉页脚:

@Test
void givenHeaderAndFooter_whenCreatingPDF_thenHeaderFooterAreOnEachPage() throws IOException {
    String dest = "documentWithHeaderFooter.pdf";
    PdfWriter writer = new PdfWriter(dest);
    PdfDocument pdf = new PdfDocument(writer);
    Document document = new Document(pdf);

    HeaderFooterEventHandler handler = new HeaderFooterEventHandler();
    pdf.addEventHandler(PdfDocumentEvent.END_PAGE, handler);

    document.add(new Paragraph("This document contains a header and footer on every page."));
    document.close();
}

初始化PDF文档后,实例化处理器并通过addEventHandler()注册到PdfDocumentEvent.END_PAGE事件。这确保每页完成渲染时自动触发页眉页脚绘制

添加内容后关闭文档完成PDF生成。

4.2. 使用PDFBox测试PDF

生成PDF后需验证页眉页脚是否正确添加。使用PDFBox提取并检查文本:

@Test
void givenHeaderAndFooter_whenTestingPDF_thenHeaderFooterAreVerified() throws IOException {
    String dest = "documentWithHeaderFooter.pdf";

    PDDocument pdDocument = PDDocument.load(new File(dest));
    PDFTextStripper stripper = new PDFTextStripper();

    String text = stripper.getText(pdDocument);
    pdDocument.close();

    assertTrue(text.contains("Header text"));
    assertTrue(text.contains("Footer text"));
}

通过PDFBox的PDDocument加载PDF,使用PDFTextStripper提取全文。断言检查特定页眉页脚内容是否存在,确保生成过程成功。

5. 总结

我们展示了如何通过iText的IEventHandler为PDF添加页眉页脚,这种事件驱动方式确保了每页的动态定制能力。

同时引入PDFBox验证生成结果,通过提取文本检查页眉页脚内容。结合iText的创建能力和PDFBox的验证机制,可确保PDF文档的准确性和专业性。

本文完整代码示例可在GitHub获取。