¿Hay una manera simple de identificar si se escanea un PDF?

8

Tengo miles de documentos y algunos de ellos están escaneados. Por lo tanto, necesito un script para probar todos los archivos PDF que pertenecen a un directorio. ¿Hay una manera simple de hacer eso?

  1. La mayoría de los PDF son informes. Por lo tanto, tienen mucho texto.
  2. Son muy diferentes, pero los escaneados como se menciona a continuación pueden encontrar texto debido a un proceso de OCR precario acoplado al escaneo.

  3. La propuesta de Sudodus en los comentarios a continuación parece ser muy interesante. Mire la diferencia entre un PDF escaneado a uno no escaneado:

Escaneado:

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>

No escaneado:

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

¡La cantidad de imágenes por página es mucho mayor (aproximadamente una por página)!

DanielTheRocketMan
fuente
77
¿Quieres decir si son texto o imágenes?
DK Bose
8
¿Por qué quieres saber si un archivo pdf se escanea o no? ¿Cómo piensa usar esa información?
sudodus
44
@sudodus hace una muy buena pregunta. Por ejemplo, la mayoría de los PDF escaneados tienen su texto disponible para su selección, convertido mediante OCR. ¿Haces una diferencia entre tales archivos y archivos de texto? ¿ Conoces la fuente de tus archivos PDF?
tubería
1
¿Hay alguna diferencia en los metadatos de los documentos escaneados y no escaneados? Eso ofrecería una manera muy limpia y fácil.
postre
1
Si un pdfarchivo contiene una imagen (insertada en un documento junto al texto o como páginas completas, 'pdf escaneado'), el archivo a menudo (tal vez siempre) contiene la cadena /Image/, que se puede encontrar con la línea de comando grep --color -a 'Image' filename.pdf. Esto separará los archivos que contienen solo texto de los que contienen imágenes (imágenes de página completa, así como páginas de texto con logotipos pequeños e imágenes ilustrativas de tamaño mediano).
sudodus

Respuestas:

4

Shellscript

  • Si un pdfarchivo contiene una imagen (insertada en un documento junto al texto o como páginas completas, 'pdf escaneado'), el archivo a menudo (tal vez siempre) contiene la cadena /Image/.

  • De la misma manera, puede buscar la cadena /Textpara saber si un archivo pdf contiene texto (no escaneado).

Hice el shellscript pdf-text-or-image, y podría funcionar en la mayoría de los casos con sus archivos. El shellscript busca las cadenas de texto /Image/y /Textlos pdfarchivos.

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

Hacer el shellscript ejecutable,

chmod ugo+x pdf-text-or-image

Cambie el directorio a donde tiene los pdfarchivos y ejecute el shellscript.

Los archivos identificados se mueven a los siguientes subdirectorios

  • scanned
  • text
  • s-and-t (para documentos con imágenes [escaneadas?] y contenido de texto)

Los objetos de archivo no identificados, 'Ovnis', permanecen en el directorio actual.

Prueba

He probado el shellscript con dos de sus archivos, AR-G1002.pdfy AR-G1003.pdf, y con algunos propios pdfarchivos (que he creado usando Libre Oficina 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

Esperemos que

  • no hay ovnis en tu conjunto de archivos
  • la clasificación es correcta en relación con el texto versus las imágenes escaneadas
sudodus
fuente
en lugar de redirigir a / dev / null, simplemente puede usargrep -q
phuclv
1
@phuclv, gracias por el consejo :-) Esto también lo hace algo más rápido, particularmente con archivos grandes, porque grep -qsale inmediatamente con estado cero si se encuentra alguna coincidencia (en lugar de buscar en los archivos completos).
sudodus el
6
  1. Ponga todos los archivos .pdf en una carpeta.
  2. No hay archivo .txt en esa carpeta.
  3. En la terminal, cambie el directorio a esa carpeta con cd <path to dir>
  4. Cree un directorio más para archivos no escaneados. Ejemplo:
mkdir ./x 
for file in *.pdf; do
    if [ $(pdftotext "$file")"x" == "x" ] ; then mv "$file" ./x; fi
rm *.txt
done

Todos los archivos escaneados en PDF permanecerán en la carpeta y otros archivos se moverán a otra carpeta.

Vijay
fuente
esto es genial. Sin embargo, este archivo va a la otra carpeta y se escanea: drive.google.com/open?id=12xIQdRo_cyTf27Ck6DQKvRyRvlkYEzjl ¿Qué está pasando?
DanielTheRocketMan
8
Los PDF escaneados a menudo siempre contienen el contenido de texto OCR, por lo que supongo que una prueba simple fallará para ellos. Un mejor indicador podría ser una imagen grande por página, independientemente del contenido del texto.
Joey
2
Votado a favor debido a la falla muy obvia: ¿cómo saber si los archivos se escanean o no en primer lugar? Eso es lo que pregunta el OP: cómo realizar pruebas de escaneo o no mediante programación.
jamesqf
1
@DanielTheRocketMan La versión del archivo PDF probablemente tenga un impacto en la herramienta que está utilizando para seleccionar texto. La salida de file pdf-filename.pdfproducirá un número de versión. No pude buscar texto específico en BR-L1411-3.pdf BR-L1411-3.pdf: documento PDF, versión 1.3, pero pude buscar texto en los otros dos archivos que proporcionó, que son la versión 1.5 y 1.6 y obtener uno o más partidos. Utilicé el visor PDF XChange para buscar estos archivos pero obtuve resultados similares con evince. el documento de la versión 1.3 no coincidía con nada.
Élder Geek
1
@DanielTheRocketMan Si ese es el caso, es posible que clasifique los documentos por versión utilizando la salida de fileútil para completar su proyecto. Aunque, como parece, otros todavía no tienen claro exactamente lo que está tratando de lograr.
Élder Geek
2

