Apache PDFBox - 图像和文本位置之间的垂直匹配

Apache PDFBox - vertical match between image and text position

我需要帮助来实现 PDF 文档中文本和图像对象之间的映射。

如第一张图所示,我的 PDF 文档有 3 张图像在 y 方向上随机排列。在它们的左边是文本。文字沿着图片的高度延伸。

我的目标是将文本组合成“ImObj”对象(参见 class ImObj)。

图2表示我想用图片的高度来检测文字的位置(所有超出图片高度的文字都应该被忽略)。在示例中,将有 3 个图像形成 3 个 ImObj 对象。

pdf 文件的 link 在这里(在 wetransfer 上): [在此处输入 link 描述][3]

但是我的映射不起作用,因为我可能使用了错误的图像坐标。现在我已经看了一些例子,但我仍然不太明白如何让文本和图像的坐标一起工作? 这是我的代码:

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import org.apache.pdfbox.util.Matrix;

public class ImExample extends PDFTextStripper {

    public static void main(String[] args) {
        File file = new File("C://example document.pdf");

        try {
            PDDocument document = PDDocument.load(file);

            ImExample example = new ImExample();

            for (int pnr = 0; pnr < document.getPages().getCount(); pnr++) {
                PDPage page = document.getPages().get(pnr);
                PDResources res = page.getResources();
            
                example.processPage(page);
             
                int idx = 0;

                for (COSName objName : res.getXObjectNames()) {
                    PDXObject xObj = res.getXObject(objName);
                    if (xObj instanceof PDImageXObject) {

                        System.out.println("...add a new image");

                        PDImageXObject imXObj = (PDImageXObject) xObj;
                        BufferedImage image = imXObj.getImage();

                        // Here is my mistake ... but I do not know how to solve it.
                        ImObj imObj = new ImObj(image, idx++, pnr, image.getMinY(), image.getMinY() + image.getHeight());
                        example.imObjects.add(imObj);
                    }
                } 
            }

            example.setSortByPosition(true);
            example.getText(document);

            // Output
            for (ImObj iObj : example.imObjects)
                System.out.println(iObj.idx + " -> " + iObj.text);

            document.close();

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    public List<ImObj> imObjects = new ArrayList<ImObj>();

    public ImExample() throws IOException {
        super();
    }

    @Override
    protected void writeString(String text, List<TextPosition> textPositions) throws IOException {

        // match between imagesize and textposition
        TextPosition txtPos = textPositions.get(0);

        for (ImObj im : imObjects) {
            if(im.page == (this.getCurrentPageNo()-1))
                if (im.minY < txtPos.getY() && (txtPos.getY() + txtPos.getHeight()) < im.maxY)
                    im.text.append(text + " "); 
        }
    }
}

class ImObj {

    float minY, maxY;

    Image image = null;
    StringBuilder text = new StringBuilder("");
    int idx, page = 0;

    public ImObj(Image im, int idx, int pnr, float yMin, float yMax) {
        this.idx = idx;
        this.image = im;
        this.minY = yMin;
        this.maxY = yMax;
        this.page = pnr;
    } 
}

此致

您在(有些)错误的地方查找图像!

您遍历页面本身的图像 XObject 资源并检查它们。但这没有帮助:

  • 图像 XObject 资源仅仅是一种资源。 IE。它可以在页面上使用,甚至不止一次,但您不能仅从该资源确定它是如何使用的(在哪里?以何种规模?以某种方式转换?)

  • 页面上还有其他地方可以存储和使用图像,例如在页面上使用的某种形式的 XObject 或模式的资源中,或在内容流中内联。

您真正需要的是解析页面内容流以使用图像和使用时的当前变换矩阵。有关此的基本实现,请查看 PDFBox 示例 PrintImageLocations.


您将 运行 遇到的下一个问题是 TextPosition 方法 getXgetY 中的坐标 PDFBox returns 不是来自有问题的 PDF 页面的原始坐标系,但是为了在文本提取代码中更容易处理,来自一些标准化的坐标系。因此,您很可能应该使用 un-normalized 坐标。

您可以在 中找到相关信息。