当前位置: 首页 > 知识库问答 >
问题:

从PDF中提取不可选择的内容

牛经赋
2023-03-14

我正在使用Apache PDFBox从PDF文件中提取页面,我找不到一种方法来提取不可选择的内容(文本或图像)。有了可从PDF文件中选择的内容,就没有问题了。

请注意,所讨论的PDF文件在复制内容方面没有任何限制,至少从我在文件的“文档限制摘要”中看到的是这样的:它们都允许“内容复制”和“内容复制以供访问”!在同一个PDF文件中,有可选择的内容,也有不可选择的其他部分。发生的情况是,提取的页面带有“漏洞”,即它们只有PDF的可选择部分。然而,在MS Word上,如果我将PDF作为对象添加,则会显示PDF页面的全部内容!因此,我希望对PDFBox lib或任何其他Javalib做同样的事情!

以下是我用来将PDF页面转换为图像的代码:

private void convertPdfToImage(File pdfFile, int pdfId) throws IOException {
   PDDocument document = PDDocument.loadNonSeq(pdfFile, null);
   List<PDPage> pdPages = document.getDocumentCatalog().getAllPages();
   for (PDPage pdPage : pdPages) { 
       BufferedImage bim = pdPage.convertToImage(BufferedImage.TYPE_INT_RGB, 300);
       ImageIOUtil.writeImage(bim, TEMP_FILEPATH + pdfId + ".png", 300);
   }
   document.close();
}

有没有办法用这个ApachePDFBox库(或其他类似库)从PDF中提取不可选择的内容?或者这根本不可能?如果事实并非如此,为什么?

非常感谢您的帮助!

编辑:我使用Adobe Reader作为PDF查看器和PDFBox v1。8.以下是PDF示例:https://dl.dropboxusercontent.com/u/2815529/test.pdf

共有1个答案

池兴邦
2023-03-14

这两幅图片,右上角的fischer徽标和稍微向下的小草图,都是通过在页面的某个区域填充平铺图案绘制的,而平铺图案在其内容流中依次绘制相应的图像。

Adobe Reader不允许选择模式的内容,自动图像提取器通常也不会遍历模式资源树。

您可以使用PDFBox相当轻松地构建图案图像提取器,例如,对于PDFBox 1.8.10:

public void extractPatternImages(PDDocument document, String fileNameFormat) throws IOException
{
    List<PDPage> pages = document.getDocumentCatalog().getAllPages();
    if (pages == null)
        return;

    for (int i = 0; i < pages.size(); i++)
    {
        String pageFormat = String.format(fileNameFormat, "-" + i + "%s", "%s");
        extractPatternImages(pages.get(i), pageFormat);
    }
}

public void extractPatternImages(PDPage page, String pageFormat) throws IOException
{
    PDResources resources = page.getResources();
    if (resources == null)
        return;
    Map<String, PDPatternResources> patterns = resources.getPatterns();

    for (Map.Entry<String, PDPatternResources> patternEntry : patterns.entrySet())
    {
        String patternFormat = String.format(pageFormat, "-" + patternEntry.getKey() + "%s", "%s");
        extractPatternImages(patternEntry.getValue(), patternFormat);
    }
}

public void extractPatternImages(PDPatternResources pattern, String patternFormat) throws IOException
{
    COSDictionary resourcesDict = (COSDictionary) pattern.getCOSDictionary().getDictionaryObject(COSName.RESOURCES);
    if (resourcesDict == null)
        return;
    PDResources resources = new PDResources(resourcesDict);
    Map<String, PDXObject> xObjects = resources.getXObjects();
    if (xObjects == null)
        return;

    for (Map.Entry<String, PDXObject> entry : xObjects.entrySet())
    {
        PDXObject xObject = entry.getValue();
        String xObjectFormat = String.format(patternFormat, "-" + entry.getKey() + "%s", "%s");
        if (xObject instanceof PDXObjectForm)
            extractPatternImages((PDXObjectForm)xObject, xObjectFormat);
        else if (xObject instanceof PDXObjectImage)
            extractPatternImages((PDXObjectImage)xObject, xObjectFormat);
    }
}

