<?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: IronSoftware</title>
    <description>The latest articles on DEV Community by IronSoftware (@ironsoftware).</description>
    <link>https://dev.to/ironsoftware</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%2F714737%2F30e70529-1628-476f-9a14-3b157c0f5c82.png</url>
      <title>DEV Community: IronSoftware</title>
      <link>https://dev.to/ironsoftware</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ironsoftware"/>
    <language>en</language>
    <item>
      <title># DevExpress Reporting Alternative for .NET: Skip the Drag-and-Drop Designer (2026)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Tue, 21 Jul 2026 00:33:06 +0000</pubDate>
      <link>https://dev.to/ironsoftware/-devexpress-reporting-alternative-for-net-skip-the-drag-and-drop-designer-2026-2jj8</link>
      <guid>https://dev.to/ironsoftware/-devexpress-reporting-alternative-for-net-skip-the-drag-and-drop-designer-2026-2jj8</guid>
      <description>&lt;p&gt;One question keeps landing in our inbox at Iron Software: "We use DevExpress Reporting, but our PDFs get generated on a headless server and nobody opens the visual designer anymore. Is there something lighter?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full disclosure: we work on IronPDF at Iron Software, so we're clearly not neutral here.&lt;/em&gt; IronPDF comes up constantly as a DevExpress Reporting alternative for .NET, but it's not a drop-in replacement. The two tools solve overlapping problems from opposite directions.&lt;/p&gt;

&lt;p&gt;Here's our honest take: if business users design your reports in a banded designer, DevExpress is hard to beat. If your reports are really HTML and CSS that happen to end up as a PDF on a server, a code-first library like &lt;a href="https://ironpdf.com/" rel="noopener noreferrer"&gt;IronPDF&lt;/a&gt; can feel like taking off a heavy backpack.&lt;/p&gt;

&lt;p&gt;Here's our entire IronPDF version of generating a PDF report, so you can see the shape of it before we go further:&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="c1"&gt;// dotnet add package IronPdf&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Q3 Revenue Report&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Generated on the server, no designer required.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q3-report.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole program. No report definition file, no viewer control, no designer to open. Whether that's a relief or a red flag depends entirely on how your team builds reports, so let's unpack that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Tools, One Word Called Reporting
&lt;/h2&gt;

&lt;p&gt;The word reporting hides the real decision here. Both tools end with a PDF, but they start from different places.&lt;/p&gt;

&lt;p&gt;DevExpress Reporting, built on XtraReports, is a full reporting platform. You lay out reports in a visual, banded designer inside Visual Studio, bind them to data through SQL, Entity Framework, XPO, JSON, or XML, and the SkiaSharp engine renders the result. It even ships an embeddable End-User Report Designer so business users can build their own reports at runtime.&lt;/p&gt;

&lt;p&gt;IronPDF isn't a reporting platform; it's a programmatic PDF library. No designer, no report definition format. Your layout language is HTML, CSS, and JavaScript, rendered through Chromium, the same engine behind Chrome. We build the markup however we like (Razor, a template engine, plain strings) and IronPDF turns it into a PDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  DevExpress Reporting vs IronPDF at a Glance
&lt;/h2&gt;

&lt;p&gt;Before the code, here's our head-to-head. We've tried to keep each row honest rather than flattering:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;DevExpress Reporting (XtraReports)&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Authoring model&lt;/td&gt;
&lt;td&gt;Visual banded report designer + code&lt;/td&gt;
&lt;td&gt;HTML, CSS, JavaScript (+ Razor/Blazor)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rendering engine&lt;/td&gt;
&lt;td&gt;SkiaSharp document engine&lt;/td&gt;
&lt;td&gt;Chromium (Chrome)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-user / ad-hoc designer&lt;/td&gt;
&lt;td&gt;Yes, embeddable at runtime&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in data binding&lt;/td&gt;
&lt;td&gt;Yes (SQL, EF, XPO, JSON, XML)&lt;/td&gt;
&lt;td&gt;You bind in your own code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Licensing&lt;/td&gt;
&lt;td&gt;Per-developer annual subscription&lt;/td&gt;
&lt;td&gt;Perpetual, per-developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ideal use case&lt;/td&gt;
&lt;td&gt;User-designed, multi-format enterprise reports&lt;/td&gt;
&lt;td&gt;Code-driven, HTML-templated PDFs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Table 1: A capability comparison, not a scoreboard. The "ideal use case" row matters more than any single feature row.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Same Report, Two Ways
&lt;/h2&gt;

&lt;p&gt;Let's look at the same task (a data-bound invoice exported to PDF on the server) in both tools.&lt;/p&gt;

&lt;p&gt;With DevExpress, the layout already exists as a report class built in the designer. The code just binds data and exports:&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="c1"&gt;// DevExpress: export a pre-designed XtraReport to PDF on the server&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;DevExpress.XtraReports.UI&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;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvoiceReport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// class generated from your .repx banded layout&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataSource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;invoiceData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// bind the data&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;            &lt;span class="c1"&gt;// build the document tree&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryStream&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExportToPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;         &lt;span class="c1"&gt;// render to PDF bytes&lt;/span&gt;
&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAllBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;InvoiceReport&lt;/code&gt; carries the layout drawn visually. &lt;code&gt;ExportToPdf&lt;/code&gt; (and the async &lt;code&gt;ExportToPdfAsync&lt;/code&gt;) render it, and &lt;code&gt;PdfExportOptions&lt;/code&gt; customizes the output, all covered in &lt;a href="https://docs.devexpress.com/XtraReports/2574/detailed-guide-to-devexpress-reporting/store-and-distribute-reports/export-reports/export-to-pdf" rel="noopener noreferrer"&gt;DevExpress's export-to-PDF documentation&lt;/a&gt;. The strength is obvious: the layout, banding, and grouping came from a designer, not code. The cost: that layout lives in a proprietary &lt;code&gt;.repx&lt;/code&gt; file only DevExpress tooling understands.&lt;/p&gt;

&lt;p&gt;With IronPDF, the layout is HTML we generate, and the renderer does the rest:&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;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CenterText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Acme Corp - Invoice"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextFooter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RightText&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Page {page} of {total-pages}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InvoiceTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoiceData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// your own templating: Razor, interpolation, etc.&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ChromePdfRenderer&lt;/code&gt; runs the Chromium engine, so CSS Grid, Flexbox, web fonts, and JavaScript-drawn charts render exactly as they do in the browser. Data binding, though, is on you: you write the HTML. That's the trade: less structure handed to you, more freedom over the output. The &lt;a href="https://ironpdf.com/how-to/csharp-pdf-reports/" rel="noopener noreferrer"&gt;C# PDF reports how-to&lt;/a&gt; walks through headers, footers, and page breaks if you want more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where DevExpress Reporting Still Wins
&lt;/h2&gt;

&lt;p&gt;We won't pretend IronPDF wins every scenario. Here are real cases where we'd point you toward DevExpress Reporting, even though it competes with us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Business users design the reports.&lt;/strong&gt; The visual banded designer and embeddable End-User Report Designer are differentiators HTML can't match.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One definition, many formats.&lt;/strong&gt; DevExpress exports the same report to PDF, DOCX, XLSX, RTF, CSV, and images. IronPDF is PDF-only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want an in-app viewer.&lt;/strong&gt; DevExpress ships interactive viewer controls with print preview and parameter panels; IronPDF only generates files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If two or more of those describe your project, stick with DevExpress. We'd rather send you down the right path than force a migration that fights your requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where IronPDF Pulls Ahead
&lt;/h2&gt;

&lt;p&gt;Plenty of the reporting we see isn't interactive at all: it's a scheduled job or an API endpoint turning data into a PDF nobody designs by hand. For that pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your layout language is the web.&lt;/strong&gt; If your team already knows HTML and CSS, you reuse your existing design system instead of learning banded-layout concepts, and there's no designer to license separately, no &lt;code&gt;.repx&lt;/code&gt; to version-control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chromium fidelity.&lt;/strong&gt; What renders in Chrome renders in the PDF: modern CSS, custom fonts, SVG, JavaScript charts. The &lt;a href="https://ironpdf.com/tutorials/html-to-pdf/" rel="noopener noreferrer"&gt;HTML-to-PDF tutorial&lt;/a&gt; covers the rendering options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform without ceremony.&lt;/strong&gt; IronPDF runs on Linux and in containers, and a recent release cut the Docker image size by roughly 60 percent, worth knowing if you deploy to &lt;a href="https://ironpdf.com/get-started/ironpdf-docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; or a cloud function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also like that IronPDF ships monthly: recent versions added PDF/UA-2 accessibility and PDF/A-4 archival compliance, active investment worth checking before you bet a production pipeline on a dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating from XtraReports? Here's the Map
&lt;/h2&gt;

&lt;p&gt;The API swap itself is small: &lt;code&gt;report.ExportToPdf(path)&lt;/code&gt; becomes &lt;code&gt;renderer.RenderHtmlAsPdf(html).SaveAs(path)&lt;/code&gt;, &lt;code&gt;ExportToPdfAsync&lt;/code&gt; becomes &lt;code&gt;await renderer.RenderHtmlAsPdfAsync(html)&lt;/code&gt;, and &lt;code&gt;XRPageInfo&lt;/code&gt; page numbers become &lt;code&gt;{page}&lt;/code&gt; / &lt;code&gt;{total-pages}&lt;/code&gt; placeholders in &lt;code&gt;RenderingOptions&lt;/code&gt;. The real work is re-expressing banded layouts and &lt;code&gt;report.DataSource&lt;/code&gt; bindings as HTML and template loops.&lt;/p&gt;

&lt;p&gt;Invoices and summary reports translate in an afternoon. Heavily banded reports with subreports and cross-tabs take longer. Those concepts don't have a one-line HTML equivalent. On .NET 10, the current LTS, the same &lt;code&gt;ChromePdfRenderer&lt;/code&gt; code runs whether you call it from a minimal API or a full MVC controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensing: Subscription vs Perpetual
&lt;/h2&gt;

&lt;p&gt;Licensing is where the two models diverge most, and we'd encourage you to run the numbers for your own team size before committing either way.&lt;/p&gt;

&lt;p&gt;DevExpress Reporting is licensed per developer as an annual subscription. At the time of writing, the standalone Reporting subscription runs around $783.99 per developer per year through resellers, and the broader Universal subscription (600-plus UI controls) is around $2,253.99 per developer per year, with renewals near half the first-year price.&lt;/p&gt;

&lt;p&gt;IronPDF uses perpetual, per-developer licensing instead: each tier is a one-time purchase with a 30-day trial, and you own the version you buy. Current tiers are on the &lt;a href="https://ironsoftware.com/csharp/pdf/licensing/" rel="noopener noreferrer"&gt;IronPDF licensing page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A subscription keeps you current but never stops charging; a perpetual license is a bigger one-time outlay you own outright. We've seen it cost less over three to four years for a small, stable team, while a team wanting continuous updates across a large control suite may prefer the subscription. Numbers change, so confirm current pricing with each vendor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;DevExpress Reporting and IronPDF aren't really competitors so much as tools built for different definitions of reporting. If a human designs the report, DevExpress earns its subscription. If code generates it from HTML, IronPDF removes a lot of weight, licensing cost included. Plenty of teams run both: DevExpress for interactive, user-designed reports, IronPDF for the server-side jobs nobody opens a designer for.&lt;/p&gt;

&lt;p&gt;If your reports have quietly become HTML behind a server endpoint, prototype the move. Grab the 30-day trial, &lt;a href="https://ironpdf.com/get-started/installation-overview/" rel="noopener noreferrer"&gt;install the package&lt;/a&gt;, point &lt;code&gt;ChromePdfRenderer&lt;/code&gt; at one of your existing templates, and see how close the output lands on the first try.&lt;/p&gt;

&lt;p&gt;What's your experience: are your reports still designed interactively, or have they quietly turned into HTML behind an API? Tell us in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DevExpress and XtraReports are trademarks of Developer Express Inc. We're not affiliated with DevExpress; the facts about their products above come from their own public documentation as of this writing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>pdf</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Telerik Reporting Alternative: Code-First PDFs in .NET</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Mon, 20 Jul 2026 22:28:17 +0000</pubDate>
      <link>https://dev.to/ironsoftware/telerik-reporting-alternative-code-first-pdfs-in-net-37n7</link>
      <guid>https://dev.to/ironsoftware/telerik-reporting-alternative-code-first-pdfs-in-net-37n7</guid>
      <description>&lt;p&gt;We keep hearing a version of the same question from .NET teams: the Telerik Reporting renewal is coming up, and most of what the team actually needs is to &lt;a href="https://ironpdf.com/tutorials/html-to-pdf/" rel="noopener noreferrer"&gt;turn this data into a clean PDF&lt;/a&gt;. Is there something simpler?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full disclosure: we work on IronPDF at Iron Software. We'll be upfront about where our tool wins and where Telerik Reporting still wins.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's our honest take up front: &lt;a href="https://ironpdf.com/" rel="noopener noreferrer"&gt;IronPDF&lt;/a&gt; is a strong alternative when your reports can be expressed as HTML and CSS and you want code-first control. It's not a drop-in clone. Telerik Reporting is a visual, banded report platform; IronPDF is an HTML-to-PDF engine. Once that distinction clicks, the decision gets a lot easier.&lt;/p&gt;

&lt;p&gt;Here's the whole "hello, report" example. One NuGet package is the entire dependency:&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="c1"&gt;// Program.cs (.NET 10, top-level statements)&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR-LICENSE-KEY"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// a free 30-day trial key works here&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Q3 Sales Report&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Generated with IronPDF.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"report.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ChromePdfRenderer&lt;/code&gt; spins up an embedded Chromium engine and renders that markup the way a browser would. No report server, no designer file, no viewer runtime. That's the trade you're evaluating, so let's break it down.&lt;/p&gt;

&lt;p&gt;We've walked plenty of teams through this exact evaluation, and it almost always comes down to one question: is your report really a document, or does it need to stay interactive?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Teams Go Looking for an Alternative
&lt;/h2&gt;

&lt;p&gt;Most teams don't leave Telerik Reporting because it's bad. They leave because of fit. &lt;a href="https://www.telerik.com/products/reporting.aspx" rel="noopener noreferrer"&gt;Telerik Reporting&lt;/a&gt; is a feature-complete embedded reporting suite, and it carries the weight of one. Here's what our conversations with developers turn up most often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Licensing and bundling.&lt;/strong&gt; Telerik Reporting starts around $499 per developer per year, often bundled inside the larger DevCraft suite. If reporting is the only piece you use, you're paying for a lot of product you don't touch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The banded-designer model.&lt;/strong&gt; Telerik's power comes from WYSIWYG designers and &lt;code&gt;.trdp&lt;/code&gt;/&lt;code&gt;.trdx&lt;/code&gt; definition files, great for report specialists and end-user self-service but friction for a team that lives in source control and CI/CD, where a binary report definition is hard to diff and test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legacy surface area.&lt;/strong&gt; The engine grew up in the Windows Forms and Web Forms era and has been extended forward to ASP.NET Core and Blazor, which means viewers, REST report services, and designer tooling to deploy and version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that makes Telerik the wrong choice. It makes it a &lt;em&gt;heavy&lt;/em&gt; choice for teams whose real requirement is a clean PDF. That's the gap IronPDF fills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telerik Reporting vs. IronPDF at a Glance
&lt;/h2&gt;

&lt;p&gt;We've tried to keep this table fair: notice how many rows Telerik wins.F&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Telerik Reporting&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Report authoring model&lt;/td&gt;
&lt;td&gt;Visual banded designers&lt;/td&gt;
&lt;td&gt;Code + HTML / CSS / Razor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-user self-service authoring&lt;/td&gt;
&lt;td&gt;Yes (Web Report Designer)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive report viewer&lt;/td&gt;
&lt;td&gt;Yes (drill-down, sort, parameters)&lt;/td&gt;
&lt;td&gt;No, outputs a static PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML / CSS / JS rendering fidelity&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Chromium-accurate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export formats&lt;/td&gt;
&lt;td&gt;PDF, Excel, Word, PPT, CSV, RTF, images&lt;/td&gt;
&lt;td&gt;PDF (plus raster images)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF manipulation (merge, sign, PDF/A, PDF/UA)&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Extensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment footprint&lt;/td&gt;
&lt;td&gt;Engine + optional REST service + viewers&lt;/td&gt;
&lt;td&gt;Single NuGet package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-platform (Linux / Docker / macOS)&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Licensing&lt;/td&gt;
&lt;td&gt;From ~$499/yr per dev, royalty-free&lt;/td&gt;
&lt;td&gt;Perpetual, per developer, royalty-free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Telerik leads on authoring and export breadth; IronPDF leads on rendering fidelity, PDF control, and deployment.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Telerik Reporting Still Does Well
&lt;/h2&gt;

