有没有一种简单的方法可以识别是否扫描了PDF?


8

我有成千上万的文档,其中一些已扫描。因此,我需要一个脚本来测试属于目录的所有PDF文件。有没有简单的方法可以做到这一点?

  1. 大多数PDF是报告。因此,他们有很多文字。
  2. 它们是非常不同的,但是由于不稳定的OCR处理与扫描相结合,因此如下所述的扫描对象可以找到一些文本。

  3. 在下面的评论中,由于Sudodus提出的提案似乎非常有趣。查看已扫描的PDF与未扫描的PDF之间的区别:

已扫描:

grep --color -a 'Image' AR-G1002.pdf
<</BitsPerComponent 8/ColorSpace/DeviceRGB/Filter[/DCTDecode]/Height 2197/Length 340615/Name/Obj13/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 40452/Name/Obj18/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 41680/Name/Obj23/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 41432/Name/Obj28/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 59084/Name/Obj33/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 8/ColorSpace/DeviceRGB/Filter[/DCTDecode]/Height 2197/Length 472681/Name/Obj38/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 8/ColorSpace/DeviceRGB/Filter[/DCTDecode]/Height 2197/Length 469340/Name/Obj43/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 8/ColorSpace/DeviceRGB/Filter[/DCTDecode]/Height 2197/Length 371863/Name/Obj48/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 8/ColorSpace/DeviceRGB/Filter[/DCTDecode]/Height 2197/Length 344092/Name/Obj53/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 59416/Name/Obj58/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 48308/Name/Obj63/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 51564/Name/Obj68/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 63184/Name/Obj73/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 40824/Name/Obj78/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 23320/Name/Obj83/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 31504/Name/Obj93/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 18996/Name/Obj98/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 8/ColorSpace/DeviceRGB/Filter[/DCTDecode]/Height 2197/Length 292932/Name/Obj103/Subtype/Image/Type/XObject/Width 1698>>stream
<</BitsPerComponent 1/ColorSpace/DeviceGray/DecodeParms<</Columns 1698/K -1>>/Filter/CCITTFaxDecode/Height 2197/Length 27720/Name/Obj108/Subtype/Image/Type/XObject/Width 1698>>stream
               <rdf:li xml:lang="x-default">Image</rdf:li>
               <rdf:li xml:lang="x-default">Image</rdf:li>

未扫描:

