4

Suppose I have a directory full of many PDFs. In most of them, the text is completely search-able, which is the way I need them to be. But a few of them are just image scans, and they need to be OCR-ed.

Other then simply doing a batch OCR on the entire directory, is there a way to quickly identify which PDFs are the image-only ones that actually need to be OCR-ed?

I'm not a programmer, but a linux-friendly solution would be preferred.

3

I'm not sure if this is a 100% solution, but I came up with the following script which should get you a good part of the way if not the whole way (I have not gone through the spec) It should be run from the directory which has all the PDF's (it will search subdirectories).

#! /bin/bash

if [[ ! "$#" = "1" ]]
  then
      echo "Usage: $0 /path/to/PDFDirectory"
      exit 1
fi

PDFDIRECTORY="$1"

while IFS= read -r -d $'\0' FILE; do
    PDFFONTS_OUT="$(pdffonts "$FILE" 2>/dev/null)"
    RET_PDFFONTS="$?"
    FONTS="$(( $(echo "$PDFFONTS_OUT" | wc -l) - 2 ))"
    if [[ ! "$RET_PDFFONTS" = "0" ]]
      then
          READ_ERROR=1
          echo "Error while reading $FILE. Skipping..."
          continue
    fi
    if [[ "$FONTS" = "0" ]]
      then
          echo "NOT SEARCHABLE: $FILE"
      else
          echo "SEARCHABLE: $FILE"
    fi
done < <(find "$PDFDIRECTORY" -type f -name '*.pdf' -print0)

echo "Done."
if [[ "$READ_ERROR" = "1" ]]
  then
      echo "There were some errors."
fi

It works by looking for the number of fonts specified in each PDF. If the file does not have any fonts it is assumed to be comprised only of an image. (This might trip up on password protected files, I have no idea, don't have any to test against). If there is some stuff which is searchable and some stuff which is an image, this won't work - but it will probably be useful to seperate scanned image documents in a PDF container from "real" PDF's.

You can, of-course, comment out the part of the if-then-else loop which does not apply if you only want to print out the files which are not searchable.

  • Looks promising! But when I run this script I think I am getting an error. It says: find: paths must precede expression: Anker2001.pdf Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] "Anker2001.pdf" is the second file alphabetically in the directory. – Brian Z Sep 7 '13 at 13:26
  • I've made a couple of changes to the script, which might fix your problem - you now run it and pass the directory you wish to check as an argument. I also fixed a big bug in the check by removing the "." after $FONTSFOUND !!! – davidgo Sep 7 '13 at 19:15
  • This seems strange, but it stopped working. Any idea why that would be? – Brian Z Sep 10 '13 at 21:37
  • None whatsoever - I'd need to know more about how/when it stopped working, errors or what have you. I wonder if you have any PDF's with spaces in them, and if something something like that threw the script. (Not a solution, but a mitigation might be to throw in an additional line to move the checked files OUT OF THE PATH of the script and then rerun it, see where it gets stuck etc - and then move the files back). – davidgo Sep 11 '13 at 3:14
  • I'm getting the same error as I posted in my original comment. The only way I can get it to work right now is if there is only one PDF file in the folder. I keep trying it with different files, simple file names with no spaces etc., but nothing works. – Brian Z Sep 11 '13 at 14:15
2

I will use a trick, it is a peculiar secondary fact I noticed if a pdf file doesn't have any font it is usually not searchable. So knowing this we can use pdffonts.

First 2 lines of the pdffonts are the table header, so when a file is searchable has more than two line output, knowing this we can create:

gedit check_pdf_searchable.sh

then paste this

#!/bin/bash 
#set -vx
if ((`pdffonts "$1" | wc -l` < 3 )); then
echo $1
pypdfocr "$1" # alternatively you can use ocrmypdf "$1" "${1}_ocr.pdf"
fi

then make it executable

chmod +x check_pdf_searchable.sh

then list all non-searchable pdfs in the directory:

ls -1 ./*.pdf | xargs -L1 -I {} ./check_pdf_searchable.sh {}

or in the directory and its subdirectories:

tree -fai . | grep -P ".pdf$" | xargs -L1 -I {} ./check_pdf_searchable.sh {}
1

I have had difficulty with tree so this solution worked for me, using the same script.

find . -name "*.pdf" -type f -exec ~/check_pdf_searchable.sh {} \;

~/ assumes the script is in your home directory. Makes things easier.

  • Given that (1) check_pdf_searchable.sh comes from Eduard Florinescu’s answer, (2) Eduard’s answer is a rewrite of davidgo’s answer (with the addition of the pypdfocr command), and (3) davidgo’s answer already uses find, it seems to me that this answer is not breaking any new ground. – Scott Apr 30 '19 at 1:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.