&lt;p&gt;We'd be doing you a disservice if we glossed over this: there are jobs where Telerik Reporting is the better answer.&lt;/p&gt;

&lt;p&gt;Its three WYSIWYG designers (Visual Studio, standalone desktop, and web) let non-developers build and adjust reports, self-service that an HTML-to-PDF library doesn't offer. The Report Viewer controls are the other big win: interactive viewers across HTML5, ASP.NET Core, Blazor, Angular, React, WPF, and WinForms, complete with drill-down, sorting, and parameter prompts. One report definition can export to PDF, Excel, Word, PowerPoint, CSV, RTF, and images.&lt;/p&gt;

&lt;p&gt;If your business analysts author their own reports, or you need an in-app interactive viewer, keep Telerik. That's a genuine platform need IronPDF doesn't cover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where IronPDF Fits Better
&lt;/h2&gt;

&lt;p&gt;IronPDF wins when your report is really a &lt;em&gt;document&lt;/em&gt;, and you'd rather build it with the web skills your team already has. We see this pattern constantly: an invoice, a statement, or a compliance packet that was forced into a banded designer when it was a web page all along.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;ChromePdfRenderer&lt;/code&gt; is Chromium under the hood, your report is styled with the same HTML5, CSS3, and JavaScript a browser uses: Flexbox, Grid, web fonts, SVG charts, print media queries. You can reuse an existing invoice or dashboard template instead of rebuilding it in a proprietary designer.&lt;/p&gt;

&lt;p&gt;Everything is code, so everything is testable and diffable. Your template lives in the repo, goes through code review, and runs in CI. Deployment is a single NuGet package (no report server, no viewer runtime), and it runs the same on Windows, Linux, macOS, Docker, and Azure.&lt;/p&gt;

&lt;p&gt;IronPDF is also a full PDF toolkit, not just a renderer: &lt;a href="https://ironpdf.com/how-to/merge-or-split-pdfs/" rel="noopener noreferrer"&gt;merge and split documents&lt;/a&gt;, add headers/footers/watermarks, fill forms, digitally sign (including HSM tokens as of the late-2025 releases), and produce &lt;a href="https://ironpdf.com/how-to/pdfa/" rel="noopener noreferrer"&gt;PDF/A and PDF/UA compliant output&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's the gotcha to know up front: IronPDF has &lt;strong&gt;no visual designer, no end-user self-service authoring, and no interactive viewer&lt;/strong&gt;. It produces a finished PDF, full stop. Its export is PDF-first; for native Excel or Word output, that's a job for IronXL or IronWord, not IronPDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real Report in C#
&lt;/h2&gt;

&lt;p&gt;Enough theory. Here's a data-driven report with a running footer and automatic page numbers, the banded-report feature people worry about losing:&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="c1"&gt;// QuarterlySalesReport.cs (.NET 10)&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&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;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// rows would come from EF Core, Dapper, or any data layer you already have&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Wireless Mouse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="n"&gt;Units&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Revenue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;30_876.00m&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Mechanical Keyboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Units&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;860&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;Revenue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;51_540.00m&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"USB-C Hub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="n"&gt;Units&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Revenue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;42_411.00m&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Quarterly Sales&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;table&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Product&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Units&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Revenue&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;N0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextFooter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TextHeaderFooter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;LeftText&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Confidential - Contoso Ltd."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RightText&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Page {page} of {total-pages}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;DrawDividerLine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"quarterly-sales.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TextHeaderFooter&lt;/code&gt; gives you the running header/footer band; &lt;code&gt;{page}&lt;/code&gt; and &lt;code&gt;{total-pages}&lt;/code&gt; are resolved per page at render time, so pagination is handled for you. For richer layouts, swap &lt;code&gt;TextFooter&lt;/code&gt; for &lt;code&gt;HtmlFooter&lt;/code&gt; (an &lt;code&gt;HtmlHeaderFooter&lt;/code&gt;) and use full markup. The &lt;a href="https://ironpdf.com/how-to/csharp-pdf-reports/" rel="noopener noreferrer"&gt;C# PDF reports guide&lt;/a&gt; and &lt;a href="https://ironpdf.com/how-to/headers-and-footers/" rel="noopener noreferrer"&gt;headers and footers how-to&lt;/a&gt; go deeper on both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating From Telerik Reporting
&lt;/h2&gt;

&lt;p&gt;A migration is mostly a translation exercise: most Telerik concepts have an IronPDF equivalent that lives in a different place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visual report definition (&lt;code&gt;.trdp&lt;/code&gt;/&lt;code&gt;.trdx&lt;/code&gt;) → HTML/CSS or Razor template in your project&lt;/li&gt;
&lt;li&gt;Report band (page header/footer) → &lt;code&gt;TextHeader&lt;/code&gt;/&lt;code&gt;HtmlHeader&lt;/code&gt; + CSS &lt;code&gt;@page&lt;/code&gt; rules&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ObjectDataSource&lt;/code&gt;/&lt;code&gt;SqlDataSource&lt;/code&gt; → your existing EF Core/Dapper query feeding the template&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReportProcessor.RenderReport("PDF", ...)&lt;/code&gt; → &lt;code&gt;ChromePdfRenderer.RenderHtmlAsPdf(...)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Report Viewer control → serve &lt;code&gt;pdf.BinaryData&lt;/code&gt; (or embed a JS PDF viewer)&lt;/li&gt;
&lt;li&gt;Export to Excel/Word → IronXL/IronWord (separate libraries)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server-side render is the part people expect to be hard. In IronPDF, the "definition" is your template method, and the render is one call. Here it is as a minimal API endpoint that streams the PDF back, the job the Report Viewer used to do:&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="c1"&gt;// ASP.NET Core minimal API (.NET 10)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/reports/sales/{quarter}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SalesReportTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// your template + data query&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"sales-&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;quarter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pdf.BinaryData&lt;/code&gt; is the rendered &lt;code&gt;byte[]&lt;/code&gt;, so returning it from a controller, a Blazor endpoint, or a background job is trivial. Report parameters become ordinary method arguments. If your Telerik reports were CSHTML-adjacent already, IronPDF's &lt;a href="https://ironpdf.com/how-to/cshtml-to-pdf-mvc-core/" rel="noopener noreferrer"&gt;Razor and MVC rendering&lt;/a&gt; lets you render views directly. The one part with no automatic equivalent is multi-format export; plan to route Excel and Word output to IronXL and IronWord.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensing, in Plain Terms
&lt;/h2&gt;

&lt;p&gt;Telerik Reporting is royalty-free and starts near &lt;a href="https://www.telerik.com/purchase/individual/reporting.aspx" rel="noopener noreferrer"&gt;$499 per developer per year&lt;/a&gt;, with unlimited application and server deployment. That's predictable, and it scales cleanly with team size, though it recurs and is frequently bundled inside DevCraft.&lt;/p&gt;

&lt;p&gt;IronPDF uses a perpetual, per-developer license instead of a per-seat subscription: a one-time purchase with a fully functional 30-day free trial and free use during development. Deployment to your own test, staging, and production servers is included; redistributing IronPDF inside a product you ship to third parties uses a separate OEM add-on. Check current tiers on the &lt;a href="https://ironsoftware.com/csharp/pdf/licensing/" rel="noopener noreferrer"&gt;IronPDF licensing page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Should You Choose?
&lt;/h2&gt;

&lt;p&gt;Choose &lt;strong&gt;Telerik Reporting&lt;/strong&gt; if non-developers author reports, you need an interactive in-app viewer with drill-down and parameters, or one definition must export to Excel, Word, and PowerPoint as well as PDF.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;IronPDF&lt;/strong&gt; if your reports are documents, you'd rather build them in HTML/CSS/Razor and keep everything in source control, you deploy to Linux, Docker, or &lt;a href="https://ironpdf.com/how-to/azure/" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;, or you want deep PDF manipulation from a single package.&lt;/p&gt;

&lt;p&gt;Our advice, distilled: don't migrate a &lt;em&gt;platform&lt;/em&gt; to a &lt;em&gt;library&lt;/em&gt; and expect feature parity. Migrate the reports that are really documents, and you'll wonder why they ever needed more.&lt;/p&gt;

&lt;p&gt;What's the report in your app that's secretly just a PDF waiting to happen? Tell us what you're migrating in the comments.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>pdf</category>
      <category>analytics</category>
    </item>
    <item>
      <title>QRCoder Alternatives for C#: When Generation Isn't Enough</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Tue, 14 Jul 2026 04:20:26 +0000</pubDate>
      <link>https://dev.to/ironsoftware/qrcoder-alternatives-for-c-when-generation-isnt-enough-e6j</link>
      <guid>https://dev.to/ironsoftware/qrcoder-alternatives-for-c-when-generation-isnt-enough-e6j</guid>
      <description>&lt;p&gt;The first time I reached for &lt;a href="https://github.com/codebude/QRCoder" rel="noopener noreferrer"&gt;QRCoder&lt;/a&gt;, I had a QR code saved to disk inside of five minutes. A payment link, encoded, rendered, done. It is free under the MIT license, the core has no external dependencies, and it turns a string into a clean QR code in a handful of lines. If the job is purely to &lt;em&gt;generate&lt;/em&gt; QR codes, nothing heavier is needed. That is worth saying plainly up front, because most "alternatives" articles cannot bring themselves to admit the incumbent is good. QRCoder is good.&lt;/p&gt;

&lt;p&gt;Full transparency: I am a developer advocate at Iron Software, and IronBarcode is one of the options below. The others are free libraries we do not sell. Having shipped &lt;a href="https://ironsoftware.com/csharp/barcode/features/read/" rel="noopener noreferrer"&gt;barcode reading&lt;/a&gt; into systems that scanned thousands of times a day, I have watched the exact moment a QRCoder-only setup hits its ceiling, and that moment is what this article is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  QRCoder: free, focused, and genuinely enough
&lt;/h2&gt;

&lt;p&gt;One package, no imaging dependency to wire up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package QRCoder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;QRCoder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// PngByteQRCode avoids any System.Drawing dependency, so this runs anywhere.&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;QRCodeGenerator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;QRCodeData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateQrCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/order/12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRCodeGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ECCLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Q&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;var&lt;/span&gt; &lt;span class="n"&gt;qrCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PngByteQRCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;png&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetGraphic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAllBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-qr.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;png&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That writes a scannable &lt;code&gt;order-qr.png&lt;/code&gt; to disk. Short, dependency-light, free.&lt;/p&gt;

&lt;p&gt;The honest limit is scope, and it is a design decision rather than a flaw. QRCoder generates QR codes and nothing else. Reading and decoding are out. So are 1D barcodes like Code 128 or EAN-13, which live in a &lt;a href="https://ironsoftware.com/csharp/barcode/get-started/supported-barcode-formats/" rel="noopener noreferrer"&gt;different symbology family&lt;/a&gt; entirely. And it has no concept of pulling a code out of a scanned PDF or a noisy camera frame.&lt;/p&gt;

&lt;p&gt;That is fine until a feature request crosses one of those lines, and the request almost always arrives in one of three flavors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Now we need to &lt;em&gt;scan&lt;/em&gt; the codes back in."&lt;/li&gt;
&lt;li&gt;"The warehouse team also uses linear barcodes."&lt;/li&gt;
&lt;li&gt;"The invoices arrive as PDFs. Can we read the barcode off those?"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ZXing.Net: the free reader and writer
&lt;/h2&gt;

&lt;p&gt;When generation-only stops being enough, &lt;a href="https://github.com/micjahn/ZXing.Net" rel="noopener noreferrer"&gt;ZXing.Net&lt;/a&gt; is the usual next step. It is the .NET port of the long-running Java "Zebra Crossing" project, Apache 2.0 licensed, and unlike QRCoder it goes both directions.&lt;/p&gt;

&lt;p&gt;The symbology coverage is genuinely broad: UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 93, Code 128, ITF, Codabar, MSI, RSS-14, QR Code, Data Matrix, Aztec, and PDF-417. One free library covering 1D, 2D, &lt;a href="https://ironsoftware.com/csharp/barcode/features/generate/" rel="noopener noreferrer"&gt;generation&lt;/a&gt;, and scanning is what pulls people off QRCoder.&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;ZXing&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;ZXing.Windows.Compatibility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The core package has no imaging binding, so BarcodeReader comes from a companion package.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ZXing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecodingOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;TryHarder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&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;var&lt;/span&gt; &lt;span class="n"&gt;bitmap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bitmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&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;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-qr.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Result&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;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bitmap&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;span class="s"&gt;"No barcode found."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prints the decoded string, or a miss. Note the second &lt;code&gt;using&lt;/code&gt; line: it is the whole trade-off in one import.&lt;/p&gt;

&lt;p&gt;ZXing.Net's core is pixel-oriented. Binding it to an actual image file means pulling in a companion package (System.Drawing, ImageSharp, SkiaSharp, or OpenCvSharp) and writing the glue that turns a file or stream into the luminance source the decoder expects. It works, and it works well, but the plumbing, the preprocessing, and the platform-specific bindings all become yours. On more than one project that glue has quietly grown into its own subsystem, complete with its own bugs around image rotation and contrast. Budget for that, and ZXing.Net is a strong choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  SkiaSharp: styling, not scope
&lt;/h2&gt;

&lt;p&gt;A lighter route leaves QRCoder in place and simply dresses it up. QRCoder hands back a raw bitmap or an SVG, and pairing it with &lt;a href="https://github.com/mono/SkiaSharp" rel="noopener noreferrer"&gt;SkiaSharp&lt;/a&gt; allows compositing, resizing, recoloring, or stamping a logo before saving. Dedicated barcode libraries expose the same idea through &lt;a href="https://ironsoftware.com/csharp/barcode/features/style/" rel="noopener noreferrer"&gt;built-in styling APIs&lt;/a&gt;, but here the drawing stack does the work.&lt;/p&gt;

&lt;p&gt;This is the lowest-effort option, and the right one when the requirement is purely cosmetic: a branded code on a landing page, an SVG that scales for print.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Trap:&lt;/strong&gt; &lt;code&gt;System.Drawing.Common&lt;/code&gt; is Windows-only on modern .NET, so a cross-platform project gets pushed toward SkiaSharp whether it planned to or not.&lt;/p&gt;

&lt;p&gt;What styling does &lt;em&gt;not&lt;/em&gt; do is move QRCoder's boundary. A drawing library can style an image but cannot decode one, it knows nothing about 1D symbologies, and it has no notion of error correction. The styling is real. The scope is unchanged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud barcode APIs: convenient until they aren't
&lt;/h2&gt;

&lt;p&gt;Hosted services move the work off the machine entirely. An endpoint takes an uploaded image and returns the decoded value as JSON. No native dependency to manage, no decoding engine to keep current, and for a low-volume feature inside a bigger workflow that convenience can genuinely outweigh everything else.&lt;/p&gt;

&lt;p&gt;The costs are worth listing without flinching. Every scan is a network round trip, which adds latency and rules out offline use. Image data leaves the application boundary, which is disqualifying for documents under privacy or regulatory constraints. And pricing is per call, so a high-throughput pipeline that was &lt;em&gt;free&lt;/em&gt; with QRCoder becomes a recurring line item. Cloud APIs fit sporadic, online, non-sensitive workloads. They fit batch-processing confidential files very badly.&lt;/p&gt;

&lt;h2&gt;
  
  
  IronBarcode: one library for the whole lifecycle
&lt;/h2&gt;

