You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中用openhtmltopdf-pdfbox为PDF添加每页页眉页脚图片

为openhtmltopdf生成的PDF添加页眉页脚图片

方法一:使用CSS @page 结合运行元素(推荐)

openhtmltopdf支持CSS Paged Media规范,通过定义**运行元素(running elements)**和@page规则,可实现每页重复的页眉页脚。

步骤1:修改输入HTML,添加页眉页脚结构与样式

在你的inputHTMlString中插入以下内容(和原有HTML内容拼接):

<style>
/* 定义运行元素,用于存储页眉页脚内容 */
.header-image {
    position: running(header);
    width: 100%;
    height: 50px; /* 根据实际图片尺寸调整 */
}
.footer-image {
    position: running(footer);
    width: 100%;
    height: 40px; /* 根据实际图片尺寸调整 */
}

/* 配置页面布局,预留页眉页脚空间 */
@page {
    size: A4;
    margin: 70px 20px 60px 20px; /* 上下边距需大于页眉页脚高度,避免内容重叠 */

    /* 调用运行元素作为页眉 */
    @top-center {
        content: element(header);
    }
    /* 调用运行元素作为页脚 */
    @bottom-center {
        content: element(footer);
    }
}

body {
    margin: 0;
}
</style>

<!-- 页眉图片容器(仅渲染一次,每页自动调用) -->
<div class="header-image">
    <img src="header-logo.png" alt="页眉图片" style="width: 100%; height: 100%; object-fit: contain;" />
</div>

<!-- 页脚图片容器 -->
<div class="footer-image">
    <img src="footer-logo.png" alt="页脚图片" style="width: 100%; height: 100%; object-fit: contain;" />
</div>

<!-- 原有业务HTML内容 -->
<div class="content">
    <!-- 这里放你从数据库获取的原有HTML内容 -->
</div>

注意事项

  • 图片路径需确保baseUri可访问:你的代码中baseUri来自CORRESPONDANCE_PATH配置,需将图片放在该目录下,或使用绝对路径。
  • 页边距设置必须足够大,防止主内容与页眉页脚重叠。
  • 若需动态替换图片路径,可在拼接HTML时替换src属性的值。

方法二:通过Java代码自定义PageSupplier

如果CSS方式无法满足需求,可直接通过Java代码控制每页的页眉页脚绘制。

步骤1:实现PageSupplier接口

创建自定义PageSupplier,在每页绘制时添加图片:

import com.openhtmltopdf.pdfboxout.PdfBoxPageSupplier;
import com.openhtmltopdf.pdfboxout.PdfBoxRenderer;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import java.io.File;
import java.io.IOException;

public class CustomPageSupplier implements PdfBoxPageSupplier {
    private final String headerImagePath;
    private final String footerImagePath;

    public CustomPageSupplier(String headerImagePath, String footerImagePath) {
        this.headerImagePath = headerImagePath;
        this.footerImagePath = footerImagePath;
    }

    @Override
    public PDPage createPage(PdfBoxRenderer renderer, int pageIndex) {
        return new PDPage(renderer.getDefaultPageSize());
    }

    @Override
    public void drawPage(PdfBoxRenderer renderer, PDPage page, int pageIndex, PDDocument document) throws IOException {
        // 绘制页眉图片
        PDImageXObject headerImage = PDImageXObject.createFromFile(headerImagePath, document);
        try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, true, true)) {
            float pageHeight = page.getMediaBox().getHeight();
            // 调整坐标和缩放比例,适配你的图片尺寸和页面布局
            contentStream.drawImage(headerImage, 20, pageHeight - 50 - 20, headerImage.getWidth() * 0.5f, 50);

            // 绘制页脚图片
            PDImageXObject footerImage = PDImageXObject.createFromFile(footerImagePath, document);
            contentStream.drawImage(footerImage, 20, 20, footerImage.getWidth() * 0.5f, 40);
        }
    }
}

步骤2:修改xhtmlToPdf方法,配置自定义PageSupplier

public void xhtmlToPdf(Document doc, String filePath) throws IOException {
        String str = applicationRepository.findByApplicationKey("CORRESPONDANCE_PATH").getApplicationValue();
        String baseUri = FileSystems.getDefault().getPath(str).toUri().toString();
        
        // 拼接图片路径,根据实际存储位置调整
        String headerImgPath = str + File.separator + "header-logo.png";
        String footerImgPath = str + File.separator + "footer-logo.png";
        
        OutputStream os = new FileOutputStream(filePath);
        PdfRendererBuilder builder = new PdfRendererBuilder();
        builder.toStream(os);
        builder.withW3cDocument(doc, baseUri);
        
        // 绑定自定义PageSupplier
        builder.usePageSupplier(new CustomPageSupplier(headerImgPath, footerImgPath));
        
        builder.run();
        os.close();
    }

注意事项

  • 确保程序对图片路径有读取权限。
  • 绘制坐标需根据页面尺寸(A4默认宽595、高842)调整,避免位置偏移。
  • 使用AppendMode.PREPEND保证页眉页脚在内容底层,不会被覆盖。

常见问题排查

  • CSS方式不生效:检查CSS Paged Media语法是否正确,openhtmltopdf对部分复杂CSS特性支持有限,尽量使用简洁的选择器和属性。
  • 图片不显示:确认图片路径正确,baseUri指向的目录包含目标图片,或直接使用绝对路径。
  • 内容与页眉页脚重叠:调整@page的margin值,确保主内容区域处于页眉页脚之外。

内容的提问来源于stack exchange,提问作者swapnil skate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:45:39