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

1ページあたりの画像数がはるかに多い(1ページあたり約1)。


7
それらがテキストか画像かを意味しますか?
DK Bose

8
PDFファイルがスキャンされているかどうか、なぜ知りたいですか?その情報をどのように使用しますか?
sudodus 2018年

4
@sudodus非常に良い質問をします。たとえば、ほとんどのスキャンされたPDFのテキストは選択可能で、OCRを使用して変換されます。そのようなファイルとテキストファイルを区別しますか?PDFのソースを知っていますか?
パイプ

1
スキャンしたドキュメントとスキャンしていないドキュメントのメタデータに違いはありますか?それは非常にクリーンで簡単な方法を提供します。
デザート

1
pdfファイルに画像が含まれている場合(テキストと一緒に、またはページ全体として「スキャンされたpdf」としてドキュメントに挿入されます)、ファイルには多くの場合(たぶん常に)文字列が含まれます。この文字列/Image/はコマンドラインで見つけることができますgrep --color -a 'Image' filename.pdf。これにより、テキストのみが含まれているファイルと画像が含まれているファイル(ページ全体の画像、および小さなロゴと中程度のサイズの図解付きのテキストページ)が分離されます。
sudodus

回答:


4

シェルスクリプト

  • pdfファイルに画像が含まれている場合(テキストと一緒に、またはページ全体として「スキャンされたpdf」としてドキュメントに挿入されます)、ファイルには(多くの場合、常に)文字列が含まれます/Image/

  • 同様に、文字列/Textを検索して、PDFファイルにテキスト(スキャンされていない)が含まれているかどうかを確認できます。

私はshellscriptを作りましたpdf-text-or-image、そしてそれはあなたのファイルでほとんどの場合うまくいくかもしれません。シェルスクリプトは、テキスト文字列を検索する/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

シェルスクリプトを実行可能にし、

chmod ugo+x pdf-text-or-image

pdfファイルがある場所にディレクトリを変更し、シェルスクリプトを実行します。

識別されたファイルは、次のサブディレクトリに移動されます

  • scanned
  • text
  • s-and-t ([スキャンした?]画像とテキストコンテンツの両方を含むドキュメントの場合)

識別されていないファイルオブジェクト「UFO」は、現在のディレクトリに残ります。

テスト

私はあなたのファイルの2とシェルスクリプトをテストし、AR-G1002.pdfそしてAR-G1003.pdf、そして、いくつかの自分とpdf(私はリブレオフィスインプレスを使用して作成されていること)ファイル。

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

1
@phuclv、ヒントをありがとう:-)これにより、特に大きなファイルのgrep -q場合、一致が見つかった場合にステータスがゼロですぐに終了するため(ファイル全体を検索するのではなく)、これも多少速くなります。
sudodus 2018年

6
  1. すべての.pdfファイルを1つのフォルダーに配置します。
  2. そのフォルダに.txtファイルがありません。
  3. 端末でディレクトリをそのフォルダに変更します cd <path to dir>
  4. スキャンされていないファイル用にもう1つのディレクトリを作成します。例:
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 '19年

8
スキャンしたPDFには常にOCRedテキストコンテンツが含まれていることが多いので、簡単なテストは失敗するでしょう。より良い指標は、テキストの内容に関係なく、ページごとに1つの大きな画像にすることです。
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、1つ以上の一致を取得します。PDF XChangeビューアを使用してこれらのファイルを検索しましたが、同様の結果が得られました。バージョン1.3のドキュメントは何も一致しませんでした。
オタク長老

1
@DanielTheRocketManその場合file、プロジェクトの完了に役立つの出力を使用して、バージョンごとにドキュメントを並べ替えることができます。他の人のように思えますが、あなたが達成しようとしていることについてはまだはっきりしていません。
オタク長老

2

PDFがOCRdかどうかを検出するスクリプトを作成しました。主なアイデア:OCRd PDFではテキストは非表示です。