public void extractPatternImages(PDXObjectForm form, String imageFormat) throws IOException
{
    PDResources resources = form.getResources();
    if (resources == null)
        return;
    Map<String, PDXObject> xObjects = resources.getXObjects();
    if (xObjects == null)
        return;

    for (Map.Entry<String, PDXObject> entry : xObjects.entrySet())
    {
        PDXObject xObject = entry.getValue();
        String xObjectFormat = String.format(imageFormat, "-" + entry.getKey() + "%s", "%s");
        if (xObject instanceof PDXObjectForm)
            extractPatternImages((PDXObjectForm)xObject, xObjectFormat);
        else if (xObject instanceof PDXObjectImage)
            extractPatternImages((PDXObjectImage)xObject, xObjectFormat);
    }

    Map<String, PDPatternResources> patterns = resources.getPatterns();

    for (Map.Entry<String, PDPatternResources> patternEntry : patterns.entrySet())
    {
        String patternFormat = String.format(imageFormat, "-" + patternEntry.getKey() + "%s", "%s");
        extractPatternImages(patternEntry.getValue(), patternFormat);
    }
}

public void extractPatternImages(PDXObjectImage image, String imageFormat) throws IOException
{
    image.write2OutputStream(new FileOutputStream(String.format(imageFormat, "", image.getSuffix())));
}

