OCRmyPDF batch processing image with jbig2 and unpaper on Ubuntu rolling base image
3.1K
A Docker image that watches a folder and turns scanned PDFs into searchable, text-based PDFs — automatically, unattended, forever.
Built on OCRmyPDF, with jbig2 for smaller PDF/A files and unpaper for descreening and cleanup.
The GitHub repository can be found here. The Docker Hub repository can be found here.
IN_FOLDER on startup, then watches for new files via inotify.OUT_FOLDER; the original is moved to PROCESSED_FOLDER only once OCR succeeds.IN_FOLDER with a clear log message, so nothing is lost and it's retried on the next restart. (OCRmyPDF feature)docker stop, the file currently being processed is allowed to finish before the container exits.1001:1001), no capabilities required at all. Change the container's user (--user/user:) to match any other host folder ownership.amd64 and arm64.deu, eng, fra, por, spa.The container always runs as an unprivileged user — by default 1001:1001, baked into the image. The host folders it mounts must already be owned by that same UID/GID, so create and chown them first:
mkdir -p in out processed
sudo chown 1001:1001 in out processed
docker run -d \
--name=ocrmypdf-batch \
--read-only \
--tmpfs /tmp \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--volume $PWD/in:/in \
--volume $PWD/out:/out \
--volume $PWD/processed:/processed \
meyay/ocrmypdf-batch:latest
An example docker-compose.yml is included in this repository:
services:
ocrmypdf-batch:
image: meyay/ocrmypdf-batch:latest
container_name: ocrmypdf-batch
restart: unless-stopped
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges
environment:
OCRMYPDF_OPTIONS: "-l deu+eng"
# user: "1000:1000" # run as a different UID/GID; chown ./in ./out ./processed to match
volumes:
- ./in:/in
- ./out:/out
- ./processed:/processed
Run it with docker compose up -d.
Both examples run the container hardened: a read-only root filesystem (with a tmpfs for /tmp, which ocrmypdf/tesseract need for scratch space but never execute anything from), every Linux capability dropped with none re-added (nothing the container does needs any capability at all — no root, no privilege dropping), and no-new-privileges to block escalation. Verified end-to-end with cap_drop: ALL and zero cap_add.
To run as a different UID/GID (e.g. to match an existing NAS share), change the container's user (--user/user:) and the ownership of the host folders together. If they disagree, the container refuses to start with a clear error rather than silently failing partway through.
Drop a scanned PDF into ./in. A searchable copy appears in ./out; the original moves to ./processed. If your scanner can deliver PDFs straight to a network share, point IN_FOLDER at that share and let the container do the rest.
IN_FOLDER, OUT_FOLDER, and PROCESSED_FOLDER are owned by whichever user the container is actually running as, and that it can enter, read, and write each of them. Exits with a clear error rather than continuing on a partial match.IN_FOLDER is OCR'd once, in order.inotify watch on IN_FOLDER picks up anything created or moved in afterwards.SIGTERM/SIGINT (e.g. docker stop) stops the watch loop only after the file currently being processed has finished; no half-written PDFs.| ENV | Default | Description |
|---|---|---|
IN_FOLDER | /in | Path inside the container watched for incoming PDFs. |
OUT_FOLDER | /out | Path inside the container where searchable PDFs are written. |
PROCESSED_FOLDER | /processed | Path inside the container where successfully OCR'd originals are moved. |
OCRMYPDF_OPTIONS | -l deu+eng | Command-line options passed straight through to ocrmypdf — see OCRmyPDF Options below. |
Changing any environment variable requires recreating the container.
| Volume | Description |
|---|---|
/in | Mount point for incoming files. Must match IN_FOLDER. |
/out | Mount point for finished, searchable PDFs. Must match OUT_FOLDER. |
/processed | Mount point for processed originals. Must match PROCESSED_FOLDER. |
OCRMYPDF_OPTIONS accepts any command-line option that ocrmypdf itself supports. Since that list grows and changes with the ocrmypdf version bundled in the image, look it up directly from the container instead of a hardcoded copy here:
docker run --rm meyay/ocrmypdf-batch:latest help
Passing help as the container command short-circuits the normal startup — it just prints ocrmypdf -h and exits, without touching any volumes.
Content type
Image
Digest
sha256:82905d4e3…
Size
248.3 MB
Last updated
4 days ago
docker pull meyay/ocrmypdf-batch