rust-paddle-ocr

Library Listed

A lightweight and efficient OCR library based on PaddleOCR models, using the MNN inference framework for high-performance text detection and recognition

Checked · Sources

Downloads
2,742
Dependents
5
Stars
346
Forks
49
Contributors
3
Commits
112
Latest release
2.4.1 ·

About

From the project README ·

English | 中文 | 日本語 | 한국어

A lightweight Rust OCR library based on PaddleOCR models and the MNN inference runtime. It provides text detection, text recognition, and end-to-end OCR with file or in-memory model loading.

Related projects:

Supported Models

All runtime model files should be placed under models/.

FamilyDetectionRecognitionNotes
PP-OCRv4ch_PP-OCRv4_det_infer.mnnch_PP-OCRv4_rec_infer.mnnLegacy CN/EN model
PP-OCRv5PP-OCRv5_mobile_det.mnn or PP-OCRv5_mobile_det_fp16.mnnPP-OCRv5_mobile_rec*.mnnDefault CN/EN/JP plus script-specific models
PP-OCRv6 tinyPP-OCRv6_tiny_det.mnnPP-OCRv6_tiny_rec.mnnLightweight v6 tier; Japanese is not supported
PP-OCRv6 smallPP-OCRv6_small_det.mnnPP-OCRv6_small_rec.mnnBalanced v6 tier
PP-OCRv6 mediumPP-OCRv6_medium_det.mnnPP-OCRv6_medium_rec.mnnAccuracy-first v6 tier
Read the full README

PP-OCRv6 small and medium support the official 50 v6 recognition languages: Simplified Chinese, Traditional Chinese, English, Japanese, and 46 Latin-script languages. PP-OCRv6 tiny follows the same set except Japanese. Korean, Cyrillic, Arabic, Devanagari, Thai, Greek, Tamil, and Telugu should continue using the PP-OCRv5 script-specific recognition models.

V6 charset files are tier-specific:

models/ppocr_keys_v6_tiny.txt
models/ppocr_keys_v6_small.txt
models/ppocr_keys_v6_medium.txt

Convert Paddle Models To MNN

The converter defaults to MNN FP16 to reduce model size. Use --install-dir ./models to copy converted runtime files into the expected directory and filenames.

python script/convert_paddle_to_mnn.py \
  --ocr-dir /path/to/paddle/inference/models \
  --install-dir ./models

Use --no-fp16 only when full precision MNN output is required.

Rust Usage

use ocr_rs::OcrEngine;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let engine = OcrEngine::new(
        "models/PP-OCRv6_small_det.mnn",
        "models/PP-OCRv6_small_rec.mnn",
        "models/ppocr_keys_v6_small.txt",
        None,
    )?;

    let image = image::open("test.jpg")?;
    let results = engine.recognize(&image)?;

    for item in results {
        println!("{:.2}: {}", item.confidence, item.text);
    }

    Ok(())
}

Detection-only and recognition-only engines are also available:

let det = ocr_rs::OcrEngine::det_only("models/PP-OCRv6_small_det.mnn", None)?;
let rec = ocr_rs::OcrEngine::rec_only(
    "models/PP-OCRv6_small_rec.mnn",
    "models/ppocr_keys_v6_small.txt",
    None,
)?;
Mixed horizontal and vertical text

The existing recognize method keeps the original single-pass behavior. For images that mix horizontal text with text rotated by 90 or 270 degrees, enable the opt-in robust mode for that call:

use ocr_rs::{RecognizeOptions, RotatedTextMode};

let options = RecognizeOptions::new()
    .with_rotated_text_mode(RotatedTextMode::Robust);
let results = engine.recognize_with_options(&image, &options)?;

Robust mode runs detection on 90° and 270° copies, maps recovered boxes back to the input coordinates, and recognizes only vertical candidates. This adds no work to existing recognize calls. RotatedTextMode::DetectedOnly is a lighter option when the normal detector already finds the vertical boxes.

Character alignment

Use the additive alignment API when an image UI needs character hit testing or selection geometry:

let results = engine.recognize_with_options_and_alignment(&image, &options)?;
for line in results {
    for character in line.characters {
        println!("{}: {:?}", character.character, character.points);
    }
}

