Tools,

PaddleOCR-VL, tested on a real scanned PDF

1,947

of 1,955 scan words, read in order

Get the setup

On a Mac, use llama.cpp

PaddleOCR-VL 1.6 has a GGUF model. llama.cpp runs it on the Mac GPU. The layout model stays on the CPU.

1,947 of 1,955 words, in order

73 s for 10 pages, Mac GPU

Install paddlepaddle, paddleocr[doc-parser] and python-docx. Put llama-server and the two GGUF files next to the PDF, then run sh llama.sh. Each page gets a Markdown file in out/.

The full llama.sh script
./llama-b12316/llama-server -m gguf/PaddleOCR-VL-1.6-GGUF.gguf --mmproj gguf/PaddleOCR-VL-1.6-GGUF-mmproj.gguf --port 8091 --temp 0 --threads 2 2> server.log &
SERVER=$!
until curl -sf http://127.0.0.1:8091/health > /dev/null; do sleep 1; done
paddleocr doc_parser -i book.pdf --pipeline_version v1.6 --vl_rec_backend llama-cpp-server --vl_rec_server_url http://127.0.0.1:8091/v1 --save_path out --cpu_threads 2
CODE=$?
kill $SERVER
exit $CODE

Two stock problems on a Mac

The second one leaves a good Markdown file for page 1 only. Count the pages before you trust the output.

Typed pages: 13 of 13 cover words

PaddleOCR-VL reads every page as a picture, typed pages too. In the 11-page file, it read all 13 words of the typed cover page. The scan words stayed at 1,947, in 75 s.

German worked with no language setting

The doc parser has no language option. I gave it 3 German pages. One is a magazine page with two columns.

188 of 206 umlauts

956 of 972 words in order, two columns

PaddleOCR-VL beat our Actor here

Our Actor makes Markdown from a file URL, with no install:

curl -s -X POST "https://api.apify.com/v2/acts/brasspage~pdf-ocr-to-markdown/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"documentUrls": ["https://api.apify.com/v2/key-value-stores/sTnmNrGoSsi7tLQvs/records/anythingllm-mixed-11-pages.pdf"]}' \
  | jq -r '.[].markdown' > mixed.md
Same files, PaddleOCR-VL on the Mac GPU
Test PaddleOCR-VL Actor
Scan words in order 1,947 1,874
Typed cover words 13 13
Umlauts 188 192
Two columns, in order 956 954
Time, 11 pages 75 s 133 s
Time, 3 German pages 40 s 59 s

The Actor read 4 more umlauts. It needs no GPU and no 3.2 GB setup. It costs $0.006 a page.

The license allows business use

The model, the layout model and the code are Apache 2.0. I read the full license file before the download. It adds no use terms.

How I tested it
  • Scan: the 10 pages of OCR in n8n, proofread Wikisource book scans, 1,955 true words. The 11-page file adds the 13-word typed cover page of AnythingLLM OCR.
  • German: the 3 pages of Paperless-ngx OCR, 1,887 words, 206 umlauts.
  • Score: true words found in order in the Markdown pages, with the scorer of the tessdata test. German: the scorer of Tesseract German.
  • paddlepaddle 3.3.1, paddleocr 3.7.0, paddlex 3.7.2, Python 3.12 arm64, llama.cpp b12316 for macOS, on an Apple Silicon Mac GPU, at the lowest priority. GGUF revision 511b09642bb3, layout model PP-DocLayoutV3. One run each. Times include the model start.
  • The script above is the file that ran. The Actor: two real runs earlier the same day, build 0.1.65, on the same files.
What I did not test
  • The CPU path with more than 2 threads. I cap jobs at 2 threads on this Mac.
  • The mlx-vlm-server backend, the transformers script and the Ollama community upload.
  • The GGUF card's tip to raise image_max_pixels. I used the files as shipped.
  • vLLM, NVIDIA GPUs, handwriting, tables, math and forms.
Sources

Two ways to skip the work

Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.

Try the Actor

Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.

Get one page free

Questions people ask

Does PaddleOCR-VL run on a Mac?

Yes. With its GGUF model in llama.cpp on the Mac GPU, it read 10 scanned pages in 73 s. The Paddle CPU path with 2 threads did not finish page 1 in 10 minutes.

Why does paddleocr doc_parser say No module named 'docx'?

The CLI also saves each page as a Word file, and paddleocr[doc-parser] does not install python-docx. It wrote page 1, then stopped. Run pip install python-docx.

Can a business use PaddleOCR-VL?

Yes. The model, the layout model and the code are Apache 2.0, with no added use terms. Keep the license and notices if you share the model.