Có cách nào đơn giản để xác định xem PDF có được quét không?


8

Tôi có hàng ngàn tài liệu và một số trong số chúng được quét. Vì vậy, tôi cần một tập lệnh để kiểm tra tất cả các tệp PDF thuộc về một thư mục. Có một cách đơn giản để làm điều đó?

  1. Hầu hết các tệp PDF là báo cáo. Do đó họ có rất nhiều văn bản.
  2. Chúng rất khác nhau, nhưng những cái được quét như được đề cập dưới đây, người ta có thể tìm thấy một số văn bản do quá trình OCR bấp bênh được kết hợp với quá trình quét.

  3. Đề xuất do Sudodus trong các ý kiến ​​dưới đây dường như rất thú vị. Nhìn vào sự khác biệt giữa bản PDF được quét sang bản PDF không được quét:

Quét:

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>

Không được quét:

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>>

Số lượng hình ảnh trên mỗi trang lớn hơn nhiều (khoảng một trên mỗi trang)!


7
Bạn có nghĩa là cho dù họ là văn bản hoặc hình ảnh?
DK Bose

8
Tại sao bạn muốn biết, nếu một tập tin pdf được quét hay không? Làm thế nào để bạn có ý định sử dụng thông tin đó?
sudodus

4
@sudodus Hỏi một câu hỏi rất hay. Ví dụ: hầu hết các tệp PDF được quét đều có sẵn văn bản để lựa chọn, được chuyển đổi bằng OCR. Bạn có tạo sự khác biệt giữa các tệp như vậy và tệp văn bản không? Bạn có biết nguồn PDF của mình không?
đường ống

1
Có sự khác biệt nào trong siêu dữ liệu của các tài liệu được quét và không được quét không? Điều đó sẽ cung cấp một cách rất sạch sẽ và dễ dàng.
tráng miệng

1
Nếu một pdftệp chứa hình ảnh (được chèn trong tài liệu bên cạnh văn bản hoặc toàn bộ trang, 'pdf được quét'), thì tệp thường (có thể luôn luôn) chứa chuỗi /Image/, có thể được tìm thấy bằng dòng lệnh grep --color -a 'Image' filename.pdf. Điều này sẽ tách các tệp chỉ chứa văn bản khỏi các tệp chứa hình ảnh (hình ảnh toàn trang cũng như các trang văn bản có logo nhỏ và hình ảnh minh họa cỡ trung bình).
sudodus

Câu trả lời:


4

Vỏ sò

  • Nếu một pdftệp chứa hình ảnh (được chèn trong tài liệu bên cạnh văn bản hoặc toàn bộ trang, 'pdf được quét'), tệp thường (có thể luôn luôn) chứa chuỗi /Image/.

  • Theo cùng một cách bạn có thể tìm kiếm chuỗi /Textđể cho biết nếu một tệp pdf có chứa văn bản (không được quét).

Tôi đã tạo shellscript pdf-text-or-imagevà nó có thể hoạt động trong hầu hết các trường hợp với các tệp của bạn. Shellscript tìm các chuỗi văn bản /Image//Texttrong các pdftệp.

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

Làm cho shellscript thực thi,

chmod ugo+x pdf-text-or-image

Thay đổi thư mục đến nơi bạn có các pdftệp và chạy shellscript.

Các tệp đã xác định được chuyển đến các thư mục con sau

  • scanned
  • text
  • s-and-t (đối với tài liệu có cả hình ảnh và nội dung văn bản [được quét?]

Các đối tượng tệp không xác định, 'UFO', vẫn còn trong thư mục hiện tại.

Kiểm tra

Tôi đã kiểm tra shellscript với hai trong số các tệp của bạn AR-G1002.pdfAR-G1003.pdfvà với một số pdftệp riêng (mà tôi đã tạo bằng Libre Office Impress).

$ ./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

Hãy để chúng tôi hy vọng rằng

  • không có UFO trong bộ tệp của bạn
  • sắp xếp là chính xác liên quan đến văn bản so với quét / hình ảnh

thay vì chuyển hướng đến / dev / null, bạn chỉ có thể sử dụnggrep -q
phuclv

1
@phuclv, Cảm ơn vì tiền boa :-) Điều này làm cho nó cũng nhanh hơn một chút, đặc biệt là với các tệp lớn, vì grep -qthoát ngay lập tức với trạng thái bằng 0 nếu tìm thấy bất kỳ kết quả khớp nào (thay vì tìm kiếm trong toàn bộ tệp).
sudodus

6
  1. Đặt tất cả các tệp .pdf trong một thư mục.
  2. Không có tệp .txt trong thư mục đó.
  3. Trong thư mục thay đổi thiết bị đầu cuối vào thư mục đó với cd <path to dir>
  4. Tạo thêm một thư mục cho các tệp không được quét. Thí dụ:
