如何在PDFBox 2.0.27中更改文本渲染方向?
解决PDFBox文本从上到下渲染及多行重叠问题
PDFBox默认以页面左下角为坐标原点,Y轴向上延伸,所以showText()看起来是从下往上绘制文本。要实现从上到下的逐行排版,核心是主动调整文本绘制的Y坐标,而非修改渲染方向。针对不同字号文本重叠的问题,可通过以下步骤解决:
关键思路
- 计算每行文本的实际高度(结合字体字号与字体自身的边界框)
- 每完成一行文本绘制后,将当前Y坐标减去该行高度,确保下一行落在当前行的视觉下方
具体实现步骤
1. 获取单行文本的实际高度
字体字号代表em-square的大小,实际行高需结合字体边界框计算,公式为:实际行高 = 字号 * (字体边界框高度 / 1000)
(PDF字体的边界框默认以1000为基准单位)
通过PDFont的API获取边界框并计算高度:
float getLineHeight(PDFont font, float fontSize) { BoundingBox bbox = font.getFontDescriptor().getFontBoundingBox(); return fontSize * (bbox.getHeight() / 1000); }
2. 逐行绘制并调整位置
初始化时从页面顶部附近开始绘制,每写完一行就下移Y坐标,示例代码:
try (PDDocument doc = new PDDocument(); PDPage page = new PDPage(PDRectangle.A4); PDPageContentStream contentStream = new PDPageContentStream(doc, page)) { // 页面基础参数 float pageWidth = page.getMediaBox().getWidth(); float pageHeight = page.getMediaBox().getHeight(); float margin = 50; float currentX = margin; float currentY = pageHeight - margin; // 从页面顶部内侧开始绘制 // 待绘制的多行文本(搭配不同字号) List<String> texts = Arrays.asList("第一行(12号字)", "第二行(16号字)", "第三行(10号字)"); List<Float> sizes = Arrays.asList(12f, 16f, 10f); PDFont font = PDType1Font.HELVETICA; for (int i = 0; i < texts.size(); i++) { String text = texts.get(i); float fontSize = sizes.get(i); float lineHeight = getLineHeight(font, fontSize); // 设置字体与字号 contentStream.setFont(font, fontSize); // 绘制文本 contentStream.beginText(); contentStream.newLineAtOffset(currentX, currentY); contentStream.showText(text); contentStream.endText(); // 调整Y坐标,下移一行高度(额外加2作为行间距) currentY -= lineHeight + 2; } doc.save("从上到下排版.pdf"); } catch (IOException e) { e.printStackTrace(); }
3. 精准行高计算(可选)
若需要更精确的文本高度(考虑字体的上升、下降值),可使用以下方法:
float getPreciseLineHeight(PDFont font, float fontSize) { float ascent = font.getFontDescriptor().getAscent() * fontSize / 1000; float descent = font.getFontDescriptor().getDescent() * fontSize / 1000; return ascent - descent; // descent为负数,实际是上升值加下降值的绝对值 }
注意事项
- 自定义字体需确保加载正确,且
getFontDescriptor()能正常返回边界框信息 - 行间距可根据需求自行调整,示例中的
+2为额外空白间距 - 若文本过长需自动换行,还需结合
PDFont.getStringWidth()计算文本宽度,判断是否超出页面宽度后手动拆分
内容的提问来源于stack exchange,提问作者Tomas Sexenian
相关产品推荐
相关产品推荐