grep --color -a 'Image' AR-G1003.pdf
<</Lang(en-US)/MarkInfo<</Marked true>>/Metadata 167 0 R/Pages 2 0 R/StructTreeR<</Contents 4 0 R/Group<</CS/DeviceRGB/S/Transparency/Type/Group>>/MediaBox[0 0 612 792]/Parent 2 0 R/Resources<</Font<</F1 5 0 R/F2 7 0 R/F3 9 0 R/F4 11 0 R/F5 13 0 R>>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/StructParents 0/Tabs/S/Type/<</Filter/FlateDecode/Length 5463>>stream
<</BaseFont/Times#20New#20Roman,Bold/Encoding/WinAnsiEncoding/FirstChar 32/FontD<</Ascent 891/AvgWidth 427/CapHeight 677/Descent -216/Flags 32/FontBBox[-558 -216 2000 677]/FontName/Times#20New#20Roman,Bold/FontWeight 700/ItalicAngle 0/Leadi<</BaseFont/Times#20New#20Roman/Encoding/WinAnsiEncoding/FirstChar 32/FontDescri<</Ascent 891/AvgWidth 401/CapHeight 693/Descent -216/Flags 32/FontBBox[-568 -216 2000 693]/FontName/Times#20New#20Roman/FontWeight 400/ItalicAngle 0/Leading 42<</BaseFont/Arial,Bold/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 10 0<</Ascent 905/AvgWidth 479/CapHeight 728/Descent -210/Flags 32/FontBBox[-628 -210 2000 728]/FontName/Arial,Bold/FontWeight 700/ItalicAngle 0/Leading 33/MaxWidth<</BaseFont/Times#20New#20Roman,Italic/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 12 0 R/LastChar 118/Name/F4/Subtype/TrueType/Type/Font/Widths 164 0 <</Ascent 891/AvgWidth 402/CapHeight 694/Descent -216/Flags 32/FontBBox[-498 -216 1333 694]/FontName/Times#20New#20Roman,Italic/FontWeight 400/ItalicAngle -16.4<</BaseFont/Arial/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 14 0 R/La<</Ascent 905/AvgWidth 441/CapHeight 728/Descent -210/Flags 32/FontBBox[-665 -210 2000 728]/FontName/Arial/FontWeight 400/ItalicAngle 0/Leading 33/MaxWidth 2665<</Contents 16 0 R/Group<</CS/DeviceRGB/S/Transparency/Type/Group>>/MediaBox[0 0 612 792]/Parent 2 0 R/Resources<</Font<</F1 5 0 R/F2 7 0 R/F5 13 0 R>>/ProcSet[<</Filter/FlateDecode/Length 7534>>streamarents 1/Tabs/S/Type/Page>>
<</Contents 18 0 R/Group<</CS/DeviceRGB/S/Transparency/Type/Group>>/MediaBox[0 0 612 792]/Parent 2 0 R/Resources<</Font<</F1 5 0 R/F2 7 0 R/F5 13 0 R>>/ProcSet[<</Filter/FlateDecode/Length 6137>>streamarents 2/Tabs/S/Type/Page>>
<</Contents 20 0 R/Group<</CS/DeviceRGB/S/Transparency/Type/Group>>/MediaBox[0 0 612 792]/Parent 2 0 R/Resources<</Font<</F1 5 0 R/F2 7 0 R/F5 13 0 R/F6 21 0 R><</Filter/FlateDecode/Length 6533>>stream>>/StructParents 3/Tabs/S/Type/Page>>
<</BaseFont/Times#20New#20Roman/DescendantFonts 22 0 R/Encoding/Identity-H/Subty<</BaseFont/Times#20New#20Roman/CIDSystemInfo 24 0 R/CIDToGIDMap/Identity/DW 100<</Ascent 891/AvgWidth 401/CapHeight 693/Descent -216/Flags 32/FontBBox[-568 -216 2000 693]/FontFile2 160 0 R/FontName/Times#20New#20Roman/FontWeight 400/Italic<</Contents 27 0 R/Group<</CS/DeviceRGB/S/Transparency/Type/Group>>/MediaBox[0 0 612 792]/Parent 2 0 R/Resources<</ExtGState<</GS28 28 0 R/GS29 29 0 R>>/Font<</F1 5 0 R/F2 7 0 R/F3 9 0 R/F5 13 0 R/F6 21 0 R>>/ProcSet[/PDF/Text/ImageB/ImageC<</Filter/FlateDecode/Length 5369>>streamge>>

每页的图像数量要大得多(每页大约一张)!


7
您是说它们是文字还是图像?
DK Bose

8
为什么想知道是否扫描了pdf文件?您打算如何使用这些信息?
sudodus

4
@sudodus提出一个很好的问题。例如,大多数扫描的PDF都具有可供选择的文本,可以使用OCR进行转换。这样的文件和文本文件之间有区别吗?您知道 PDF的来源吗?
管道

1
扫描文档和未扫描文档的元数据是否有差异?那将提供一个非常干净和容易的方法。
甜点

1
如果pdf文件包含图像(在文本旁边或整个页面中插入到文档中,称为“扫描的pdf”),则该文件通常(也许总是)包含字符串/Image/,可以在命令行中找到该字符串grep --color -a 'Image' filename.pdf。这会将仅包含文本的文件与包含图像的文件(整页图像以及带有小徽标和中型插图图片的文本页)分开。
sudodus

Answers:


4

Shell脚本

  • 如果pdf文件包含图像(在文本旁边或整个页面中插入文档中,称为“扫描的pdf”),则该文件通常(也许总是)包含字符串/Image/

  • 以相同的方式,您可以搜索字符串/Text以判断pdf文件是否包含文本(未扫描)。

我制作了shellscript pdf-text-or-image,它在大多数情况下都可以与您的文件一起使用。该shell脚本查找文本字符串/Image/,并/Textpdf文件中。

#!/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

使shellscript可执行,

chmod ugo+x pdf-text-or-image

将目录更改为您拥有pdf文件的目录,然后运行shellscript。

识别的文件将移动到以下子目录

  • scanned
  • text
  • s-and-t (对于同时具有[扫描的?]图像和文本内容的文档)

未识别的文件对象“ UFO”保留在当前目录中。

测试

我用您的两个文件AR-G1002.pdfAR-G1003.pdf以及一些自己的pdf文件(我使用Libre Office Impress创建的文件)测试了shellscript 。

$ ./pdf-text-or-image
shellscript ./pdf-text-or-image
s-and-t                                 mkUSB-quick-start-manual-11.pdf    mkUSB-quick-start-manual-nox-11.pdf
scanned                                 mkUSB-quick-start-manual-12-0.pdf  mkUSB-quick-start-manual-nox.pdf
text                                    mkUSB-quick-start-manual-12.pdf    mkUSB-quick-start-manual.pdf
AR-G1002.pdf                            mkUSB-quick-start-manual-74.pdf    OBI-quick-start-manual.pdf
AR-G1003.pdf                            mkUSB-quick-start-manual-75.pdf    oem.pdf
DescriptionoftheOneButtonInstaller.pdf  mkUSB-quick-start-manual-8.pdf     pdf-text-or-image
GrowIt.pdf                              mkUSB-quick-start-manual-9.pdf     pdf-text-or-image0
list-files.pdf                          mkUSB-quick-start-manual-bas.pdf   README.pdf
Is it OK to use this shellscript in this directory? (y/N) y

$ ls -1 *
pdf-text-or-image
pdf-text-or-image0

s-and-t:
DescriptionoftheOneButtonInstaller.pdf
GrowIt.pdf
mkUSB-quick-start-manual-11.pdf
mkUSB-quick-start-manual-12-0.pdf
mkUSB-quick-start-manual-12.pdf
mkUSB-quick-start-manual-8.pdf
mkUSB-quick-start-manual-9.pdf
mkUSB-quick-start-manual.pdf
OBI-quick-start-manual.pdf
README.pdf

scanned:
AR-G1002.pdf

text:
AR-G1003.pdf
list-files.pdf
mkUSB-quick-start-manual-74.pdf
mkUSB-quick-start-manual-75.pdf
mkUSB-quick-start-manual-bas.pdf
mkUSB-quick-start-manual-nox-11.pdf
mkUSB-quick-start-manual-nox.pdf
oem.pdf

让我们希望

  • 您的文件集中没有UFO
  • 关于文本与扫描/图像的排序是正确的

而不是重定向到/ dev / null即可使用grep -q
phuclv

1
@phuclv,感谢您的提示:-)这也使其速度更快,特别是对于大文件,因为grep -q如果找到任何匹配项,则立即以零状态退出(而不是在整个文件中进行搜索)。
sudodus

