SimdPaddleOCR (NuGet: Sdcb.SimdPaddleOCR) is out today. It is a complete OCR inference engine written entirely in C#. It does not depend on Paddle Inference, does not depend on ONNX Runtime, and does not ship OpenCV native DLLs.
If you open the GitHub repo right now, the language bar in the sidebar is solid purple — 100% C#. The whole pipeline runs in managed code, from start to finish. There is no second language.
After years of maintaining PaddleSharp and OpenVINO.NET, I have seen too many projects blow up in production with every flavor of error. The C++ engines themselves are strong, and P/Invoke is not hard to write. The real pain is always deployment and distribution: it works on Windows x64, then fails on Linux ARM; it is fine on the developer machine, then the customer's box is missing a .so, missing the VC++ runtime, or running on a CPU without the expected instruction set. You thought you were calling OCR. What you actually signed up for was a cross-platform native shipping matrix.
The point of SimdPaddleOCR is to drag that dirty OCR-inference work back into the managed world we already know. No native dependencies means no more "it won't even start on the next machine."
What can it do?
Official PaddleOCR is a large document-AI ecosystem. This library is much narrower: end-to-end scene OCR inference. It fully implements the PP-OCRv6 DET (detection) + CLS (orientation classification) + REC (recognition) pipeline.
To stay 100% managed, the library ships a lightweight C# ONNX interpreter. Models are embedded as assembly resources, so loading them does not unpack temporary files to disk.
One more important detail: the core API accepts only raw 8-bit BGR memory.
When I built PaddleSharp, I bound image decoding to OpenCvSharp so the samples would be easy to write. Callers who only wanted to pass in a picture still had to pull in a full OpenCV native runtime.
This time, the choice is yours. Whether the project uses ImageSharp, SkiaSharp, OpenCvSharp, or even old System.Drawing, convert the image to a BGR byte array and hand it over. Inference will run. The library does not take over file I/O, and it does not lock you to any image library.
Performance
The obvious question: if inference is written in pure C#, is it going to be painfully slow?
Early in this project I used lw.PPOCR.C as a reference — an excellent pure-C PP-OCRv6 tiny inference engine. After a deep rewrite around C# memory layout and SIMD, the result is: on the same model, the C# version is faster end-to-end than the pure C version (the trade-off is higher managed memory; native C still wins there).
GitHub Actions, win-x64, tiny model, the same 99 test images (no warmup), end-to-end mean:
| workers | C# | C | C vs C# |
|---|---|---|---|
| 1 | 296.6 ms | 485.7 ms | 1.64× slower |
| 4 | 168.4 ms | 393.3 ms | 2.34× slower |
How it uses .NET Vector<T>, and how it squeezes AVX-512 on Zen 5, will get a detailed comparison table in Wednesday's follow-up post.
On target frameworks, it supports both net10.0 and netstandard2.0.
- On the latest .NET 10, you get the full hardware SIMD path, plus solid NativeAOT support.
- If you are still maintaining a legacy .NET Framework 4.8 system, it runs there too.
(Note: the current release is CPU-only. There is no GPU plan for now.)
Get it running in ten minutes
Install the core package and the tiny Chinese model in your project (installing tiny automatically pulls in the orientation classification package TextLineOrientation):
dotnet add package Sdcb.SimdPaddleOCR
dotnet add package Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny
# ImageSharp is used here as an example; swap in any decoder you prefer
dotnet add package SixLabors.ImageSharp --version 3.1.11
A minimal ImageSharp 3 sample that loads an image and runs OCR:
using Sdcb.SimdPaddleOCR;
using Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
// Load models (embedded in the assembly, read directly)
using PaddleOcrAll ocr = await PaddleOcrAll.LoadAsync(ChineseV6TinyModels.Default);
// Decode with a third-party library and extract BGR pixels
using Image<Bgr24> image = await Image.LoadAsync<Bgr24>("sample.jpg");
byte[] bgr = new byte[image.Width * image.Height * 3];
image.CopyPixelDataTo(bgr);
// Core inference
PaddleOcrResult result = ocr.Run(bgr, image.Width, image.Height);
Console.WriteLine(result.Text);
(The repo README also has samples for SkiaSharp, OpenCvSharp5, and WinForms LockBits.)
Packages and model choice
| NuGet package | Purpose |
|---|---|
Sdcb.SimdPaddleOCR |
Managed inference core (net10.0;netstandard2.0) |
Sdcb.SimdPaddleOCR.ModelProvider |
Model contract (usually pulled in transitively) |
Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny |
PP-OCRv6 tiny model package |
Sdcb.SimdPaddleOCR.Models.ChineseV6Small |
PP-OCRv6 small model package |
Sdcb.SimdPaddleOCR.Models.ChineseV6Medium |
PP-OCRv6 medium model package |
Sdcb.SimdPaddleOCR.Models.TextLineOrientation |
Text-line orientation CLS model package |
For everyday use, just pick Tiny: small package, fast inference. Reach for Small or Medium only if you need higher character accuracy.
If you already have your own ONNX files and dictionary locally, the core library can load from a local path as well. You are not required to use the model packages. The license is Apache-2.0; see THIRD-PARTY-NOTICES.md in the repo for model provenance.
If native-dependency deployment used to keep OCR out of your .NET project, this managed path is worth a try.
Repo: https://github.com/sdcb/SimdPaddleOCR
NuGet search: Sdcb.SimdPaddleOCR
Star the repo if you like it, or open an issue with suggestions and bugs.
You can also join the SimdPaddleOCR WeChat group: 
If the WeChat QR code has expired, join the C# / .NET computer-vision QQ group: 579060605.


Top comments (0)