aboutsummaryrefslogtreecommitdiff
path: root/pdf-txt
diff options
context:
space:
mode:
Diffstat (limited to 'pdf-txt')
-rwxr-xr-xpdf-txt80
1 files changed, 80 insertions, 0 deletions
diff --git a/pdf-txt b/pdf-txt
new file mode 100755
index 0000000..92da697
--- /dev/null
+++ b/pdf-txt
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+# pdf-txt — extract clean text from OCR'd PDFs, recursively
+#
+# Usage: pdf-txt <path> [<path>...]
+#
+# <path> can be a .pdf file or a directory (walked recursively).
+# For each PDF with a text layer, writes a sibling .txt file using
+# pdftotext -layout, with "=== Page N ===" markers inserted.
+# Skips PDFs without a text layer.
+# Skips PDFs whose .txt is newer than the source.
+
+set -eu
+
+die() { printf "ERROR: %s\n" "$*" >&2; exit 1; }
+need() { command -v "$1" >/dev/null 2>&1 || die "Missing: $1 (apt install $2)"; }
+
+need pdftotext poppler-utils
+need find findutils
+need awk gawk
+
+processed=0; skipped_no_ocr=0; skipped_existing=0; failed=0
+
+extract_one() {
+ local pdf="$1"
+ local txt="${pdf%.[Pp][Dd][Ff]}.txt"
+
+ if [ -f "$txt" ] && [ "$txt" -nt "$pdf" ]; then
+ printf " up-to-date %s\n" "$pdf"
+ skipped_existing=$((skipped_existing + 1))
+ return 0
+ fi
+
+ # OCR/text-layer detection: sample first 3 pages
+ local tmp; tmp=$(mktemp)
+ pdftotext -l 3 "$pdf" "$tmp" 2>/dev/null || true
+ local nchars; nchars=$(tr -d '[:space:]' < "$tmp" | wc -c)
+ rm -f "$tmp"
+
+ if [ "$nchars" -lt 50 ]; then
+ printf " no OCR %s\n" "$pdf"
+ skipped_no_ocr=$((skipped_no_ocr + 1))
+ return 0
+ fi
+
+ if pdftotext -layout "$pdf" - 2>/dev/null | awk '
+ BEGIN { page = 1; printf "=== Page %d ===\n\n", page }
+ /\014/ { page++; printf "\n=== Page %d ===\n\n", page; next }
+ { print }
+ ' > "$txt"; then
+ printf " extracted %s\n" "$txt"
+ processed=$((processed + 1))
+ else
+ rm -f "$txt"
+ printf " FAILED %s\n" "$pdf" >&2
+ failed=$((failed + 1))
+ fi
+}
+
+walk() {
+ local target="$1"
+ if [ -f "$target" ]; then
+ case "$target" in
+ *.pdf|*.PDF) extract_one "$target" ;;
+ *) printf " not a PDF %s\n" "$target" >&2 ;;
+ esac
+ elif [ -d "$target" ]; then
+ while IFS= read -r -d '' pdf; do
+ extract_one "$pdf"
+ done < <(find "$target" -type f -iname '*.pdf' -print0 | sort -z)
+ else
+ printf " not found %s\n" "$target" >&2
+ fi
+}
+
+[ $# -ge 1 ] || die "Usage: pdf-txt <path> [<path>...]"
+
+for arg in "$@"; do walk "$arg"; done
+
+printf "\nDone. processed=%d no_ocr=%d up_to_date=%d failed=%d\n" \
+ "$processed" "$skipped_no_ocr" "$skipped_existing" "$failed"