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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:41:22