LightOnOCR-3, tested on a real scanned PDF
1,953
of 1,955 scan words, read in order
On a Mac, use llama.cpp
LightOnOCR-3-4B is the new 4B model of LightOnOCR. A GGUF copy runs in llama.cpp on the Mac GPU.
1,953 of 1,955 words, in order
130 s for 10 pages, Mac GPU
Install Poppler for pdftoppm, and jq. Put llama.cpp and
the two GGUF files next to the PDF, then run
sh lighton3.sh. You get one Markdown file, book.md.
The full lighton3.sh script
pdftoppm -scale-to 2048 -png book.pdf page
./llama-b12316/llama-server -m gguf/LightOnOCR-3-4B.Q8_0.gguf --mmproj gguf/LightOnOCR-3-4B.mmproj-f16.gguf \
--reasoning off --host 127.0.0.1 --port 8094 --threads 2 --no-warmup > server.log 2>&1 &
S=$!
until curl -sf http://127.0.0.1:8094/health > /dev/null; do kill -0 $S || exit 1; sleep 1; done
for p in page-*.png; do
{ printf '{"messages":[{"role":"user","content":[{"type":"image_url","image_url":{"url":"data:image/png;base64,'
base64 -i "$p" | tr -d '\n'
printf '"}}]}],"max_tokens":4096,"temperature":0.2,"top_p":0.9,"seed":42}'; } > req.json
curl -sf http://127.0.0.1:8094/v1/chat/completions -H "Content-Type: application/json" -d @req.json \
| jq -er '.choices[0].message.content' > "${p%.png}.md" || { kill $S; wait $S; exit 1; }
done
kill $S; wait $S
cat page-*.md > book.md
The settings come from the model card
The script uses the settings on the model card:
- No text prompt. The message holds only the page image.
- Pages drawn with the longest side at 2,048 px
- Thinking off, as in the card's vLLM command
- Temperature 0.2, top_p 0.9, up to 4,096 tokens
In llama-server, --reasoning off turns thinking off. No
output had a think tag. A fixed seed gives the same text on a rerun.
Its 2 misses were double dashes
Both missed words ended in a long double dash, and the model wrote a single dash. Every other word matched the proofread text.
It also kept only 1 running page header. The older LightOnOCR-2 kept 3. Fewer headers means cleaner text for search.
Typed pages: all 13 cover words
LightOnOCR-3 reads every page as a picture, typed pages too. It read all 13 words of the typed cover page, COVER SHEET included.
In the 11-page file, the scan words stayed at 1,953, in 143 s.
The older 1B model is faster here
The same 10 scanned pages, scorer and Mac GPU:
| Model | Words | Time |
|---|---|---|
| LightOnOCR-3 | 1,953 | 130 s |
| LightOnOCR-2 | 1,954 | 72 s |
| GLM-OCR | 1,950 | 118 s |
| DeepSeek OCR | 1,948 | 83 s |
| dots.ocr | 1,946 | 168 s |
Of the 130 s, llama-server took 62 s, model start included. The rest was pdftoppm, which draws the pages at 2,048 px.
German: better than LightOnOCR-2
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.
202 of 206 umlauts
961 of 972 words in order, two columns
Next to LightOnOCR-2 on the same files: 3 more umlauts, 2 more two-column words.
dots.ocr read 2 more umlauts and 8 more two-column words.
It took 80 s for the 3 pages. dots.ocr took 157 s.
LightOnOCR-3 and our Actor: 3 wins, 2 losses
Our Actor, 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
| Test | LightOnOCR-3 | Actor |
|---|---|---|
| Scan words in order | 1,953 | 1,874 |
| Typed cover words | 13 | 13 |
| Umlauts | 202 | 192 |
| Two columns, in order | 961 | 954 |
| Time, 11 pages | 143 s | 133 s |
| Time, 3 German pages | 80 s | 59 s |
LightOnOCR-3 read more words. The Actor was faster, and both read all 13 cover words.
The Actor needs no GPU and no 5.2 GB download. It costs $0.006 a page.
The license allows business use
The model card says Apache 2.0, for research and commercial use. The GitHub repo has the plain Apache 2.0 license. I read both before the download.
I planned to test Nanonets-OCR2 first. It has no license, and its base model allows only non-commercial use. So I did not test it.
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 d73ad16828c6, Q8_0 model and f16 mmproj. Times include one model start.
- The GGUF copy is by mradermacher. ggml-org has none. Its files matched the Hub checksums.
- One run each. The 11-page file holds the same 10 scan pages, and their text was the same in both runs, page for page.
- The other models: the same files and scorer, on the same Mac, on November 12. Each page has its own setup.
- 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
- Grounding mode, which adds a box to each block.
- The 0.8B and 1B models, the BF16 files and the MTP copies.
- Transformers, vLLM and NVIDIA GPUs.
- Handwriting, tables, charts, math and forms.
Sources
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 LightOnOCR-3 run on a Mac?
Yes. With a GGUF copy in llama.cpp on the Mac GPU, it read 10 scanned pages in 130 s. The two GGUF files are 5.2 GB.
Is LightOnOCR-3 better than LightOnOCR-2?
Not on our English scan. It read 1 word less, and the older model was faster. On German pages, it read 3 more umlauts.
Can a business use LightOnOCR-3?
Yes. The model card says Apache 2.0, for research and commercial use, with no added terms. Keep the license and notices if you share the model.
Related guides
- olmOCR on a Mac: the toolkit with llama.cpp, tested
- Qwen3-VL OCR on a scanned PDF: tested in Ollama on a Mac
- Ollama OCR on a scanned PDF: 2 models tested on a Mac
- LightOnOCR on a scanned PDF: Mac setup and results, tested
- Granite-Docling on a scanned PDF: Mac setup, tested
- GLM-OCR on a scanned PDF: Mac setup and results, tested
- DeepSeek OCR on a scanned PDF: Mac setup and results, tested
- dots.ocr on a scanned PDF: Mac setup and results, tested
- PDF to Markdown in Python: 5 libraries tested