Tools,

DeepSeek OCR, tested on a real scanned PDF

1,948

of 1,955 scan words, read in order

Get the setup

On a Mac, use llama.cpp

DeepSeek-OCR 2 has a GGUF model, and llama.cpp runs it on the Mac GPU. The model card's own code is for NVIDIA GPUs.

1,948 of 1,955 words, in order

83 s for 10 pages, Mac GPU

Install Poppler for pdftoppm. Put llama.cpp and the two q8_0 GGUF files next to the PDF, then run sh deepseek.sh. You get one Markdown file, book.md.

The full deepseek.sh script
pdftoppm -r 144 -png book.pdf page
for p in page-*.png; do
  ./llama-b12316/llama-mtmd-cli -m gguf/deepseek-ocr-2-q8_0.gguf --mmproj gguf/mmproj-deepseek-ocr-2-q8_0.gguf \
    --image "$p" -p "<|grounding|>Convert the document to markdown." --chat-template deepseek-ocr \
    --temp 0 --flash-attn off --no-warmup -n 2048 --dry-multiplier 0.8 --dry-base 1.75 \
    --dry-allowed-length 2 --dry-sequence-breaker none --threads 2 > "${p%.png}.md" 2>> cli.log || exit 1
done
sed -E 's/<\|ref\|>[^<]*<\|\/ref\|><\|det\|>[^<]*<\|\/det\|>//' page-*.md > book.md

One flag from the PR fails

Typed pages: 13 of 13 cover words

DeepSeek OCR 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,948, in 86 s.

German: best umlauts, weaker two columns

The script has no language option. I gave it 3 German pages. One is a magazine page with two columns. It kept the column order, but misread more words there.

193 of 206 umlauts

921 of 972 words in order, two columns

Next to PaddleOCR-VL on the same files: 5 more umlauts and 1 more scan word, but 35 fewer two-column words.

DeepSeek OCR beat our Actor, mostly

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, DeepSeek OCR on the Mac GPU
Test DeepSeek Actor
Scan words in order 1,948 1,874
Typed cover words 13 13
Umlauts 193 192
Two columns, in order 921 954
Time, 11 pages 86 s 133 s
Time, 3 German pages 31 s 59 s

The Actor read 33 more words on the two-column page. It needs no GPU and no 3.6 GB download. It costs $0.006 a page.

The license allows business use

DeepSeek-OCR 2 is Apache 2.0. The first DeepSeek-OCR is MIT. I read both full license files before the download. Neither adds 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 book.md, with the scorer of the tessdata test. German: the scorer of Tesseract German.
  • llama.cpp b12316 for macOS on an Apple Silicon Mac GPU, at the lowest priority, 2 threads. GGUF revision d08e5af400c6, q8_0 model and q8_0 mmproj. Pages drawn at 144 dpi. One run each. Times include the model start on every page.
  • 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 first DeepSeek-OCR, the bf16 and Q4_K_M files, and the Free OCR prompt.
  • The DRY penalty over the whole output, the PR's intent with -1.
  • The transformers script, vLLM, mlx-vlm and 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 DeepSeek OCR run on a Mac?

Yes. With its GGUF model in llama.cpp on the Mac GPU, DeepSeek-OCR 2 read 10 scanned pages in 83 s. The model card's own code is for NVIDIA GPUs.

Why does llama-mtmd-cli say invalid dry-penalty-last-n = -1?

The command in the llama.cpp pull request for DeepSeek-OCR 2 has --dry-penalty-last-n -1. llama.cpp b12316 does not accept -1. Leave that flag out. The default is 64.

Can a business use DeepSeek OCR?

Yes. DeepSeek-OCR 2 is Apache 2.0 and the first DeepSeek-OCR is MIT, with no added use terms. Keep the license and notices if you share the model.