The four source-image points for each character are derived from the recognition model's CTC time steps and the detected text quadrilateral. This does not run an additional inference pass. The existing RecognitionResult, OcrResult_, recognize, and recognize_with_options APIs are unchanged.

Build

cargo build --release
cargo test

Performance Checks

Run Criterion benchmarks locally:

cargo bench --bench bench_metrics

Run the CI-style performance smoke test:

OCR_RS_PERF_TESTS=1 cargo test --release --test performance_tests -- --nocapture --test-threads=1

GitHub Actions runs these release tests serially and stores the PERF_METRIC log as an artifact. The regression guard compares the direct exact-width pipeline with the legacy crop pipeline on the same runner and fails when the median ratio exceeds OCR_RS_PERF_REGRESSION_LIMIT (default 1.15), avoiding unstable absolute latency limits.

Native MNN ownership is provided by mnn-runtime, while ocr-rs keeps its existing public inference API through a compatibility layer. This lets multiple model crates in one application share a single mnn-runtime-sys / MNN link owner.

Compatible CPU and GPU prebuilts are selected automatically. Unsupported target/feature combinations fall back to building MNN from source:

cargo build --features build-mnn-from-source
cargo build --release --features cuda
cargo build --release --features vulkan

Install the SDK and development libraries required by the selected backend before building. GPU backends are selected through OcrEngineConfig:

use ocr_rs::{Backend, OcrEngineConfig};

let config = OcrEngineConfig::new().with_backend(Backend::Metal);
assert!(Backend::Metal.is_available());

Engine creation returns MnnError::BackendUnavailable when the requested backend was not registered instead of silently falling back to CPU.

OcrEngineConfig uses OpenCL buffer memory by default so very wide text regions do not exceed the GPU's 2D image-width limit. Advanced users can override this with with_gpu_memory_mode(GpuMemoryMode::Auto) or GpuMemoryMode::Image; the setting is ignored by non-OpenCL backends.

x86_64-pc-windows-gnu builds MNN from source and requires a MinGW C/C++ toolchain. By default, applications must distribute the matching MinGW runtime DLLs. Enable static-cpp-runtime to statically link libstdc++, libgcc, and winpthreads so the resulting binary does not depend on MinGW runtime DLLs:

cargo build --release --target x86_64-pc-windows-gnu --features static-cpp-runtime

NVIDIA's Windows CUDA toolchain requires MSVC; use x86_64-pc-windows-msvc for source-built CUDA, or provide a compatible MNN library with mnn-dynamic/mnn-static.

This feature controls the runtime linked by ocr-rs; a user-supplied DLL selected with mnn-dynamic may still have its own MinGW runtime dependencies.

License

Apache-2.0

GPU cold-start and wide-image troubleshooting

OpenCL OCR defaults to Buffer memory and fast tuning. Vulkan OCR defaults to no tuning and High precision when OcrEngineConfig uses Normal precision. Use with_gpu_tuning to choose another tuning tradeoff and with_gpu_cache_dir to persist model-specific kernels. See issue #49 validation and cache guidance for CPU/GPU text comparisons, cold/warm benchmarks and driver-specific testing.

Runs on
CUDA, Metal, Vulkan
What shows it
  • CUDA: ocr-rs feature cuda
  • Metal: ocr-rs feature metal
  • Vulkan: ocr-rs feature vulkan
Native code
Build tool
  • Build uses a native toolchain: bindgen, cc, cmake
Python bindings
No Python binding crate found
License
Apache-2.0

Compare with similar projects

Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days.

rust-paddle-ocr beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
rust-paddle-ocr This page Listed

A lightweight and efficient OCR library based on PaddleOCR models, using the MNN inference framework for high-performance text detection and recognition

2,742 downloads over 30 days 5 346 2.4.1 CUDA, Metal, Vulkan Build uses a native toolchain: bindgen, cc, cmake Apache-2.0
oar-ocr Listed

An Optical Character Recognition (OCR) and Document Layout Analysis library written in Rust.

34,387 downloads over 30 days 9 204 0.10.2 CUDA, WebGPU, Metal Binds native code: ort-sys Apache-2.0
tesseract-rs Listed Dormant

Higher-level bindings for Tesseract OCR

24,101 downloads over 30 days 12 176 0.15.2 GPU support unknown Binds native code: tesseract-sys, leptonica-sys MIT
leptess Listed Dormant

