Gibt es eine einfache Möglichkeit, festzustellen, ob ein PDF gescannt wurde?

8

Ich habe Tausende von Dokumenten und einige davon werden gescannt. Ich benötige also ein Skript, um alle PDF-Dateien zu testen, die zu einem Verzeichnis gehören. Gibt es eine einfache Möglichkeit, das zu tun?

  1. Die meisten PDFs sind Berichte. Sie haben also viel Text.
  2. Sie sind sehr unterschiedlich, aber die gescannten, wie unten erwähnt, können aufgrund eines prekären OCR-Prozesses, der mit dem Scan gekoppelt ist, Text finden.

  3. Der Vorschlag aufgrund von Sudodus in den Kommentaren unten scheint sehr interessant zu sein. Sehen Sie sich den Unterschied zwischen einem gescannten und einem nicht gescannten PDF an:

Gescannt:

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>

Nicht gescannt:

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

Die Anzahl der Bilder pro Seite ist viel größer (ungefähr eines pro Seite)!

DanielTheRocketMan
quelle
7
Meinst du, ob es sich um Text oder Bilder handelt?
DK Bose
8
Warum möchten Sie wissen, ob eine PDF-Datei gescannt wird oder nicht? Wie wollen Sie diese Informationen nutzen?
Sudodus
4
@sudodus Stellt eine sehr gute Frage. Bei den meisten gescannten PDF-Dateien steht beispielsweise der Text zur Auswahl und wird mithilfe von OCR konvertiert. Machen Sie einen Unterschied zwischen solchen Dateien und Textdateien? Haben Sie wissen , die Quelle Ihrer PDF - Dateien?
Pipe
1
Gibt es einen Unterschied in den Metadaten von gescannten und nicht gescannten Dokumenten? Das wäre ein sehr sauberer und einfacher Weg.
Nachtisch
1
Wenn eine pdfDatei ein Bild enthält (in ein Dokument neben Text oder als ganze Seiten eingefügt, 'gescanntes PDF'), enthält die Datei häufig (möglicherweise immer) die Zeichenfolge /Image/, die über die Befehlszeile gefunden werden kann grep --color -a 'Image' filename.pdf. Dadurch werden Dateien, die nur Text enthalten, von Dateien getrennt, die Bilder enthalten (ganzseitige Bilder sowie Textseiten mit kleinen Logos und mittelgroßen Illustrationsbildern).
Sudodus

Antworten:

4

Shell-Skript

  • Wenn eine pdfDatei ein Bild enthält (in ein Dokument neben Text oder als ganze Seiten eingefügt, 'gescanntes PDF'), enthält die Datei häufig (möglicherweise immer) die Zeichenfolge /Image/.

  • Auf die gleiche Weise können Sie nach der Zeichenfolge suchen, um festzustellen /Text, ob eine PDF-Datei Text enthält (nicht gescannt).

Ich habe das Shellscript erstellt pdf-text-or-imageund es funktioniert in den meisten Fällen mit Ihren Dateien. Das Shellscript sucht nach den Textzeichenfolgen /Image/und /Textin den pdfDateien.

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

Machen Sie das Shellscript ausführbar,

chmod ugo+x pdf-text-or-image

Wechseln Sie in das Verzeichnis, in dem Sie die pdfDateien haben, und führen Sie das Shellscript aus.

Identifizierte Dateien werden in die folgenden Unterverzeichnisse verschoben

  • scanned
  • text
  • s-and-t (für Dokumente mit [gescannten?] Bildern und Textinhalten)

Nicht identifizierte Dateiobjekte, 'UFOs', verbleiben im aktuellen Verzeichnis.

Prüfung

Getestet habe ich den Shell mit zwei Ihren Dateien, AR-G1002.pdfund AR-G1003.pdf, und mit einigen eigenen pdfDateien (die ich unter Verwendung des Libre Office - Impress erstellt).

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

Hoffen wir das

  • Ihre Dateien enthalten keine UFOs
  • Die Sortierung ist in Bezug auf Text und gescannte Bilder korrekt
Sudodus
quelle
Anstatt nach / dev / null umzuleiten, können Sie einfachgrep -q
phuclv
1
@phuclv, Danke für den Tipp :-) Dies macht es auch etwas schneller, insbesondere bei großen Dateien, da es grep -qsofort mit dem Status Null beendet wird, wenn eine Übereinstimmung gefunden wird (anstatt die gesamten Dateien zu durchsuchen).
Sudodus
6
  1. Legen Sie alle PDF-Dateien in einem Ordner ab.
  2. Keine TXT-Datei in diesem Ordner.
  3. Wechseln Sie im Terminal das Verzeichnis in diesen Ordner mit cd <path to dir>
  4. Erstellen Sie ein weiteres Verzeichnis für nicht gescannte Dateien. Beispiel:
mkdir ./x 
for file in *.pdf; do
    if [ $(pdftotext "$file")"x" == "x" ] ; then mv "$file" ./x; fi
rm *.txt
done

Alle im PDF-Format gescannten Dateien verbleiben im Ordner, und andere Dateien werden in einen anderen Ordner verschoben.

Vijay
quelle
das ist toll. Diese Datei wird jedoch in den anderen Ordner verschoben und gescannt: drive.google.com/open?id=12xIQdRo_cyTf27Ck6DQKvRyRvlkYEzjl Was passiert?
DanielTheRocketMan
8
Gescannte PDFs enthalten häufig immer den OCRed-Textinhalt, daher würde ich vermuten, dass ein einfacher Test für sie fehlschlagen würde. Ein besserer Indikator könnte ein großes Bild pro Seite sein, unabhängig vom Textinhalt.
Joey
2
Wegen des sehr offensichtlichen Fehlers herabgestuft: Woher wissen Sie, ob die Dateien gescannt werden oder nicht? Das ist es, was das OP fragt: Wie kann programmgesteuert gescannt werden oder nicht?
Jamesqf
1
@DanielTheRocketMan Die Version der PDF-Datei hat wahrscheinlich Auswirkungen auf das Tool, mit dem Sie Text auswählen. Die Ausgabe von file pdf-filename.pdferzeugt eine Versionsnummer. Ich konnte nicht nach einem bestimmten Text in BR-L1411-3.pdf suchen. BR-L1411-3.pdf: PDF-Dokument, Version 1.3, konnte jedoch in beiden anderen von Ihnen bereitgestellten Dateien, Version 1.5 und Version, nach Text suchen 1.6 und erhalten Sie eine oder mehrere Übereinstimmungen. Ich habe PDF XChange Viewer verwendet, um diese Dateien zu durchsuchen, hatte aber ähnliche Ergebnisse mit evince. Das Dokument der Version 1.3 stimmte mit nichts überein.
Elder Geek
1
@DanielTheRocketMan Wenn dies der Fall ist, können Sie die Dokumente nach Version sortieren, indem Sie die Ausgabe von verwenden, um fileIhr Projekt abzuschließen. Obwohl ich, wie es scheint, anderen immer noch unklar ist, was genau Sie erreichen wollen.
Elder Geek
2

Ich habe ein Skript erstellt, um festzustellen, ob eine PDF-Datei OCRd war. Die Hauptidee: In OCRd PDFs ist der Text unsichtbar.

Algorithmus zum Testen, ob ein bestimmtes PDF ( f1) OCRd war:

  1. Erstellen Sie eine Kopie von f1notiert alsf2
  2. Löschen Sie den gesamten Text auf f2
  3. Erstellen Sie Bilder (PNG) für alle (oder nur einige) Seiten für f1undf2
  4. f1war OCRd, wenn alle Bilder von f1und f2identisch sind.

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
Johannes Filter
quelle
1

Hobbyist bietet eine gute Lösung, wenn den gescannten Dokumenten der Dokumentensammlung kein Text mit optischer Zeichenerkennung (OCR) hinzugefügt wurde. Wenn dies möglich ist, möchten Sie möglicherweise ein Skript pdfinfo -metaerstellen , das die Ausgabe von liest und nach dem Tool sucht, mit dem die Datei erstellt wurde, oder eine Python-Routine verwenden, die eine der Python-Bibliotheken verwendet, um sie zu untersuchen. Die Suche nach Text mit einem Tool wie stringsist unzuverlässig, da PDF-Inhalte komprimiert werden können. Das Überprüfen des Erstellungswerkzeugs ist auch nicht ausfallsicher, da PDF-Seiten kombiniert werden können. Ich kombiniere routinemäßig PDF-Textdokumente mit gescannten Bildern, um die Dinge zusammenzuhalten.

Es tut mir leid, dass ich keine konkreten Vorschläge machen kann. Es ist schon eine Weile her, dass ich mich mit der internen PDF-Struktur befasst habe, aber je nachdem, wie streng Ihre Anforderungen sind, möchten Sie vielleicht wissen, dass dies etwas kompliziert ist. Viel Glück!

ichabod
quelle
2
Ich versuche auch, Python zu verwenden, aber es ist nicht trivial zu wissen, ob ein PDF gescannt wird oder nicht. Der Punkt ist, dass selbst Dokumente, bei denen Sie keinen Text auswählen können, Text anzeigen, wenn dieser in txt konvertiert wird. Zum Beispiel verwende ich PDF-Miner in Python und ich kann Text in der Konvertierung finden, selbst für PDFs, bei denen das Auswahlwerkzeug nicht funktioniert.
DanielTheRocketMan
1