&lt;p&gt;Between "free but generation-only" and "outsource it to a cloud" sits a commercial in-process library covering the whole lifecycle. &lt;a href="https://ironsoftware.com/csharp/barcode/" rel="noopener noreferrer"&gt;IronBarcode&lt;/a&gt; targets the requests that send people away from QRCoder in the first place.&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;IronBarCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Generate: one line, no imaging binding to configure.&lt;/span&gt;
&lt;span class="n"&gt;QRCodeWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateQrCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/order/12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;SaveAsPng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order-qr.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Read straight out of a PDF: the case a QRCoder-only stack has no answer for.&lt;/span&gt;
&lt;span class="n"&gt;BarcodeResults&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scanned-invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BarcodeResult&lt;/span&gt; &lt;span class="n"&gt;barcode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&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="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;barcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BarcodeType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;barcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That writes a PNG, then prints the type and value of every code found across the PDF's pages. The detail worth noticing is &lt;code&gt;BarcodeReader.ReadPdf&lt;/code&gt; sitting two lines under &lt;code&gt;QRCodeWriter.CreateQrCode&lt;/code&gt;: same namespace, both directions, and &lt;a href="https://ironsoftware.com/csharp/barcode/how-to/read-barcodes-from-pdf/" rel="noopener noreferrer"&gt;reading from a PDF&lt;/a&gt; is the same entry point that handles images and streams, not a bolt-on.&lt;/p&gt;

&lt;p&gt;It also ships &lt;a href="https://ironsoftware.com/csharp/barcode/features/fault-tolerance/" rel="noopener noreferrer"&gt;fault tolerance&lt;/a&gt; and &lt;a href="https://ironsoftware.com/csharp/barcode/how-to/image-correction/" rel="noopener noreferrer"&gt;image correction&lt;/a&gt; for skewed or low-quality scans, instead of handing preprocessing back to the caller.&lt;/p&gt;

&lt;p&gt;For a project where QR &lt;em&gt;is&lt;/em&gt; the product rather than one symbology among many, &lt;a href="https://ironsoftware.com/csharp/qr/" rel="noopener noreferrer"&gt;IronQR&lt;/a&gt; goes deeper on styling and detection than a general barcode library does.&lt;/p&gt;

&lt;p&gt;The honest caveat: IronBarcode is commercial, while QRCoder and ZXing.Net are free. What is being bought is the elimination of integration work, not the ability to draw a QR code, because QRCoder does that for nothing. If that integration work is not part of the problem, this is not the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they compare
&lt;/h2&gt;

&lt;p&gt;Five options blur together fast, so here they are side by side. The row that ends most of these decisions is not "generate," it is "read from PDF."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;QRCoder&lt;/th&gt;
&lt;th&gt;ZXing.Net&lt;/th&gt;
&lt;th&gt;SkiaSharp&lt;/th&gt;
&lt;th&gt;Cloud API&lt;/th&gt;
&lt;th&gt;IronBarcode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generate QR&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Styling only&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read / decode QR&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1D barcodes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read from PDF&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Manual rasterize&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image correction&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Bring your own&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Server-side&lt;/td&gt;
&lt;td&gt;Built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Imaging binding needed&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works offline&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Per call&lt;/td&gt;
&lt;td&gt;Commercial&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  So which one should you pick?
&lt;/h2&gt;

&lt;p&gt;Match the tool to the scope of the job, not to an imaginary "best library" ranking.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only generating QR codes.&lt;/strong&gt; Stay on QRCoder. Free, MIT-licensed, dependency-light, proven. Add SkiaSharp for branding and there is never a reason to leave the open-source world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Also decoding, or handling 1D barcodes.&lt;/strong&gt; ZXing.Net is the established free option, as long as the team is comfortable wiring up an imaging binding and owning the preprocessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrequent scans, always online, non-sensitive images.&lt;/strong&gt; A cloud API is worth a look.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading barcodes out of PDFs, fixing imperfect scans, or covering 1D and 2D in one supported .NET API&lt;/strong&gt; without assembling the pieces: that is the gap &lt;a href="https://ironsoftware.com/csharp/barcode/features/" rel="noopener noreferrer"&gt;a dedicated library&lt;/a&gt; is built to close.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;QRCoder did not lose this comparison. It answers one question extremely well, and the moment a project asks a &lt;em&gt;second&lt;/em&gt; question, the options above are what is actually on the table.&lt;/p&gt;

&lt;p&gt;So what tipped it for you? I am curious how the room splits between teams who stayed on QRCoder and bolted an imaging binding onto ZXing.Net, and teams who gave up and bought the PDF path. Those seem to be the two real routes, and I have never seen a good count of which one wins.&lt;/p&gt;

&lt;p&gt;If your second question is "can it read this PDF," IronBarcode has a &lt;a href="https://ironsoftware.com/csharp/barcode/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt; so you can point it at your own documents first. Run it against the messy files, not the clean ones.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;QRCoder, ZXing.Net, and SkiaSharp are the property of their respective owners. This article isn't affiliated with, endorsed by, or sponsored by any of them. Comparisons reflect publicly available information at the time of writing and are provided for informational purposes only.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>opensource</category>
      <category>qrcode</category>
    </item>
    <item>
      <title>AWS Textract vs Google Vision (and When to Skip Both)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Sun, 12 Jul 2026 15:23:52 +0000</pubDate>
      <link>https://dev.to/ironsoftware/aws-textract-vs-google-vision-and-when-to-skip-both-19il</link>
      <guid>https://dev.to/ironsoftware/aws-textract-vs-google-vision-and-when-to-skip-both-19il</guid>
      <description>&lt;p&gt;The first time I had to choose an OCR service for a document pipeline, I spent a week benchmarking accuracy. Then I watched the whole decision get made in a single meeting by someone from legal who asked where the patient data would be processed. Accuracy barely came up. That meeting reshaped how I evaluate OCR: the question that decides a project is usually not "which engine reads better," it's "what shape are the documents, where is the data allowed to live, and how does the bill behave as volume grows."&lt;/p&gt;

&lt;p&gt;Full transparency: I'm a developer advocate at Iron Software, and one of the three options here (IronOCR) is ours. The other two are cloud services we don't sell. I'll keep this grounded in real code and call out where &lt;a href="https://aws.amazon.com/textract/" rel="noopener noreferrer"&gt;AWS Textract&lt;/a&gt; or &lt;a href="https://cloud.google.com/vision/docs/ocr" rel="noopener noreferrer"&gt;Google Cloud Vision&lt;/a&gt; is the better pick, because for a lot of workloads one of them is exactly right. Judge the code and the trade-offs for yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Textract
&lt;/h2&gt;

&lt;p&gt;Textract is built for structured documents. Beyond returning a wall of text, its Analyze Document API extracts key-value pairs, reconstructs tables with rows and columns intact, detects signatures, and supports queries like "what is the total due?" There are purpose-built APIs for expenses, identity documents, and lending packages. If your core problem is pulling fields out of standardized paperwork, that erases a lot of custom parsing code you'd otherwise own forever.&lt;/p&gt;

&lt;p&gt;In .NET you call it through the AWS SDK. The minimal text-detection call looks like this:&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;Amazon.Textract&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;Amazon.Textract.Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AmazonTextractClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Read the file into memory; Textract accepts raw bytes for synchronous calls.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DetectDocumentTextRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Bytes&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;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllBytesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doc.png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;DetectDocumentTextResponse&lt;/span&gt; &lt;span class="n"&gt;response&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DetectDocumentTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Blocks come back typed; LINE blocks hold the reading-order text.&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BlockType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BlockType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINE&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;block&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prints each detected line of text in reading order. The trade-offs I'd weigh: Textract's OCR is tuned for a focused set of Latin-script languages (English, Spanish, German, Italian, French, Portuguese), so a global multi-script corpus isn't its strength. Pricing is per page and per API, so text, tables, and forms are billed separately, and a document that needs forms plus tables gets charged for both. And the document leaves your machine for AWS to process it. For an English-or-European invoice workflow already running on AWS, none of that is a dealbreaker. Confirm current details on the &lt;a href="https://aws.amazon.com/textract/faqs/" rel="noopener noreferrer"&gt;Textract FAQ&lt;/a&gt; and &lt;a href="https://aws.amazon.com/textract/pricing/" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Cloud Vision
&lt;/h2&gt;

&lt;p&gt;Vision is built around broad language reach. Its OCR covers 80+ languages, and the recommended practice is to leave the language hint empty so the service auto-detects the script. That makes it a natural fit for mixed-language archives, international receipts, or user-submitted photos where the language isn't known ahead of time. It exposes &lt;code&gt;TEXT_DETECTION&lt;/code&gt; for short strings in natural images and &lt;code&gt;DOCUMENT_TEXT_DETECTION&lt;/code&gt; for dense pages and handwriting, returning a structured hierarchy of pages, blocks, paragraphs, words, and characters with bounding boxes.&lt;/p&gt;

&lt;p&gt;The .NET client library keeps the call short:&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;Google.Cloud.Vision.V1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ImageAnnotatorClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&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;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doc.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// DetectDocumentText is the dense-page mode; it also handles handwriting.&lt;/span&gt;
&lt;span class="n"&gt;TextAnnotation&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DetectDocumentText&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;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;That prints the full extracted text as one string, with the structured hierarchy available on &lt;code&gt;result&lt;/code&gt; when you need geometry. Where Vision stops is form semantics: it returns text geometry, but it does not natively pair a label with its value or rebuild a table as a table. Applications that need that from Google typically add the separate Document AI product or build the logic themselves. Like Textract, it's cloud-only and metered per unit (the first 1,000 units each month are free, with a tiered rate after), and requesting both detection features on one image counts as two units. Current rates and supported languages live on the &lt;a href="https://cloud.google.com/vision/docs/ocr" rel="noopener noreferrer"&gt;Cloud Vision OCR docs&lt;/a&gt; and &lt;a href="https://cloud.google.com/vision/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  IronOCR
&lt;/h2&gt;

&lt;p&gt;IronOCR is a commercial .NET library built on a tuned Tesseract 5 engine that runs entirely inside your own process. It reads images and PDFs and returns text and structured output without sending any data to an external service, which is the whole point: no REST client, no API key, no per-call billing, and it works offline.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Runs in-process. No network call, no document leaves this machine.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doc.png"&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;That prints the recognized text, and installation is a single &lt;code&gt;Install-Package IronOcr&lt;/code&gt;. It supports 125+ languages through downloadable packs and returns structured results down to pages, blocks, lines, and words for layout-aware work. Because the engine runs locally, the same code runs identically on a developer laptop, a build server, or an air-gapped production host. There's no endpoint to be unreachable.&lt;/p&gt;

&lt;p&gt;I'll be honest about where IronOCR is weaker. It does not match Textract's purpose-built form and table extraction, and its handwriting recognition is tuned for printed text rather than free handwriting. If the core problem is parsing handwritten forms in volume, a cloud service is the better tool. What you get in exchange is data residency, predictable licensing, and offline operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they compare
&lt;/h2&gt;

&lt;p&gt;Three options is enough to blur together, so here they are side by side. The row that ends most evaluations isn't accuracy, it's data privacy.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;AWS Textract&lt;/th&gt;
&lt;th&gt;Google Cloud Vision&lt;/th&gt;
&lt;th&gt;IronOCR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pricing&lt;/td&gt;
&lt;td&gt;Per page, per API&lt;/td&gt;
&lt;td&gt;Per unit, tiered after free tier&lt;/td&gt;
&lt;td&gt;Perpetual license, no per-call fees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Languages&lt;/td&gt;
&lt;td&gt;Focused Latin-script set&lt;/td&gt;
&lt;td&gt;80+ with auto-detect&lt;/td&gt;
&lt;td&gt;125+ via Tesseract 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forms &amp;amp; tables&lt;/td&gt;
&lt;td&gt;Strong, dedicated features&lt;/td&gt;
&lt;td&gt;Text geometry only&lt;/td&gt;
&lt;td&gt;Structured output, no form pairing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Cloud-only (AWS)&lt;/td&gt;
&lt;td&gt;Cloud-only (Google)&lt;/td&gt;
&lt;td&gt;In-process, on your server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data privacy&lt;/td&gt;
&lt;td&gt;Sent to AWS&lt;/td&gt;
&lt;td&gt;Sent to Google&lt;/td&gt;
&lt;td&gt;Never leaves your machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offline use&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two cloud services compete most directly on accuracy and managed scale, with continuously updated models a local library can't match on the hardest inputs. The on-prem column doesn't try to win that fight; it competes on residency, predictability, and offline capability. For healthcare records, legal discovery, documents under strict residency rules, or any system inside an air-gapped network, sending the document to a third party is either prohibited or operationally impossible, and that's the gap a local library fills.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one?
&lt;/h2&gt;

&lt;p&gt;There's no single winner here, and I'd be suspicious of any comparison that claimed otherwise.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick &lt;strong&gt;AWS Textract&lt;/strong&gt; if your documents are structured (invoices, IDs, receipts), the value is in key-value pairs and tables, and you're already on AWS.&lt;/li&gt;
&lt;li&gt;Pick &lt;strong&gt;Google Cloud Vision&lt;/strong&gt; if your documents span many languages, include handwriting, or arrive as everyday photos where auto-detection matters more than form structure.&lt;/li&gt;
&lt;li&gt;Pick &lt;strong&gt;IronOCR&lt;/strong&gt; if the data can't leave your network, you need offline or air-gapped operation, or you want a fixed cost with no per-page cloud fees inside a native .NET app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A hybrid is also reasonable: handle the bulk of documents locally for residency and cost, and route the small share of complex forms to a cloud service. The fairest test is your own data, so run the same batch of representative documents through all three and compare the text output, the cost, and where the data ended up.&lt;/p&gt;

&lt;p&gt;Which OCR are you running in production, cloud or on-prem, and what made you pick it? I'd genuinely like to hear what won on your documents, and whether it was accuracy or something around it that decided things.&lt;/p&gt;

&lt;p&gt;If you want to benchmark the on-prem option against your own files, IronOCR has a &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;AWS, Amazon Textract, Google Cloud, and Google Cloud Vision are trademarks of their respective owners. This comparison reflects publicly available information at the time of writing and is provided for informational purposes only.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>ocr</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Open-Source OCR for C#: The Real Options and Trade-Offs</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Fri, 10 Jul 2026 03:18:20 +0000</pubDate>
      <link>https://dev.to/ironsoftware/open-source-ocr-for-c-the-real-options-and-trade-offs-2o71</link>
      <guid>https://dev.to/ironsoftware/open-source-ocr-for-c-the-real-options-and-trade-offs-2o71</guid>
      <description>&lt;p&gt;When a developer asks me for "an open-source OCR library for C#," they're usually picturing something that doesn't exist: a pure-.NET text-recognition engine written from scratch. There isn't one worth shipping. Almost everything you'll find on NuGet is a wrapper, a binding, or a thin .NET surface over a native engine written in C or C++. Tesseract is C++. PaddleOCR runs on Baidu's PaddlePaddle inference runtime. OpenCV, which several of these tools lean on, is C++ too. What .NET gives you is a way to call those engines from idiomatic C# without leaving Visual Studio.&lt;/p&gt;

&lt;p&gt;Full transparency: I'm a developer advocate at Iron Software, and we make a commercial OCR library called IronOCR. So I'm biased, but I've spent enough time wiring up the free options on real projects to give you a fair map of the landscape, and I'll be upfront about where our paid tool fits and where it doesn't. The open-source route is the right call for plenty of projects. The trick is knowing what each option actually wraps, and how the licensing shakes out, before you build it into something you have to ship.&lt;/p&gt;

&lt;p&gt;That last part matters more than people expect. The license on the .NET wrapper and the license on the underlying engine can differ, and "free to install" is not the same thing as "free to ship in a closed-source product." Let me walk through the choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default: the charlesw Tesseract wrapper
&lt;/h2&gt;

&lt;p&gt;If you do nothing else, this is where you start. The most common answer to "how do I do OCR in C#" is the &lt;a href="https://github.com/charlesw/tesseract" rel="noopener noreferrer"&gt;charlesw/tesseract&lt;/a&gt; wrapper, distributed on NuGet as the &lt;code&gt;Tesseract&lt;/code&gt; package. It binds the &lt;a href="https://github.com/tesseract-ocr/tesseract" rel="noopener noreferrer"&gt;Tesseract engine&lt;/a&gt;, the one Google maintained until 2018 and a community of contributors keeps alive today. Tesseract reads more than 100 languages and uses an LSTM neural network for line recognition in version 4 and up.&lt;/p&gt;