mkdir ./x 
for file in *.pdf; do
    if [ $(pdftotext "$file")"x" == "x" ] ; then mv "$file" ./x; fi
rm *.txt
done

Tất cả các tệp được quét pdf sẽ vẫn còn trong thư mục và các tệp khác sẽ chuyển sang thư mục khác.


điều đó thật tuyệt. Tuy nhiên, tệp này đi đến thư mục khác và nó được quét: drive.google.com/open?id=12xIQdRo_cyTf27Ck6DQKvRyRvlkYEzjl Chuyện gì đang xảy ra?
DanielTheRocketMan

8
Các tệp PDF được quét thường luôn chứa nội dung văn bản OCRed, vì vậy tôi đoán rằng thử nghiệm đơn giản sẽ thất bại đối với chúng. Một chỉ báo tốt hơn có thể là một hình ảnh lớn trên mỗi trang, bất kể nội dung văn bản.
Joey

2
Bị từ chối vì lỗ hổng rất rõ ràng: làm thế nào để bạn biết nếu các tập tin được quét hay không ở vị trí đầu tiên? Đó là những gì OP đang hỏi: làm thế nào để kiểm tra lập trình để quét hay không.
jamesqf

1
@DanielTheRocketMan Phiên bản của tệp PDF có thể có tác động đến công cụ bạn đang sử dụng để chọn văn bản. Đầu ra của file pdf-filename.pdfsẽ tạo ra một số phiên bản. Tôi không thể tìm kiếm văn bản cụ thể trong BR-L1411-3.pdf BR-L1411-3.pdf: Tài liệu PDF, phiên bản 1.3 nhưng có thể tìm kiếm văn bản trong cả hai tệp khác mà bạn cung cấp, đó là phiên bản 1.5 và 1.6 và nhận được một hoặc nhiều trận đấu. Tôi đã sử dụng trình xem PDF XChange để tìm kiếm các tệp này nhưng có kết quả tương tự với evince. tài liệu phiên bản 1.3 không có gì phù hợp.
Anh Cả Geek

1
@DanielTheRocketMan Nếu đó là trường hợp bạn có thể tìm thấy sắp xếp các tài liệu theo phiên bản bằng cách sử dụng đầu ra filehữu ích trong việc hoàn thành dự án của bạn. Mặc dù tôi có vẻ như những người khác vẫn chưa rõ chính xác những gì bạn đang cố gắng thực hiện.
Anh Cả Geek

2

Tôi đã tạo một tập lệnh để phát hiện xem PDF có phải là OCRd hay không. Ý tưởng chính: Trong OCRd PDFs là văn bản vô hình.

Thuật toán để kiểm tra xem một tệp PDF ( f1) đã cho có phải là OCRd hay không:

  1. tạo một bản sao f1ghi chú làf2
  2. xóa tất cả văn bản trên f2
  3. tạo hình ảnh (PNG) cho tất cả (hoặc chỉ một vài) trang cho f1f2
  4. f1là OCRd nếu tất cả các hình ảnh của f1f2giống hệt nhau.

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

Sở thích cung cấp một giải pháp tốt nếu các tài liệu được quét của bộ sưu tập tài liệu không có văn bản được thêm bằng nhận dạng ký tự quang học (OCR). Nếu đây là một khả năng, bạn có thể muốn thực hiện một số đoạn script đọc đầu ra pdfinfo -metavà kiểm tra công cụ được sử dụng để tạo tệp hoặc sử dụng một thói quen Python sử dụng một trong các thư viện Python để kiểm tra chúng. Tìm kiếm văn bản với một công cụ như stringssẽ không đáng tin cậy vì nội dung PDF có thể được nén. Và việc kiểm tra công cụ tạo cũng không phải là không an toàn, vì các trang PDF có thể được kết hợp; Tôi thường xuyên kết hợp các tài liệu văn bản PDF với các hình ảnh được quét để giữ mọi thứ lại với nhau.

Tôi xin lỗi vì tôi không thể đưa ra đề xuất cụ thể. Đã được một thời gian kể từ khi tôi chọc vào cấu trúc bên trong PDF, nhưng tùy thuộc vào mức độ nghiêm ngặt của các yêu cầu của bạn, bạn có thể muốn biết rằng nó khá phức tạp. Chúc may mắn!


2
Tôi cũng đang cố gắng sử dụng python, nhưng nó không tầm thường để biết liệu pdf có được quét hay không. Vấn đề là ngay cả các tài liệu mà bạn không thể chọn văn bản trình bày một số văn bản khi nó được chuyển đổi thành txt. Chẳng hạn, tôi đang sử dụng công cụ khai thác pdf trong Python và tôi có thể tìm thấy một số văn bản trong chuyển đổi ngay cả đối với các pdf mà công cụ chọn không hoạt động.
DanielTheRocketMan

