如何在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
相关产品推荐
相关产品推荐

