blob: 36994b534f46277407aea8d6d55ec3a12c000b3b (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#!/usr/bin/env bash
# ocr-scan.sh — recursively OCR un-OCR'd PDFs
# Deps: ocrmypdf, poppler-utils (pdftotext), tesseract-ocr
# Optional: python3-langdetect (for -a auto-detect)
set -euo pipefail
LANG_CODE="eng"
AUTO_DETECT=false
MIN_CHARS=50 # chars per page threshold — below = needs OCR
DIR="."
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS] [DIRECTORY]
Recursively find un-OCR'd PDFs and produce OCR'd copies with _OCR suffix.
OPTIONS:
-l LANG Tesseract language code(s) (default: eng)
Single: -l pol
Multiple: -l pol+eng
Examples: eng pol tha deu fra rus chi_sim jpn ara
-a Auto-detect language via langdetect (requires: pip install langdetect)
Note: falls back to eng for fully un-OCR'd scans (no text layer)
-h Show this help and exit
ARGUMENTS:
DIRECTORY Root directory to search recursively (default: current directory)
OUTPUT:
Each processed file is saved alongside the original:
original.pdf → original_OCR.pdf
Files already having an _OCR copy or sufficient text are skipped.
DEPENDENCIES:
Required: ocrmypdf, poppler-utils (pdftotext, pdfinfo), tesseract-ocr
Per-lang: apt install tesseract-ocr-pol tesseract-ocr-tha ...
Optional: pip install langdetect (for -a flag)
EXAMPLES:
$(basename "$0") # current dir, English
$(basename "$0") ~/docs # ~/docs recursively, English
$(basename "$0") -l pol ~/docs # Polish
$(basename "$0") -l pol+eng ~/docs # Polish + English mixed
$(basename "$0") -a ~/docs # auto-detect language
EOF
exit 0
}
while getopts ":l:ah" opt; do
case $opt in
l) LANG_CODE="$OPTARG" ;;
a) AUTO_DETECT=true ;;
h) usage ;;
:) echo "Option -$OPTARG requires an argument."; usage ;;
\?) echo "Unknown option: -$OPTARG"; usage ;;
esac
done
shift $((OPTIND - 1))
[[ $# -gt 0 ]] && DIR="$1"
# Map ISO 639-1 → Tesseract lang codes
map_lang() {
case "$1" in
pl|pol) echo "pol" ;;
en|eng) echo "eng" ;;
th|tha) echo "tha" ;;
de|deu) echo "deu" ;;
fr|fra) echo "fra" ;;
ru|rus) echo "rus" ;;
zh|chi) echo "chi_sim" ;;
ja|jpn) echo "jpn" ;;
ar|ara) echo "ara" ;;
*) echo "eng" ;;
esac
}
detect_lang() {
local pdf="$1"
local sample
sample=$(pdftotext "$pdf" - 2>/dev/null | head -c 500)
if [[ -z "$sample" ]]; then
echo "eng"; return
fi
python3 - <<EOF 2>/dev/null || echo "eng"
from langdetect import detect
try:
print("$(echo "$sample" | tr -d "'" | head -c 300)")
except:
print("eng")
EOF
# simpler: call python directly
python3 -c "
from langdetect import detect
import sys
try:
lang = detect('''$sample''')
print(lang)
except:
print('eng')
" 2>/dev/null || echo "eng"
}
needs_ocr() {
local pdf="$1"
local pages
pages=$(pdfinfo "$pdf" 2>/dev/null | awk '/^Pages:/{print $2}')
[[ -z "$pages" || "$pages" -eq 0 ]] && pages=1
local chars
chars=$(pdftotext "$pdf" - 2>/dev/null | wc -c)
local threshold=$(( pages * MIN_CHARS ))
[[ "$chars" -lt "$threshold" ]]
}
find "$DIR" -type f -iname "*.pdf" ! -iname "*_OCR.pdf" | while read -r pdf; do
out="${pdf%.pdf}_OCR.pdf"
if [[ -f "$out" ]]; then
echo "[SKIP] Already has OCR copy: $out"
continue
fi
if ! needs_ocr "$pdf"; then
echo "[SKIP] Already has text: $pdf"
continue
fi
lang="$LANG_CODE"
if $AUTO_DETECT; then
detected=$(detect_lang "$pdf")
lang=$(map_lang "$detected")
echo "[DETECT] $pdf → $detected → $lang"
fi
echo "[OCR] $pdf (lang: $lang) → $out"
ocrmypdf \
--language "$lang" \
--output-type pdfa \
--skip-text \
--rotate-pages \
--deskew \
"$pdf" "$out" \
&& echo "[DONE] $out" \
|| echo "[FAIL] $pdf"
done
|