【问题标题】:How can I distinguish a digitally-created PDF from a searchable PDF?如何区分数字创建的 PDF 和可搜索的 PDF?
【发布时间】:2021-06-12 00:23:03
【问题描述】:

我目前正在分析一组 PDF 文件。我想知道有多少 PDF 文件属于这 3 个类别:

  • 以数字方式创建的 PDF:文本存在(可复制)并且保证正确,因为它是直接创建的,例如来自Word
  • 仅图像 PDF:扫描文档
  • 可搜索的 PDF:扫描的文档,但使用了 OCR 引擎。 OCR 引擎将文本放在图像“下方”,以便您可以搜索/复制内容。由于 OCR 非常好,因此大多数情况下这是正确的。但不保证正确。

在我的域中识别纯图像 PDF 很容易,因为每个 PDF 都包含文本。如果我无法提取任何文本,它只是图像。但是我怎么知道它是“只是”一个可搜索的 PDF 还是一个数字创建的 PDF?

顺便说一句,它并不像我看到的扫描文档那样简单地查看生产者字段,其中生产者字段显示为“Microsoft Word”。

注意:作为人类,这很容易。我只是放大文字。如果我看到像素,它“只是”可搜索的。

以下是用于测试解决方案的 3 个示例 PDF 文件:

我尝试/想到了什么

  • 使用创建者/制作者:我在扫描的文档中看到“Microsoft Word”。这也很乏味。
  • 嵌入式字体:您可以extract embedded fonts。这个想法是扫描的文档不会嵌入字体,而只是使用默认字体。从这个例子可以看出,这个想法是错误的。

【问题讨论】:

  • 如果有一个页面那么大的图片却有文字?
  • @Nathan 不,它没有。虽然问题似乎相同,但答案集中在文本提取部分。我对文本提取不感兴趣。我想知道文档是否经过 OCR 处理。
  • @Nathan This answer 试图回答我的问题(我认为),但它是一个 bash 脚本而不是 Python 代码
  • @MartinThoma 这个答案会两次渲染 PDF:一次是保留文本,一次是剥离文本。然后它会在输出页面之间进行成对的图像比较。

标签: python pdf


【解决方案1】:

使用 PyMuPDF,您可以根据 @ypnos 的建议轻松删除所有文本。

作为替代方案,您还可以使用 PyMuPDF 检查文本是否隐藏在 PDF 中。在 PDF 的相关“迷你语言”中,这是由命令 3 Tr 触发的(“文本渲染模式”,例如参见 https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf 的第 402 页)。 因此,如果所有文本都受此命令的影响,则不会呈现任何文本 - 允许得出“这是一个 OCR 页面”的结论。

【讨论】:

  • "这是由3 Tr命令触发的" - 这只是一种选择,在PDF中绘制不可见文本有多种方法,不同的OCR服务使用不同的那些..
  • @mkl 还有什么其他方法?
  • 很高兴知道我能做到 - 但我该怎么做呢?
  • 啊,我明白了,您发布了code on GitHub - 谢谢!
  • @JorjMcKie “还有其他方法吗?” - 例如先绘制文本,然后是覆盖它的扫描位图。或者字体仅与空字形一起使用。见here
【解决方案2】:

How to check if PDF is scanned image or contains text修改this answer

在这个解决方案中,您不必渲染 pdf,所以我猜它会更快。基本上我修改的答案是使用文本覆盖的pdf区域的百分比来确定它是文本文档还是扫描文档(图像)。

我添加了一个类似的推理,计算图像覆盖的总面积来计算图像覆盖的百分比。如果它大部分被图像覆盖,您可以假设它是扫描文档。您可以移动阈值以适合您的文档集合。

我还添加了逐页检查的逻辑。这是因为至少在我拥有的文档集合中,一些文档可能有一个数字创建的第一页,然后扫描其余的。

修改代码:

import fitz #pip install PyMuPDF

def page_type(page):

    page_area =abs(page.rect) #total page area

    img_area=0.0
    for block in page.getText("RAWDICT")["blocks"]:
        if block["type"]==1: #Type=1 are images
            bbox=block["bbox"]
            img_area+=(bbox[2]-bbox[0])*(bbox[3]-bbox[1]) # width*height
    img_perc=img_area / page_area
    print("Image area proportion: "+str(img_perc))

    text_area = 0.0
    for b in page.getTextBlocks():
        r = fitz.Rect(b[:4])  # rectangle where block text appears
        text_area = text_area + abs(r)
    text_perc=text_area / page_area
    print("Text area proportion: "+str(text_perc))

    if text_perc < 0.01: #No text = Scanned
        page_type="Scanned"
    elif img_perc > .8:  #Has text but very large images = Searchable
        page_type="Searchable text" 
    else:
        page_type="Digitally created"
    return page_type


doc=fitz.open(pdffilepath)

for page in doc: #Iterate through pages to find different types
    print(page_type(page))

【讨论】:

    【解决方案3】:

    你可以通过 bash 脚本来完成。

        #!/bin/bash
    
        echo "shellscript $0"
        ls --color --group-directories-first
        read -p "Is it OK to use this shellscript in this directory? (y/N) " ans
        if [ "$ans" != "y" ]
        then
         exit
        fi
    
        mkdir -p scanned
        mkdir -p text
        mkdir -p "s-and-t"
    
        for file in *.pdf
        do
         grep -aq '/Image/' "$file"
         if [ $? -eq 0 ]
         then
          image=true
         else
          image=false
         fi
         grep -aq '/Text' "$file"
         if [ $? -eq 0 ]
         then
          text=true
         else
          text=false
         fi
    
    
         if $image && $text
         then
          mv "$file" "s-and-t"
         elif $image
         then
          mv "$file" "scanned"
         elif $text
         then
          mv "$file" "text"
         else
          echo "$file undecided"
         fi
        done    
    

    谢谢

    【讨论】:

      猜你喜欢
      • 2021-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多