Creé un script para detectar si un PDF era OCRd. La idea principal: en PDF OCRd es el texto invisible.

Algoritmo para probar si un PDF ( f1) dado era OCRd:

  1. crear una copia de f1anotado comof2
  2. eliminar todo el texto en f2
  3. crear imágenes (PNG) para todas (o solo algunas) páginas para f1yf2
  4. f1fue OCRd si todas las imágenes de f1y f2son idénticas.

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

Hobbyist ofrece una buena solución si los documentos escaneados de la colección de documentos no tienen texto agregado con reconocimiento óptico de caracteres (OCR). Si esta es una posibilidad, es posible que desee realizar algunas secuencias de comandos que lean el resultado pdfinfo -metay comprueben la herramienta utilizada para crear el archivo, o empleen una rutina de Python que use una de las bibliotecas de Python para examinarlas. La búsqueda de texto con una herramienta como stringsno será confiable porque el contenido PDF se puede comprimir. Y verificar la herramienta de creación tampoco es seguro, ya que las páginas PDF se pueden combinar; Combino documentos de texto PDF con imágenes escaneadas para mantener las cosas juntas.

Lamento no poder ofrecer sugerencias específicas. Ha pasado un tiempo desde que examiné la estructura interna del PDF, pero dependiendo de cuán estrictos sean sus requisitos, es posible que desee saber que es un poco complicado. ¡Buena suerte!

ichabod
fuente
2
También estoy tratando de usar Python, pero no es trivial saber si un pdf se escanea o no. El punto es que incluso los documentos que no puede seleccionar texto presentan algo de texto cuando se convierte a txt. Por ejemplo, estoy usando pdf miner en Python y puedo encontrar algo de texto en la conversión incluso para archivos PDF que seleccionan la herramienta no funciona.
DanielTheRocketMan
1

Si se trata más de detectar si el PDF se creó escaneando en lugar de que el pdf tenga imágenes en lugar de texto, entonces es posible que deba profundizar en los metadatos del archivo, no solo en el contenido.

En general, para los archivos que pude encontrar en mi computadora y sus archivos de prueba, lo siguiente es cierto:

  • Los archivos escaneados tienen menos de 1000 caracteres / página frente a los no escaneados que siempre tienen más de 1000 caracteres / página
  • Múltiples archivos escaneados independientes tenían "Canon" listado como el creador del PDF, probablemente haciendo referencia al software del escáner Canon
  • Es probable que los PDF con "Microsoft Word" como creador no se escaneen, ya que son exportaciones de palabras. Pero alguien podría escanear a Word y luego exportar a PDF; algunas personas tienen un flujo de trabajo muy extraño .

Estoy usando Windows en este momento, así que usé node.jspara el siguiente ejemplo:

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

Para ejecutarlo, debe tener Node.js instalado (debe ser un solo comando) y también debe llamar a:

npm install mz pdf-parse

Uso:

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

Este ejemplo no se considera una solución terminada, pero con el debugindicador, obtiene una idea de la metainformación de un archivo:

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

La ingenua función que escribí tiene un 100% de éxito en los documentos que pude encontrar en mi computadora (incluidas sus muestras). Puse un nombre a los archivos en función de su estado antes de ejecutar el programa, para que sea posible ver si los resultados son correctos.

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

Puede usar el modo de depuración junto con un poco de programación para mejorar enormemente sus resultados. Puede pasar la salida del programa a otros programas, siempre tendrá una ruta completa por línea.

Tomáš Zato - Restablece a Monica
fuente
Re "Microsoft Word" como creador, eso dependerá de la fuente de los documentos originales. Si, por ejemplo, son artículos científicos, muchos, si no la mayoría, serán creados por algo en la cadena de herramientas LaTeX.
jamesqf
0

2 maneras en que puedo pensar:

  1. Uso de la herramienta de selección de texto: si está utilizando un PDF escaneado, los textos no se pueden seleccionar, sino que aparecerá un cuadro. Puede usar este hecho para crear el script. Sé que en C ++ QT hay una forma, aunque no estoy seguro en Linux.

  2. Buscar palabra en el archivo: en un PDF no escaneado, su búsqueda funcionará, pero no en el archivo escaneado. Solo necesita encontrar algunas palabras comunes a todos los PDF o preferiría buscar la letra 'e' en todos los PDF. Tiene la distribución de frecuencia más alta, por lo que es probable que la encuentre en todos los documentos que tienen texto (a menos que sea gadsby )

p.ej

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

Utilice cualquiera de las herramientas de procesamiento de texto.

swapedoc
fuente
1
un PDF escaneado también puede tener textos seleccionables porque OCR no es algo extraño hoy en día e incluso muchos lectores de PDF gratuitos tienen la función OCR
phuclv
@phuclv: Pero si el archivo se convirtió en texto con OCR, ya no es un archivo "escaneado", al menos según entiendo el propósito del OP. Aunque realmente ahora tendría 3 tipos de archivos pdf: texto ab initio, texto de OCR y "texto" que es una imagen escaneada.
jamesqf
1
@jamesqf, mira el ejemplo anterior. Son escaneados en pdf. La mayor parte del texto no puedo recuperarlo usando un pdfminer convencional.
DanielTheRocketMan
1
Creo que el operador necesita repensar / reformular la definición de escaneado en ese caso o dejar de usar acrobat x, que toma una copia escaneada y la toma como un ocr en lugar de una imagen
swapedoc