6
  1. 将所有.pdf文件放在一个文件夹中。
  2. 该文件夹中没有.txt文件。
  3. 在终端将目录更改为该文件夹 cd <path to dir>
  4. 为未扫描的文件再创建一个目录。例:
mkdir ./x 
for file in *.pdf; do
    if [ $(pdftotext "$file")"x" == "x" ] ; then mv "$file" ./x; fi
rm *.txt
done

所有pdf扫描文件将保留在该文件夹中,其他文件将移至另一个文件夹。


这很棒。但是,此文件将转到另一个文件夹并被扫描:drive.google.com/open ? id=12xIQdRo_cyTf27Ck6DQKvRyRvlkYEzjl这是怎么回事?
DanielTheRocketMan

8
扫描的PDF通常总是包含OCRed文本内容,因此我猜想简单的测试将对它们失败。更好的指示符可能是每页一张大图像,无论文本内容如何。
乔伊(Joey)

2
由于存在一个非常明显的缺陷而被否决:一开始就如何知道是否扫描文件?这就是OP的要求:如何以编程方式测试是否扫描。
jamesqf

1
@DanielTheRocketMan PDF文件的版本可能会影响您用来选择文本的工具。的输出file pdf-filename.pdf将产生版本号。我无法在BR-L1411-3.pdf中搜索特定的文本BR-L1411-3.pdf:PDF文档,版本1.3,但能够在您提供的其他两个文件(版本1.5和以下版本)中搜索文本1.6并获得一场或更多场比赛。我使用PDF XChange Viewer搜索这些文件,但有类似的结果。版本1.3文档没有匹配项。
年长者极客

