【问题标题】:PDFBox: how to determine bounding box of vector figure (path shape)PDFBox:如何确定矢量图的边界框(路径形状)
【发布时间】:2021-07-28 18:34:08
【问题描述】:

我有由 Apache FOP + jEuclid 生成的简单 PDF。此 PDF 包含数学公式和文本的矢量图形:

PDF 链接:https://www.dropbox.com/s/w4ksnud78bu9oz5/test.pdf?dl=0

我想知道每个矢量图形的边界框(x,y,width,height)。我试过这个例子:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.24/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java,但它没有输出任何信息,只有这个:

Processing page: 1

在 Acrobat 中,我可以在标签树中选择矢量图像并突出显示它们:

我的问题 - 如何通过 PDFBox API 确定矢量图像的边界框?

【问题讨论】:

  • 也许你可以修改这个解决方案? stackoverflow.com/questions/38931422/…
  • @TilmanHausherr 谢谢你的建议。我已经尝试过了,但看起来 PDFGraphicsStreamEngine 对于我的目的来说是非常低级的功能。它允许确定公式中每个字形的坐标,即它捕获每个具体字形的路径。我无法理解一组路径何时结束并开始另一组......
  • 您可以捕获“fillPath”,这将有助于此 PDF。
  • fillPath 调用了 13 次,即针对两个公式中的每个字形/字符。实际上,除了边界框之外,我还需要知道与公式相关的替代(或实际)文本。所以可能我必须使用 PDFMarkedContentExtractor。
  • 您的 PDF 没有这些矢量图形的替代文本。你可以用 PDFDebugger 看看。

标签: pdf pdfbox


【解决方案1】:

只要有问题的图形被适当地标记(就像它们在您的示例文档中一样),您就可以根据 PDFBox PDFGraphicsStreamEngine 确定它们的边界框。

您实际上可以使用this answer中的BoundingBoxFinder(基于PDFGraphicsStreamEngine)确定页面所有内容的边界框,您只需通过以下方式检索标记内容序列的边界框信息标记的内容序列。

以下类通过将边界框信息存储在 MarkedContext 对象的层次结构中来实现这一点

public class MarkedContentBoundingBoxFinder extends BoundingBoxFinder {
    public MarkedContentBoundingBoxFinder(PDPage page) {
        super(page);
        contents.add(content);
    }

    @Override
    public void processPage(PDPage page) throws IOException {
        super.processPage(page);
        endMarkedContentSequence();
    }

    @Override
    public void beginMarkedContentSequence(COSName tag, COSDictionary properties) {
        MarkedContent current = contents.getLast();
        if (rectangle != null) {
            if (current.boundingBox != null)
                add(current.boundingBox);
            current.boundingBox = rectangle;
        }
        rectangle = null;
        MarkedContent newContent = new MarkedContent(tag, properties);
        contents.addLast(newContent);
        current.children.add(newContent);

        super.beginMarkedContentSequence(tag, properties);
    }

    @Override
    public void endMarkedContentSequence() {
        MarkedContent current = contents.removeLast();
        if (rectangle != null) {
            if (current.boundingBox != null)
                add(current.boundingBox);
            current.boundingBox = (Rectangle2D) rectangle.clone();
        } else if (current.boundingBox != null)
            rectangle = (Rectangle2D) current.boundingBox.clone();

        super.endMarkedContentSequence();
    }

    public static class MarkedContent {
        public MarkedContent(COSName tag, COSDictionary properties) {
            this.tag = tag;
            this.properties = properties;
        }

        public final COSName tag;
        public final COSDictionary properties;
        public final List<MarkedContent> children = new ArrayList<>();
        public Rectangle2D boundingBox = null;
    }

    public final MarkedContent content = new MarkedContent(COSName.DOCUMENT, null);
    public final Deque<MarkedContent> contents = new ArrayDeque<>();
}

(MarkedContentBoundingBoxFinder 实用程序类)

您可以像这样将其应用于PDPage pdPage

MarkedContentBoundingBoxFinder boxFinder = new MarkedContentBoundingBoxFinder(pdPage);
boxFinder.processPage(pdPage);
MarkedContent markedContent = boxFinder.content;

(摘自DetermineBoundingBox辅助方法drawMarkedContentBoundingBoxes

您可以像这样从 markedContent 对象输出边界框:

void printMarkedContentBoundingBoxes(MarkedContent markedContent, String prefix) {
    StringBuilder builder = new StringBuilder();
    builder.append(prefix).append(markedContent.tag.getName());
    builder.append(' ').append(markedContent.boundingBox);
    System.out.println(builder.toString());
    for (MarkedContent child : markedContent.children)
        printMarkedContentBoundingBoxes(child, prefix + "  ");
}

(DetermineBoundingBox 辅助方法)

如果您获得示例文档

Document java.awt.geom.Rectangle2D$Double[x=90.35800170898438,y=758.10498046875,w=128.63946533203125,h=10.2509765625]
  Figure java.awt.geom.Rectangle2D$Double[x=90.35800170898438,y=758.10498046875,w=44.6771240234375,h=10.2509765625]
  P java.awt.geom.Rectangle2D$Double[x=136.79600524902344,y=760.1184081963065,w=43.137100359018405,h=6.383056943803922]
  Figure java.awt.geom.Rectangle2D$Double[x=184.2926788330078,y=758.10498046875,w=34.70478820800781,h=10.2509765625]

同样,您可以使用DetermineBoundingBoxdrawMarkedContentBoundingBoxes 方法在PDF 上绘制边界框。如果是您的示例文档,您将获得:

【讨论】:

  • 谢谢!很有帮助!
猜你喜欢
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 2017-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多