【问题标题】:How can I check if PDF page is image(scanned) by PDFBOX, XPDF如何检查 PDF 页面是否为 PDFBOX、XPDF 的图像(扫描)
【发布时间】:2017-03-24 17:35:50
【问题描述】:

提取图像时出现 PDFBox 问题。 嗨,我如何检查 pdf 页面是否为图像并通过 PDFBOX 库提取该图像,有一种获取图像的方法,但如果 PDF 页面是图像,则无法获取。有人可以帮我解决这个问题。

关于提取图像的 Xpdf 问题。 我尝试通过另一个库 xpdf 提取图像,如果它是图像,它会在页面上进行奇怪的翻转。如果 pdf 包含一个小图像作为对象图像它给我确定,如果页面被扫描他我们做翻转。

我想从 PDF 中提取所有图像,如果扫描 PAGE 以将它们作为图像,如果 Page 包含纯文本和图像也从该页面获取图像。

我的意思是从 PDF 中提取所有图像。不仅形成一个页面,而且即使页面是一个图像,也可以将它们提取为图像,但不要跳过它们我认为 PDFbox 的表现如何。

XPDF 正在做一些事情,但是当他导出扫描的页面时页面上出现问题 FLIP(top,right)

我该如何解决这个问题谢谢。

Download File example for to test

    `PDDocument document = PDDocument.load(new File("/home/dru/IdeaProjects2/PDFExtractor/test/t1.pdf"));
    PDPageTree list = document.getPages();

    for (PDPage page : list) {
        PDResources pdResources = page.getResources();
        System.out.println(pdResources.getResourceCache());

        for (COSName c : pdResources.getXObjectNames()) {
            PDXObject o = pdResources.getXObject(c);

            if (o instanceof org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject) {
                File file = new File("/home/dru/IdeaProjects2/PDFExtractor/test/out/" + System.nanoTime() + ".png");
                ImageIO.write(((org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject)o).getImage(), "png", file);
            }
        }
    }`

【问题讨论】:

  • 您的问题不清楚。即使没有扫描,PDF 也可以包含图像。翻转可能是因为用户将纸张以错误的方向插入进纸器。
  • PDF 文件的 PAGE 是 IMAGE,例如您是否扫描纸张,扫描仪给您选择将图像保存为 PDF 文件 ok。我如何检测是否使用 PDFBOX 扫描了 PDF,因为如果我尝试通过 PDFbox 从页面获取图像,它正在寻找一些具有图像类型的对象,但他没有检测到 PDF 页面是否为完整图像。
  • 那么您真正要问的是图像是否具有页面大小?但即使这样也不能确定图像是否被扫描。
  • 请分享一个示例 PDF 来说明问题以及无法提取图像的关键代码。
  • 我已经添加了使用pdfbox进行测试和代码的文件

标签: pdfbox xpdf


【解决方案1】:

正确提取图像

更新后的 PDF 清楚地表明,问题在于它没有任何图像立即在页面上,但它具有绘制在其上的包含图像的表单 xobjects。因此,图像搜索必须递归到 xobjects 形式。

这还不是全部:更新后的 PDF 中的所有页面共享相同的资源字典,它们只是选择不同的形式 xobjects 来显示。因此,确实必须解析相应的页面内容流以确定给定页面上存在哪些 xobject(带有哪些图像)。

其实这是 PDFBox 工具ExtractImages 所做的事情。不幸的是,它并没有显示找到相关图像的页面,参见。 ExtractImages.java test method testExtractPageImagesTool10948New

但我们可以简单地借鉴该工具使用的技术:

PDDocument document = PDDocument.load(resource);
int page = 1;
for (final PDPage pdPage : document.getPages())
{
    final int currentPage = page;
    PDFGraphicsStreamEngine pdfGraphicsStreamEngine = new PDFGraphicsStreamEngine(pdPage)
    {
        int index = 0;
        
        @Override
        public void drawImage(PDImage pdImage) throws IOException
        {
            if (pdImage instanceof PDImageXObject)
            {
                PDImageXObject image = (PDImageXObject)pdImage;
                File file = new File(RESULT_FOLDER, String.format("10948-new-engine-%s-%s.%s", currentPage, index, image.getSuffix()));
                ImageIOUtil.writeImage(image.getImage(), image.getSuffix(), new FileOutputStream(file));
                index++;
            }
        }

        @Override
        public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException { }

        @Override
        public void clip(int windingRule) throws IOException { }

        @Override
        public void moveTo(float x, float y) throws IOException {  }

        @Override
        public void lineTo(float x, float y) throws IOException { }

        @Override
        public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException {  }

        @Override
        public Point2D getCurrentPoint() throws IOException { return null; }

        @Override
        public void closePath() throws IOException { }

        @Override
        public void endPath() throws IOException { }

        @Override
        public void strokePath() throws IOException { }

        @Override
        public void fillPath(int windingRule) throws IOException { }

        @Override
        public void fillAndStrokePath(int windingRule) throws IOException { }

        @Override
        public void shadingFill(COSName shadingName) throws IOException { }
    };
    pdfGraphicsStreamEngine.processPage(pdPage);
    page++;
}

(ExtractImages.java测试方法testExtractPageImages10948New)

此代码输出文件名为“10948-new-engine-1-0.tiff”、“10948-new-engine-2-0.tiff”、“10948-new-engine-3-0.tiff”的图像”和“10948-new-engine-4-0.tiff”,即每页一个。

PS:请记住在你的类路径中包含com.github.jai-imageio:jai-imageio-core,它是TIFF输出所必需的。

翻转图像

OP 的另一个问题是图像有时会出现上下颠倒,例如如果是他现在最新的示例文件“t1_edited.pdf”。原因是这些图像确实是作为图像资源倒置存储在 PDF 中的。

当这些图像被绘制到页面上时,当时有效的当前变换矩阵会镜像垂直绘制的图像,从而创建预期的外观。

通过稍微增强上述代码中的drawImage 实现,可以在导出图像的名称中包含此类翻转的指示符:

public void drawImage(PDImage pdImage) throws IOException
{
    if (pdImage instanceof PDImageXObject)
    {
        Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
        String flips = "";
        if (ctm.getScaleX() < 0)
            flips += "h";
        if (ctm.getScaleY() < 0)
            flips += "v";
        if (flips.length() > 0)
            flips = "-" + flips;
        PDImageXObject image = (PDImageXObject)pdImage;
        File file = new File(RESULT_FOLDER, String.format("t1_edited-engine-%s-%s%s.%s", currentPage, index, flips, image.getSuffix()));
        ImageIOUtil.writeImage(image.getImage(), image.getSuffix(), new FileOutputStream(file));
        index++;
    }
}

现在可以相应地标记垂直或水平翻转的图像。

【讨论】:

  • 我对大小约为 1MB 的文件进行了测试,但测试失败,线程 "main" java.lang.OutOfMemoryError: Java heap space 中的异常,请您下载示例并进行相同的测试看到错误的痕迹,我想知道如何解决这个问题?谢谢你
  • 我刚刚通过上述提取器运行了您的示例文件(参见ExtractImages test testExtractPageImagesT1Edited,但没有得到OutOfMemoryError,只是花了一些时间......您应该尝试分配更多该进程的内存。
  • 我用的是pdfbox 2.0.3,你们有同样的版本吗?
  • 我实际使用的是当前的PDFBox开发分支,2.1.0-SNAPSHOT。但我只是用 PDFBox 2.0.3 重复了测试,没有问题。此外,我正在研究 Java 8; Java 7 和 Java 8 之间的内存管理发生了很大变化。如果您碰巧使用 Java 7 或更早版本,您可能会更早遇到内存耗尽。
  • 我使用的是 Java 8,PDFBox 2.0.3,我会看看如何解决这个问题,如果你知道增加内存限制会很好,可能是 IDE 对运行时执行的限制,为了避免自动退出,我使用 Intellij Idea
猜你喜欢
  • 2011-01-25
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
  • 2011-05-30
  • 2013-11-11
  • 1970-01-01
  • 2019-12-20
相关资源
最近更新 更多