指定されたPDF(f1)がOCRd かどうかをテストするアルゴリズム:

  1. f1として記載のコピーを作成f2
  2. 上のすべてのテキストを削除 f2
  3. およびのすべての(または数個の)ページの画像(PNG)を作成しf1f2
  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)で追加されたテキストがない場合、Hobbyistは優れたソリューションを提供します。これが可能である場合はpdfinfo -meta、ファイルの作成に使用するツールの出力を読み取ってチェックするスクリプトを実行するか、Pythonライブラリの1つを使用してそれらを検査するPythonルーチンを使用することができます。などのツールを使用してテキストを検索すると、stringsPDFコンテンツを圧縮できるため、信頼性が低くなります。また、PDFページを組み合わせることができるため、作成ツールのチェックもフェイルセーフではありません。PDFテキストドキュメントとスキャンした画像を定期的に組み合わせて、物事をまとめています。

特定の提案を提供できなくて申し訳ありません。PDFの内部構造を見てから久しぶりですが、要件がどれほど厳しいかに応じて、それがある程度複雑であることを知りたいと思うかもしれません。幸運を!


2
私もpythonを使用しようとしていますが、pdfがスキャンされるかどうかを知るのは簡単ではありません。重要なのは、テキストを選択できないドキュメントでも、テキストに変換するとテキストが表示されることです。たとえば、Pythonでpdfマイナーを使用していて、選択ツールが機能しないpdfであっても、変換中にテキストを見つけることができます。
DanielTheRocketMan 2018年

1

これが、PDF ではなくスキャンによって作成された PDF テキストでなく画像であるかどうかを実際に検出することに関する場合は、コンテンツだけでなく、ファイルのメタデータを詳しく調べる必要がある場合があります。

一般に、私がコンピューターで見つけることができるファイルとテストファイルについては、次のことが当てはまります。

  • スキャンされたファイルはページあたり1000文字未満であるのに対し、スキャンされていないファイルは常にページあたり1000文字を超える
  • 複数の独立したスキャンファイルにPDF作成者として「Canon」がリストされ、おそらくCanonスキャナーソフトウェアを参照している
  • 「Microsoft Word」を作成者として含むPDFは、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

デバッグモードと小さなプログラミングを使用して、結果を大幅に改善できます。プログラムの出力を他のプログラムに渡すことができます。常に1行にフルパスが1つあります。


作成者として「Microsoft Word」を再作成します。これは、元のドキュメントのソースに依存します。たとえば、それらが科学論文である場合、ほとんどではないにしても多くのものがLaTeXツールチェーンの何かによって作成されます。
jamesqf 2018年

0

私が考えることができる2つの方法:

  1. テキスト選択ツールの使用:スキャンしたPDFを使用している場合、テキストは選択できず、ボックスが表示されます。このファクトを使用してスクリプトを作成できます。C ++ QTには方法があることはわかっていますが、Linuxではわかりません。

  2. ファイル内の単語を検索:スキャンされていないPDFでは検索は機能しますが、スキャンされたファイルでは機能しません。すべてのPDFに共通するいくつかの単語を見つける必要があるか、すべてのPDFで「e」の文字を検索することをお勧めします。これは頻度分布が最も高いため、テキストを含むすべてのドキュメントで見つかる可能性があります(そのgadsbyを除く

例えば

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

任意のテキスト処理ツールを使用する


1
OCRは、今日でも多くの無料のPDFリーダーは、OCR機能を持って奇妙なことではありませんので、スキャンしたPDFはまた、選択テキストを持つことができます
phuclv

@phuclv:しかし、ファイルがOCRでテキストに変換された場合、少なくともOPの目的を理解しているため、「スキャンされた」ファイルではなくなりました。実際には、3種類のPDFファイルがあります。テキストab initio、OCRからのテキスト、スキャンした画像である「テキスト」です。
-jamesqf

1
@jamesqf上記の例をご覧ください。彼らはPDFをスキャンしています。従来のpdfminerを使用して取得できないテキストのほとんど。
DanielTheRocketMan 2018年

1
その場合、opはスキャンの定義を再考/言い換えるか、スキャンされたコピーを取得してイメージではなくOCRとして取得するacrobat xの使用を停止する必要があると思います
swapedoc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.