Granite-Docling, tested on a real scanned PDF
1,897
of 1,955 scan words, in order
On a Mac, one Docling command
A tiny 258M model. Docling runs it on the Mac GPU.
1,897 of 1,955 words, in order
54 s for 10 pages, Mac GPU
Install two packages, then run the command from the model card. I
added --num-threads 2. You get book.md.
pip install docling==2.150.0 mlx-vlm==0.7.12
docling --to md --pipeline vlm --vlm-model granite_docling --num-threads 2 book.pdf
The first run downloads the model, 0.64 GB.
Docling sets up the model
On a Mac, the granite_docling preset picks the MLX copy and sets:
- Pages drawn at 2x scale
- The prompt "Convert this page to docling."
- Temperature 0, up to 8,192 new tokens
The model writes DocTags, and Docling turns them into Markdown. You do not touch either.
Most misses are spaces
It got few letters wrong. But it sets quote marks off with a space:
" Well ? " for “Well?”. My scorer matches whole words.
31 quotes with a space inside
1,922 words with those spaces closed
It also made 5 running page headers into headings, like
## THE UNCOMMON PRAYER-BOOK. Strip them before you split
the text for RAG.
Typed pages: all 13 cover words
Granite-Docling reads every page as a picture, typed pages too. It read all 13 words of the typed cover page.
In the 11-page file, the scan words stayed at 1,897, in 71 s.
The fastest, with the fewest words
The same 10 scanned pages, scorer and Mac GPU:
| Model | Words | Time |
|---|---|---|
| LightOnOCR-2 | 1,954 | 72 s |
| GLM-OCR | 1,950 | 118 s |
| DeepSeek OCR | 1,948 | 83 s |
| PaddleOCR-VL | 1,947 | 73 s |
| dots.ocr | 1,946 | 168 s |
| Granite-Docling | 1,897 | 54 s |
Granite-Docling was the fastest of the six. The spaces cost it the most words.
German is not on its list
The model card lists English. Japanese, Arabic and Chinese are experimental. I gave it 3 German pages anyway. One has two columns.
156 of 206 umlauts
813 of 972 words in order, two columns
LightOnOCR on the same pages: 43 more umlauts, 146 more two-column words.
Granite-Docling and our Actor: 3 wins, 2 losses
Our Actor, from a file URL, 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
| Test | Granite | Actor |
|---|---|---|
| Scan words in order | 1,897 | 1,874 |
| Typed cover words | 13 | 13 |
| Umlauts | 156 | 192 |
| Two columns, in order | 813 | 954 |
| Time, 11 pages | 71 s | 133 s |
| Time, 3 German pages | 51 s | 59 s |
Granite-Docling won on scan words and time. The Actor won on German. Both read all 13 cover words.
The Actor needs no GPU and no 0.6 GB download. It costs $0.006 a page.
The license allows business use
The Granite-Docling model card says Apache 2.0. I read it, and the card of the MLX copy, before the download. Neither adds use terms.
The card asks you to run the model inside Docling. That is how I ran it. Docling itself is MIT.
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.
- Docling 2.150.0 and mlx-vlm 0.7.12 on an Apple Silicon Mac GPU, at the lowest priority, 2 threads. MLX model revision e9939db25d2f. Times include one model start, not the download.
- One run each. The 11-page file holds the same 10 scan pages, and their text was the same in both runs.
- The other models: the same files and scorer, on the same Mac, on November 12. Each page has its own setup.
- The command above is the one that ran. The Actor: two real runs earlier the same day, build 0.1.65, on the same files.
What I did not test
- Transformers on CPU, vLLM and NVIDIA GPUs.
- The GGUF model in llama.cpp.
- Tables, math, code, charts and handwriting.
- Docling's default pipeline. It has its own page, Docling OCR.
Two ways to skip the work
Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.
Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.
Questions people ask
Does Granite-Docling run on a Mac?
Yes. Docling runs it with MLX on the Mac GPU. It read 10 scanned pages in 54 s. The model download is 0.64 GB.
Why does Granite-Docling miss words?
Few letters are wrong. It puts a space inside quote marks and before question marks, so exact word matches fail. It also keeps page headers as headings.
Can a business use Granite-Docling?
Yes. The model card says Apache 2.0, with no added use terms. Docling itself is MIT.
Related guides
- LightOnOCR-3 4B on a scanned PDF: Mac setup and results
- Docling OCR engines: EasyOCR vs Tesseract vs RapidOCR
- docling-serve OCR, tested on a scanned PDF
- LightOnOCR on a scanned PDF: Mac setup and results, tested
- GLM-OCR on a scanned PDF: Mac setup and results, tested
- PDF to Markdown in Python: 5 libraries tested