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

如何在PDFBox 2表格单元格中添加图片与文本(文本顶对齐、图片居中)?

我来帮你搞定这个需求!在PDFBox 2里实现单元格内同时放置顶对齐文本和居中图片,核心思路是把单元格当成一块独立的画布,手动控制文本和图片的绘制位置——直接用默认的单元格内容添加方式很难实现这么精细的布局,下面是具体的实现思路和代码示例:

实现思路

PDFBox的PDTableCell默认支持添加单一内容元素,但要同时控制文本顶对齐、图片居中,最灵活的方式是自定义单元格的绘制逻辑:要么通过PDFormXObject预先绘制好文本+图片的组合内容,再赋值给单元格;要么先绘制表格获取单元格坐标,再在对应位置手动绘制文本和图片。

完整代码示例

下面是两种常用实现方式的代码,你可以根据场景选择:

方式1:用PDFormXObject封装单元格内容(推荐,适合复用)

这种方式把文本和图片预先绘制到一个可复用的表单对象里,再作为单元格内容,表格会自动处理布局:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.table.PDTable;
import org.apache.pdfbox.pdmodel.table.PDTableCell;
import org.apache.pdfbox.pdmodel.table.PDTableRow;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;

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

public class TableImageTextDemo {
    public static void main(String[] args) throws IOException {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            // 创建表格,设置列宽
            PDTable table = new PDTable();
            table.addColumn(200);
            table.addColumn(200);

            // 创建目标单元格,设置高度(确保能放下文本和图片)
            PDTableCell cell = new PDTableCell();
            cell.setHeight(160);
            float cellWidth = cell.getWidth();
            float cellHeight = cell.getHeight();

            // 1. 创建表单对象,封装文本+图片内容
            PDFormXObject cellContent = new PDFormXObject(document);
            cellContent.setResources(new PDResources());
            cellContent.setBBox(new PDRectangle(0, 0, cellWidth, cellHeight));

            try (PDPageContentStream xobjStream = new PDPageContentStream(document, cellContent)) {
                // 绘制顶部对齐的文本
                String text = "这是顶部对齐的文本";
                PDType1Font font = PDType1Font.HELVETICA_BOLD;
                float fontSize = 12;
                // 计算文本上升高度(确保文本顶部紧贴单元格顶部)
                float textAscent = font.getFontDescriptor().getAscent() * fontSize / 1000;
                
                xobjStream.beginText();
                xobjStream.setFont(font, fontSize);
                // 坐标相对于表单左上角(0, cellHeight),加5px左边距
                xobjStream.newLineAtOffset(5, cellHeight - textAscent);
                xobjStream.showText(text);
                xobjStream.endText();

                // 绘制居中的图片
                PDImageXObject image = PDImageXObject.createFromFile("your-image-path.png", document);
                // 缩放图片,避免超出单元格(留20px左右边距)
                float maxImgWidth = cellWidth - 20;
                float maxImgHeight = cellHeight - textAscent - 20; // 给文本预留空间
                float scale = Math.min(maxImgWidth / image.getWidth(), maxImgHeight / image.getHeight());
                float imgWidth = image.getWidth() * scale;
                float imgHeight = image.getHeight() * scale;

                // 计算居中坐标
                float imgX = (cellWidth - imgWidth) / 2;
                float imgY = cellHeight - textAscent - 10 - imgHeight; // 文本和图片间留10px间距
                xobjStream.drawImage(image, imgX, imgY, imgWidth, imgHeight);
            }

            // 2. 将表单对象设为单元格内容,添加到表格
            cell.setCellContent(cellContent);
            PDTableRow row = new PDTableRow();
            row.addCell(cell);
            row.addCell(new PDTableCell("普通单元格"));
            table.addRow(row);

            // 绘制表格到页面
            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                table.draw(contentStream, 50, 700);
            }

            document.save("table-with-image-text.pdf");
        }
    }
}

方式2:先绘制表格再手动绘制内容(适合临时需求)

如果只是单个单元格需要这种布局,也可以先绘制表格获取单元格坐标,再直接在页面上绘制文本和图片:

// 省略重复的导入和初始化代码...
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
    // 先绘制表格,获取单元格的实际坐标
    table.addRow(row);
    table.draw(contentStream, 50, 700);
    PDRectangle cellRect = cell.getRectangle();
    
    // 绘制文本和图片的逻辑和方式1一致,只是坐标换成单元格的实际页面坐标
    float cellX = cellRect.getLowerLeftX();
    float cellY = cellRect.getUpperRightY();
    
    // 绘制顶部文本...
    contentStream.beginText();
    contentStream.setFont(font, fontSize);
    contentStream.newLineAtOffset(cellX + 5, cellY - textAscent);
    contentStream.showText(text);
    contentStream.endText();
    
    // 绘制居中图片...
    contentStream.drawImage(image, cellX + (cellRect.getWidth() - imgWidth)/2, cellY - textAscent -10 - imgHeight, imgWidth, imgHeight);
}
关键细节说明
  • 文本顶对齐:通过字体的ascent属性计算文本基线到顶部的距离,确保文本顶部紧贴单元格上边界,避免默认绘制时的留白。
  • 图片居中:通过单元格宽高减去图片宽高的一半,计算出图片的起始坐标,同时缩放图片避免超出单元格范围。
  • 布局兼容性:如果需要适配不同单元格大小,建议把绘制逻辑封装成工具方法,动态传入单元格尺寸、文本内容和图片路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:49:49