1
@DanielTheRocketMan如果是这种情况,您可能会发现使用file有助于完成项目的输出帮助按版本对文档进行排序。尽管我看来其他人仍不清楚您要完成的目标。
极客长老

2

我创建了一个脚本来检测PDF是否为OCRd。主要思想:在OCRd PDF中,文本是不可见的。

测试给定PDF(f1)是否为OCRd的算法:

  1. 创建副本的f1标注为f2
  2. 删除所有文字 f2
  3. 创建所有图像(PNG)(或少数几个)的页面f1f2
  4. f1是OCRD如果所有图像f1f2是相同的。

https://github.com/jfilter/pdf-scripts/blob/master/is_ocrd_pdf.sh

#!/usr/bin/env bash
set -e
set -x

################################################################################
# Check if a PDF was scanned or created digitally, works on OCRd PDFs
#
# Usage:
#   bash is_scanned_pdf.sh [-p] file
#
#   Exit 0: Yes, file is a scanned PDF
#   Exit 99: No, file was created digitally
#
# Arguments:
#   -p or --pages: pos. integer, only consider first N pages
#
# Please report issues at https://github.com/jfilter/pdf-scripts/issues
#
# GPLv3, Copyright (c) 2020 Johannes Filter
################################################################################

# parse arguments
# h/t https://stackoverflow.com/a/33826763/4028896
max_pages=-1
# skip over positional argument of the file(s), thus -gt 1
while [[ "$#" -gt 1 ]]; do
  case $1 in
  -p | --pages)
    max_pages="$2"
    shift
    ;;
  *)
    echo "Unknown parameter passed: $1"
    exit 1
    ;;
  esac
  shift
done

# increment to make it easier with page numbering
max_pages=$((max_pages++))

command_exists() {
  if ! [ -x $($(command -v $1 &>/dev/null)) ]; then
    echo $(error: $1 is not installed.) >&2
    exit 1
  fi
}

command_exists mutool && command_exists gs && command_exists compare
command_exists pdfinfo

orig=$PWD
num_pages=$(pdfinfo $1 | grep Pages | awk '{print $2}')

echo $num_pages

echo $max_pages

if ((($max_pages > 1) && ($max_pages < $num_pages))); then
  num_pages=$max_pages
fi

cd $(mktemp -d)

for ((i = 1; i <= num_pages; i++)); do
  mkdir -p output/$i && echo $i
done

# important to filter text on output of GS (tmp1), cuz GS alters input PDF...
gs -o tmp1.pdf -sDEVICE=pdfwrite -dLastPage=$num_pages $1 &>/dev/null
gs -o tmp2.pdf -sDEVICE=pdfwrite -dFILTERTEXT tmp1.pdf &>/dev/null
mutool convert -o output/%d/1.png tmp1.pdf 2>/dev/null
mutool convert -o output/%d/2.png tmp2.pdf 2>/dev/null

for ((i = 1; i <= num_pages; i++)); do
  echo $i
  # difference in pixels, if 0 there are the same pictures
  # discard diff image
  if ! compare -metric AE output/$i/1.png output/$i/2.png null: 2>&1; then
    echo " pixels difference, not a scanned PDF, mismatch on page $i"
    exit 99
  fi
done

1

如果文档集的扫描文档中未添加带有光学字符识别(OCR)的文本,则Hobbyist提供了很好的解决方案。如果可能的话,您可能需要做一些脚本来读取文件的输出pdfinfo -meta并检查用于创建文件的工具,或者采用使用一个Python库之一检查它们的Python例程。strings由于可以压缩PDF内容,因此使用之类的工具搜索文本将不可靠。而且,由于可以合并PDF页面,因此检查创建工具也不是不安全的。我通常将PDF文本文档与扫描的图像组合在一起,以使内容保持在一起。