Productive Rust binding for Tesseract and Leptonica.

16,918 downloads over 30 days 14 286 0.14.0 GPU support unknown Binds native code: leptonica-sys, tesseract-sys MIT

RustO! - Pure Rust OCR library based on RapidOCR with PaddleOCR engine

1,618 downloads over 30 days 1 127 0.3.2 CUDA, Metal, Vulkan Binds native code: rusto-mnn-sys. Build uses a native toolchain: bindgen, cc, cmake MIT

Pure-Rust, CPU-hyper-optimized runner for the Baidu Unlimited-OCR model (single-binary CLI: focr)

40 downloads over 30 days 0 346 0.9.0 GPU support unknown No native code found Not measured
Why ListedNo archive, New or Featured rule places it, so it is Listed.

What it lacks for Featured

  • It has 2 active dependents and 2 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 346 stars, 49 forks and 3 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.

What else the check found

  • The last activity is on 11 Sep 2026, 59 days ago. The rules expect an update within 365 days. Dormancy rule

Exact rules: Listed, Featured library. The check on applied thresholds version 9.

Every rule outcome, as the check records it
  • expected-interval: version 2.4.1 base 300, raised to the 365-day floor: E = 365 days
  • dormancy: last activity 2026-09-11, 59 days ago, E = 365: active
  • featured: not featured: active_users 2 < 11 and new_adopters 2 < 9 and repository route stars 346 (needs 4539), forks 49 (needs 434), contributors 3 (needs 79)
  • listed: listed: no archive, new or featured rule applies

Measurements and sources

Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.

Sources6 sources
Adoption2 active dependents, 2 new dependents in 365 days1 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependents2crates.io database dumpYes
New dependents (365 days)2crates.io database dumpYes
Peak active dependents2crates.io database dumpYes
Active dependents as a share of the peak1crates.io database dumpYes
Binary downloads per releaseNot measuredYes
MaintenanceLatest human commit: 59 days ago3 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2026-09-11GitHub repositoryYes
Latest release2026-08-05crates.io database dumpYes
First release2025-12-21crates.io database dumpYes
Latest version2.4.1crates.io database dumpYes
Days the oldest outside issue waits for a reply0GitHub repositoryYes
Maintainer replies over 365 days63GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repotruecrates.io packageYes
Published docstruecrates.io database dumpYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityUnpatched vulnerabilities: none
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windownoneRustSec advisory databaseYes
RustSec unmaintained advisorynoneRustSec advisory databaseYes
Deprecation noticenonecrates.io database dumpYes
Deprecated requirementnonecrates.io database dumpYes
Distribution16 releases, 2,742 downloads over 30 days5 not measured
Distribution measurements
SignalValueSourceFetchedCounts
Releases16crates.io database dumpYes
Downloads over 30 days2742crates.io database dumpYes
Binary downloads over the last 3 releasesNot measuredYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleasefalsecrates.io database dumpYes
Every version 0.0.xfalsecrates.io database dumpYes
Every version yankedfalsecrates.io database dumpYes
Crate deleted from crates.iofalsecrates.io database dumpYes
Repository346 stars, 49 forks, 3 contributors, 112 commits. Stars alone never qualify a project.
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars346GitHub repositoryYes — one part of the repository route
GitHub forks49GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account3GitHub contributorsYes — one part of the repository route
Commits on the default branch112GitHub repositoryNo
Repository's main crate left out of the entrynonecrates.io database dumpYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseApache-2.0crates.io database dumpNo
Runs on, from listed crates and their direct dependenciesCUDA, Metal, Vulkancrates.io database dumpNo
What shows each backendCUDA: ocr-rs feature cuda; Metal: ocr-rs feature metal; Vulkan: ocr-rs feature vulkancrates.io database dumpNo
Native code, from listed crates and their dependenciesBuild uses a native toolchain: bindgen, cc, cmakecrates.io database dumpNo
Python bindings, from direct dependencies of listed cratesNo Python binding crate foundcrates.io database dumpNo
Crates that depend on a listed crate directly5crates.io database dumpNo

Corrections and review history

Report a correction

No correction applies to this entry.

Judgments

A judgment enters only through an approved issue and a merged pull request.

No judgment applies to this entry.