需单独安装 Ghostscript 和 Tesseract OCR 外部程序;非英语识别要另装 Tesseract 语言包并用 -l 指定;Tesseract 需 4.1.1 及以上版本。
OCRmyPDF
ocrmypdfMPL-2.0活跃维护给扫描版 PDF 加上 OCR 文字层,让原本只能看的图片型 PDF 变成可搜索、可复制文本的文件。
OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched
apt install ocrmypdf
ocrmypdf --output-type pdfa input.pdf output.pdfREADME 未说明显存或 GPU 要求;纯 Python 实现,可运行在 Linux、macOS、Windows、FreeBSD,需额外安装 Ghostscript 和 Tesseract OCR。
给扫描版 PDF 加 OCR 文字层的命令行工具,让 PDF 可搜索可复制
给扫描版 PDF 加上 OCR 文字层,让原本只能看的图片型 PDF 变成可搜索、可复制文本的文件。
核心能力
- 把 OCR 文字层精确放在图像下方,方便复制粘贴
- 默认输出 PDF/A 归档格式并校验输入输出文件
- 尽可能以无损方式插入 OCR 信息,不破坏原有内容
- 优化 PDF 图像,常能生成比输入更小的文件
- 按 CPU 核心数并行处理,可应对数千页文件
容易踩的坑
- v17.14.0最新正式版2026-11-08 · 2026-11-08 21:00 UTC
New features
- New optional OCR engine, RapidOCR, which runs PaddleOCR's PP-OCR models on
ONNX Runtime. Install it with
uv tool install 'ocrmypdf[rapidocr]'(oruv pip install/pip installwith the same extra) and select it with--ocr-engine rapidocr. It often reads numbers and table cells more accurately than Tesseract, at a higher CPU and memory cost. It supports--rotate-pagesand--deskewwithout Tesseract, and the new option--rapidocr-max-side-len(API:rapidocr_max_side_len=) controls how far large pages are downscaled. See the cookbook for languages and limitations. - With RapidOCR,
--rotate-pagesuses PaddlePaddle's PP-LCNet_x1_0_doc_ori page orientation model (6.8 MB, Apache-2.0), downloaded on first use and checked against its checksum, together with the shape of the detected text lines. A page is turned only when both agree. python -m ocrmypdf.builtin_plugins.rapidocr_ocr download [LANGUAGE...]downloads RapidOCR's page orientation model and any additional language models in advance, for offline use or container images.- The Docker images do not include RapidOCR, to keep them small.
.docker/Dockerfile.rapidocrbuilds an image with RapidOCR, its page orientation model and any additional languages on top of the Ubuntu image.
Fixes
- Selecting an OCR engine other than Tesseract, including
--ocr-engine none, no longer requires Tesseract to be installed. - Fixed
--redo-ocrand--mode stripremoving visible text from a text object that also contains invisible text, such as when the text rendering mode changes to invisible partway through it. Only the invisible text is now removed, and font and spacing settings made where it is removed are kept for the text that follows. {issue}1769 - Fixed the fpdf2 renderer writing the text of a line that rises to the right too large, by up to the height of its rise, which also made the text of neighbouring lines overlap. A sloped line's box spans its rise as well as its text; the text size is now measured at the end of the line where the baseline is highest, as it already was for lines that fall to the right.
- New optional OCR engine, RapidOCR, which runs PaddleOCR's PP-OCR models on
ONNX Runtime. Install it with
- v17.13.02026-09-28 · 2026-09-28 18:55 UTC
查看更新说明
Changes
- PDF/A made without Ghostscript ("speculative" conversion) is now validated
with pikepdf's PDF/A support (
pikepdf.pdfa) instead of veraPDF, and the final output is validated again after the metadata and optimization steps. veraPDF is no longer used, so the Ghostscript-free path is available whether or not veraPDF is installed, including in the Docker image. Files the validator does not approve go to Ghostscript as before; run with-v1to see why. - Speculative conversion now supports PDF/A-1b, and repairs common problems
that previously always sent a file to Ghostscript: it replaces other output
intents with sRGB, removes image interpolation flags, sets the Print flag on
annotations, adds the
/CIDSetPDF/A-1 requires, and removes XMP properties and hidden annotations that PDF/A does not permit. - New option
--pdfa-backend {auto,ghostscript,internal}(API:pdfa_backend=).auto, the default, tries OCRmyPDF's own conversion and then Ghostscript.internalnever uses Ghostscript, so JPEGs pass through unchanged; if the result is not approved, thepdfaoutput types fail with exit code 10 and--output-type autooutputs a regular PDF.ghostscriptalways uses Ghostscript. Options that only Ghostscript implements (--pdfa-image-compression,--ghostscript-jpeg-quality,--ghostscript-jpeg-maxdpi, and--color-conversion-strategyCMYK,GrayorUseDeviceIndependentColor) now select Ghostscript underautoand are an error withinternal. - OCRmyPDF now requires
pikepdf[pdfa]10.15 or later. Thepdfaextra brings injsonschema,referencingandfonttools, all packaged by Debian and Red Hat. --force-ocrnow keeps hyperlinks, moving link annotations onto the rasterized page; so do--deskewand--clean-final. The new mode--mode force-ocr-no-linkskeeps the old behaviour. {issue}605- When Ghostscript substitutes fonts that are not embedded, it now always uses
its own fonts (
-dNONATIVEFONTMAP), so output is the same on every platform; on macOS, native font lookup could embed tens of megabytes of system fonts. OCRmyPDF warns when fonts other than the standard 14 are substituted, or when a substitute loses bold or italic styling. {issue}1369 - A creation date without a time zone is now taken to be local time, and the
output's dates get that zone, with a warning. Set
TZto choose another zone. - In the default mode, a page that already has text now stops OCRmyPDF
straight after the initial scan, instead of after OCRing the pages before
it. The error names the page. {issue}
613 - The check of the output file is much faster: each stream is checked in the
cheapest way for its compression instead of being fully decoded, and a
progress bar is shown. JPEG 2000 and CCITT images are now checked too, but
JPEGs that are corrupt without being truncated are no longer detected.
{issue}
1570 - OCRmyPDF now ships a PyInstaller hook, so apps that use it can be bundled
without extra options. Tesseract and Ghostscript must still be installed.
{issue}
1024 - New
PageInfo.has_visible_text, which excludes invisible text such as an OCR layer.has_textis unchanged.
Fixes
--force-ocron a scan that already had an invisible OCR layer rasterized it at no less than 400 dpi, as if the text were visible, which could multiply the file size. {issue}961- Process workers (
use_threads=Falseon Windows and macOS) failed on every page with'OcrOptions' object has no attribute 'tesseract'. {issue}1757 ocrmypdf.ocr()rejected thresholding method names such astesseract_thresholding='adaptive-otsu'. {issue}1460--rotate-pages --tesseract-timeout 0detected page orientation but did not rotate the pages. The cookbook now recommends this combination for rotating or deskewing without OCR. {issue}778- With
--output-type autoand--force-ocr, output was labelled PDF/A without bein
- PDF/A made without Ghostscript ("speculative" conversion) is now validated
with pikepdf's PDF/A support (
- v17.12.12026-09-16 · 2026-09-16 23:20 UTC
查看更新说明
Fixes
ocrmypdf --versionandocrmypdf --helpprinted to standard error instead of standard output, soversion=$(ocrmypdf --version)came back empty andocrmypdf --help | lessshowed nothing. OCRmyPDF redirects file descriptor 1 to standard error early in startup, before it parses the command line, so that a stray write from a plugin or a library cannot corrupt a PDF being written to standard output; argparse's own output was caught by that redirection too and is now routed back to the real standard output. Error messages continue to go to standard error. Broken since v17.8.0.
- v17.12.02026-09-16 · 2026-09-16 20:43 UTC
查看更新说明
Changes
- OCRmyPDF now requires pikepdf 10.2 or later, up from pikepdf 10. This is the
first release that provides
pikepdf.NamePath, theObject.as_int()family of type-safe accessors, and a thread-localexplicit_conversion(). OCRmyPDF uses all three to read optional values out of PDFs it did not write. - HEIF/HEIC input support is now an opt-in extra,
ocrmypdf[heic], instead of a default dependency. Thepi-heifpackage we previously depended on is discontinued; its successorpillow-heifbundles libheif, libde265 and x265 in its wheels, making the wheel as a whole GPLv2-licensed, so we do not install it by default. Installocrmypdf[heic]if you feed HEIC images to OCRmyPDF. The Docker image and snap do not include it. {issue}1746 - A Tagged PDF that is refused because it appears to contain real text now
exits with code 6 (
already_done_ocr) instead of code 2 (input_file), matching the exit code for a PDF with prior OCR. Scripts that check for exit code 2 on tagged PDFs need updating. Thanks @BetterAndBetterII. {issue}1551 - The snap package is now built and published from our CI rather than
Launchpad, so the
stablechannel tracks releases again instead of being frozen at v16.4.2. It is based on core26 and includes a JBIG2 encoder.
Fixes
- Text copied or searched in a
--output-type pdfafile came out as garbage (a stable substitution of unrelated characters, or nothing at all) when the PDF/A conversion ran through Ghostscript 9.56 through 10.04.x, which includes the Ghostscript in Ubuntu 24.04. fpdf2 writes each font's ToUnicode CMap as a singlebfcharblock, but the CMap specification allows at most 100 entries per block, and those Ghostscript releases discard the whole map when a block is larger. Any page with more than 100 distinct glyphs was affected, which is nearly every page of prose. CFF CID-keyed fonts such as Noto Sans CJK have the same problem in their Encoding CMap, where those Ghostscript releases then also draw the wrong glyphs. OCRmyPDF now splits every CMap block to 100 entries as fpdf2 writes it, for every fpdf2 release. fpdf2 2.8.9 will split the ToUnicode blocks itself but not the Encoding blocks, so the fix stays in place. Thanks @olafure for the analysis ({issue}1747, fpdf2 issue py-pdf/fpdf2#1952). - Words containing
fi,ff,fland similar pairs extracted with the letters missing (con dentiality,e ects) from--output-type pdfafiles when the PDF/A conversion ran through Ghostscript 10.05.0 through 10.06.x. Those Ghostscript releases drop ToUnicode entries that expand to more than one character (Ghostscript bug 709030, fixed in 10.07.0), and the fpdf2 renderer's HarfBuzz shaping had been forming optional Latin ligatures whose entries do exactly that. Invisible text in scripts that do not need shaping is now encoded one glyph per character, so no such entries exist to lose. Complex scripts still get shaped, and OCRmyPDF now warns when an affected Ghostscript is in use, since their conjunct mappings can still be dropped. Thanks @kmn5 ({issue}1744). - A malformed PDF that stores something other than a dictionary at a
structural key --
/Resources,/Resources /XObject,/Root /AcroForm,/Root /MarkInfo,/Root /Names,/Root /PieceInfo, an annotation's/A, or an image's/SMask-- is now tolerated everywhere rather than in the handful of places that had been hardened individually. Such a file is read as though the key were absent, which is what the well-guarded paths already did. - An image XObject with no
/Subtypeno longer raises out of the optimizer. PdfInfono longer aborts on a/MarkInfo << /Marked 1 >>, where a producer wrote a flag as an integer instead of a Boolean. Thanks @linhongyu510 ({issue}1742).- A page
/UserUnitwritten as a PDF Real is now read exactly rather than via binary floating point, so the digits the file wrote are the dig
- OCRmyPDF now requires pikepdf 10.2 or later, up from pikepdf 10. This is the
first release that provides
- v17.11.02026-08-28 · 2026-08-28 22:15 UTC
查看更新说明
Enhancements
- New
--max-ocr-image-mpixelsdownsamples the image sent to OCR when a page exceeds the given size, which bounds the largest consumer of memory. The visible page is never downsampled, so output appearance is unaffected in every mode; what it trades is OCR accuracy on very high resolution scans. A 34 megapixel page that peaks at 492 MB peaks at 325 MB under--max-ocr-image-mpixels 8, and recognizes the same text. See the "Memory" section of the performance documentation for how to size a memory limit. watcher.py(thewatcherextra) gained a configurable output layout and conflict policy. These are watcher-only changes; they do not affect theocrmypdflibrary API.- New
OCR_OUTPUT_STRUCTUREsetting (--output-structure):FLAT(default, all outputs directly in the destination directory),YEAR_MONTH({destination}/{year}/{month}/{filename}, same layout as the oldOCR_OUTPUT_DIRECTORY_YEAR_MONTH=1), orHIERARCHY, which mirrors the input directory tree under the destination, e.g.input/a/b/c.pdf→output/a/b/c.pdf. - New
OCR_ON_CONFLICTsetting (--on-conflict) controls what happens when the intended destination file already exists:SUFFIX(default) writesname (1).pdf,name (2).pdf, ... in the OS style;SKIPlogs and leaves the file unprocessed;OVERWRITEis the old behavior. Behavior change: the default is nowSUFFIX, so existing output files are no longer silently overwritten. - Both settings now apply equally to
OCR_OUTPUT_DIRECTORYand to the archive directory used byOCR_ON_SUCCESS_ARCHIVE; previously the archive directory was always flat and silently overwrote on a name collision. - Output and archive filenames and directory components are sanitized
for filesystems more restrictive than the input side (e.g. an SMB
share): characters illegal on Windows/SMB (
<>:"/\|?*and control characters) are replaced with_, trailing dots/spaces are stripped, and reserved DOS device names (CON,PRN,AUX,NUL,COM1-9,LPT1-9) are prefixed with_. OCR_OUTPUT_DIRECTORY_YEAR_MONTHis now deprecated in favor ofOCR_OUTPUT_STRUCTURE=YEAR_MONTH. It is still honored and logs a deprecation warning; if both are set,OCR_OUTPUT_STRUCTUREwins.- See the "Watched folders with watcher.py" section of the batch processing documentation for the full description, including a note for SMB users about client-side directory/file-info caching delays.
- New
Performance
- The image sent to OCR is no longer decoded and re-encoded when nothing needs
to change it. On a page with no pre-existing text to mask and no filtering
plugin -- the ordinary case for a scanned document -- the rasterized page
already is the OCR image, so it is linked rather than rewritten. Producing
it was costing 3.3 seconds and a full-size buffer on a 34 megapixel page, out
of about 15 seconds for the whole file. Building the mask is now deferred
until a text area actually needs blanking, since that step is what forced the
decode. The minimum Pillow version is raised to 12, because deciding whether
anything decoded the image reads an attribute whose shape settled in Pillow 11
(
pi-heifalready required Pillow 11.1, so the effective floor barely moves). - Reduced peak memory on files with large images by about a third at default settings. On a 34 megapixel page the process tree peaked at 752 MB and now peaks at 492 MB. Two changes account for it: rasterizing a page no longer allocates a third full-page buffer to correct PDFium's rounding of the rendered size by a pixel or two, and freed heap memory is now returned to the operating system before the OCR engine runs, instead of counting against our resident set for as long as the engine is working. Rasterization is also faster, since correcting
- New
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched or copy-pasted.
ocrmypdf # it's a scriptable command line program
-l eng+fra # it supports multiple languages
--rotate-pages # it can fix pages that are misrotated
--deskew # it can deskew crooked PDFs!
--title "My PDF" # it can change output metadata
--jobs 4 # it uses multiple cores by default
--output-type pdfa # it produces PDF/A by default
input_scanned.pdf # takes PDF input (or images)
output_searchable.pdf # produces validated PDF output
See the release notes for details on the latest changes.
Main features
- Generates a searchable PDF/A file from a regular PDF
- Places OCR text accurately below the image to ease copy / paste
- Keeps the exact resolution of the original embedded images
- When possible, inserts OCR information as a "lossless" operation without disrupting any other content
- Optimizes PDF images, often producing files smaller than the input file
- If requested, deskews and/or cleans the image before performing OCR
- Validates input and output files
- Distributes work across all available CPU cores
- Uses Tesseract OCR engine to recognize more than 100 languages
- Keeps your private data private.
- Scales properly to handle files with thousands of pages.
- Battle-tested on millions of PDFs.
For details: please consult the documentation.
Motivation
I searched the web for a free command line tool to OCR PDF files: I found many, but none of them were really satisfying:
- Either they produced PDF files with misplaced text under the image (making copy/paste impossible)
- Or they did not handle accents and multilingual characters
- Or they changed the resolution of the embedded images
- Or they generated ridiculously large PDF files
- Or they crashed when trying to OCR
- Or they did not produce valid PDF files
- On top of that none of them produced PDF/A files (format dedicated for long time storage)
...so I decided to develop my own tool.
Installation
Linux, Windows, macOS and FreeBSD are supported. Docker images are also available, for both x64 and ARM.
| Operating system | Install command |
|---|---|
| Debian, Ubuntu | apt install ocrmypdf |
| Windows Subsystem for Linux | apt install ocrmypdf |
| Fedora | dnf install ocrmypdf |
| macOS (Homebrew) | brew install ocrmypdf |
| macOS (MacPorts) | port install ocrmypdf |
| macOS (nix) | nix-env -i ocrmypdf |
| LinuxBrew | brew install ocrmypdf |
| FreeBSD | pkg install py-ocrmypdf |
| OpenBSD | pkg_add ocrmypdf |
| Ubuntu Snap | snap install ocrmypdf |
For everyone else, see our documentation for installation steps.
Languages
OCRmyPDF uses Tesseract for OCR, and relies on its language packs. For Linux users, you can often find packages that provide language packs:
# Debian/Ubuntu users
apt-cache search tesseract-ocr # Display a list of all Tesseract language packs
apt-get install tesseract-ocr-chi-sim # Example: Install Chinese Simplified language pack
# Arch Linux users
pacman -S tesseract-data-eng tesseract-data-deu # Example: Install the English and German language packs
# OpenBSD users
pkg_info -aQ tesseract # Display a list of all Tesseract language packs
pkg_add tesseract-cym # Example: Install the Welsh language pack
# brew macOS users
brew install tesseract-lang
# Fedora users
dnf search tesseract-langpack # Display a list of all Tesseract language packs
dnf install tesseract-langpack-ita # Example: Install the Italian language pack
You can then pass the -l LANG argument to OCRmyPDF to give a hint as to what languages it should search for. Multiple languages can be requested.
OCRmyPDF supports Tesseract 4.1.1+. It will automatically use whichever version it finds first on the PATH environment variable. On Windows, if PATH does not provide a Tesseract binary, we use the highest version number that is installed according to the Windows Registry.
Documentation and support
Once OCRmyPDF is installed, the built-in help which explains the command syntax and options can be accessed via:
ocrmypdf --help
Our documentation is served on Read the Docs.
Please report issues on our GitHub issues page, and follow the issue template for quick response.
Feature demo
# Add an OCR layer and require PDF/A
ocrmypdf --output-type pdfa input.pdf output.pdf
# Convert an image to single page PDF
ocrmypdf input.jpg output.pdf
# Add OCR to a file in place (only modifies file on success)
ocrmypdf myfile.pdf myfile.pdf
# OCR with non-English languages (look up your language's ISO 639-3 code)
ocrmypdf -l fra LeParisien.pdf LeParisien.pdf
# OCR multilingual documents
ocrmypdf -l eng+fra Bilingual-English-French.pdf Bilingual-English-French.pdf
# Deskew (straighten crooked pages)
ocrmypdf --deskew input.pdf output.pdf
For more features, see the documentation.
Requirements
In addition to the required Python version, OCRmyPDF requires external program installations of Ghostscript and Tesseract OCR. OCRmyPDF is pure Python, and runs on pretty much everything: Linux, macOS, Windows and FreeBSD.
Plugins
OCRmyPDF provides a plugin interface allowing its capabilities to be extended or replaced. Here are some plugins we are aware of:
- OCRmyPDF-AppleOCR: replaces the standard Tesseract OCR engine with Apple Vision Framework. Requires macOS.
- OCRmyPDF-EasyOCR: replaces the standard Tesseract OCR engine with EasyOCR, a newer OCR engine based on PyTorch. GPU strongly recommended.
- OCRmyPDF-PaddleOCR: replaces the standard Tesseract OCR engine with PaddleOCR, a powerful GPU accelerated OCR engine.
paperless-ngx provides integration of OCRmyPDF into a searchable document management system.
Press & Media
- Going paperless with OCRmyPDF
- Converting a scanned document into a compressed searchable PDF with redactions
- c't 1-2014, page 59: Detailed presentation of OCRmyPDF v1.0 in the leading German IT magazine c't
- heise Open Source, 09/2014: Texterkennung mit OCRmyPDF
- heise Durchsuchbare PDF-Dokumente mit OCRmyPDF erstellen
- Excellent Utilities: OCRmyPDF
- LinuxUser Texterkennung mit OCRmyPDF und Scanbd automatisieren
- Y Combinator discussion
Business enquiries
OCRmyPDF would not be the software that it is today without companies and users choosing to provide support for feature development and consulting enquiries. We are happy to discuss all enquiries, whether for extending the existing feature set, or integrating OCRmyPDF into a larger system.
License
The OCRmyPDF software is licensed under the Mozilla Public License 2.0 (MPL-2.0). This license permits integration of OCRmyPDF with other code, included commercial and closed source, but asks you to publish source-level modifications you make to OCRmyPDF.
Some components of OCRmyPDF have other licenses, as indicated by standard SPDX license identifiers or the DEP5 copyright and licensing information file. Generally speaking, non-core code is licensed under MIT, and the documentation and test files are licensed under Creative Commons ShareAlike 4.0 (CC-BY-SA 4.0).
Disclaimer
The software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.