From 3cd9138c9d8fb9be248c75330cca9da47f4d2e8a Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Sun, 10 May 2026 22:57:02 +0200 Subject: added a whole bunch of scripts --- pdf-txt | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 pdf-txt (limited to 'pdf-txt') 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 [...] +# +# 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 [...]" + +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" -- cgit v1.3