&lt;p&gt;Here's roughly what a minimal read looks like with that wrapper:&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;Tesseract&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;var&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TesseractEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"./tessdata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"eng"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EngineMode&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="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Pix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice-scan.png"&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;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetText&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="s"&gt;$"Mean confidence: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMeanConfidence&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prints the recognized text block followed by a single percentage, something like &lt;code&gt;Mean confidence: 87%&lt;/code&gt;. And that's the whole shape of it: point a &lt;code&gt;TesseractEngine&lt;/code&gt; at a &lt;code&gt;tessdata&lt;/code&gt; folder, load an image, process it, read the text back.&lt;/p&gt;

&lt;p&gt;The licensing is the cleanest story in this entire article: the wrapper is Apache-2.0, and the Tesseract engine is Apache-2.0, so the whole stack is safe inside proprietary, closed-source software. No copyleft strings attached.&lt;/p&gt;

&lt;p&gt;The friction is operational. You manage the native binaries across platforms yourself, you supply the correct &lt;code&gt;tessdata&lt;/code&gt; language files, and you live with the fact that raw Tesseract is very sensitive to image quality. Skewed scans, low resolution, and background noise will ruin your accuracy unless you preprocess the image first. For clean, high-contrast documents, though, it's a solid free starting point and the one I reach for first when prototyping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tesseract through the command line
&lt;/h2&gt;

&lt;p&gt;There's a scrappier variant worth knowing. If a NuGet binding feels like the wrong dependency, you can install the Tesseract executable on the host and call it as a separate process from C#.&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;System.Diagnostics&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;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The CLI appends its own .txt extension, so pass "result", not "result.txt".&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;startInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProcessStartInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tesseract"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"invoice-scan.png result"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;RedirectStandardError&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;UseShellExecute&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&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;var&lt;/span&gt; &lt;span class="n"&gt;tesseractProcess&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;tesseractProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForExit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Exit code is the only error signal a separate process gives you.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tesseractProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExitCode&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&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;tesseractProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadToEnd&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;else&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;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"result.txt"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On success this writes &lt;code&gt;result.txt&lt;/code&gt; to disk and prints its contents. On failure you get whatever Tesseract wrote to stderr, which is the whole problem with this approach.&lt;/p&gt;

&lt;p&gt;It trades convenience for isolation. There's no marshalling layer to keep in sync with the engine, and you inherit whatever Tesseract version the OS has installed, which is handy on Linux, where &lt;code&gt;tesseract-ocr&lt;/code&gt; is a standard package. The cost is real, though. Process startup overhead per image makes it poor for high-throughput batch work, your error handling becomes parsing exit codes and stderr instead of catching exceptions, and you've now got an external binary to install and version on every deployment target. I'd use it for scripts, scheduled jobs, and container images that already bundle the engine. I wouldn't put it behind a latency-sensitive service.&lt;/p&gt;

&lt;h2&gt;
  
  
  The built-in Windows engine almost nobody uses
&lt;/h2&gt;

&lt;p&gt;This one gets overlooked constantly: Windows already ships an OCR engine, for free, in the &lt;a href="https://learn.microsoft.com/en-us/uwp/api/windows.media.ocr" rel="noopener noreferrer"&gt;Windows.Media.Ocr namespace&lt;/a&gt; of the Windows Runtime. The &lt;code&gt;OcrEngine&lt;/code&gt; class runs entirely on the client, works offline, and supports around 21 languages depending on which language packs are installed on the machine. No NuGet packages to vet, no native binaries to chase, no runtime fees. It's genuinely free for commercial use.&lt;/p&gt;

&lt;p&gt;The catch is right there in the name. This is a Windows-only API, unavailable on Linux or macOS, which rules it out for cross-platform services or Linux-based containers. Calling it cleanly from a packaged desktop app has historically meant getting your project configuration and Windows SDK targeting just right, which is where some people get stuck. But for a Windows desktop tool that needs reasonable accuracy with zero extra dependencies and no licensing paperwork, it's an easy choice that too many developers pass over. For anything that has to run on a Linux server, though, it's a non-starter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emgu CV: not an OCR engine, but the missing preprocessing layer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/emgucv/emgucv" rel="noopener noreferrer"&gt;Emgu CV&lt;/a&gt; is a cross-platform .NET wrapper around OpenCV. It's not primarily an OCR library, and I almost left it off, but it earns its place because OCR pipelines so often need exactly what it provides: image loading, thresholding, deskewing, denoising, and contour detection to isolate text regions before recognition runs. In practice, a lot of developers pair Emgu CV preprocessing with a Tesseract pass to claw back accuracy on messy inputs. That combination is the biggest accuracy lever in the free stack.&lt;/p&gt;

&lt;p&gt;The licensing is where you have to slow down, because it's the part that trips people up. Emgu CV uses a dual-license model. The free option is GNU GPL v3, which obliges you to release your own source under a compatible license. If you're building closed-source commercial software, GPL v3 is usually not viable, and you'd need to buy a commercial license from the vendor. So Emgu CV is open source, but "open source" here does not mean "free to ship in a proprietary product." That's a different situation from the Apache-2.0 Tesseract wrapper, and one I'd confirm with your legal team before you build it into anything you sell.&lt;/p&gt;

&lt;h2&gt;
  
  
  PaddleSharp: the strongest free accuracy, at a weight cost
&lt;/h2&gt;

&lt;p&gt;When the inputs get hard, like photographs, rotated text, or Asian scripts, raw Tesseract starts to struggle, and this is where I point people next. The &lt;a href="https://github.com/sdcb/PaddleSharp" rel="noopener noreferrer"&gt;PaddleSharp&lt;/a&gt; project provides a .NET binding for Baidu's PaddleOCR and the PaddlePaddle inference runtime. On NuGet the relevant packages are &lt;code&gt;Sdcb.PaddleOCR&lt;/code&gt;, &lt;code&gt;Sdcb.PaddleInference&lt;/code&gt;, and the matching native runtime packages for your platform and CPU-or-GPU target. Both the binding and PaddleOCR are Apache-2.0, so the closed-source story is clean.&lt;/p&gt;

&lt;p&gt;PaddleOCR's detection-plus-recognition pipeline tends to handle real-world scenes, curved text, and over 50 languages noticeably better than a single Tesseract pass, and it can download models on demand. The trade-off is weight. You're pulling in a deep-learning inference runtime, model files, and platform-specific native dependencies, which is a bigger deployment footprint and a more involved platform matrix than a lone &lt;code&gt;tessdata&lt;/code&gt; folder. For a service where recognition quality on difficult images is the priority and you can stomach the dependency surface, it's one of the strongest free options available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud OCR SDKs: a different category entirely
&lt;/h2&gt;

&lt;p&gt;The last "open-source" category isn't a local library at all, and it's worth flagging the distinction. &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/computer-vision/" rel="noopener noreferrer"&gt;Azure AI Vision&lt;/a&gt;, Amazon Textract, and Google Cloud Vision all ship official .NET SDKs that send your image to a hosted endpoint and return structured text. The SDKs themselves are usually open source and permissively licensed, but the service behind them is a metered, paid API, and your data leaves your infrastructure.&lt;/p&gt;

&lt;p&gt;These services lead on accuracy for the truly hard inputs: handwriting, forms, dense tables. They also take the burden of managing native engines and models off your plate entirely. The trade-offs are predictable, though. Per-call pricing stops being rounding-error money somewhere around the first few thousand pages a month, you take on a dependency on network availability and latency, and data-residency rules will exclude some regulated or air-gapped workloads outright. If those constraints are acceptable and accuracy is paramount, a cloud SDK is a legitimate choice. If you need to run offline, keep documents in-house, or avoid per-page billing, you're back to a local library.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the options compare
&lt;/h2&gt;

&lt;p&gt;That's a lot to hold in your head at once, so here they are side by side. The column that surprises people is licensing, not accuracy.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Wraps&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Cross-platform&lt;/th&gt;
&lt;th&gt;Preprocessing included&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;charlesw/tesseract&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tesseract (C++)&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;Yes, you ship the binaries&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesseract CLI via &lt;code&gt;Process&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Host-installed Tesseract&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;Yes, host must have it&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Windows.Media.Ocr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Windows Runtime engine&lt;/td&gt;
&lt;td&gt;Windows license&lt;/td&gt;
&lt;td&gt;No, Windows only&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emgu CV&lt;/td&gt;
&lt;td&gt;OpenCV (C++)&lt;/td&gt;
&lt;td&gt;GPL v3 or commercial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;It &lt;em&gt;is&lt;/em&gt; the preprocessing&lt;/td&gt;
&lt;td&gt;Free under GPL v3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PaddleSharp&lt;/td&gt;
&lt;td&gt;PaddleOCR, PaddlePaddle&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Detection model helps&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud SDKs&lt;/td&gt;
&lt;td&gt;Hosted service&lt;/td&gt;
&lt;td&gt;SDK permissive, service metered&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Server-side&lt;/td&gt;
&lt;td&gt;Per call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IronOCR&lt;/td&gt;
&lt;td&gt;Tuned Tesseract 5&lt;/td&gt;
&lt;td&gt;Commercial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Paid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where a commercial library actually fits
&lt;/h2&gt;

&lt;p&gt;Let me be direct, because the brief here is honesty: &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;IronOCR&lt;/a&gt; is not open source. It's a commercial .NET library, and it belongs on this list as the paid alternative, not as another free option. I'm not going to dress that up.&lt;/p&gt;

&lt;p&gt;The reason it comes up in open-source comparisons at all is that it's built on a tuned Tesseract 5 engine and packages the things the free wrappers leave to you. Native binaries bundled per platform. Built-in image filters for deskewing and denoising, the Emgu CV preprocessing step but already wired in. &lt;a href="https://ironsoftware.com/csharp/ocr/features/languages/" rel="noopener noreferrer"&gt;125+ languages&lt;/a&gt; with downloadable model packs. One managed API surface instead of three NuGet packages and a &lt;code&gt;tessdata&lt;/code&gt; folder you maintain by hand.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// A trial key is enough to evaluate this against your own scans.&lt;/span&gt;
&lt;span class="n"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR-TRIAL-KEY"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// OcrInput accepts images, PDFs, and multi-page documents through the same type.&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice-scan.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;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="s"&gt;$"Mean confidence: &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;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output looks the same as the &lt;code&gt;charlesw/tesseract&lt;/code&gt; snippet near the top: recognized text, then a confidence percentage. The difference is in what &lt;code&gt;OcrInput&lt;/code&gt; and &lt;code&gt;OcrResult&lt;/code&gt; accept and return. &lt;code&gt;OcrInput&lt;/code&gt; takes PDFs and multi-page documents directly, and &lt;code&gt;OcrResult&lt;/code&gt; hands you text alongside per-word &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/tesseract-result-confidence/" rel="noopener noreferrer"&gt;confidence scores&lt;/a&gt; and structured pages, blocks, and lines.&lt;/p&gt;

&lt;p&gt;Because it's commercial, licensing is the trade-off you weigh: you pay for production use. The fair way to frame it, and I'd say this even if I didn't work here, is that you're paying to skip the integration and preprocessing work, not buying a fundamentally different engine. It's the same Tesseract lineage underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one should you pick?
&lt;/h2&gt;

&lt;p&gt;There's no single best OCR library for C#. There's only the one that fits your constraints on platform, accuracy, and licensing. Here's how I'd choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clean documents, fully free, cross-platform:&lt;/strong&gt; the &lt;code&gt;charlesw/tesseract&lt;/code&gt; wrapper (Apache-2.0) is the default. Add Emgu CV preprocessing if your inputs are noisy, but check its GPL-or-commercial license for your distribution model first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows desktop only:&lt;/strong&gt; the built-in &lt;code&gt;Windows.Media.Ocr&lt;/code&gt; engine costs nothing and adds no dependencies. Don't overlook it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficult images, scene text, or Asian scripts:&lt;/strong&gt; PaddleSharp (Apache-2.0) gives stronger accuracy at the cost of a heavier deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximum accuracy with no infrastructure:&lt;/strong&gt; a cloud SDK, if metered pricing and sending data off-box are acceptable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineering time is your bottleneck, not budget:&lt;/strong&gt; a commercial library like IronOCR, weighed honestly against the free routes above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whatever you pick, the one piece of advice I'd stake my name on is this: prototype on your real inputs before you commit. OCR accuracy depends far more on your specific documents (their resolution, contrast, layout, and language) than on any vendor's headline numbers. The library that wins on a clean PDF can lose badly on a photographed receipt, and the only way to know is to run your own files through it. If the free stack covers your case, use it with a clear conscience. That's the honest recommendation as often as not.&lt;/p&gt;

&lt;p&gt;So what are you actually running in production? I'm curious how the room splits between people who stayed on &lt;code&gt;charlesw/tesseract&lt;/code&gt; with an Emgu CV preprocessing step bolted on, and people who moved to PaddleSharp once their inputs got messy. Those seem to be the two real paths, and I've never seen a good count of which one wins.&lt;/p&gt;

&lt;p&gt;If you want to test the integrated route on your own documents, IronOCR has a &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt; you can point at your own files.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tesseract, PaddleOCR, Emgu CV, and the cloud OCR services named here are the property of their respective owners. This article isn't affiliated with, endorsed by, or sponsored by any of them. Licensing details reflect publicly available information at the time of writing and should be verified against each project's current terms.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>ocr</category>
      <category>opensource</category>
    </item>
    <item>
      <title>OCR on Windows 11: Built-In Tools and a .NET Library</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Thu, 09 Jul 2026 04:41:15 +0000</pubDate>
      <link>https://dev.to/ironsoftware/ocr-on-windows-11-built-in-tools-and-a-net-library-36n0</link>
      <guid>https://dev.to/ironsoftware/ocr-on-windows-11-built-in-tools-and-a-net-library-36n0</guid>
      <description>&lt;p&gt;A few years back, if you wanted the text out of a screenshot, you typed it back in by hand. Today, my Windows 11 machine can pull text off the screen with a keyboard shortcut, and most people I talk to have no idea it can do that. I have spent a good while across QA, .NET development, and now developer relations watching teams reach for a heavyweight OCR setup when a built-in tool would have done the job in two seconds, and, just as often, reach for a keyboard shortcut when what they actually needed was code running on a server at 3 a.m. with nobody at the keyboard.&lt;/p&gt;

&lt;p&gt;Full transparency: I work at Iron Software as a Developer Advocate, and I build with &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;IronOCR&lt;/a&gt;, so I am biased toward our tools. I will keep this focused on working code and call out the real trade-offs, including the places where the free, built-in Windows tools are genuinely the better choice and you should not pay for anything. That happens more than you might expect.&lt;/p&gt;

&lt;p&gt;Here is the way I think about it. There are two completely different OCR problems hiding under one name. One is "I can see some text on my screen and I want it on my clipboard." The other is "my software needs to read text out of files, unattended, possibly on Linux, possibly thousands of them." Windows 11 has gotten genuinely good at the first one. The second one is where you write code. Let me walk through both.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Snipping Tool already does OCR
&lt;/h2&gt;

&lt;p&gt;This is the one I show people first because it is free, it is already installed, and it reuses a shortcut a lot of folks already have in muscle memory.&lt;/p&gt;

&lt;p&gt;Press &lt;code&gt;Win + Shift + S&lt;/code&gt; to open the capture overlay, draw a box around the text you want, and the snip opens in the Snipping Tool window. Click the &lt;strong&gt;Text Actions&lt;/strong&gt; button on the toolbar. Every recognized word lights up, and you can drag to select part of it or hit &lt;strong&gt;Copy all text&lt;/strong&gt; to grab the whole block. There is also a &lt;strong&gt;Quick Redact&lt;/strong&gt; option that masks detected email addresses and phone numbers before you copy, which I use constantly when I am about to paste a screenshot into a public ticket or a chat channel.&lt;/p&gt;

&lt;p&gt;What I like about it: recognition runs on the device, so the text never leaves your machine, and it handles clean printed text in a single language well. What it deliberately does not do is expose any image preprocessing, language tuning, or batch input, and that is fine, because it is a manual capture tool, not a pipeline. For grabbing a confirmation number off a receipt or a paragraph out of a PDF preview, I genuinely have not found anything faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  PowerToys Text Extractor, for when you do not want a screenshot at all
&lt;/h2&gt;

&lt;p&gt;Microsoft PowerToys is a free utility suite, and its Text Extractor module is the one I keep enabled on every machine I set up. It predates the Snipping Tool's OCR, and it is still my reflex because of how direct it is: there is no screenshot to manage afterward.&lt;/p&gt;