(ExtractPatternImages.java

我把它应用到你的样本PDF上,就像这样

public void testtestDrJorge() throws IOException
{
    try (InputStream resource = getClass().getResourceAsStream("testDrJorge.pdf"))
    {
        PDDocument document = PDDocument.load(resource);
        extractPatternImages(document, "testDrJorge%s.%s");;
    }
}

(ExtractPatternImages.java)

有两张照片:

>

testDrJorge-0-R38-R37。巴布亚新几内亚

这些图像失去了红色部分。这很可能是由于PDFBox版本1。x、 x不正确支持CMYK图像的提取,参见PDFBOX-2128(不正确支持CMYK图像),并且您的图像在CMYK中。

我将代码更新为PDFBox 2.0.0(目前仅作为候选版本提供):

public void extractPatternImages(PDDocument document, String fileNameFormat) throws IOException
{
    PDPageTree pages = document.getDocumentCatalog().getPages();
    if (pages == null)
        return;

    for (int i = 0; i < pages.getCount(); i++)
    {
        String pageFormat = String.format(fileNameFormat, "-" + i + "%s", "%s");
        extractPatternImages(pages.get(i), pageFormat);
    }
}

public void extractPatternImages(PDPage page, String pageFormat) throws IOException
{
    PDResources resources = page.getResources();
    if (resources == null)
        return;
    Iterable<COSName> patternNames = resources.getPatternNames();

    for (COSName patternName : patternNames)
    {
        String patternFormat = String.format(pageFormat, "-" + patternName + "%s", "%s");
        extractPatternImages(resources.getPattern(patternName), patternFormat);
    }
}

public void extractPatternImages(PDAbstractPattern pattern, String patternFormat) throws IOException
{
    COSDictionary resourcesDict = (COSDictionary) pattern.getCOSObject().getDictionaryObject(COSName.RESOURCES);
    if (resourcesDict == null)
        return;
    PDResources resources = new PDResources(resourcesDict);
    Iterable<COSName> xObjectNames = resources.getXObjectNames();
    if (xObjectNames == null)
        return;

    for (COSName xObjectName : xObjectNames)
    {
        PDXObject xObject = resources.getXObject(xObjectName);
        String xObjectFormat = String.format(patternFormat, "-" + xObjectName + "%s", "%s");
        if (xObject instanceof PDFormXObject)
            extractPatternImages((PDFormXObject)xObject, xObjectFormat);
        else if (xObject instanceof PDImageXObject)
            extractPatternImages((PDImageXObject)xObject, xObjectFormat);
    }
}

public void extractPatternImages(PDFormXObject form, String imageFormat) throws IOException
{
    PDResources resources = form.getResources();
    if (resources == null)
        return;
    Iterable<COSName> xObjectNames = resources.getXObjectNames();
    if (xObjectNames == null)
        return;

    for (COSName xObjectName : xObjectNames)
    {
        PDXObject xObject = resources.getXObject(xObjectName);
        String xObjectFormat = String.format(imageFormat, "-" + xObjectName + "%s", "%s");
        if (xObject instanceof PDFormXObject)
            extractPatternImages((PDFormXObject)xObject, xObjectFormat);
        else if (xObject instanceof PDImageXObject)
            extractPatternImages((PDImageXObject)xObject, xObjectFormat);
    }

    Iterable<COSName> patternNames = resources.getPatternNames();

    for (COSName patternName : patternNames)
    {
        String patternFormat = String.format(imageFormat, "-" + patternName + "%s", "%s");
        extractPatternImages(resources.getPattern(patternName), patternFormat);
    }
}

public void extractPatternImages(PDImageXObject image, String imageFormat) throws IOException
{
    String filename = String.format(imageFormat, "", image.getSuffix());
    ImageIOUtil.writeImage(image.getOpaqueImage(), "png", new FileOutputStream(filename));
}

得到

>

  • testDrJorge-0-COSName{R15}-COSName{R14}。巴布亚新几内亚

    testDrJorge-0-COSName{R38}-COSName{R37}. png

    看起来像一个改进...;)

  •  类似资料:
    • 问题陈述: 我有一个PDF的结构像表格,但行是不可见的。请参阅下面的示例: 上图是我的表格在其中一个PDF页面中的样子。 我的研究 > 如何使用Python从PDF中提取表作为文本?--看了这道题,看了所有的答案。没有帮助 tabula:尝试了tabula API,但它只是提取标题而不是文本,可能是因为没有行。 我可以将整个pdf转换成文本,然后尝试用regex或数据操作来提取它。但这可能是非常乏

    • 问题内容: 我有一堆PDF-可能是数百或数千。它们的格式并非全部相同,但是它们中的任何一个都可以具有一个或多个表,这些表包含我想收集到单独数据库中的有趣信息。 当然,我知道我必须写点东西才能做到这一点。Perl是我的选择-也许是Java。只要是免费的,我就不在乎什么语言(或者免费试用,以确保它适合我的目的)。 我正在查看CAM :: Parse(使用Strawberry Perl),但是我不确定如

    • 我用Adobe LiveCycle Designer创建了一个PDF表单。我现在正在努力从PDF中以编程方式提取填充后的数据。 我尝试使用poppler(qt4绑定,但我想这并不重要),但显然poppler无法处理XFA表单。虽然evince和okular能够显示表单。。。 据我所知,PDF包含一个XDP,而XDP又包含XFA表单。我的问题是,我如何从PDF中提取这些数据?

    • 我必须从PDF签名文档中提取签名字段,以创建打印签名版本。到目前为止,我已经能够使用以下iText代码恢复签名者证书、原因、签名日期和其他字段: 据我所知,PDF签名是使用iText PdfPkcs7类制作的,使用setExternalDigest方法添加在外部应用程序中创建的PKCS1字节数组。文件看起来已由外部工具正确签名和验证。 但是,打印版本所需的字段之一是“签名数字戳”,它是签名文档哈希

    • 我正在尝试从PDF中提取文本(https://www.sec.gov/litigation/admin/2015/34-76574.pdf)使用PyPDF2,我得到的唯一结果是以下字符串: 这是我的代码: 这段代码在我正在使用的一些PDF上正常工作(例如。https://www.sec.gov/litigation/admin/2016/34-76837-proposed-amended-dist

    • 假设我的用户去了他们办公室的扫描仪。扫描仪能够生成扫描文档的PDF。这基本上就是我拥有的文件类型。 我想做的是从这个PDF中提取文本。这不是“第一代”pdf,因为文本没有嵌入到pdf中。文本嵌入在PDF中的图像中。 PDFBox的iText中是否有允许检索此数据的功能?如果可能的话,我正在尝试避免对图像进行OCR。我希望IText或PDFBox中有一些内置的东西可以做到这一点。 请注意,我不是在谈