<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jie Zhou</title>
    <description>The latest articles on DEV Community by Jie Zhou (@jie_zhou_0a5f30396492377a).</description>
    <link>https://dev.to/jie_zhou_0a5f30396492377a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4015203%2F4bb4a364-9a5b-4392-be8e-8e9e645c484a.png</url>
      <title>DEV Community: Jie Zhou</title>
      <link>https://dev.to/jie_zhou_0a5f30396492377a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jie_zhou_0a5f30396492377a"/>
    <language>en</language>
    <item>
      <title>Releasing SimdPaddleOCR — a complete OCR inference library in pure C#</title>
      <dc:creator>Jie Zhou</dc:creator>
      <pubDate>Mon, 07 Sep 2026 03:07:38 +0000</pubDate>
      <link>https://dev.to/jie_zhou_0a5f30396492377a/releasing-simdpaddleocr-a-complete-ocr-inference-library-in-pure-c-24nb</link>
      <guid>https://dev.to/jie_zhou_0a5f30396492377a/releasing-simdpaddleocr-a-complete-ocr-inference-library-in-pure-c-24nb</guid>
      <description>&lt;p&gt;&lt;strong&gt;SimdPaddleOCR&lt;/strong&gt; (NuGet: &lt;code&gt;Sdcb.SimdPaddleOCR&lt;/code&gt;) 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhe2l18no41duslw38io.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhe2l18no41duslw38io.png" alt=" " width="800" height="897"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open the GitHub repo right now, the language bar in the sidebar is solid purple — &lt;strong&gt;100% C#&lt;/strong&gt;. The whole pipeline runs in managed code, from start to finish. There is no second language.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;deployment and distribution&lt;/strong&gt;: 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 &lt;code&gt;.so&lt;/code&gt;, 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.&lt;/p&gt;

&lt;p&gt;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."&lt;/p&gt;

&lt;h2&gt;
  
  
  What can it do?
&lt;/h2&gt;

&lt;p&gt;Official PaddleOCR is a large document-AI ecosystem. This library is much narrower: &lt;strong&gt;end-to-end scene OCR inference&lt;/strong&gt;. It fully implements the PP-OCRv6 DET (detection) + CLS (orientation classification) + REC (recognition) pipeline.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;One more important detail: &lt;strong&gt;the core API accepts only raw 8-bit BGR memory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This time, the choice is yours. Whether the project uses ImageSharp, SkiaSharp, OpenCvSharp, or even old &lt;code&gt;System.Drawing&lt;/code&gt;, 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;The obvious question: if inference is written in pure C#, is it going to be painfully slow?&lt;/p&gt;

&lt;p&gt;Early in this project I used &lt;code&gt;lw.PPOCR.C&lt;/code&gt; 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: &lt;strong&gt;on the same model, the C# version is faster end-to-end than the pure C version&lt;/strong&gt; (the trade-off is higher managed memory; native C still wins there).&lt;/p&gt;

&lt;p&gt;GitHub Actions, win-x64, tiny model, the same 99 test images (no warmup), end-to-end mean:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;workers&lt;/th&gt;
&lt;th&gt;C#&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;C vs C#&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;296.6 ms&lt;/td&gt;
&lt;td&gt;485.7 ms&lt;/td&gt;
&lt;td&gt;1.64× slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;168.4 ms&lt;/td&gt;
&lt;td&gt;393.3 ms&lt;/td&gt;
&lt;td&gt;2.34× slower&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;How it uses .NET &lt;code&gt;Vector&amp;lt;T&amp;gt;&lt;/code&gt;, and how it squeezes AVX-512 on Zen 5, will get a detailed comparison table in Wednesday's follow-up post.&lt;/p&gt;

&lt;p&gt;On target frameworks, it supports both &lt;code&gt;net10.0&lt;/code&gt; and &lt;code&gt;netstandard2.0&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the latest .NET 10, you get the full hardware SIMD path, plus solid NativeAOT support.&lt;/li&gt;
&lt;li&gt;If you are still maintaining a legacy .NET Framework 4.8 system, it runs there too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(Note: the current release is CPU-only. There is no GPU plan for now.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get it running in ten minutes
&lt;/h2&gt;

&lt;p&gt;Install the core package and the tiny Chinese model in your project (installing tiny automatically pulls in the orientation classification package &lt;code&gt;TextLineOrientation&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Sdcb.SimdPaddleOCR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# ImageSharp is used here as an example; swap in any decoder you prefer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SixLabors.ImageSharp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;3.1.11&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal ImageSharp 3 sample that loads an image and runs OCR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Sdcb.SimdPaddleOCR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SixLabors.ImageSharp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SixLabors.ImageSharp.PixelFormats&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Load models (embedded in the assembly, read directly)&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;PaddleOcrAll&lt;/span&gt; &lt;span class="n"&gt;ocr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;PaddleOcrAll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChineseV6TinyModels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Decode with a third-party library and extract BGR pixels&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Bgr24&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Bgr24&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample.jpg"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;bgr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CopyPixelDataTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bgr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Core inference&lt;/span&gt;
&lt;span class="n"&gt;PaddleOcrResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ocr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bgr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(The repo README also has samples for SkiaSharp, OpenCvSharp5, and WinForms &lt;code&gt;LockBits&lt;/code&gt;.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Packages and model choice
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NuGet package&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sdcb.SimdPaddleOCR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Managed inference core (&lt;code&gt;net10.0;netstandard2.0&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sdcb.SimdPaddleOCR.ModelProvider&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Model contract (usually pulled in transitively)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sdcb.SimdPaddleOCR.Models.ChineseV6Tiny&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PP-OCRv6 tiny model package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sdcb.SimdPaddleOCR.Models.ChineseV6Small&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PP-OCRv6 small model package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sdcb.SimdPaddleOCR.Models.ChineseV6Medium&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PP-OCRv6 medium model package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sdcb.SimdPaddleOCR.Models.TextLineOrientation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text-line orientation CLS model package&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fki7se2heiad8wc84xik8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fki7se2heiad8wc84xik8.png" alt=" " width="800" height="1006"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For everyday use, just pick &lt;strong&gt;Tiny&lt;/strong&gt;: small package, fast inference. Reach for Small or Medium only if you need higher character accuracy.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;THIRD-PARTY-NOTICES.md&lt;/code&gt; in the repo for model provenance.&lt;/p&gt;




&lt;p&gt;If native-dependency deployment used to keep OCR out of your .NET project, this managed path is worth a try.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/sdcb/SimdPaddleOCR" rel="noopener noreferrer"&gt;https://github.com/sdcb/SimdPaddleOCR&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;NuGet search:&lt;/strong&gt; &lt;code&gt;Sdcb.SimdPaddleOCR&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Star the repo if you like it, or open an issue with suggestions and bugs.&lt;/p&gt;

&lt;p&gt;You can also join the SimdPaddleOCR WeChat group: &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjo2jda1rz3x5msg2qz08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjo2jda1rz3x5msg2qz08.png" width="800" height="1119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the WeChat QR code has expired, join the C# / .NET computer-vision QQ group: &lt;strong&gt;579060605&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>paddleocr</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