&lt;p&gt;Install PowerToys from the Microsoft Store or &lt;a href="https://github.com/microsoft/PowerToys" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, then enable &lt;strong&gt;Text Extractor&lt;/strong&gt; in the PowerToys settings. The default shortcut is &lt;code&gt;Win + Shift + T&lt;/code&gt;. Press it, the screen dims with a crosshair, you drag a rectangle over any text, and the characters land straight on your clipboard. No window, no button to click afterward.&lt;/p&gt;

&lt;p&gt;The part that has saved me more than once: it reads text that you cannot normally select. Text baked into a video frame. The label on a disabled button. An error dialog that blocks copy. I have pulled stack traces out of modal error boxes that would not let me select a single character otherwise.&lt;/p&gt;

&lt;p&gt;You can change the activation shortcut and pick the OCR language pack in settings, which matters if you read non-English text often. Like the Snipping Tool, it is built for a person at the keyboard. There is no command-line entry point and no way to point it at a folder, so it is a power-user convenience, not an automation tool. That distinction is the whole article, really.&lt;/p&gt;

&lt;h2&gt;
  
  
  OneNote and Photos read text out of files you already have
&lt;/h2&gt;

&lt;p&gt;The two tools above grab text off the live screen. Sometimes the source is a file sitting on disk instead, and Windows handles that too.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;OneNote&lt;/strong&gt;, paste or insert an image into a page, right-click it, and choose &lt;strong&gt;Copy Text from Picture&lt;/strong&gt;. OneNote runs OCR and drops the result on your clipboard. I use this for the occasional scanned page I dropped into my notes, and it works well for one document at a time. The &lt;strong&gt;Photos&lt;/strong&gt; app and the Snipping Tool's file mode can do the same when you open an existing image and invoke Text Actions on it.&lt;/p&gt;

&lt;p&gt;These are convenient because they meet the image where it already lives. The catch is the recurring theme: every extraction is a manual, one-image-at-a-time action with no way to script it. If you have three images, this is perfect. If you have three thousand, you need code, and that is where the rest of this article lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows.Media.Ocr: the engine Windows hands to developers
&lt;/h2&gt;

&lt;p&gt;Here is the thing most developers miss. The same on-device engine those built-in tools use is available to you in code, through the &lt;code&gt;Windows.Media.Ocr&lt;/code&gt; API in the Windows Runtime. No NuGet package, no third-party anything; it ships with Windows. If you are building a Windows-only desktop app and you want zero external dependencies, this is a reasonable place to start.&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;Windows.Globalization&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;Windows.Graphics.Imaging&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;Windows.Media.Ocr&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;Windows.Storage&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;Windows.Storage.Streams&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create an OCR engine for the user's language (English here).&lt;/span&gt;
&lt;span class="n"&gt;OcrEngine&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OcrEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryCreateFromLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Language&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Load an image file into a SoftwareBitmap that the engine can read.&lt;/span&gt;
&lt;span class="n"&gt;StorageFile&lt;/span&gt; &lt;span class="n"&gt;file&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;StorageFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFileFromPathAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"C:\scans\invoice.png"&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;IRandomAccessStream&lt;/span&gt; &lt;span class="n"&gt;stream&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;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OpenAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FileAccessMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;BitmapDecoder&lt;/span&gt; &lt;span class="n"&gt;decoder&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;BitmapDecoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;SoftwareBitmap&lt;/span&gt; &lt;span class="n"&gt;bitmap&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;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSoftwareBitmapAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Run recognition and print the full text.&lt;/span&gt;
&lt;span class="n"&gt;OcrResult&lt;/span&gt; &lt;span class="n"&gt;result&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;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RecognizeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bitmap&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;That runs with nothing installed beyond Windows itself, which is a real advantage. The trade-off is sitting right in the namespace. &lt;code&gt;Windows.Media.Ocr&lt;/code&gt; only runs on Windows, so the moment your code touches a Linux container it is gone. The language packs you get depend on what the host machine happens to have installed, which makes deployment unpredictable. And there is no image filtering in the box, so a low-contrast or skewed scan comes back with mistakes you have to handle yourself. If your app ships only to Windows desktops and the inputs are clean, that may be a fair deal. The further you drift from that, the more it costs you.&lt;/p&gt;

&lt;h2&gt;
  
  
  When OCR becomes part of your software, reach for a library
&lt;/h2&gt;

&lt;p&gt;Once OCR has to run server-side, inside Docker, on Linux or macOS, or across a large batch of files, the manual tools and the WinRT engine both run out of road. This is the category IronOCR is built for: a .NET library on a tuned Tesseract 5 engine, aimed at programmatic scenarios, not at replacing a quick screen grab. I will be clear about that boundary, because installing a library to copy a phone number off your screen would be silly.&lt;/p&gt;

&lt;p&gt;The three things you get over the WinRT engine are portability, bundled language data, and image correction. IronOCR runs on .NET across Windows, Linux, and macOS; it ships with 125+ languages so you are not at the mercy of what the host has installed; and it includes &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/filter-wizard/" rel="noopener noreferrer"&gt;image filters&lt;/a&gt; that deskew, denoise, and binarize a scan before recognition.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Set your license key once at startup (a free trial key works here).&lt;/span&gt;
&lt;span class="n"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR-LICENSE-KEY"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"C:\scans\invoice.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Clean up a noisy or skewed scan before reading.&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeNoise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Deskew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;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="s"&gt;$"Confidence: &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;Confidence&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;OcrInput&lt;/code&gt; object is where the batch and quality work happens. You can load many images or whole PDFs, apply filters per page, and read them in one pass. The &lt;code&gt;OcrResult&lt;/code&gt; carries more than plain text: there is a &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/tesseract-result-confidence/" rel="noopener noreferrer"&gt;confidence score&lt;/a&gt; I lean on to flag low-quality pages for human review instead of silently trusting bad output, plus structured access to lines and words. For unattended jobs that grind through documents on a schedule, &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/async/" rel="noopener noreferrer"&gt;asynchronous reading&lt;/a&gt; keeps throughput up.&lt;/p&gt;

&lt;p&gt;Installation is one package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package IronOcr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That confidence score is the feature I would not give up. In a real pipeline you do not want OCR quietly returning garbage that flows downstream into a database. You want a number you can threshold on, so anything below, say, 80% gets routed to a person. The built-in tools do not give you that, because for a manual grab you are the confidence check. You are looking right at the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one do you actually use?
&lt;/h2&gt;

&lt;p&gt;There is no single best OCR tool on Windows 11. There is a best tool for each kind of job, and the honest answer crosses vendor lines.&lt;/p&gt;

&lt;p&gt;For pulling text off your screen right now, the built-in options win on speed and cost, full stop. The &lt;a href="https://learn.microsoft.com/en-us/windows/snip-tool/" rel="noopener noreferrer"&gt;Snipping Tool's Text Actions&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/windows/powertoys/text-extractor" rel="noopener noreferrer"&gt;PowerToys Text Extractor&lt;/a&gt; cost nothing, run on-device, and need no code. Reach for those first for any manual, one-off extraction. I do, every day, and I work at an OCR company.&lt;/p&gt;

&lt;p&gt;The moment OCR moves into your own software, a server, or a stack of files, those manual tools stop being an option at all. A Windows-only desktop app with clean inputs can use &lt;code&gt;Windows.Media.Ocr&lt;/code&gt; and ship zero dependencies. For anything that has to run cross-platform, process many files unattended, clean up poor scans, or report a confidence score you can act on, a library is the layer to build on.&lt;/p&gt;

&lt;p&gt;If your project lands in that programmatic category, you can &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;start a free IronOCR trial&lt;/a&gt; and run it against your own documents before you commit to anything. The tutorials cover reading &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/read-scanned-document/" rel="noopener noreferrer"&gt;scanned documents&lt;/a&gt; and the other formats you will hit in practice. Match the tool to the job, and most days the right tool turns out to be free.&lt;/p&gt;

</description>
      <category>ocr</category>
      <category>microsoft</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Read Handwritten Text From an Image in C# (Handwriting OCR)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Tue, 07 Jul 2026 19:37:10 +0000</pubDate>
      <link>https://dev.to/ironsoftware/read-handwritten-text-from-an-image-in-c-handwriting-ocr-4bo7</link>
      <guid>https://dev.to/ironsoftware/read-handwritten-text-from-an-image-in-c-handwriting-ocr-4bo7</guid>
      <description>&lt;h1&gt;
  
  
  Read Handwritten Text From an Image in C# (Handwriting OCR)
&lt;/h1&gt;

&lt;p&gt;Reading handwritten text from an image is one of the hardest problems in OCR, and I want to set expectations before you write a line of code. Printed text has consistent glyph shapes and predictable spacing, which is why most engines handle it well. Handwriting brings variable stroke widths, joined cursive letters, slanted baselines, and quirks that no two writers share. What follows is the practical path for pulling handwriting out of an image in C#, with honest notes on where it holds up and where it falls apart.&lt;/p&gt;

&lt;p&gt;Quick disclosure: I work on &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;IronOCR&lt;/a&gt; at Iron Software, so the code here uses it. I'll be straight: handwriting is the hardest case in OCR, and no library (IronOCR included) reads messy cursive reliably. IronOCR builds on the Tesseract LSTM engine, a neural model trained on text lines rather than isolated characters, and that line-based recognition is what gives it any chance against handwriting at all. If your real target is fast cursive on a phone photo, you should know up front that cloud and ML services like Azure and Google Cloud Vision usually beat Tesseract-based engines on genuine handwriting. Where IronOCR earns its place is neat print or block capitals on a clean scan, fully on your own hardware with no image leaving the machine.&lt;/p&gt;

&lt;p&gt;Here is the smallest read that returns text from a handwritten sample.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"handwritten-note.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;For neat block printing on a clean, high-resolution scan, that output is often usable. For cursive on a low-resolution photo, expect missing words and substituted characters. Treat the basic path as a baseline to improve on, not a finished result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing IronOCR
&lt;/h2&gt;

&lt;p&gt;Install the &lt;code&gt;IronOcr&lt;/code&gt; NuGet package. It bundles the Tesseract 5 engine and the English language data, so there are no separate downloads to manage.&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;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IronOcr&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once it restores, I add a single &lt;code&gt;using IronOcr;&lt;/code&gt; directive to reach &lt;code&gt;IronTesseract&lt;/code&gt;, &lt;code&gt;OcrInput&lt;/code&gt;, and &lt;code&gt;OcrResult&lt;/code&gt;. I recommend confirming the install with a trivial read against any image first, so you can separate setup problems from recognition problems later. I like to keep that smoke test around, because it tells me at a glance whether a later failure is the engine or my image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling the LSTM engine
&lt;/h2&gt;

&lt;p&gt;Setting the engine to LSTM-only is the change that helps handwriting most. It relies on the neural model that handles connected, irregular strokes better than the legacy character-matching path.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="n"&gt;IronTesseract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;EngineMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TesseractEngineMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LstmOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PageSegmentationMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TesseractPageSegmentationMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SingleBlock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ReadBarCodes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"handwritten-note.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;I use &lt;code&gt;SingleBlock&lt;/code&gt; for a paragraph of handwriting, while a single handwritten line reads more reliably with &lt;code&gt;SingleLine&lt;/code&gt;. Page segmentation mode is worth testing per document type, because the wrong mode can cut accuracy more than any filter restores. One gotcha I keep hitting: even with the LSTM engine, handwriting accuracy sits well below the high-90s figures quoted for clean printed text, so do not promise a stakeholder those numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-processing the image
&lt;/h2&gt;

&lt;p&gt;Pre-processing usually delivers a larger gain on handwriting than any engine setting, because handwriting is so often photographed at an angle under uneven lighting. Apply IronOCR's &lt;a href="https://ironsoftware.com/csharp/ocr/tutorials/c-sharp-ocr-image-filters/" rel="noopener noreferrer"&gt;built-in image filters&lt;/a&gt; before recognition runs.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="n"&gt;IronTesseract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;EngineMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TesseractEngineMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LstmOnly&lt;/span&gt; &lt;span class="p"&gt;}&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"handwritten-note.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Order matters: straighten first so later filters work on aligned text&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Deskew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// rotate so text lines sit horizontal&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contrast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// widen the gap between ink and paper&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeNoise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// strip speckle and paper grain&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;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="s"&gt;$"Confidence after filters: &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;Confidence&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Deskew&lt;/code&gt; helps line-based recognition directly, &lt;code&gt;Contrast&lt;/code&gt; rescues faint pencil and low-light photos, and &lt;code&gt;DeNoise&lt;/code&gt; removes grain the engine would otherwise read as strokes. A common mistake I've made myself is stacking every filter at maximum: over-filtering erases thin pencil strokes and smears closely spaced cursive together. I add one filter at a time and compare the confidence score before keeping it. For tougher samples, IronOCR also exposes &lt;code&gt;Binarize&lt;/code&gt;, &lt;code&gt;GrayScale&lt;/code&gt;, and &lt;code&gt;Sharpen&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a specific region
&lt;/h2&gt;

&lt;p&gt;On forms, you often want one handwritten field, like a comments box or signature line, without surrounding printed labels interfering. Pass an &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/ocr-region-of-an-image/" rel="noopener noreferrer"&gt;&lt;code&gt;OcrRegion&lt;/code&gt;&lt;/a&gt; so recognition runs only on the coordinates you give it.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="n"&gt;IronTesseract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;EngineMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TesseractEngineMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LstmOnly&lt;/span&gt; &lt;span class="p"&gt;}&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// x, y, width, height in pixels from the top-left corner&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;commentsBox&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;180&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"filled-form.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrRegion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commentsBox&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Deskew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contrast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;Restricting the region does double duty: it removes distracting printed text and speeds up recognition by giving the engine less to scan. I still run pre-processing on the cropped area for the same accuracy reasons. For fixed positions on a standardized form, hardcoding the rectangle is reliable. For variable layouts, detect the field first, then read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking confidence and flagging low-confidence words
&lt;/h2&gt;

&lt;p&gt;With handwriting, this check is the safeguard that keeps wrong text out of your data. Read the mean &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/tesseract-result-confidence/" rel="noopener noreferrer"&gt;&lt;code&gt;Confidence&lt;/code&gt;&lt;/a&gt;, then walk &lt;code&gt;result.Words&lt;/code&gt; to surface the individual words the engine was least sure about. That per-word view is what lets you flag exactly which handwriting needs a human, rather than rejecting a whole page over one bad word.&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="n"&gt;IronTesseract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;EngineMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TesseractEngineMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LstmOnly&lt;/span&gt; &lt;span class="p"&gt;}&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"handwritten-note.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Deskew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contrast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeNoise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Tune the threshold to your accuracy tolerance&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;minimumConfidence&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;70d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&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;Confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;minimumConfidence&lt;/span&gt;&lt;span class="p"&gt;)&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="s"&gt;"Accepted:"&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;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&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="s"&gt;$"Low confidence (&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;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;). Flag for manual review."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Surface the weak spots so a reviewer sees only what needs checking&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&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;Words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;minimumConfidence&lt;/span&gt;&lt;span class="p"&gt;)&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="s"&gt;$"Uncertain word: '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&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;span class="s"&gt;' (&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose the threshold to match your tolerance: a legal-records pipeline might demand a high bar, while a search-indexing job can accept more noise. One caution worth repeating: confidence is a relative signal, not a guarantee. The engine can report high confidence on a word it read wrong, especially when the misread is itself a plausible word. For anything consequential, pair the score with human verification rather than treating it as proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;p&gt;The honest summary is that these techniques give handwriting recognition its best shot in a fully on-premises .NET pipeline, and the confidence gate is what makes the output safe to act on. I treat clean block printing as the realistic success case, and treat cursive or low-resolution photos as work that still needs human review. If neat handwriting on your own hardware is the goal, the &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;IronOCR free trial&lt;/a&gt; lets you benchmark against your own samples. If your inputs are genuinely messy cursive, test a cloud OCR service alongside it before you commit. That comparison is worth the afternoon.&lt;/p&gt;

&lt;p&gt;The step with the biggest payoff is usually better input: scan at 300 DPI or higher and control the lighting before reaching for software filters. From there, tune page segmentation mode and the filter combination per document type rather than chasing one universal setting.&lt;/p&gt;

