Zotero OCR, tested on a real scan
1,879
of 1,955 words found, 10-page scan
Zotero cannot search a scan
Zotero has no OCR. It reads PDF text with pdf.js, which found 0 words in my scan. The zotero-ocr plugin adds OCR with Tesseract.
| Added | For 10 scanned pages |
|---|---|
| A note | All the text |
| A new PDF, title.ocr | Hidden text layer, 4.0 MB |
| HTML pages | 5 of 10 pages |
| Page images, kept | 10 JPEGs, 4.0 MB |
pdf.js read 1,876 words from the new PDF, so search has text now. The original PDF stays as it was.
Not working? Run its two steps
With its default settings, the plugin runs pdftoppm, then Tesseract. I
saved the same commands as zotero-ocr.sh and ran
sh zotero-ocr.sh eng next to book.pdf:
pdftoppm -progress -cropbox -jpeg -jpegopt quality=70,progressive=y,optimize=y -r 300 book.pdf KEY-page
ls KEY-page-*.jpg > KEY-list.txt
tesseract KEY-list.txt book.ocr --psm 3 -l "$1" txt pdf hocr
It took 29 s for the 10 pages, and Terminal shows the whole error.
Zotero 7 and later make the page images with pdf.js, and use pdftoppm only when that fails.
PNG pages: same words, 9 times bigger
A plugin request asks for PNG page images instead of JPEG. I set the hidden imageFormat to png and ran the scan again.
| Page images | Words | New PDF |
|---|---|---|
| JPEG, quality 70 (default) | 1,879 | 4.0 MB |
| PNG | 1,879 | 36.8 MB |
PNG also took 141 s, 5 times as long. My scan was clean, so test a poor one yourself.
To drop the kept JPEGs, untick "Save the intermediate images as well in the folder".
Other languages on a Mac
With eng, the 3 German pages lost all 206 umlauts. With deu, Tesseract
stopped: Failed loading language 'deu'. Homebrew
Tesseract had only eng and osd.
lang.sh puts the German file where that Tesseract looks:
curl -sL -o "$(brew --prefix)/share/tessdata/deu.traineddata" https://github.com/tesseract-ocr/tessdata/raw/main/deu.traineddata
Then set the language to deu in the plugin settings. For Spanish, change deu to spa in both places.
189 of 206 umlauts
913 of 972 words in order, two columns
Nothing to install: the Actor
Our OCR Actor runs in the cloud. On the 11-page file:
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' > book.md
1,874 of 1,955 words, plugin 1,879
954 of 972 in order on two columns, plugin 913
With deu it got 192 umlauts, the plugin 189. With no language set, 0.
It was slower: 142 s for 11 pages, the plugin 31 s.
It costs $0.006 a page. It gives Markdown, not a PDF that Zotero can search. The plugin is free and offline.
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. One is a two-column magazine page.
- The plugin: I read the code of zotero-ocr 0.9.7 and ran its commands with its defaults. Homebrew Tesseract 5.5.4 and pdftoppm 26.03.0 on an arm64 Mac, 2 cores at the lowest priority.
- Search: pdf.js 6.4.299, the library in Zotero's PDF worker. Score: true words found in order, with the scorer of the tessdata test. German: the scorer of Tesseract German.
- The code blocks above are the files that ran. I removed the German file after. The Actor: three real runs, build 0.1.65, one German run with no language.
What I did not test
- Zotero itself. I ran the plugin's commands, not the plugin.
- The pdf.js page images of Zotero 7 and later. I used pdftoppm with the same settings.
- Windows, and PNG on a poor scan.
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 Zotero have built-in OCR?
No. Zotero indexes the text that a PDF already has. In my scanned PDF, pdf.js found 0 words. The zotero-ocr plugin adds OCR with Tesseract.
Why does Zotero OCR say no tesseract executable found?
The plugin looks in a few folders, like /opt/homebrew/bin and /usr/local/bin. MacPorts uses /opt/local/bin, which it does not check. Run which tesseract and paste that path into the plugin settings.
Does the Zotero OCR plugin replace my PDF?
Not by default. It attaches a new PDF with .ocr at the end of the title. The setting Overwrite the initial PDF with the output replaces the original.
Related guides
- How to make a PDF searchable, in one command
- TesseractNotFoundError: tesseract is not installed, fixed
- Tesseract and German: eng reads no ä, ö, ü or ß
- Tesseract and two columns: the default reads them right
- Calibre OCR: why your EPUB comes out empty
- LibreOffice OCR: what works on a scanned PDF
- Obsidian OCR for scanned PDFs: Omnisearch, tested