1

Nếu đây là về việc thực sự phát hiện nếu PDF được tạo bằng cách quét chứ không phải pdf có hình ảnh thay vì văn bản thì bạn có thể cần phải đào sâu vào siêu dữ liệu của tệp chứ không chỉ nội dung.

Nói chung, đối với các tệp tôi có thể tìm thấy trên máy tính của mình và các tệp thử nghiệm của bạn, sau đây là đúng:

  • Các tệp được quét có ít hơn 1000chars / trang so với các tệp không được quét luôn có hơn 1000chars / trang
  • Nhiều tệp được quét độc lập có "Canon" được liệt kê là trình tạo PDF, có thể tham chiếu phần mềm máy quét Canon
  • Các tệp PDF có "Microsoft Word" là người tạo có thể sẽ không được quét, vì chúng là bản xuất từ. Nhưng ai đó có thể quét từ, sau đó xuất sang PDF - một số người có quy trình làm việc rất lạ .

Hiện tại tôi đang sử dụng Windows, vì vậy tôi đã sử dụng node.jsví dụ sau:

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;
}

Để chạy nó, bạn cần cài đặt Node.js (nên là một lệnh duy nhất) và bạn cũng cần gọi:

npm install mz pdf-parse

Sử dụng:

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

Ví dụ này không được coi là giải pháp hoàn thành, nhưng với debugcờ, bạn sẽ hiểu rõ hơn về thông tin meta của tệp:

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

Hàm ngây thơ mà tôi đã viết đã thành công 100% trên các tài liệu mà tôi có thể tìm thấy trên máy tính của mình (bao gồm cả các mẫu của bạn). Tôi đặt tên cho các tệp dựa trên trạng thái của chúng trước khi chạy chương trình, để có thể xem kết quả có đúng không.

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

Bạn có thể sử dụng chế độ gỡ lỗi cùng với một chút lập trình để cải thiện rất nhiều kết quả của bạn. Bạn có thể chuyển đầu ra của chương trình cho các chương trình khác, nó sẽ luôn có một đường dẫn đầy đủ trên mỗi dòng.


Re "Microsoft Word" là người tạo, điều đó sẽ phụ thuộc vào nguồn tài liệu gốc. Ví dụ, nếu chúng là những bài báo khoa học, nhiều thứ nếu không phải hầu hết sẽ được tạo ra bởi thứ gì đó trong chuỗi công cụ LaTeX.
jamesqf

0

2 cách tôi có thể nghĩ ra:

  1. Sử dụng công cụ văn bản chọn: nếu bạn đang sử dụng bản PDF được quét, các văn bản không thể được chọn, thay vào đó, một hộp sẽ xuất hiện. Bạn có thể sử dụng thực tế này để tạo ra kịch bản. Tôi biết trong C ++ QT có một cách, không chắc chắn trong Linux.

  2. Tìm kiếm từ trong tệp: Trong tệp PDF không được quét, tìm kiếm của bạn sẽ hoạt động, tuy nhiên không phải trong tệp được quét. Bạn chỉ cần tìm một số từ phổ biến cho tất cả các tệp PDF hoặc tôi muốn nói rằng tìm kiếm chữ 'e' trong tất cả các tệp PDF. Nó có sự phân bố tần số cao nhất thì bạn có thể sẽ tìm thấy nó trong tất cả các văn bản có văn bản (Trừ khi nó Gadsby )

ví dụ

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

Sử dụng bất kỳ công cụ xử lý văn bản


1
PDF được quét cũng có thể có các văn bản có thể chọn vì ngày nay OCR không phải là một điều lạ và thậm chí nhiều trình đọc PDF miễn phí có tính năng OCR
phuclv

@phuclv: Nhưng nếu tệp được chuyển đổi thành văn bản với OCR, thì đó không còn là tệp "được quét", ít nhất là tôi hiểu mục đích của OP. Mặc dù thực sự bây giờ bạn có 3 loại tệp pdf: văn bản ab initio, văn bản từ OCR và "văn bản" là hình ảnh được quét.
jamesqf

1
@jamesqf vui lòng xem ví dụ trên. Chúng được quét pdf. Hầu hết các văn bản tôi không thể truy xuất bằng pdfminer thông thường.
DanielTheRocketMan

1
Tôi nghĩ rằng op cần phải suy nghĩ lại / định nghĩa lại định nghĩa về quét trong trường hợp đó hoặc ngừng sử dụng acrobat x, lấy bản sao được quét và lấy nó dưới dạng ocr thay vì hình ảnh
swgedoc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.