&lt;p&gt;What handwriting have you tried to read in code, and how did it go? If you have found a preprocessing combination or a threshold that holds up on real-world notes, I would like to hear what worked and what did not. The configs people share usually beat any benchmark table.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Read OCR Confidence Scores in C# and Trust Your Tesseract Results</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Fri, 03 Jul 2026 18:42:29 +0000</pubDate>
      <link>https://dev.to/ironsoftware/how-to-read-ocr-confidence-scores-in-c-and-trust-your-tesseract-results-4d4j</link>
      <guid>https://dev.to/ironsoftware/how-to-read-ocr-confidence-scores-in-c-and-trust-your-tesseract-results-4d4j</guid>
      <description>&lt;h1&gt;
  
  
  How to Read OCR Confidence Scores in C# and Trust Your Tesseract Results
&lt;/h1&gt;

&lt;p&gt;When you run OCR over a scanned invoice or a photographed receipt, the extracted text is only half the story. The other half is how much you can trust each piece of it. A street address read from a crisp PDF and the same address read from a &lt;a href="https://ironsoftware.com/csharp/ocr/how-to/input-image-quality" rel="noopener noreferrer"&gt;blurry phone photo&lt;/a&gt; both come back as plain strings, but only one of them deserves to flow straight into your database without a second look.&lt;/p&gt;

&lt;p&gt;That trust signal is what makes OCR safe to automate. Instead of accepting a whole page blindly, you can route high-confidence documents straight through and send the doubtful ones to a person. &lt;strong&gt;Confidence scores&lt;/strong&gt; are how you draw that line.&lt;/p&gt;

&lt;p&gt;Quick disclosure: we work on IronOCR at Iron Software, so the API here is its result's confidence data. The pattern (threshold, then human-review the doubtful ones) applies to any OCR engine that reports confidence, including raw Tesseract. We'll be honest about the limits too: a confident reading can still be a confident mistake, so the score is a routing heuristic, not a correctness guarantee.&lt;/p&gt;

&lt;p&gt;Here's the fastest version. After reading an image, the overall confidence sits on the result as a &lt;code&gt;double&lt;/code&gt; between 0 and 100:&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="c1"&gt;// IronOcr namespace exposes the engine and result types&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the OCR engine&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Load the image directly as an OCR input&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice-scan.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Recognize the document&lt;/span&gt;
&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Single number summarizing how confident the engine is overall (0-100)&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="s"&gt;$"Overall confidence: &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;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to follow along, install the package the same way you'd add any other dependency:&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="c"&gt;# Install the IronOCR NuGet package&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IronOcr&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What an OCR confidence score actually means
&lt;/h2&gt;

&lt;p&gt;A confidence score estimates how certain the engine is about the characters it produced. It reflects how cleanly the recognizer matched glyph shapes against its trained model. Sharp edges, good contrast, and a standard font push the number up, while noise, skew, and odd typefaces push it down.&lt;/p&gt;

&lt;p&gt;What it does not tell you is whether the text is semantically right. The engine can be 98% sure it read an &lt;code&gt;8&lt;/code&gt; when the original ink was a &lt;code&gt;3&lt;/code&gt; that happened to render with a closed loop. We've watched that exact failure slip through, so we treat the number as a way to prioritize attention, never as a final stamp on critical fields.&lt;/p&gt;

&lt;p&gt;The same &lt;code&gt;Confidence&lt;/code&gt; property exists at every level of the result, so you can ask about the whole page or a single word:&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="c1"&gt;// IronOcr namespace exposes the engine and result types&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the OCR engine&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Load the statement image as an OCR input&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"statement.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Recognize the document&lt;/span&gt;
&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Confidence exists on the whole result...&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="s"&gt;$"Result: &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;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ...and on each individual word&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="s"&gt;$"Word:   &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;Words&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lower you go, the more granular the signal. A page might average 92% while one smudged word inside it sits at 41%. That contrast is exactly what makes per-element scores worth reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Triage a whole document with the overall score
&lt;/h2&gt;

&lt;p&gt;The overall &lt;code&gt;Confidence&lt;/code&gt; is the quickest first-pass filter we reach for. It's an averaged certainty across everything the engine recognized, so it tells you whether a document is broadly clean or broadly trouble. Here we loop a small batch and compare each against a cutoff:&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="c1"&gt;// IronOcr namespace exposes the engine and result types&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the OCR engine once and reuse it across the batch&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// The small batch of scans to triage&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"receipt-01.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"receipt-02.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"receipt-03.png"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Read each file and score it against a cutoff&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Load the current file as an OCR input&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Recognize the document&lt;/span&gt;
    &lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Quick first-pass triage on the document as a whole&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;verdict&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;Confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;85&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"auto-accept"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"needs review"&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="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &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;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;% -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha worth flagging early: the average hides outliers. A page can post a healthy 88% overall while a single critical field, an account number or a total, sits far below that. When a field matters, you check it directly rather than trusting the page average. That's the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  List the low-confidence words
&lt;/h2&gt;

&lt;p&gt;To find the tokens worth a human's eye, iterate &lt;code&gt;result.Words&lt;/code&gt; and read each word's &lt;code&gt;Confidence&lt;/code&gt;. Every entry also carries its recognized &lt;code&gt;Text&lt;/code&gt; and positional data, so you can point a reviewer straight at the spot on the page:&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="c1"&gt;// IronOcr namespace exposes the engine and result types&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the OCR engine&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Load the label image as an OCR input&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"shipping-label.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Recognize the document&lt;/span&gt;
&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Any word scoring below this needs a human's eye&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;wordThreshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Collect every word the engine was unsure about&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;suspectWords&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;Words&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;wordThreshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// keep the weak ones&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;// weakest first&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Report how many words were flagged&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="s"&gt;$"Flagged &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;suspectWords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; low-confidence word(s):"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Print each flagged word with its coordinates&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;suspectWords&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Location tells reviewers exactly where to look on the page&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="s"&gt;$"  '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&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;span class="s"&gt;' at (&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set a word-level threshold, filter the words below it, and sort the weakest to the top. This is the right granularity for structured-data extraction: a license, a passport, or an invoice has a handful of fields that truly matter, and checking those specific words beats accepting or rejecting the whole document on its average. The same iteration works on &lt;code&gt;result.Lines&lt;/code&gt; or &lt;code&gt;result.Paragraphs&lt;/code&gt; when your fields span multiple words, and only the collection changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route documents for human review
&lt;/h2&gt;

&lt;p&gt;Now you can put both signals together into a two-tier rule: one cutoff for the overall result and a stricter one for any single word. That catches both globally poor scans and locally damaged fields.&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="c1"&gt;// IronOcr namespace exposes the engine and result types&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the OCR engine&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Load the application image as an OCR input&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"loan-application.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Recognize the document&lt;/span&gt;
&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;pageThreshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// whole-document floor&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;wordThreshold&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// stricter floor for any single token&lt;/span&gt;

&lt;span class="c1"&gt;// Does the page as a whole clear the floor?&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;pageIsClean&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;Confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;pageThreshold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Does every single word clear the stricter floor?&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;everyWordIsClean&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;Words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;All&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;wordThreshold&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Auto-process only when both checks pass&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageIsClean&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;everyWordIsClean&lt;/span&gt;&lt;span class="p"&gt;)&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="s"&gt;"Auto-processing: all scores cleared the threshold."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// push extracted fields into your system of record&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Route to a person and tell them why it was flagged&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;weakest&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;Words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&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="s"&gt;"Sent to review queue."&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="s"&gt;$"Reason: weakest word '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weakest&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;span class="s"&gt;' at &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weakest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only documents that clear both floors get processed automatically; everything else goes to a person along with the reason it was flagged. We've found the thresholds are a business decision: a marketing mailing list tolerates a far lower bar than a medical record or a wire-transfer instruction.&lt;/p&gt;

&lt;p&gt;A word of caution we keep coming back to: a passing score is not verified data on high-stakes fields. For figures that carry legal or financial weight, such as totals, account numbers, and dates of birth, keep a human in the loop regardless of the number. Tuning the cutoffs is empirical work. Start strict, run a representative sample through, and watch how many documents land in review versus how many errors slip past. Loosen or tighten until the false-accept rate matches what your use case can absorb.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a score is low, fix the image first
&lt;/h2&gt;

&lt;p&gt;When a document scores poorly, the fix is usually the image rather than the threshold. You can apply preprocessing filters to the input before reading, then re-check the confidence to confirm the cleanup helped. That turns the score into a feedback loop of measure, clean, then measure again:&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="c1"&gt;// IronOcr namespace exposes the engine and result types&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the OCR engine&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// First pass on the raw, noisy scan&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;rawInput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"faded-receipt.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Record the baseline confidence before any cleanup&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;before&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawInput&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Second pass after cleaning the same image up&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cleanInput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrImageInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"faded-receipt.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cleanInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Deskew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;           &lt;span class="c1"&gt;// straighten tilted text&lt;/span&gt;
&lt;span class="n"&gt;cleanInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToGrayScale&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// drop distracting color&lt;/span&gt;
&lt;span class="n"&gt;cleanInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Binarize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;         &lt;span class="c1"&gt;// hard black-and-white separation&lt;/span&gt;
&lt;span class="n"&gt;cleanInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeNoise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// remove speckle and grain&lt;/span&gt;

&lt;span class="c1"&gt;// Record the confidence after preprocessing&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;after&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cleanInput&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Confidence&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Compare the two to see whether the cleanup actually helped&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="s"&gt;$"Before: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%  After: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%  Gain: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; pts"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One mistake we see often is stacking every available filter and hoping for the best. Aggressive binarization or denoising on an already-clean image can erode thin strokes and drag the score down. Add filters one at a time and keep only the ones that move confidence up.&lt;/p&gt;

&lt;p&gt;If you'd like to put this on your own documents, IronOCR has a &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt; you can run against your real scans and measure the scores you get back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;p&gt;The throughline is short: confidence is a routing signal that decides where attention goes, and human review stays the backstop for anything that truly matters. Read the overall score to triage, drill into per-word scores to flag weak tokens, threshold both to route the doubtful documents, and preprocess to rescue borderline scans.&lt;/p&gt;

&lt;p&gt;What thresholds have worked for you in production? If you've found a confidence cutoff that balances throughput against false accepts on a specific document type such as receipts, IDs, or forms, we'd like to hear the number and how you landed on it. And if you've been burned by a confident misread that sailed through automation, tell us where it broke.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>ocr</category>
      <category>tesseract</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ZXing Barcode Scanner in .NET: ZXing.NET vs IronBarcode</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Wed, 01 Jul 2026 18:00:04 +0000</pubDate>
      <link>https://dev.to/ironsoftware/zxing-barcode-scanner-in-net-zxingnet-vs-ironbarcode-481b</link>
      <guid>https://dev.to/ironsoftware/zxing-barcode-scanner-in-net-zxingnet-vs-ironbarcode-481b</guid>
      <description>&lt;h1&gt;
  
  
  ZXing Barcode Scanner in .NET: ZXing.NET vs IronBarcode
&lt;/h1&gt;

&lt;p&gt;If you have searched for a "ZXing barcode scanner" in C#, you have probably landed on &lt;a href="https://github.com/micjahn/ZXing.Net" rel="noopener noreferrer"&gt;ZXing.NET&lt;/a&gt;, the community port of the Java ZXing project (pronounced "zebra crossing"). It reads and writes a broad set of 1D and 2D symbologies, and it has been a reference for barcode handling for well over a decade. This comparison puts it next to IronBarcode and lets the code show where each one fits.&lt;/p&gt;

&lt;p&gt;Full disclosure: we build IronBarcode at Iron Software, one of the two libraries here. ZXing.NET is free and genuinely capable; we'll flag where it's the better pick and let the code speak.&lt;/p&gt;

&lt;p&gt;Here is the short version. ZXing.NET is free, open source, and mature, and for clean, standard barcodes it does exactly the job. The tradeoff is that you handle the imaging glue and any preprocessing yourself, and the library follows a community release cadence. IronBarcode is commercial, but it bundles the imaging stack, image correction, and PDF reading, so noisy or rotated input needs less code from you. Pick by use case, not by logo.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal ZXing.NET scan
&lt;/h2&gt;

&lt;p&gt;ZXing.NET ships on NuGet. The core package carries the format definitions and decoding logic but deliberately leaves out an imaging dependency, so you pair it with a binding. On Windows, &lt;code&gt;ZXing.Windows.Compatibility&lt;/code&gt; adds the &lt;code&gt;System.Drawing&lt;/code&gt; glue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package ZXing.Net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;System&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;System.Drawing&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;ZXing&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;ZXing.Windows.Compatibility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;barcodeReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scanResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;barcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;Bitmap&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;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"barcode.png"&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;scanResult&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;span class="c1"&gt;// null-conditional: Decode returns null on no match&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Decode&lt;/code&gt; returns a single &lt;code&gt;Result&lt;/code&gt;, or &lt;code&gt;null&lt;/code&gt; when nothing is found, which is why the null-conditional &lt;code&gt;?.Text&lt;/code&gt; matters. For a clean image of a standard symbology, we find that is all you need, and it works well.&lt;/p&gt;

&lt;p&gt;💡 If you want to spend more CPU recovering a marginal scan, set &lt;code&gt;Options = new ZXing.Common.DecodingOptions { TryHarder = true }&lt;/code&gt; on the reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ZXing.NET covers
&lt;/h2&gt;

&lt;p&gt;ZXing.NET inherits the broad symbology coverage of the Java project, which is the main reason developers reach for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1D / linear:&lt;/strong&gt; UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 93, Code 128, ITF, Codabar, MSI, RSS-14&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2D / matrix:&lt;/strong&gt; QR Code, Data Matrix, Aztec, PDF-417&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both reading and writing are supported, so the same package generates a QR code or a Code 128 as well as decoding one. If you know which formats you expect, restrict the reader to them, since it cuts false positives and speeds up the scan when the decoder stops probing symbologies you will never receive.&lt;/p&gt;

&lt;p&gt;✅ For a project that scans clean retail barcodes or generates QR codes, this is a solid, zero-cost foundation, and we would point you straight at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the friction shows up
&lt;/h2&gt;

&lt;p&gt;In our experience the rough edges are rarely in the core decoding; they show up around a real integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imaging setup
&lt;/h3&gt;

&lt;p&gt;Because the core package has no image dependency, decoding a file on modern .NET means also installing a binding such as &lt;code&gt;ZXing.Net.Bindings.SkiaSharp&lt;/code&gt;, &lt;code&gt;ZXing.Net.Bindings.ImageSharp&lt;/code&gt;, or &lt;code&gt;ZXing.Windows.Compatibility&lt;/code&gt;. You also work around &lt;code&gt;System.Drawing.Common&lt;/code&gt; being Windows-only on newer .NET, which is why cross-platform teams often standardize on SkiaSharp or ImageSharp.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image correction
&lt;/h3&gt;

&lt;p&gt;ZXing.NET handles grayscale, binarization, and a &lt;code&gt;TryHarder&lt;/code&gt; mode, but it offers fewer built-in helpers for rotation, skew, low resolution, or noisy scanner output. When a source image needs cleanup, that preprocessing is your job through whichever imaging library you bound to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Release cadence
&lt;/h3&gt;

&lt;p&gt;⚠️ ZXing.NET is community-maintained and tracks an upstream Java project, so releases arrive on a community schedule rather than a commercial timeline. For many teams that is fine; for some with stricter support needs, it is a factor to weigh. None of this makes ZXing.NET a poor choice. It describes where the work lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same scan with IronBarcode
&lt;/h2&gt;

&lt;p&gt;IronBarcode is the commercial .NET library we build: it packages the imaging stack, correction, and document handling in one namespace. There is one package to install and no per-platform binding to pick.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package BarCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;IronBarCode&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;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scanResults&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"barcode.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;barcode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;scanResults&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;barcode&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;You can install IronBarcode from NuGet and run that in about five minutes. &lt;code&gt;Read&lt;/code&gt; returns a collection rather than a single result, so an image holding several barcodes comes back in one call. For the clean single-barcode case, we think the two libraries are close enough that cost and license model should decide it, and ZXing.NET being free is a real advantage there.&lt;/p&gt;

