Чи є простий спосіб визначити, чи сканується PDF?


8

У мене тисячі документів, а деякі з них відскановані. Тому мені потрібен сценарій для тестування всіх файлів PDF, що належать до каталогу. Чи є простий спосіб це зробити?

  1. Більшість PDF-файлів - це звіти. Таким чином, у них багато тексту.
  2. Вони дуже різні, але у сканованих, як зазначено нижче, можна знайти текст через нечіткий процес OCR, пов'язаний зі скануванням.

  3. Пропозиція до Судодусу в коментарях нижче здається дуже цікавою. Подивіться різницю між відсканованим та несканованим 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
Ви маєте на увазі, чи це текст чи зображення?
ДК Босе

8
Чому ви хочете знати, чи скановано файл pdf чи ні? Як ви маєте намір використовувати цю інформацію?
sudodus

4
@sudodus Задає дуже гарне запитання. Наприклад, більшість сканованих PDF-файлів мають текст для вибору, перетворений за допомогою OCR. Чи різниш ти між такими файлами та текстовими файлами? Чи знаєте ви джерело своїх PDF-файлів?
труба

1
Чи є різниця в метаданих відсканованих і не відсканованих документів? Це запропонувало б дуже чистий і простий спосіб.
десерт

1
Якщо pdfфайл містить зображення (вставлене в документ поряд із текстом або як цілі сторінки, "сканований pdf"), файл часто (можливо, завжди) містить рядок /Image/, який можна знайти в командному рядку grep --color -a 'Image' filename.pdf. Це дозволить відокремити файли, що містять лише текст, від тих, що містять зображення (повні сторінки, а також текстові сторінки з невеликими логотипами та зображеннями середнього розміру).
sudodus

Відповіді:


4

Оболонка

  • Якщо pdfфайл містить зображення (вставлене в документ поряд із текстом або як цілі сторінки, "сканований pdf"), файл часто (можливо, завжди) містить рядок /Image/.

  • Таким же чином ви можете шукати рядок, /Textщоб визначити, чи файл PDF містить текст (не відсканований).

Я створив оболонку pdf-text-or-image, і вона може працювати в більшості випадків із вашими файлами. Shellscript шукає текстові рядки /Image/і /Textв pdfфайлах.

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

Зробіть сценарій оболонки виконуваним,

chmod ugo+x pdf-text-or-image

Змініть каталог, де ви маєте pdfфайли, і запустіть оболонку.

Ідентифіковані файли переміщуються до наступних підкаталогів

  • scanned
  • text
  • s-and-t (для документів із [сканованими?] зображеннями та текстовим вмістом)

Невідомі об’єкти файлів, "НЛО", залишаються у поточному каталозі.

Тест

Я протестував сценарій оболонки з двома вашими файлами, AR-G1002.pdfа також AR-G1003.pdfі з деякими власними pdfфайлами (які я створив за допомогою 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

Будемо сподіватися на це

  • у вашому наборі файлів немає НЛО
  • сортування правильне щодо тексту проти сканованого / зображення

замість переадресації на / 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, тому я думаю, що простий тест для них не вдасться. Кращим показником може бути одне велике зображення на сторінку незалежно від вмісту тексту.
Джої

2
Зрозуміло через дуже очевидний недолік: як дізнатись, чи файли скануються чи не в першу чергу? Ось що запитує ОП: як програмувати тестування на скановану чи ні.
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 для пошуку цих файлів, але мав подібні результати з evince. документ версії 1.3 нічого не відповідав.
Старійшина Гік

1
@DanielTheRocketMan Якщо це так, ви можете знайти сортування документів за версією, використовуючи результат fileкорисного для завершення вашого проекту. Хоча мені, як здається, іншим все ще незрозуміло, що саме ви намагаєтеся зробити.
Старійшина Гік

2

Я створив сценарій, щоб визначити, чи PDF був OCRd. Основна ідея: У PDF-файлах OCRd текст невидимий.

Алгоритм перевірки того, чи заданий PDF ( f1) був OCRd:

  1. створити копію f1зазначеного якf2
  2. видалити весь текст на f2
  3. створити зображення (PNG) для всіх (або лише декількох) сторінок для f1таf2
  4. f1було OCRd, якщо всі зображення f1та f2однакові.

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). Якщо така можливість є, ви, можливо, захочете виконати деякі сценарії, які читають вихідні дані pdfinfo -metaта перевіряють інструмент, який використовується для створення файлу, або використовувати процедуру Python, яка використовує одну з бібліотек Python для їх вивчення. Пошук тексту за допомогою такого інструменту stringsбуде недостовірним, оскільки вміст PDF може бути стиснутим. І перевірка інструмента створення також не є безпечною, оскільки сторінки PDF можна комбінувати; Я регулярно поєдную текстові документи PDF зі сканованими зображеннями, щоб зберігати речі разом.

Вибачте, що не можу запропонувати конкретних пропозицій. Минуло чимало часу, коли я роздумував над внутрішньою структурою PDF, але залежно від того, наскільки жорсткі ваші вимоги, ви, можливо, захочете знати, що це щось складне. Удачі!


2
Я також намагаюся використовувати python, але неважливо знати, сканується чи ні PDF-файл. Справа в тому, що навіть документи, які ви не можете вибрати текст, представляють певний текст при його перетворенні в txt. Наприклад, я використовую pdf-майнер у Python, і я можу знайти якийсь текст у перетворенні навіть для pdfs, що вибраний інструмент не працює.
DanielTheRocketMan

1

Якщо мова йде про фактичне виявлення того, чи PDF був створений за допомогою сканування, а не pdf, а замість тексту є зображення, то, можливо, вам доведеться зануритися у метадані файлу, а не лише у вміст.

Загалом, для файлів, які я міг знайти на своєму комп’ютері та ваших тестових файлів, справедливо таке:

  • Відскановані файли мають менше 1000 годин / сторінки порівняно з несканованими, які завжди мають більше 1000 годин / сторінку
  • У кількох незалежних сканованих файлах "Canon" вказано як PDF-файл, що, ймовірно, посилається на програмне забезпечення сканера Canon
  • PDF-файли з "Microsoft Word" як творцем, швидше за все, не будуть відскановані, оскільки це експорт слів. Але хтось може сканувати слово, а потім експортувати у 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-файлів, або я б скоріше сказати пошук літери 'e' у всіх PDF-файлах. Він має найвищу частотну частоту, тому, швидше за все, ви знайдете його у всіх документах, які містять текст (якщо тільки його gadsby )

напр

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

Використовуйте будь-який інструмент для обробки тексту


1
відсканований PDF також може мати тексти, які можна вибрати, оскільки OCR в даний час не дивна річ, і навіть багато безкоштовних читачів PDF мають функцію OCR
phuclv

@phuclv: Але якщо файл був перетворений у текст за допомогою OCR, це вже не "відсканований" файл, принаймні, наскільки я розумію призначення ОП. Хоча зараз у вас є три типи PDF-файлів: текст ab initio, текст з OCR та "текст", який є відсканованим зображенням.
jamesqf

1
@jamesqf, будь ласка, подивіться на приклад вище. Вони відскановані у форматі PDF. Більшу частину тексту я не можу отримати за допомогою звичайного pdfminer.
DanielTheRocketMan

1
я думаю, що операційному персоналу потрібно переосмислити / перефразовувати визначення сканованого в такому випадку або припинити використання acrobat x, який бере скановану копію і приймає її як ocr, а не зображення
swapedoc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.