很抱歉,我无法提供具体建议。自从我看过PDF内部结构以来已经有一段时间了,但是根据您的要求有多么严格,您可能想知道它有点复杂。祝好运!


2
我也在尝试使用python,但要知道是否扫描了pdf并非易事。关键是,即使您无法选择文本的文档在转换为txt时也会显示一些文本。例如,我在Python中使用pdf挖矿器,即使对于选择工具不起作用的pdf,我也可以在转换中找到一些文本。
DanielTheRocketMan

1

如果这实际上是要检测是否通过扫描创建的 PDF 而不是pdf)具有图像而不是文本,那么您可能需要挖掘文件的元数据,而不仅仅是内容。

通常,对于我可以在计算机上找到的文件以及您的测试文件,以下是正确的:

  • 扫描的文件少于1000chars /页,而未扫描的文件总是超过1000chars /页
  • 多个独立的扫描文件将“ Canon”列为PDF创建器,可能引用了佳能扫描仪软件
  • 创建者为“ Microsoft Word”的PDF可能不会被扫描,因为它们是单词输出。但是有人可以扫描到文字,然后导出为PDF-某些人的工作流程很奇怪

我目前正在使用Windows,因此我使用node.js了以下示例:

const fs = require("mz/fs");
const pdf_parse = require("pdf-parse");
const path = require("path");


const SHOW_SCANNED_ONES = process.argv.indexOf("scanned") != -1;

const DEBUG = process.argv.indexOf("debug") != -1;
const STRICT = process.argv.indexOf("strict") != -1;

const debug = DEBUG ? console.error : () => { };

(async () => {
    const pdfs = (await fs.readdir(".")).filter((fname) => { return fname.endsWith(".pdf") });

    for (let i = 0, l = pdfs.length; i < l; ++i) {
        const pdffilename = pdfs[i];
        try {
            debug("\n\nFILE: ", pdffilename);
            const buffer = await fs.readFile(pdffilename);
            const data = await pdf_parse(buffer);

            if (!data.info)
                data.indo = {};
            if (!data.metadata) {
                data.metadata = {
                    _metadata: {}
                };
            }


            // PDF info
            debug(data.info);
            // PDF metadata
            debug(data.metadata);
            // text length
            const textLen = data.text ? data.text.length : 0;
            const textPerPage = textLen / (data.numpages);
            debug("Text length: ", textLen);
            debug("Chars per page: ", textLen / data.numpages);
            // PDF.js version
            // check https://mozilla.github.io/pdf.js/getting_started/
            debug(data.version);

            if (evalScanned(data, textLen, textPerPage) == SHOW_SCANNED_ONES) {
                console.log(path.resolve(".", pdffilename));
            }
        }
        catch (e) {
            if (strict && !debug) {
                console.error("Failed to evaluate " + item);
            }
            {
                debug("Failed to evaluate " + item);
                debug(e.stack);
            }
            if (strict) {
                process.exit(1);
            }
        }
    }
})();
const IS_CREATOR_CANON = /canon/i;
const IS_CREATOR_MS_WORD = /microsoft.*?word/i;
// just defined for better clarity or return values
const IS_SCANNED = true;
const IS_NOT_SCANNED = false;
function evalScanned(pdfdata, textLen, textPerPage) {
    if (textPerPage < 300 && pdfdata.numpages>1) {
        // really low number, definitelly not text pdf
        return IS_SCANNED;
    }
    // definitelly has enough text
    // might be scanned but OCRed
    // we return this if no 
    // suspition of scanning is found
    let implicitAssumption = textPerPage > 1000 ? IS_NOT_SCANNED : IS_SCANNED;
    if (IS_CREATOR_CANON.test(pdfdata.info.Creator)) {
        // this is always scanned, canon is brand name
        return IS_SCANNED;
    }
    return implicitAssumption;
}

要运行它,您需要安装Node.js(应该是一个命令),并且还需要调用:

npm install mz pdf-parse

用法:

node howYouNamedIt.js [scanned] [debug] [strict]

 - scanned show PDFs thought to be scanned (otherwise shows not scanned)
 - debug shows the debug info such as metadata and error stack traces
 - strict kills the program on first error