&lt;p&gt;The gap widens on imperfect input. Where you would hand-write rotation and noise handling for ZXing.NET, we expose it through reader options:&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;IronBarCode&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;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;readerOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BarcodeReaderOptions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ExpectMultipleBarcodes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Speed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ReadingSpeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Detailed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// spend more CPU on messy input&lt;/span&gt;
    &lt;span class="n"&gt;ImageFilters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ImageFilterCollection&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SharpenFilter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ContrastFilter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skewedResults&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"skewed-scan.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;readerOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;barcode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;skewedResults&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="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;barcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BarcodeType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;barcode&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;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Detailed&lt;/code&gt; speed setting and the filter chain are what you reach for on skewed, low-contrast, or noisy scans. IronBarcode can also read straight from a PDF and batch across pages without you rasterizing each one first. That is the practical difference: less glue code for messy or multi-page input, at the cost of a commercial license.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they compare
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;ZXing.NET&lt;/th&gt;
&lt;th&gt;IronBarcode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read / write&lt;/td&gt;
&lt;td&gt;✅ Both&lt;/td&gt;
&lt;td&gt;✅ Both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Symbologies&lt;/td&gt;
&lt;td&gt;1D (UPC, EAN, Code 39/93/128, ITF, Codabar, MSI) and 2D (QR, Data Matrix, Aztec, PDF-417)&lt;/td&gt;
&lt;td&gt;Same broad 1D and 2D set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image preprocessing&lt;/td&gt;
&lt;td&gt;Manual, through bound imaging library&lt;/td&gt;
&lt;td&gt;Built-in sharpen, contrast, rotation, noise correction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Imaging dependency&lt;/td&gt;
&lt;td&gt;Separate binding package required&lt;/td&gt;
&lt;td&gt;Self-contained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read from PDF / multi-page&lt;/td&gt;
&lt;td&gt;Manual rasterization first&lt;/td&gt;
&lt;td&gt;✅ Direct, batched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET targets&lt;/td&gt;
&lt;td&gt;.NET Standard / Core / Framework (+ binding)&lt;/td&gt;
&lt;td&gt;.NET Standard / Core 2.0+, Windows, Linux, macOS, Azure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Apache 2.0, free, open source&lt;/td&gt;
&lt;td&gt;Commercial, paid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Community cadence, tracks Java upstream&lt;/td&gt;
&lt;td&gt;Commercial release cadence and support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  So which one?
&lt;/h2&gt;

&lt;p&gt;There is no single winner here, and we would distrust a comparison that claimed one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Pick &lt;strong&gt;ZXing.NET&lt;/strong&gt; if you want free, open-source, full-source-access barcode handling, your images are clean and standard, and you are comfortable wiring an imaging binding and any preprocessing yourself. For a great many projects, that is the right call.&lt;/li&gt;
&lt;li&gt;✅ Pick &lt;strong&gt;IronBarcode&lt;/strong&gt; if your input is skewed, noisy, rotated, or arrives as PDFs, you are batch-reading at volume, and a single-package install with built-in correction and commercial support is worth a license fee. The &lt;a href="https://ironsoftware.com/csharp/barcode/tutorials/reading-barcodes/" rel="noopener noreferrer"&gt;IronBarcode barcode reading tutorial&lt;/a&gt; covers PDF input and the filter options shown above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fairest test is your own data. Run the same set of representative images through both and compare what decodes and how much code each one took.&lt;/p&gt;

&lt;p&gt;Which barcode library are you running in production, and what tipped the decision? We would genuinely like to hear which one held up on your worst scans in the comments.&lt;/p&gt;

&lt;p&gt;If your worst scans are the problem, you can put IronBarcode against your own images with the &lt;a href="https://ironsoftware.com/csharp/barcode/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ZXing and ZXing.NET are trademarks of their respective owners; this comparison reflects publicly available information at the time of writing.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>barcode</category>
      <category>programming</category>
    </item>
    <item>
      <title>ZXing.NET vs IronBarcode: Pick a .NET Barcode Library</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Tue, 30 Jun 2026 17:38:03 +0000</pubDate>
      <link>https://dev.to/ironsoftware/zxingnet-vs-ironbarcode-pick-a-net-barcode-library-a8</link>
      <guid>https://dev.to/ironsoftware/zxingnet-vs-ironbarcode-pick-a-net-barcode-library-a8</guid>
      <description>&lt;h1&gt;
  
  
  ZXing.NET vs IronBarcode: Picking a Barcode Library for .NET
&lt;/h1&gt;

&lt;p&gt;Choosing a barcode library for a .NET project usually comes down to a few questions: which formats do you need, how clean are your input images, and how much budget do you have. We looked at two options that come up constantly in .NET barcode discussions: ZXing.NET and IronBarcode.&lt;/p&gt;

&lt;p&gt;Full disclosure: we're the team behind IronBarcode, one of the two libraries here. We've tried to keep this fair and flag where ZXing.NET is the better pick, so judge the code and the tradeoffs yourself.&lt;/p&gt;

&lt;p&gt;Here's what we found: both are real, working choices, and the right one depends on your situation more than on any feature checklist. ZXing.NET is free, open-source, and mature. IronBarcode trades that open-source freedom for a higher-level .NET API and built-in handling of messy real-world images. Let's look at the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  ZXing.NET
&lt;/h2&gt;

&lt;p&gt;ZXing.NET is the .NET port of the Java ZXing library ("Zebra Crossing"). It's open-source under Apache 2.0, which means it's free to use, modify, and ship commercially with attribution. It decodes and generates a wide list of 1D and 2D formats: QR Code, Data Matrix, Aztec, PDF 417, Code 128, Code 93, UPC-A/E, EAN-8/13, Codabar, and more. It has been around for years and has a large community, so most problems you hit already have an answer somewhere.&lt;/p&gt;

&lt;p&gt;You install it from NuGet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package ZXing.Net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating a code
&lt;/h3&gt;

&lt;p&gt;To produce a QR code you set up a writer, generate pixel data, and turn that into an image yourself. Here's a condensed version:&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;ZXing&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;ZXing.QrCode&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;ZXing.Common&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;qrWriter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BarcodeWriterPixelData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QR_CODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;EncodingOptions&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;250&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="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Margin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;PixelData&lt;/span&gt; &lt;span class="n"&gt;pixelData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// pixelData.Pixels is a BGRA byte array you then copy into a Bitmap and save.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reading a code
&lt;/h3&gt;

&lt;p&gt;Reading is similar: load a bitmap, hand it to the reader, and inspect the result.&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;ZXing&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;System&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;System.Drawing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;barcodeReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sourceBitmap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bitmap&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;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample-barcode-image.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Result&lt;/span&gt; &lt;span class="n"&gt;decodeResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;barcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceBitmap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decodeResult&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&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;decodeResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BarcodeFormat&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;": "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;decodeResult&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prints the format and decoded text, or skips the block when nothing decodes. The tradeoff here is that you're closer to the metal. On a clean, machine-generated image this works well and costs nothing. ZXing.NET also leans on &lt;code&gt;System.Drawing&lt;/code&gt;, so on .NET Core and later you often add a bindings package for image handling, and the decoder is sensitive to skew, rotation, and noise.&lt;/p&gt;

&lt;p&gt;✅ If your inputs are clean barcodes and your budget is zero, ZXing.NET is often the right call, and for plenty of projects it's the one we'd reach for too. The project lives at &lt;a href="https://github.com/micjahn/ZXing.Net" rel="noopener noreferrer"&gt;github.com/micjahn/ZXing.Net&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  IronBarcode
&lt;/h2&gt;

&lt;p&gt;IronBarcode is a commercial .NET library with a higher-level API for reading and writing barcodes. It targets .NET Standard and Core 2.0+ across Windows, Linux, macOS, and Azure, and supports the same broad set of 1D/2D formats plus styled QR codes with logos and color. The difference you pay for is the layer on top: a simpler API and built-in correction for imperfect images.&lt;/p&gt;

&lt;p&gt;Installation is a single NuGet package, and you can run the snippets below in about five minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package BarCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating a code
&lt;/h3&gt;

&lt;p&gt;A barcode or QR code is one statement to create, and saving to common formats is built in:&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;IronBarCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Code 128 barcode&lt;/span&gt;
&lt;span class="n"&gt;BarcodeWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBarcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://ironsoftware.com/csharp/barcode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BarcodeEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsPng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyBarCode.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// QR code with a chosen error-correction level&lt;/span&gt;
&lt;span class="n"&gt;QRCodeWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateQrCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QRCodeWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QrErrorCorrectionLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Medium&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsPng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyQR.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reading a code
&lt;/h3&gt;

&lt;p&gt;Reading a clean barcode is one call. &lt;code&gt;Read&lt;/code&gt; returns a collection of &lt;code&gt;BarcodeResult&lt;/code&gt;, so take the first match and read its &lt;code&gt;.Value&lt;/code&gt;:&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;IronBarCode&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;System&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;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;firstResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GetStarted.png"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstResult&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&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="s"&gt;"Read value: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;firstResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part that justifies the cost is reading from imperfect sources: skewed, rotated, or noisy images such as phone photos and scans. You can pass correction settings and a specific format to steer the reader:&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;IronBarCode&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;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;photoResults&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"Photo.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BarcodeReaderOptions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ExpectBarcodeTypes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Speed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ReadingSpeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Detailed&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;barcode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;photoResults&lt;/span&gt;&lt;span class="p"&gt;)&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;barcode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IronBarcode also reads barcodes directly from PDF documents and multi-frame TIFFs without you splitting pages first, and it can stamp generated barcodes onto existing PDFs. The tradeoff is honest: it's a paid, closed-source library rather than free and open-source. If your images are predictable and clean, that preprocessing buys you little. If you're pulling barcodes off real-world scans and want to stay inside a single .NET API, it removes work you'd otherwise write yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they compare
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;ZXing.NET&lt;/th&gt;
&lt;th&gt;IronBarcode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read / write&lt;/td&gt;
&lt;td&gt;✅ Both&lt;/td&gt;
&lt;td&gt;✅ Both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Symbologies&lt;/td&gt;
&lt;td&gt;QR, Data Matrix, Aztec, PDF 417, Code 128/93, UPC, EAN, Codabar, more&lt;/td&gt;
&lt;td&gt;Same broad 1D and 2D set, plus styled QR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API style&lt;/td&gt;
&lt;td&gt;Lower-level, you assemble images&lt;/td&gt;
&lt;td&gt;High-level .NET, one call to generate or read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image preprocessing&lt;/td&gt;
&lt;td&gt;You handle skew/noise yourself&lt;/td&gt;
&lt;td&gt;Built-in rotation and noise correction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF / multi-frame TIFF&lt;/td&gt;
&lt;td&gt;Manual extraction&lt;/td&gt;
&lt;td&gt;Read directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image stack&lt;/td&gt;
&lt;td&gt;Often needs a System.Drawing bindings package&lt;/td&gt;
&lt;td&gt;Self-contained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET targets&lt;/td&gt;
&lt;td&gt;.NET Standard / Core / Framework (+ binding)&lt;/td&gt;
&lt;td&gt;.NET Standard / Core 2.0+, Windows, Linux, macOS, Azure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Apache 2.0, free, open-source&lt;/td&gt;
&lt;td&gt;Commercial, paid, closed-source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Large community, tracks Java upstream&lt;/td&gt;
&lt;td&gt;Commercial support and docs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few honest takeaways. On price and openness, ZXing.NET wins outright: it's free, the source is right there, and it's backed by years of community use. IronBarcode's advantage is narrower and specific: a single-package install, a simpler API, and correction for messy inputs. For a use case with clean inputs and no budget, ZXing.NET might actually be the better choice, and we'd say so plainly.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one?
&lt;/h2&gt;

&lt;p&gt;There's no single winner here, and we'd be skeptical of any comparison that declared one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Pick &lt;strong&gt;ZXing.NET&lt;/strong&gt; if you want free, open-source code, a mature community, and your barcode images are clean and machine-generated.&lt;/li&gt;
&lt;li&gt;✅ Pick &lt;strong&gt;IronBarcode&lt;/strong&gt; if you're staying inside .NET, your inputs are noisy scans or photos that need correction, and you'd trade a license fee for a single install and a higher-level API. The &lt;a href="https://ironsoftware.com/csharp/barcode/tutorials/reading-barcodes/" rel="noopener noreferrer"&gt;IronBarcode reading and writing tutorial&lt;/a&gt; shows the PDF and correction paths end to end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fairest test is your own data. Run the same set of representative images through both and compare what decodes and how long it takes.&lt;/p&gt;

&lt;p&gt;Which barcode library are you running in production, and what made you pick it? We'd genuinely like to hear which won on your images in the comments.&lt;/p&gt;

&lt;p&gt;If you want to put IronBarcode against ZXing.NET on your own files first, there's a &lt;a href="https://ironsoftware.com/csharp/barcode/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ZXing and ZXing.NET are trademarks of their respective owners; this comparison reflects publicly available information at the time of writing.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>barcode</category>
      <category>programming</category>
    </item>
    <item>
      <title>ZXing Decoder Online vs IronBarcode in .NET</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Tue, 30 Jun 2026 00:06:49 +0000</pubDate>
      <link>https://dev.to/ironsoftware/zxing-decoder-online-vs-ironbarcode-in-net-59oo</link>
      <guid>https://dev.to/ironsoftware/zxing-decoder-online-vs-ironbarcode-in-net-59oo</guid>
      <description>&lt;h1&gt;
  
  
  ZXing Decoder Online vs IronBarcode: When Do You Actually Need a .NET Library?
&lt;/h1&gt;

&lt;p&gt;If you have a single QR code image on your desktop and you want to know what it says, the answer is almost never "write code." Open &lt;a href="https://zxing.org" rel="noopener noreferrer"&gt;ZXing Decoder Online&lt;/a&gt;, upload the file, read the text. Done in ten seconds, nothing installed, nothing to license. So why does a .NET barcode library exist at all?&lt;/p&gt;

&lt;p&gt;Full disclosure: we build IronBarcode at Iron Software, so we're not neutral. We'll be straight about when a free online decoder is all you need, and the honest answer is that it covers more cases than vendors like us tend to admit. The real split here isn't quality. It's use case: a manual web tool versus a programmatic library you embed in an app to read codes automatically, in bulk, from messy sources.&lt;/p&gt;

&lt;p&gt;Here's what we found. The ZXing project gives you two distinct things that often get lumped together, and keeping them separate is half the battle. There's the website at zxing.org for checking a single image by hand, and there's the open-source &lt;a href="https://github.com/zxing/zxing" rel="noopener noreferrer"&gt;ZXing library&lt;/a&gt; (and its .NET port, ZXing.NET) that you call from code. Both are free. Here's the ZXing.NET decode in C#:&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;ZXing&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;ZXing.QrCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;BarcodeReader&lt;/span&gt; &lt;span class="n"&gt;barcodeReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Result&lt;/span&gt; &lt;span class="n"&gt;decodeResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;barcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceBitmap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;decodedText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeResult&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;That's the whole pitch for the library side, and for a lot of projects it's genuinely enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ZXing Decoder Online tool
&lt;/h2&gt;

&lt;p&gt;The website is the part people reach for first, and rightly so. You visit zxing.org, choose a file or paste an image URL, submit, and it shows the decoded contents along with the format and raw bytes. It reads 1D and 2D formats, it's instant, and there is nothing to install or pay for.&lt;/p&gt;

&lt;p&gt;✅ For manual, occasional work we'd point you straight at this tool, and we won't pretend otherwise. Debugging a single QR code a teammate sent you, checking what a printed label encodes, sanity-checking one image during development. Reaching for a NuGet package and a build step there would be more work, not less, and we've watched plenty of developers over-engineer exactly this.&lt;/p&gt;

&lt;p&gt;The limits show up the moment the task stops being manual. The website can't run inside your application. You can't point it at a folder of 5,000 scans, hand it a 40-page PDF, or call it from a nightly job. It's a person clicking a button, one image at a time. That's a feature for its purpose, not a flaw, but it's also exactly where a library starts to matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ZXing library in code
&lt;/h2&gt;