Wenn es mehr darum geht, tatsächlich zu erkennen, ob PDF durch Scannen erstellt wurde, als dass PDF Bilder anstelle von Text enthält, müssen Sie möglicherweise die Metadaten der Datei und nicht nur den Inhalt untersuchen.

Im Allgemeinen gilt für die Dateien, die ich auf meinem Computer und Ihren Testdateien finden konnte, Folgendes:

  • Gescannte Dateien haben weniger als 1000 Zeichen / Seite im Vergleich zu nicht gescannten Dateien, die immer mehr als 1000 Zeichen / Seite haben
  • Bei mehreren unabhängigen gescannten Dateien wurde "Canon" als PDF-Ersteller aufgeführt, was wahrscheinlich auf die Canon-Scannersoftware verweist
  • PDFs mit "Microsoft Word" als Ersteller werden wahrscheinlich nicht gescannt, da es sich um Wortexporte handelt. Aber jemand könnte nach Word scannen und dann nach PDF exportieren - einige Leute haben einen sehr seltsamen Workflow .

Ich verwende momentan Windows und habe daher node.jsdas folgende Beispiel verwendet:

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

Um es auszuführen, muss Node.js installiert sein (sollte ein einzelner Befehl sein) und Sie müssen außerdem Folgendes aufrufen:

npm install mz pdf-parse

Verwendungszweck:

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

Dieses Beispiel wird nicht als fertige Lösung betrachtet, aber mit dem debugFlag erhalten Sie einen Einblick in die Metainformationen einer Datei:

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

Die naive Funktion, die ich geschrieben habe, hat 100% Erfolg mit den Dokumenten, die ich auf meinem Computer finden konnte (einschließlich Ihrer Beispiele). Ich habe die Dateien vor dem Ausführen des Programms nach ihrem Status benannt, um festzustellen, ob die Ergebnisse korrekt sind.

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

Sie können den Debug-Modus zusammen mit ein wenig Programmierung verwenden, um Ihre Ergebnisse erheblich zu verbessern. Sie können die Ausgabe des Programms an andere Programme übergeben. Es wird immer ein vollständiger Pfad pro Zeile vorhanden sein.

Tomáš Zato - Monica wieder einsetzen
quelle
Bei "Microsoft Word" als Ersteller hängt dies von der Quelle der Originaldokumente ab. Wenn es sich zum Beispiel um wissenschaftliche Arbeiten handelt, werden viele, wenn nicht die meisten von etwas in der LaTeX-Toolchain erstellt.
Jamesqf
0

2 Möglichkeiten, die ich mir vorstellen kann:

  1. Verwenden des Textwerkzeugs zum Auswählen: Wenn Sie eine gescannte PDF-Datei verwenden, können die Texte nicht ausgewählt werden. Stattdessen wird ein Feld angezeigt. Sie können diese Tatsache verwenden, um das Skript zu erstellen. Ich weiß, dass es in C ++ QT einen Weg gibt, der unter Linux allerdings nicht sicher ist.

  2. Suche nach Wörtern in einer Datei: In einer nicht gescannten PDF-Datei funktioniert Ihre Suche, jedoch nicht in einer gescannten Datei. Sie müssen nur einige Wörter finden, die allen PDFs gemeinsam sind, oder ich würde eher sagen, dass Sie in allen PDFs nach dem Buchstaben 'e' suchen. Es hat die höchste Häufigkeitsverteilung, so dass Sie es wahrscheinlich in allen Dokumenten finden, die Text enthalten (es sei denn, es ist gadsby ).

z.B

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

Verwenden Sie eines der Textverarbeitungswerkzeuge

Swapedoc
quelle
1
Ein gescanntes PDF kann auch auswählbare Texte enthalten, da OCR heutzutage keine
Seltsamkeit ist
@phuclv: Wenn die Datei jedoch mit OCR in Text konvertiert wurde, handelt es sich nicht mehr um eine "gescannte" Datei, zumindest so wie ich den Zweck des OP verstehe. Obwohl Sie jetzt wirklich drei Arten von PDF-Dateien haben würden: Text von Anfang an, Text aus OCR und "Text", der ein gescanntes Bild ist.
Jamesqf
1
@jamesqf Bitte schauen Sie sich das obige Beispiel an. Sie werden als PDF gescannt. Den größten Teil des Textes kann ich nicht mit einem herkömmlichen pdfminer abrufen.
DanielTheRocketMan
1
Ich denke, die Operation muss die Definition von gescannt in diesem Fall überdenken / umformulieren oder die Verwendung von Acrobat x beenden, das gescannte Kopien nimmt und sie als OCR und nicht als Bild verwendet
Swapedoc