该示例不被视为最终解决方案,但是通过使用debug标志,您可以深入了解文件的元信息:

FILE:  BR-L1411-3-scanned.pdf
{ PDFFormatVersion: '1.3',
  IsAcroFormPresent: false,
  IsXFAPresent: false,
  Creator: 'Canon ',
  Producer: ' ',
  CreationDate: 'D:20131212150500-03\'00\'',
  ModDate: 'D:20140709104225-03\'00\'' }
Metadata {
  _metadata:
   { 'xmp:createdate': '2013-12-12T15:05-03:00',
     'xmp:creatortool': 'Canon',
     'xmp:modifydate': '2014-07-09T10:42:25-03:00',
     'xmp:metadatadate': '2014-07-09T10:42:25-03:00',
     'pdf:producer': '',
     'xmpmm:documentid': 'uuid:79a14710-88e2-4849-96b1-512e89ee8dab',
     'xmpmm:instanceid': 'uuid:1d2b2106-a13f-48c6-8bca-6795aa955ad1',
     'dc:format': 'application/pdf' } }
Text length:  772
Chars per page:  2
1.10.100
D:\web\so-odpovedi\pdf\BR-L1411-3-scanned.pdf

在计算机上可以找到的文档(包括您的样本)上,我写的天真函数取得了100%的成功。在运行程序之前,我根据文件的状态命名了文件,以便可以查看结果是否正确。

D:\xxxx\pdf>node detect_scanned.js scanned
D:\xxxx\pdf\AR-G1002-scanned.pdf
D:\xxxx\pdf\AR-G1002_scanned.pdf
D:\xxxx\pdf\BR-L1411-3-scanned.pdf
D:\xxxx\pdf\WHO_TRS_696-scanned.pdf

D:\xxxx\pdf>node detect_scanned.js
D:\xxxx\pdf\AR-G1003-not-scanned.pdf
D:\xxxx\pdf\ASEE_-_thermoelectric_paper_-_final-not-scanned.pdf
D:\xxxx\pdf\MULTIMODE ABSORBER-not-scanned.pdf
D:\xxxx\pdf\ReductionofOxideMineralsbyHydrogenPlasma-not-scanned.pdf

您可以将调试模式与少量编程结合使用,以大大改善您的结果。您可以将程序的输出传递给其他程序,每行始终会有一个完整路径。


以“ Microsoft Word”为创建者,这将取决于原始文档的来源。例如,如果它们是科学论文,那么许多(如果不是大多数)都是由LaTeX工具链中的某些东西创建的。
jamesqf

0

我可以想到2种方式:

  1. 使用选择文本工具:如果您使用的是扫描的PDF,则无法选择文本,而是会出现一个框。您可以使用此事实来创建脚本。我知道在C ++ QT中有一种方法,但是不确定在Linux中。

  2. 在文件中搜索单词:在未扫描的PDF中,您的搜索将起作用,但在扫描的文件中则无效。您只需要查找所有PDF通用的一些单词,或者我宁愿说在所有PDF中搜索字母“ e”。它具有最高的频率分布,因此您可能会在所有包含文本的文档中找到它(除非是gadsby

例如

grep -rnw '/path/to/pdf/' -e 'e'

使用任何文本处理工具


1
扫描的PDF也可以包含可选文本,因为如今OCR并不是一件奇怪的事情,甚至许多免费的PDF阅读器都具有OCR功能
phuclv

@phuclv:但是,如果使用OCR将文件转换为文本,则至少从我了解OP的目的来看,它不再是“扫描的”文件。尽管实际上您现在拥有3种类型的pdf文件:从头开始的文本,来自OCR的文本以及作为扫描图像的“文本”。
jamesqf

1
@jamesqf,请看上面的例子。它们被扫描为pdf。我无法使用常规pdfminer检索大部分文本。
DanielTheRocketMan

1
我认为操作人员需要重新考虑/重新定义这种情况下扫描的定义,或者停止使用acrobat x,后者将扫描的副本作为ocr而不是图像,并将其作为ocr而不是图像
swapedoc '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.