&lt;p&gt;If you want decoding inside your own app, ZXing.NET is the free, open-source option, and it's a solid one. It's been around for years, has a large community, and ships under a permissive license. You generate and read codes directly:&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;ZXing&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;ZXing.QrCode&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;System.Drawing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;BarcodeWriter&lt;/span&gt; &lt;span class="n"&gt;barcodeWriter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BarcodeWriter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QR_CODE&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;Bitmap&lt;/span&gt; &lt;span class="n"&gt;qrBitmap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;barcodeWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, ZXing!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tradeoff here is what you assemble around it. ZXing.NET works on the bitmap you give it, so you handle image loading, rasterizing PDF pages yourself, and any cleanup when a scan is skewed, low-contrast, or noisy. On clean images it decodes reliably. On the imperfect inputs that real-world scanning produces, you tend to write preprocessing code before the bitmap ever reaches the decoder. For many teams that's an acceptable trade, especially when the budget is zero and the inputs are tidy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where IronBarcode fits
&lt;/h2&gt;

&lt;p&gt;IronBarcode is a commercial .NET library. That's the honest headline difference from ZXing.NET, and we'll lead with it: it costs money where ZXing is free. So the question we'd ask is what you get for that, and whether it matches your problem.&lt;/p&gt;

&lt;p&gt;Installation is one command, and the snippets below run in about five minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Install-Package BarCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generating a code is one line, and reading one back is two:&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;IronBarCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;BarcodeWriter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBarcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, IronBarcode!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BarcodeEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QRCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;SaveAsPng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"qrcode.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;IronBarCode&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;System&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;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;qrResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BarcodeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"qrcode.png"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&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;qrResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice there's no separate image-loading step and no format argument required. You point it at a file and read the value. What you're paying for is the layer around the decoder. IronBarcode reads barcodes directly from PDFs, multi-frame TIFFs, and common image formats, and it applies its own correction for rotation, low resolution, and noise so you don't hand-write that cleanup. It handles batch input across many files and supports the 1D and 2D formats you'd expect, including QR, Code 128, Code 39, EAN, UPC, PDF417, and Data Matrix.&lt;/p&gt;

&lt;p&gt;That's the use case we see it built for: programmatic reading inside a .NET app, at volume, from sources that aren't pristine. We'd be the first to say it's not a replacement for the zxing.org website, and it's not trying to be a cheaper ZXing.NET. It's a paid alternative aimed squarely at the automated-pipeline problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the three compare
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;ZXing Decoder Online&lt;/th&gt;
&lt;th&gt;ZXing.NET&lt;/th&gt;
&lt;th&gt;IronBarcode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read / decode&lt;/td&gt;
&lt;td&gt;✅ Manual, one image&lt;/td&gt;
&lt;td&gt;✅ In code&lt;/td&gt;
&lt;td&gt;✅ In code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write / generate&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Symbologies&lt;/td&gt;
&lt;td&gt;1D and 2D&lt;/td&gt;
&lt;td&gt;1D and 2D&lt;/td&gt;
&lt;td&gt;QR, Code 128, Code 39, EAN, UPC, PDF417, Data Matrix, more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image preprocessing&lt;/td&gt;
&lt;td&gt;None needed (human-driven)&lt;/td&gt;
&lt;td&gt;Manual, you write it&lt;/td&gt;
&lt;td&gt;Built-in rotation and noise correction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read from PDF / batch&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;Manual rasterization&lt;/td&gt;
&lt;td&gt;✅ Direct, batched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET targets&lt;/td&gt;
&lt;td&gt;N/A (web tool)&lt;/td&gt;
&lt;td&gt;.NET Standard / Core / Framework (+ binding)&lt;/td&gt;
&lt;td&gt;.NET Standard / Core 2.0+, Windows, Linux, macOS, Azure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Free, hosted&lt;/td&gt;
&lt;td&gt;Apache 2.0, free, open source&lt;/td&gt;
&lt;td&gt;Commercial, paid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Hosted by ZXing project&lt;/td&gt;
&lt;td&gt;Community cadence&lt;/td&gt;
&lt;td&gt;Commercial release cadence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  So which should you use?
&lt;/h2&gt;

&lt;p&gt;There's no single winner, and we'd distrust any comparison that pretended there was. It comes down to what you're actually doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Reach for &lt;strong&gt;ZXing Decoder Online&lt;/strong&gt; for one-off, manual decoding. It's free, instant, install-free, and the right call when a human is checking a single image.&lt;/li&gt;
&lt;li&gt;✅ Reach for the &lt;strong&gt;ZXing.NET library&lt;/strong&gt; when you need decoding in code, your inputs are reasonably clean, and you want a free, open-source dependency you can read and modify.&lt;/li&gt;
&lt;li&gt;✅ Reach for &lt;strong&gt;IronBarcode&lt;/strong&gt; when you're reading codes programmatically in .NET in high volume, from PDFs and imperfect scans, and a single-package install with built-in image correction is worth a license fee. The &lt;a href="https://ironsoftware.com/csharp/barcode/tutorials/reading-barcodes/" rel="noopener noreferrer"&gt;IronBarcode barcode reading tutorial&lt;/a&gt; shows the PDF and batch paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cutoff that matters is manual versus automated. If a person is decoding one image, the website wins and nothing we sell changes that. If your application is reading many codes from unpredictable sources without anyone clicking a button, that's where a library, free or paid, starts to pull its weight.&lt;/p&gt;

&lt;p&gt;The fairest test is your own data. Take a representative batch of the images you actually deal with, run them through ZXing.NET and IronBarcode, and compare what decodes and how much glue code each one needed.&lt;/p&gt;

&lt;p&gt;Do you reach for an online decoder or a library when you need to read codes, and where's your cutoff? We'd like to hear where the line falls for you in the comments.&lt;/p&gt;

&lt;p&gt;If your cutoff lands on the library side, you can test IronBarcode on your own files with the &lt;a href="https://ironsoftware.com/csharp/barcode/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ZXing is a trademark of its respective owner; this comparison reflects publicly available information at the time of writing.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>barcode</category>
      <category>programming</category>
    </item>
    <item>
      <title>Tesseract OCR in C#: Setup Pain and an Alternative</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Sat, 20 Jun 2026 01:46:53 +0000</pubDate>
      <link>https://dev.to/ironsoftware/tesseract-ocr-in-c-setup-pain-and-an-alternative-2e57</link>
      <guid>https://dev.to/ironsoftware/tesseract-ocr-in-c-setup-pain-and-an-alternative-2e57</guid>
      <description>&lt;h1&gt;
  
  
  Tesseract OCR in C#: Setup Pain and an Alternative
&lt;/h1&gt;

&lt;p&gt;If you've tried wiring Tesseract into a .NET app, you already know the first hour rarely goes to actual OCR. It goes to native binaries, C++ runtimes, and figuring out why the build that worked on your machine breaks in CI. Tesseract is a genuinely good engine, but the path from "free download" to "running in production" is bumpier than most tutorials admit.&lt;/p&gt;

&lt;p&gt;Quick disclosure: we work on IronOCR at Iron Software, so we have a horse in this race. We'll be straight about where vanilla Tesseract is the right call and where it turns into a maintenance tax. If this reads like a sales pitch, tell us in the comments and we'll tighten it up.&lt;/p&gt;

&lt;p&gt;Here's the one-liner version of what we're comparing against, so you can see the shape of the API before we get into the weeds:&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"image.png"&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;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;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That runs on Windows, Linux, and macOS from the same NuGet package, with no native install step. The rest of this post walks through three places where that difference actually matters: setup, accuracy on messy scans, and cross-platform deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and installation
&lt;/h2&gt;

&lt;p&gt;This is where most teams lose the most time, so we'll start here.&lt;/p&gt;

&lt;p&gt;Raw Tesseract in C# means dealing with the C++ side of the engine. You're matching platform-specific binaries, making sure the Visual C++ runtime is present, and juggling 32-bit versus 64-bit compatibility. If you want a current Tesseract 5 build on Windows, you're often looking at cross-compiling with MinGW, which frequently doesn't produce a working binary on the first try. The free C# wrappers on GitHub help, but several of them lag behind &lt;a href="https://github.com/tesseract-ocr/tesseract" rel="noopener noreferrer"&gt;the official Tesseract engine&lt;/a&gt;, so you can end up stuck on an older 3.x or 4.x build without meaning to.&lt;/p&gt;

&lt;p&gt;IronOCR takes a different route: one managed package, installed the way you install anything else in .NET.&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;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IronOcr&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No native DLLs to copy, no C++ runtime to chase down, no per-platform configuration. It targets .NET Framework 4.6.2+, .NET Standard 2.0+ (covering .NET 5 through 10), and .NET Core 2.0+, and the dependency resolution is handled by NuGet. The trade-off is honest: it's a commercial library rather than a free one. If your budget line is the only constraint and you have time to fight the toolchain, vanilla Tesseract is a reasonable choice. If your constraint is shipping date, the managed package usually wins back its cost in saved setup hours.&lt;/p&gt;

&lt;p&gt;💡 You can pull IronOcr from NuGet and have the three-line example above running in a few minutes, with no native install step in the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accuracy on real-world scans
&lt;/h2&gt;

&lt;p&gt;Tesseract reads clean, high-resolution, well-aligned text really well. The problems show up the moment your input looks like something a human actually scanned: a slightly rotated page, a phone photo, a low-DPI fax, background speckle from a cheap scanner.&lt;/p&gt;

&lt;p&gt;On those inputs, raw Tesseract output degrades quickly, and the usual fix is to build a preprocessing pipeline in front of it: deskew, denoise, threshold, often with a separate tool like ImageMagick. That's real work, and it tends to be different work for each document type you support.&lt;/p&gt;

&lt;p&gt;IronOCR bundles common preprocessing filters into the input pipeline so you can apply them inline:&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&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;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageIndices&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadImageFrames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"img\example.tiff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageIndices&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeNoise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// removes digital speckle so it isn't read as characters&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Deskew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// corrects rotation before the engine tries to line-segment&lt;/span&gt;
&lt;span class="n"&gt;OcrResult&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;code&gt;DeNoise()&lt;/code&gt; strips scanning artifacts and &lt;code&gt;Deskew()&lt;/code&gt; straightens rotated pages, the two corrections that most often rescue a bad scan. Iron Software claims 99.8 to 100% accuracy on typical business documents with this approach; that's their published figure, not a guarantee for your specific inputs, so benchmark it against your own worst-case pages before you commit.&lt;/p&gt;

&lt;p&gt;The result object also carries per-word confidence scores and layout blocks, which is handy when you want to flag low-confidence fields for human review instead of trusting the whole page blindly. In our experience, that confidence data is what makes OCR safe to put into an automated workflow: you route the clean pages straight through and kick the doubtful ones to a person, rather than discovering a misread invoice total three steps downstream.&lt;/p&gt;

&lt;p&gt;⚠️ One thing we'd push back on, gently: preprocessing is not magic, and neither library reads text that genuinely isn't there. If your source is a 72-DPI screenshot of a screenshot, no amount of &lt;code&gt;DeNoise()&lt;/code&gt; will recover characters that were never captured. The honest framing is that good preprocessing widens the band of inputs that work; it doesn't remove the need for reasonable scan quality.&lt;/p&gt;

&lt;p&gt;If you need a point of comparison for accuracy on hard inputs, &lt;a href="https://cloud.google.com/use-cases/ocr" rel="noopener noreferrer"&gt;Google Cloud Vision OCR&lt;/a&gt; is the usual cloud benchmark. Strong results, but it sends your documents off-machine and bills per request, which rules it out for offline or privacy-sensitive work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-platform deployment
&lt;/h2&gt;

&lt;p&gt;This is the other place native dependencies bite, and it usually bites later, in a deploy pipeline rather than on your laptop.&lt;/p&gt;

&lt;p&gt;With raw Tesseract, every target environment wants its own build. Docker needs a base image with the right libraries baked in. Azure deployments fail when the Visual C++ runtime isn't present. Linux behavior shifts between distributions depending on which packages are available. None of these are unsolvable, but each one is a separate thing to test and maintain.&lt;/p&gt;

&lt;p&gt;Because IronOCR is managed code, the same package runs across the environments teams usually target:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desktop: WPF, WinForms, Console&lt;/li&gt;
&lt;li&gt;Web: ASP.NET Core, Blazor&lt;/li&gt;
&lt;li&gt;Cloud and serverless: Azure Functions, AWS Lambda&lt;/li&gt;
&lt;li&gt;Containers: Docker, Kubernetes&lt;/li&gt;
&lt;li&gt;OS coverage: Windows, macOS (Intel and Apple Silicon), and common Linux distros including Alpine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The library handles the platform differences internally, so you're testing your code rather than your runtime's binary layout. That matters most in serverless setups, where you don't fully control the host: an AWS Lambda or Azure Functions cold start that can't find a native dependency is a frustrating thing to debug from a log stream, and avoiding native dependencies sidesteps the whole category of failure.&lt;/p&gt;

&lt;p&gt;If you do stay on raw Tesseract for deployment, our advice is to pin everything: the engine version, the wrapper version, and the base image, and treat any one of them changing as a thing to retest. Most of the "it worked yesterday" reports we've seen with native OCR trace back to one of those three drifting underneath the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick note on languages
&lt;/h2&gt;

&lt;p&gt;One more practical difference. Managing languages in raw Tesseract means downloading and placing &lt;a href="https://github.com/tesseract-ocr/tessdata" rel="noopener noreferrer"&gt;the tessdata language files&lt;/a&gt; by hand (the full set is around 4GB) with the folder structure and environment paths set exactly right at runtime. IronOCR handles languages as NuGet packages instead:&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;IronOcr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// PM&amp;gt; Install-Package IronOcr.Languages.ChineseSimplified&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;IronTesseract&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="n"&gt;Language&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OcrLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChineseSimplified&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;AddSecondaryLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OcrLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// mixed-language pages read in one pass&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OcrInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"multi-language.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&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;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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="nf"&gt;SaveAsTextFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"results.txt"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You add a language pack the same way you add any dependency, and version compatibility comes along with it. If you want the full setup, the &lt;a href="https://ironsoftware.com/csharp/ocr/docs/" rel="noopener noreferrer"&gt;IronOCR documentation&lt;/a&gt; walks through the language packs and filter options in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tesseract vs IronOCR at a glance
&lt;/h2&gt;

&lt;p&gt;Same engine family underneath, different packaging and tooling around it. Read the rows against your own constraints rather than looking for an overall winner.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Vanilla Tesseract (C# wrapper)&lt;/th&gt;
&lt;th&gt;IronOCR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install&lt;/td&gt;
&lt;td&gt;Native binaries, C++ runtime, per-platform setup&lt;/td&gt;
&lt;td&gt;Single NuGet package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engine version&lt;/td&gt;
&lt;td&gt;Depends on wrapper; several lag behind upstream&lt;/td&gt;
&lt;td&gt;Current Tesseract 5 build bundled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preprocessing&lt;/td&gt;
&lt;td&gt;Build your own, often with ImageMagick&lt;/td&gt;
&lt;td&gt;DeNoise, Deskew, and filters built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Languages&lt;/td&gt;
&lt;td&gt;Manual tessdata files (~4GB full set)&lt;/td&gt;
&lt;td&gt;NuGet language packs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-platform&lt;/td&gt;
&lt;td&gt;Separate build per OS / container&lt;/td&gt;
&lt;td&gt;Same package on Windows, macOS, Linux, Alpine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Apache 2.0, free&lt;/td&gt;
&lt;td&gt;Commercial, paid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;You pin and retest engine + wrapper + image&lt;/td&gt;
&lt;td&gt;Handled inside the package&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  So which one should you reach for?
&lt;/h2&gt;

&lt;p&gt;Vanilla Tesseract earns its place on research projects, proofs of concept, and pipelines where you control the input quality and have time to tune the toolchain. It's free, the license is permissive, and the engine is solid. If cost is the hard constraint and setup time is cheap for you, it's the right call.&lt;/p&gt;

&lt;p&gt;IronOCR makes more sense when you're shipping to production against real-world document quality, deploying across several platforms, or working to a deadline where setup time is a cost you can't absorb.&lt;/p&gt;

&lt;p&gt;What's your experience been? If you've got a Tesseract setup that runs cleanly in Docker or CI, drop your approach in the comments; the configs people share for native OCR are usually more useful than any official doc. And if you've hit the cross-platform wall, tell us where it broke; we'd like to hear it.&lt;/p&gt;

&lt;p&gt;If you want to test against your own documents first, &lt;a href="https://ironsoftware.com/csharp/ocr/" rel="noopener noreferrer"&gt;IronOCR has a free trial&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>ocr</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
