使用PDFBox按PDF文本位置放图片错位,是否文本坐标获取有误?
解决PDFBox按文本位置放置图片未覆盖文本的问题
嘿,我来帮你排查这个问题!你遇到的图片没正确覆盖目标文本的情况,主要和PDF坐标系统差异、文本位置参数的正确使用以及代码里的小疏漏有关,咱们一步步来修正:
首先,先指出代码里的关键错误
你的WriteString方法名写错了!Java是大小写敏感的,PDFTextStripper里的方法是writeString(小写开头),你写成了大写W的WriteString,这会导致这个方法根本不会被PDFBox调用——如果这只是你输入时的笔误还好,否则这是核心问题之一。
然后,文本坐标与图片坐标的匹配问题
PDF的坐标原点在页面左下角,而TextPosition的getYDirAdj()返回的是字符基线的Y坐标,但drawImage方法的Y参数是图片左下角的Y坐标。直接用text.getYDirAdj()作为图片Y坐标的话,图片的底部会对齐文本基线,文本基线以下的部分会露在外面,同时图片顶部也可能没覆盖到文本的上部区域。
另外,text.getHeightDir()返回的是字符的总高度(上部高度+下部高度),但直接用这个作为图片高度,需要配合正确的Y坐标调整才能完全覆盖文本。
修正后的示例代码
public class GetCharLocationAndSize extends PDFTextStripper { public static void main(String[] args) throws IOException { PDDocument document = PDDocument.load(new File("input.pdf")); GetCharLocationAndSize stripper = new GetCharLocationAndSize(); stripper.setSortByPosition(true); stripper.setStartPage(0); stripper.setEndPage(document.getNumberOfPages()); // 用dummy writer触发文本解析,从而调用重写的writeString Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream()); stripper.writeText(document, dummy); document.save("newdoc.pdf"); document.close(); } // 注意方法名是小写开头的writeString,确保被正确覆盖 @Override protected void writeString(String string, List<TextPosition> textPositions) throws IOException { String imagePath = "image.jpg"; PDImageXObject pdImage = PDImageXObject.createFromFile(imagePath, getDocument()); // 获取当前页面,创建内容流:APPEND模式表示在原有内容上追加(图片会画在文本上方) PDPage currentPage = getCurrentPage(); try (PDPageContentStream contentStream = new PDPageContentStream(getDocument(), currentPage, PDPageContentStream.AppendMode.APPEND, true)) { for (TextPosition text : textPositions) { if (text.getUnicode().equals("a")) { // 计算图片的左下角Y坐标:文本基线Y减去下部高度(基线以下的部分) float imageY = text.getYDirAdj() - text.getDescent(); // 图片的高度用文本的总高度(上部高度+下部高度) float imageHeight = text.getAscent() + text.getDescent(); // 绘制图片:X用文本的X坐标,Y用计算后的imageY,宽度用文本的宽度,高度用imageHeight contentStream.drawImage(pdImage, text.getXDirAdj(), imageY, text.getWidthDirAdj(), imageHeight); } } } } }
关键改动说明
- 修正了
writeString方法名的大小写,确保PDFTextStripper能正确调用你的自定义逻辑 - 使用
text.getDescent()和text.getAscent()计算图片的Y坐标和高度,确保图片完全覆盖文本的所有区域(包括基线上下的字符部分) - 使用
try-with-resources自动关闭PDPageContentStream,避免资源泄漏 - 明确指定
PDPageContentStream.AppendMode.APPEND,确保图片绘制在原有文本的上方(PDF绘制顺序是先画的在下层,后画的在上层)
额外检查点
- 确认你的图片尺寸比例合适,如果图片本身宽高比和文本的宽高比差异大,可能会导致拉伸变形,你可以根据需要调整绘制的宽高,比如固定图片宽度,按比例计算高度,或者反之
- 如果还是有位置偏移,可以打印出
text.getXDirAdj()、text.getYDirAdj()、text.getAscent()、text.getDescent()这些参数的值,直观查看文本的实际坐标范围,再调整图片的绘制参数
内容的提问来源于stack exchange,提问作者Lez
相关产品推荐
相关产品推荐

