Dynamsoft OCR SDK vs IronOCR: .NET OCR Library
Dynamsoft Label Recognizer does one thing exceptionally well — MRZ extraction from passports, VIN scanning from vehicles, and structured label reading from industrial packaging — and refuses to do anything else. That narrow expertise becomes a budget problem the moment your application needs general document OCR alongside it, because then you are licensing Dynamsoft Label Recognizer for MRZ, Dynamsoft Barcode Reader for QR codes, Dynamsoft Document Normalizer for edge detection, and still hunting for a fourth library to handle full-page documents. IronOCR covers every one of those capabilities in a single NuGet package at $999 perpetual.
Understanding Dynamsoft Label Recognizer
Dynamsoft Corporation, headquartered in Vancouver, Canada, built its Label Recognizer product around a specific proposition: reliable recognition of machine-readable structured text in constrained formats. The product NuGet package is Dynamsoft.DotNet.LabelRecognizer, and its commercial licensing operates exclusively on annual subscriptions — no perpetual option exists. Contact Dynamsoft for current pricing.
The library's recognition model is template-driven. You configure recognition tasks through a JSON settings API (AppendSettingsFromString) and then call RecognizeFile or RecognizeByFile against image files. Results come back as collections of line results containing raw text strings. Parsing those strings into meaningful structured data — field offsets, date conversions, check digit validation — is entirely your responsibility.
Key architectural characteristics of Dynamsoft Label Recognizer:
- Template-based recognition engine: MRZ, VIN, and label patterns require JSON template configuration before recognition
- Raw text output only:
RecognizeFilereturnsLineResultobjects with text strings; no structured field parsing - Image-only input: No native PDF support; PDFs require external conversion to images before processing
- Annual subscription licensing: Per-device and per-server tiers available; contact Dynamsoft for current pricing; no one-time purchase
- Separate product per capability: Barcode reading, document normalization, and camera optimization each require a separately licensed product
- Limited language coverage: Focused on Latin-character MRZ formats; lacks broad multilingual document support
The JSON Runtime Settings API
Every Dynamsoft Label Recognizer workflow begins with a template configuration step. MRZ recognition, for example, requires loading a JSON document that declares recognition parameters, character models, and region references before any image processing can occur:
using Dynamsoft.DLR;
public class DynamsoftMrzService : IDisposable
{
private readonly LabelRecognizer _recognizer;
public DynamsoftMrzService(string licenseKey)
{
// Static license initialization — must precede instance creation
LabelRecognizer.InitLicense(licenseKey);
_recognizer = new LabelRecognizer();
// MRZ requires specific template configuration loaded as JSON
string mrzTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""MRZ"",
""ReferenceRegionNameArray"": [""FullImage""],
""CharacterModelName"": ""MRZ""
}]
}";
_recognizer.AppendSettingsFromString(mrzTemplate);
}
public string ExtractRawMrz(string passportImagePath)
{
var results = _recognizer.RecognizeFile(passportImagePath);
// Returns raw MRZ text lines only — no field parsing
var mrzLines = new StringBuilder();
foreach (var result in results)
{
foreach (var lineResult in result.LineResults)
{
mrzLines.AppendLine(lineResult.Text);
}
}
return mrzLines.ToString().Trim();
}
public void Dispose() => _recognizer?.Dispose();
}
using Dynamsoft.DLR;
public class DynamsoftMrzService : IDisposable
{
private readonly LabelRecognizer _recognizer;
public DynamsoftMrzService(string licenseKey)
{
// Static license initialization — must precede instance creation
LabelRecognizer.InitLicense(licenseKey);
_recognizer = new LabelRecognizer();
// MRZ requires specific template configuration loaded as JSON
string mrzTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""MRZ"",
""ReferenceRegionNameArray"": [""FullImage""],
""CharacterModelName"": ""MRZ""
}]
}";
_recognizer.AppendSettingsFromString(mrzTemplate);
}
public string ExtractRawMrz(string passportImagePath)
{
var results = _recognizer.RecognizeFile(passportImagePath);
// Returns raw MRZ text lines only — no field parsing
var mrzLines = new StringBuilder();
foreach (var result in results)
{
foreach (var lineResult in result.LineResults)
{
mrzLines.AppendLine(lineResult.Text);
}
}
return mrzLines.ToString().Trim();
}
public void Dispose() => _recognizer?.Dispose();
}
Imports Dynamsoft.DLR
Imports System.Text
Public Class DynamsoftMrzService
Implements IDisposable
Private ReadOnly _recognizer As LabelRecognizer
Public Sub New(licenseKey As String)
' Static license initialization — must precede instance creation
LabelRecognizer.InitLicense(licenseKey)
_recognizer = New LabelRecognizer()
' MRZ requires specific template configuration loaded as JSON
Dim mrzTemplate As String = "{
""LabelRecognizerParameterArray"": [{
""Name"": ""MRZ"",
""ReferenceRegionNameArray"": [""FullImage""],
""CharacterModelName"": ""MRZ""
}]
}"
_recognizer.AppendSettingsFromString(mrzTemplate)
End Sub
Public Function ExtractRawMrz(passportImagePath As String) As String
Dim results = _recognizer.RecognizeFile(passportImagePath)
' Returns raw MRZ text lines only — no field parsing
Dim mrzLines As New StringBuilder()
For Each result In results
For Each lineResult In result.LineResults
mrzLines.AppendLine(lineResult.Text)
Next
Next
Return mrzLines.ToString().Trim()
End Function
Public Sub Dispose() Implements IDisposable.Dispose
_recognizer?.Dispose()
End Sub
End Class
The output of RecognizeFile is raw MRZ text such as P<GBRSMITH<<JOHN<<<<<<<<<<<<<<<<<<<<<<<<<<<. To get Surname = "SMITH", GivenNames = "JOHN", DocumentNumber, DateOfBirth, and ExpiryDate as typed properties, you implement a TD1/TD2/TD3 parser yourself. The Dynamsoft documentation and source files in this repository estimate that parser at approximately 150 lines of parsing code — handling character offsets, << name separators, two-digit year disambiguation, and check digit validation — none of which Dynamsoft provides.
Understanding IronOCR
IronOCR is a commercial .NET OCR library built on an optimized Tesseract 5 engine with a managed API layer that handles preprocessing, input formats, structured output, and specialized document parsing. Installation is a single NuGet command: dotnet add package IronOcr. No native binary management, no tessdata folder setup, no template configuration files.
Key characteristics:
- General-purpose and specialist: Handles full-page document OCR, multi-page PDFs, scanned image batches, and specialized formats (passports, barcodes, license plates) from the same package
- Automatic preprocessing pipeline: Deskew, DeNoise, Contrast, Binarize, and EnhanceResolution run without manual configuration on poor-quality inputs
- Native PDF support: Read scanned and digital PDFs directly, including password-protected files, without external conversion steps
- Structured output hierarchy: Results expose Pages, Paragraphs, Lines, Words, and character bounding boxes with confidence scores
- Built-in barcode reading: Enable
ocr.Configuration.ReadBarCodes = trueand barcodes are extracted alongside text in the same pass - 125+ language packs: Each language installs as a separate NuGet package; no tessdata folder management required
- Perpetual licensing: $999 Lite, $1,499 Plus, $2,999 Professional — one-time purchase, all platforms, all features included
- Cross-platform deployment: Windows, Linux, macOS, Docker, AWS, and Azure all work from the same package with no platform-specific configuration
Feature Comparison
| Feature | Dynamsoft Label Recognizer | IronOCR |
|---|---|---|
| General document OCR | Not supported | Full support |
| MRZ extraction | Specialized (raw text) | Built-in with parsed fields |
| Native PDF input | Not supported | Yes |
| Barcode reading | Separate product (Dynamsoft Barcode Reader) | Built-in (ReadBarCodes) |
| Searchable PDF output | Not supported | Yes |
| Language support | Limited (Latin MRZ) | 125+ languages |
| Licensing model | Annual subscription only | Perpetual + subscription options |
| Products required for full coverage | 3+ | 1 |
Detailed Feature Comparison
| Feature | Dynamsoft Label Recognizer | IronOCR |
|---|---|---|
| Recognition Scope | ||
| General document OCR | Not supported | Yes |
| MRZ recognition | Specialized | Yes (ReadPassport) |
| VIN recognition | Specialized | Yes (via standard OCR) |
| Industrial label reading | Specialized | Yes |
| Handwriting recognition | Not supported | Yes |
| Table extraction | Not supported | Yes |
| Input Formats | ||
| Image files (JPG, PNG, TIFF) | Yes | Yes |
| PDF (native) | Not supported | Yes |
| Password-protected PDF | Not supported | Yes |
| Byte array / stream | Yes | Yes |
| Multi-page documents | Manual aggregation | Yes (native) |
| Output Formats | ||
| Plain text | Yes (raw lines) | Yes |
| Structured fields (parsed) | Not provided | Yes (Pages, Lines, Words) |
| Searchable PDF | Not supported | Yes |
| hOCR | Not supported | Yes |
| Confidence scores | Per-line | Per word, line, and page |
| Preprocessing | ||
| Automatic preprocessing | Basic | Yes (intelligent pipeline) |
| Deskew / rotation correction | Limited | Yes |
| Noise removal | Limited | Yes |
| Contrast enhancement | Limited | Yes |
| DPI normalization | Not provided | Yes |
| Integration Capabilities | ||
| Barcode reading | Separate product | Built-in |
| Document normalization | Separate product | Not required |
| Region-based OCR | Yes (via templates) | Yes (CropRectangle) |
| Thread-safe parallel processing | Yes | Yes |
| Platform and Deployment | ||
| Windows | Yes | Yes |
| Linux | Yes | Yes |
| macOS | Yes | Yes |
| Docker | Yes | Yes |
| Azure / AWS | Yes | Yes |
| Air-gapped / offline | Yes | Yes |
| Licensing and Cost | ||
| Annual subscription | Yes (contact Dynamsoft for pricing) | Optional |
| Perpetual license | Not available | Yes ($999 one-time) |
| Single package for all features | No (3+ products) | Yes |
| Free trial | 30 days | Yes |
Specialist vs. Generalist Scope
The single most important architectural decision Dynamsoft made is to build a specialist, not a generalist. That decision has direct consequences for any application that starts with MRZ or label reading but eventually needs more.
Dynamsoft Approach
Dynamsoft Label Recognizer handles exactly what its JSON templates describe and nothing beyond. A passport processing application built on Dynamsoft needs three products before it can handle a real-world document workflow:
// Dynamsoft passport processing — MULTIPLE PRODUCTS REQUIRED
using Dynamsoft.DLR; // Label Recognizer — for MRZ (annual subscription)
using Dynamsoft.DBR; // Barcode Reader — for any barcodes (additional license)
// Plus: a separate OCR library — for full page text (more budget)
public class DynamsoftPassportProcessor : IDisposable
{
private readonly LabelRecognizer _mrzRecognizer;
private readonly BarcodeReader _barcodeReader;
// private readonly SomeOtherOcrLibrary _fullTextOcr; // third product
public DynamsoftPassportProcessor(
string mrzLicenseKey,
string barcodeLicenseKey)
{
// License each product independently
LabelRecognizer.InitLicense(mrzLicenseKey);
_mrzRecognizer = new LabelRecognizer();
// Configure MRZ template — JSON required before any recognition
string mrzTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""MRZ_Passport"",
""ReferenceRegionNameArray"": [""FullImage""],
""CharacterModelName"": ""MRZ""
}]
}";
_mrzRecognizer.AppendSettingsFromString(mrzTemplate);
// Second product, second license key
BarcodeReader.InitLicense(barcodeLicenseKey);
_barcodeReader = new BarcodeReader();
}
public PassportResult ProcessPassport(string imagePath)
{
// Step 1: MRZ extraction — raw text only, no field parsing
var mrzResults = _mrzRecognizer.RecognizeFile(imagePath);
var mrzText = new StringBuilder();
foreach (var r in mrzResults)
foreach (var line in r.LineResults)
mrzText.AppendLine(line.Text);
// Step 2: Parse MRZ manually — your 150-line TD3 parser here
var parsedMrz = ParseMrzManually(mrzText.ToString());
// Step 3: Barcodes — second product, second API
var barcodeResults = _barcodeReader.DecodeFile(imagePath);
// Step 4: Full page text — THIRD library, no Dynamsoft option
// var fullText = _fullTextOcr.ReadImage(imagePath);
return new PassportResult
{
ParsedMrz = parsedMrz,
Barcodes = barcodeResults.Select(b => b.BarcodeText).ToList(),
FullPageText = null // requires a fourth product
};
}
public void Dispose()
{
_mrzRecognizer?.Dispose();
_barcodeReader?.Dispose();
}
}
// Dynamsoft passport processing — MULTIPLE PRODUCTS REQUIRED
using Dynamsoft.DLR; // Label Recognizer — for MRZ (annual subscription)
using Dynamsoft.DBR; // Barcode Reader — for any barcodes (additional license)
// Plus: a separate OCR library — for full page text (more budget)
public class DynamsoftPassportProcessor : IDisposable
{
private readonly LabelRecognizer _mrzRecognizer;
private readonly BarcodeReader _barcodeReader;
// private readonly SomeOtherOcrLibrary _fullTextOcr; // third product
public DynamsoftPassportProcessor(
string mrzLicenseKey,
string barcodeLicenseKey)
{
// License each product independently
LabelRecognizer.InitLicense(mrzLicenseKey);
_mrzRecognizer = new LabelRecognizer();
// Configure MRZ template — JSON required before any recognition
string mrzTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""MRZ_Passport"",
""ReferenceRegionNameArray"": [""FullImage""],
""CharacterModelName"": ""MRZ""
}]
}";
_mrzRecognizer.AppendSettingsFromString(mrzTemplate);
// Second product, second license key
BarcodeReader.InitLicense(barcodeLicenseKey);
_barcodeReader = new BarcodeReader();
}
public PassportResult ProcessPassport(string imagePath)
{
// Step 1: MRZ extraction — raw text only, no field parsing
var mrzResults = _mrzRecognizer.RecognizeFile(imagePath);
var mrzText = new StringBuilder();
foreach (var r in mrzResults)
foreach (var line in r.LineResults)
mrzText.AppendLine(line.Text);
// Step 2: Parse MRZ manually — your 150-line TD3 parser here
var parsedMrz = ParseMrzManually(mrzText.ToString());
// Step 3: Barcodes — second product, second API
var barcodeResults = _barcodeReader.DecodeFile(imagePath);
// Step 4: Full page text — THIRD library, no Dynamsoft option
// var fullText = _fullTextOcr.ReadImage(imagePath);
return new PassportResult
{
ParsedMrz = parsedMrz,
Barcodes = barcodeResults.Select(b => b.BarcodeText).ToList(),
FullPageText = null // requires a fourth product
};
}
public void Dispose()
{
_mrzRecognizer?.Dispose();
_barcodeReader?.Dispose();
}
}
Imports Dynamsoft.DLR ' Label Recognizer — for MRZ (annual subscription)
Imports Dynamsoft.DBR ' Barcode Reader — for any barcodes (additional license)
' Plus: a separate OCR library — for full page text (more budget)
Public Class DynamsoftPassportProcessor
Implements IDisposable
Private ReadOnly _mrzRecognizer As LabelRecognizer
Private ReadOnly _barcodeReader As BarcodeReader
' Private ReadOnly _fullTextOcr As SomeOtherOcrLibrary ' third product
Public Sub New(mrzLicenseKey As String, barcodeLicenseKey As String)
' License each product independently
LabelRecognizer.InitLicense(mrzLicenseKey)
_mrzRecognizer = New LabelRecognizer()
' Configure MRZ template — JSON required before any recognition
Dim mrzTemplate As String = "{
""LabelRecognizerParameterArray"": [{
""Name"": ""MRZ_Passport"",
""ReferenceRegionNameArray"": [""FullImage""],
""CharacterModelName"": ""MRZ""
}]
}"
_mrzRecognizer.AppendSettingsFromString(mrzTemplate)
' Second product, second license key
BarcodeReader.InitLicense(barcodeLicenseKey)
_barcodeReader = New BarcodeReader()
End Sub
Public Function ProcessPassport(imagePath As String) As PassportResult
' Step 1: MRZ extraction — raw text only, no field parsing
Dim mrzResults = _mrzRecognizer.RecognizeFile(imagePath)
Dim mrzText = New StringBuilder()
For Each r In mrzResults
For Each line In r.LineResults
mrzText.AppendLine(line.Text)
Next
Next
' Step 2: Parse MRZ manually — your 150-line TD3 parser here
Dim parsedMrz = ParseMrzManually(mrzText.ToString())
' Step 3: Barcodes — second product, second API
Dim barcodeResults = _barcodeReader.DecodeFile(imagePath)
' Step 4: Full page text — THIRD library, no Dynamsoft option
' Dim fullText = _fullTextOcr.ReadImage(imagePath)
Return New PassportResult With {
.ParsedMrz = parsedMrz,
.Barcodes = barcodeResults.Select(Function(b) b.BarcodeText).ToList(),
.FullPageText = Nothing ' requires a fourth product
}
End Function
Public Sub Dispose() Implements IDisposable.Dispose
_mrzRecognizer?.Dispose()
_barcodeReader?.Dispose()
End Sub
End Class
The code above still does not handle PDF input. If the passport scan arrives as a PDF rather than a JPEG, you add a PDF rendering library before any of this runs. The total integration for a real passport workflow: four products, four license keys, four maintenance surfaces.
IronOCR Approach
IronOCR handles the same passport workflow — MRZ parsing, full-page OCR, barcodes, and PDF input — from one package:
using IronOcr;
public class IronOcrPassportProcessor
{
private readonly IronTesseract _ocr;
public IronOcrPassportProcessor()
{
_ocr = new IronTesseract();
_ocr.Configuration.ReadBarCodes = true; // barcodes included
}
public CompletePassportResult ProcessPassport(string imagePath)
{
// Structured MRZ fields — no manual parsing required
var mrzData = _ocr.ReadPassport(imagePath);
// Full page OCR + barcodes in the same call
var fullResult = _ocr.Read(imagePath);
return new CompletePassportResult
{
// MRZ fields are already parsed properties
DocumentType = mrzData.DocumentType,
IssuingCountry = mrzData.IssuingCountry,
Surname = mrzData.Surname,
GivenNames = mrzData.GivenNames,
PassportNumber = mrzData.DocumentNumber,
Nationality = mrzData.Nationality,
DateOfBirth = mrzData.DateOfBirth,
ExpiryDate = mrzData.ExpiryDate,
RawMrz = mrzData.MRZ,
// Full page text from same package
FullPageText = fullResult.Text,
// Barcodes alongside text — no separate product
Barcodes = fullResult.Barcodes.Select(b => b.Value).ToList(),
Confidence = fullResult.Confidence
};
}
}
using IronOcr;
public class IronOcrPassportProcessor
{
private readonly IronTesseract _ocr;
public IronOcrPassportProcessor()
{
_ocr = new IronTesseract();
_ocr.Configuration.ReadBarCodes = true; // barcodes included
}
public CompletePassportResult ProcessPassport(string imagePath)
{
// Structured MRZ fields — no manual parsing required
var mrzData = _ocr.ReadPassport(imagePath);
// Full page OCR + barcodes in the same call
var fullResult = _ocr.Read(imagePath);
return new CompletePassportResult
{
// MRZ fields are already parsed properties
DocumentType = mrzData.DocumentType,
IssuingCountry = mrzData.IssuingCountry,
Surname = mrzData.Surname,
GivenNames = mrzData.GivenNames,
PassportNumber = mrzData.DocumentNumber,
Nationality = mrzData.Nationality,
DateOfBirth = mrzData.DateOfBirth,
ExpiryDate = mrzData.ExpiryDate,
RawMrz = mrzData.MRZ,
// Full page text from same package
FullPageText = fullResult.Text,
// Barcodes alongside text — no separate product
Barcodes = fullResult.Barcodes.Select(b => b.Value).ToList(),
Confidence = fullResult.Confidence
};
}
}
Imports IronOcr
Public Class IronOcrPassportProcessor
Private ReadOnly _ocr As IronTesseract
Public Sub New()
_ocr = New IronTesseract()
_ocr.Configuration.ReadBarCodes = True ' barcodes included
End Sub
Public Function ProcessPassport(imagePath As String) As CompletePassportResult
' Structured MRZ fields — no manual parsing required
Dim mrzData = _ocr.ReadPassport(imagePath)
' Full page OCR + barcodes in the same call
Dim fullResult = _ocr.Read(imagePath)
Return New CompletePassportResult With {
' MRZ fields are already parsed properties
.DocumentType = mrzData.DocumentType,
.IssuingCountry = mrzData.IssuingCountry,
.Surname = mrzData.Surname,
.GivenNames = mrzData.GivenNames,
.PassportNumber = mrzData.DocumentNumber,
.Nationality = mrzData.Nationality,
.DateOfBirth = mrzData.DateOfBirth,
.ExpiryDate = mrzData.ExpiryDate,
.RawMrz = mrzData.MRZ,
' Full page text from same package
.FullPageText = fullResult.Text,
' Barcodes alongside text — no separate product
.Barcodes = fullResult.Barcodes.Select(Function(b) b.Value).ToList(),
.Confidence = fullResult.Confidence
}
End Function
End Class
One package, one license key, one API. For the passport reading guide and the barcode reading feature, IronOCR documentation covers both in the same product context because they are the same product.
Multi-Product Cost and Complexity
Building a warehouse inventory scanner demonstrates the cost model divergence most clearly. The system needs to read product labels (text), scan barcodes (QR/EAN), and process attached shipment PDFs. With Dynamsoft, that is three separately licensed products with separate initialization patterns.
Dynamsoft Approach
// Dynamsoft warehouse scanner — THREE products, THREE license keys
using Dynamsoft.DLR; // Label Recognizer — product labels
using Dynamsoft.DBR; // Barcode Reader — product barcodes
using Dynamsoft.DDN; // Document Normalizer — document edge detection
public class DynamsoftWarehouseScanner : IDisposable
{
private readonly LabelRecognizer _labelRecognizer;
private readonly BarcodeReader _barcodeReader;
private readonly DocumentNormalizer _documentNormalizer;
public DynamsoftWarehouseScanner(
string labelLicenseKey,
string barcodeLicenseKey,
string documentLicenseKey)
{
LabelRecognizer.InitLicense(labelLicenseKey);
_labelRecognizer = new LabelRecognizer();
BarcodeReader.InitLicense(barcodeLicenseKey);
_barcodeReader = new BarcodeReader();
DocumentNormalizer.InitLicense(documentLicenseKey);
_documentNormalizer = new DocumentNormalizer();
}
public WarehouseItemResult ScanItem(string imagePath)
{
// Three separate API calls, three result types to aggregate manually
var labelResults = _labelRecognizer.RecognizeFile(imagePath);
var barcodeResults = _barcodeReader.DecodeFile(imagePath);
var docResults = _documentNormalizer.Normalize(imagePath);
// Merge three result sets into one model — your code
return AggregateResults(labelResults, barcodeResults, docResults);
}
public void Dispose()
{
_labelRecognizer?.Dispose();
_barcodeReader?.Dispose();
_documentNormalizer?.Dispose();
}
}
// Dynamsoft warehouse scanner — THREE products, THREE license keys
using Dynamsoft.DLR; // Label Recognizer — product labels
using Dynamsoft.DBR; // Barcode Reader — product barcodes
using Dynamsoft.DDN; // Document Normalizer — document edge detection
public class DynamsoftWarehouseScanner : IDisposable
{
private readonly LabelRecognizer _labelRecognizer;
private readonly BarcodeReader _barcodeReader;
private readonly DocumentNormalizer _documentNormalizer;
public DynamsoftWarehouseScanner(
string labelLicenseKey,
string barcodeLicenseKey,
string documentLicenseKey)
{
LabelRecognizer.InitLicense(labelLicenseKey);
_labelRecognizer = new LabelRecognizer();
BarcodeReader.InitLicense(barcodeLicenseKey);
_barcodeReader = new BarcodeReader();
DocumentNormalizer.InitLicense(documentLicenseKey);
_documentNormalizer = new DocumentNormalizer();
}
public WarehouseItemResult ScanItem(string imagePath)
{
// Three separate API calls, three result types to aggregate manually
var labelResults = _labelRecognizer.RecognizeFile(imagePath);
var barcodeResults = _barcodeReader.DecodeFile(imagePath);
var docResults = _documentNormalizer.Normalize(imagePath);
// Merge three result sets into one model — your code
return AggregateResults(labelResults, barcodeResults, docResults);
}
public void Dispose()
{
_labelRecognizer?.Dispose();
_barcodeReader?.Dispose();
_documentNormalizer?.Dispose();
}
}
Imports Dynamsoft.DLR ' Label Recognizer — product labels
Imports Dynamsoft.DBR ' Barcode Reader — product barcodes
Imports Dynamsoft.DDN ' Document Normalizer — document edge detection
Public Class DynamsoftWarehouseScanner
Implements IDisposable
Private ReadOnly _labelRecognizer As LabelRecognizer
Private ReadOnly _barcodeReader As BarcodeReader
Private ReadOnly _documentNormalizer As DocumentNormalizer
Public Sub New(labelLicenseKey As String, barcodeLicenseKey As String, documentLicenseKey As String)
LabelRecognizer.InitLicense(labelLicenseKey)
_labelRecognizer = New LabelRecognizer()
BarcodeReader.InitLicense(barcodeLicenseKey)
_barcodeReader = New BarcodeReader()
DocumentNormalizer.InitLicense(documentLicenseKey)
_documentNormalizer = New DocumentNormalizer()
End Sub
Public Function ScanItem(imagePath As String) As WarehouseItemResult
' Three separate API calls, three result types to aggregate manually
Dim labelResults = _labelRecognizer.RecognizeFile(imagePath)
Dim barcodeResults = _barcodeReader.DecodeFile(imagePath)
Dim docResults = _documentNormalizer.Normalize(imagePath)
' Merge three result sets into one model — your code
Return AggregateResults(labelResults, barcodeResults, docResults)
End Function
Public Sub Dispose() Implements IDisposable.Dispose
_labelRecognizer?.Dispose()
_barcodeReader?.Dispose()
_documentNormalizer?.Dispose()
End Sub
End Class
Shipment PDFs still require a fourth product — Dynamsoft has no native PDF OCR. Annual licensing for three Dynamsoft products at the per-server tier: $5,997+/year. Add a PDF library and you are at $6,300+/year before a single line of business logic is written.
IronOCR Approach
using IronOcr;
public class IronOcrWarehouseScanner
{
private readonly IronTesseract _ocr;
public IronOcrWarehouseScanner()
{
_ocr = new IronTesseract();
_ocr.Configuration.ReadBarCodes = true; // barcodes in same pass
}
public WarehouseItemResult ScanItem(string imagePath)
{
// One call: text + barcodes + structured word positions
var result = _ocr.Read(imagePath);
return new WarehouseItemResult
{
AllText = result.Text,
Barcodes = result.Barcodes.Select(b => new BarcodeInfo
{ Format = b.Format.ToString(), Value = b.Value }).ToList(),
Confidence = result.Confidence
};
}
public string ScanLabelRegion(string imagePath, int x, int y, int width, int height)
{
// Target a specific label area — no template JSON required
var region = new CropRectangle(x, y, width, height);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
input.Deskew();
input.Contrast();
return _ocr.Read(input).Text;
}
public string ProcessShipmentPdf(string pdfPath)
{
// Native PDF — no external library, no page conversion loop
return _ocr.Read(pdfPath).Text;
}
}
using IronOcr;
public class IronOcrWarehouseScanner
{
private readonly IronTesseract _ocr;
public IronOcrWarehouseScanner()
{
_ocr = new IronTesseract();
_ocr.Configuration.ReadBarCodes = true; // barcodes in same pass
}
public WarehouseItemResult ScanItem(string imagePath)
{
// One call: text + barcodes + structured word positions
var result = _ocr.Read(imagePath);
return new WarehouseItemResult
{
AllText = result.Text,
Barcodes = result.Barcodes.Select(b => new BarcodeInfo
{ Format = b.Format.ToString(), Value = b.Value }).ToList(),
Confidence = result.Confidence
};
}
public string ScanLabelRegion(string imagePath, int x, int y, int width, int height)
{
// Target a specific label area — no template JSON required
var region = new CropRectangle(x, y, width, height);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
input.Deskew();
input.Contrast();
return _ocr.Read(input).Text;
}
public string ProcessShipmentPdf(string pdfPath)
{
// Native PDF — no external library, no page conversion loop
return _ocr.Read(pdfPath).Text;
}
}
Imports IronOcr
Public Class IronOcrWarehouseScanner
Private ReadOnly _ocr As IronTesseract
Public Sub New()
_ocr = New IronTesseract()
_ocr.Configuration.ReadBarCodes = True ' barcodes in same pass
End Sub
Public Function ScanItem(imagePath As String) As WarehouseItemResult
' One call: text + barcodes + structured word positions
Dim result = _ocr.Read(imagePath)
Return New WarehouseItemResult With {
.AllText = result.Text,
.Barcodes = result.Barcodes.Select(Function(b) New BarcodeInfo With {
.Format = b.Format.ToString(),
.Value = b.Value
}).ToList(),
.Confidence = result.Confidence
}
End Function
Public Function ScanLabelRegion(imagePath As String, x As Integer, y As Integer, width As Integer, height As Integer) As String
' Target a specific label area — no template JSON required
Dim region = New CropRectangle(x, y, width, height)
Using input As New OcrInput()
input.LoadImage(imagePath, region)
input.Deskew()
input.Contrast()
Return _ocr.Read(input).Text
End Using
End Function
Public Function ProcessShipmentPdf(pdfPath As String) As String
' Native PDF — no external library, no page conversion loop
Return _ocr.Read(pdfPath).Text
End Function
End Class
For the region-based OCR documentation and PDF input guide, IronOCR covers both without any additional products.
Deployment Model
Both libraries run on-premise with no cloud transmission of document data. The key deployment differences involve initialization patterns, configuration file management, and what each library bundles into its deployment artifact.
Dynamsoft Approach
Dynamsoft requires static initialization calls on the SDK class before creating any instance. Each product has its own initialization pattern, and the license key activates that specific product only. Template configuration files — the JSON settings documents for MRZ, VIN, or custom label patterns — must be present and correctly referenced at runtime. A deployment that includes Label Recognizer and Barcode Reader manages two activation flows, two template sets, and two Dispose chains.
For warehouse or kiosk deployments, the configuration file dependency adds a deployment artifact beyond the binaries. The JSON templates are separate files, not compiled into the package. Misconfigure the template path on a new server and recognition silently returns empty results or throws at runtime during the AppendSettingsFromString call.
IronOCR Approach
IronOCR deploys as a single NuGet package. License activation is a one-line string assignment:
// Application startup — one line, works for all features
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
// Application startup — one line, works for all features
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
' Application startup — one line, works for all features
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
No template files. No native binary management. No tessdata folder. The Docker deployment guide requires only libgdiplus on Linux — one apt-get install line in the Dockerfile.
FROM mcr.microsoft.com/dotnet/aspnet:8.0
RUN apt-get update && apt-get install -y libgdiplus
COPY --from=build /app/publish /app
WORKDIR /app
ENTRYPOINT ["dotnet", "YourApp.dll"]
The same package supports Linux, AWS Lambda, and Azure App Service without platform-specific configuration. For teams running CI/CD pipelines, there are no template files to version-control or artifact-deploy separately.
API Mapping Reference
| Dynamsoft Label Recognizer | IronOCR Equivalent |
|---|---|
LabelRecognizer.InitLicense(key) |
IronOcr.License.LicenseKey = key |
new LabelRecognizer() |
new IronTesseract() |
_recognizer.AppendSettingsFromString(json) |
Not required — engine auto-configured |
_recognizer.RecognizeFile(path) |
ocr.Read(path) |
_recognizer.RecognizeByFile(path, "") |
ocr.Read(path) |
result.LineResults[i].Text |
result.Lines[i].Text |
| Manual TD3 MRZ parser (150+ lines) | ocr.ReadPassport(path).Surname etc. |
BarcodeReader.InitLicense(key) (separate product) |
ocr.Configuration.ReadBarCodes = true |
_barcodeReader.DecodeFile(path) |
result.Barcodes (same call as OCR) |
barcode.BarcodeFormatString |
barcode.Format.ToString() |
barcode.BarcodeText |
barcode.Value |
DocumentNormalizer.InitLicense(key) (separate product) |
Not required |
| No PDF support | ocr.Read("document.pdf") |
| No searchable PDF output | result.SaveAsSearchablePdf(path) |
recognizer.Dispose() |
using var ocr = new IronTesseract() |
When Teams Consider Moving from Dynamsoft to IronOCR
Application Scope Expands Beyond MRZ or Labels
The majority of migrations happen when a project starts narrow — "just read passport MRZ" — and then product requirements arrive. The client wants to archive the scanned passports as searchable PDFs. The compliance team wants to OCR the visa stamps. The support queue has tickets about PDFs that Dynamsoft cannot ingest. At that point, the team is maintaining Dynamsoft for MRZ plus a second OCR library for everything else. Two license agreements, two maintenance tracks, two API patterns in the same codebase. IronOCR handles the original MRZ requirement through ReadPassport() and the expanded requirements through the same IronTesseract instance. Teams moving from a two-library system to one package typically report a 30-40% reduction in integration-layer code.
Annual Subscription Costs Are Not Sustainable
Multi-product Dynamsoft licensing costs compound annually — contact Dynamsoft for current pricing. Over multiple years, the combined annual subscription fees for multiple products can substantially exceed IronOCR's $999 one-time cost. The perpetual licensing model matters most for products with a defined commercial lifetime — a government document processing system that will run for seven years does not want an annual renewal dependency on a specialist vendor for a core component.
PDF Input Is Required
Dynamsoft Label Recognizer has no native PDF support. Every PDF-delivered document requires a preprocessing step: render each page to an image, pass the image through Dynamsoft, collect and reassemble results. That pipeline adds a PDF rendering dependency, a page-iteration loop, and a coordinate-mapping problem if you need to correlate recognition results back to the original PDF geometry. IronOCR reads PDFs natively — ocr.Read("passport-scans.pdf") processes every page, and result.Pages gives you per-page access to text, words, and confidence scores. For teams where 20% or more of inputs arrive as PDFs, the Dynamsoft workaround adds meaningful maintenance burden every time the PDF rendering library updates.
The Multi-Product Integration Tax Is Too High
Every additional Dynamsoft product is a separate static initialization call, a separate Dispose chain, and a separate JSON configuration file to manage. Teams that have integrated three Dynamsoft products report that integration surface is the primary maintenance cost — not the recognition quality. License key rotation, SDK version upgrades, and template file deployment must be coordinated across all three products simultaneously. IronOCR's single-package model means one version to upgrade, one license key to rotate, and one API surface to maintain regardless of how many OCR capabilities the application uses.
International Document Types Are Needed
Dynamsoft Label Recognizer is built around Latin-character MRZ formats per ICAO Doc 9303. Applications processing CJK-language identity documents, Arabic-script passports, or multilingual shipment labels hit language coverage limits quickly. IronOCR ships 125+ language packs as individual NuGet packages — Arabic, Chinese Simplified, Chinese Traditional, Japanese, Korean, and more. Each installs via dotnet add package IronOcr.Languages.Arabic without changing the recognition code. The multiple languages guide covers simultaneous multilingual recognition in a few lines of configuration.
Common Migration Considerations
Replacing the MRZ Parser
The most immediate migration step is replacing the Dynamsoft RecognizeFile + manual TD3 parser combination with ReadPassport. The Dynamsoft extraction path returns raw text like P<GBRSMITH<<JOHN<<<<<<<<<<<<<<<<<<<<<<<<<< and requires 150+ lines of character-offset parsing for TD3 format. The IronOCR replacement:
// Before: Dynamsoft raw extraction + manual 150-line parser
var results = _recognizer.RecognizeFile(imagePath);
var rawMrz = string.Join("\n", results.SelectMany(r => r.LineResults).Select(l => l.Text));
var parsed = MyTd3Parser.Parse(rawMrz); // delete this file
// After: IronOCR parsed output directly
var passportData = new IronTesseract().ReadPassport(imagePath);
string surname = passportData.Surname;
string docNum = passportData.DocumentNumber;
DateTime? dob = passportData.DateOfBirth;
// Before: Dynamsoft raw extraction + manual 150-line parser
var results = _recognizer.RecognizeFile(imagePath);
var rawMrz = string.Join("\n", results.SelectMany(r => r.LineResults).Select(l => l.Text));
var parsed = MyTd3Parser.Parse(rawMrz); // delete this file
// After: IronOCR parsed output directly
var passportData = new IronTesseract().ReadPassport(imagePath);
string surname = passportData.Surname;
string docNum = passportData.DocumentNumber;
DateTime? dob = passportData.DateOfBirth;
Imports System
Imports System.Linq
' Before: Dynamsoft raw extraction + manual 150-line parser
Dim results = _recognizer.RecognizeFile(imagePath)
Dim rawMrz = String.Join(vbCrLf, results.SelectMany(Function(r) r.LineResults).Select(Function(l) l.Text))
Dim parsed = MyTd3Parser.Parse(rawMrz) ' delete this file
' After: IronOCR parsed output directly
Dim passportData = New IronTesseract().ReadPassport(imagePath)
Dim surname As String = passportData.Surname
Dim docNum As String = passportData.DocumentNumber
Dim dob As DateTime? = passportData.DateOfBirth
The manual parser is deleted entirely. TD1 (ID cards), TD2 (visas), and TD3 (passports) format detection is automatic inside ReadPassport. The passport reading how-to documents every returned field.
Consolidating Multi-Product Initialization
Dynamsoft multi-product applications have multiple static InitLicense calls at startup, each requiring its own key. Consolidate these into a single IronOCR license line and remove the per-product initialization blocks:
// Before: three static initializations
LabelRecognizer.InitLicense(mrzKey);
BarcodeReader.InitLicense(barcodeKey);
DocumentNormalizer.InitLicense(documentKey);
// After: one line, all capabilities enabled
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
var ocr = new IronTesseract();
ocr.Configuration.ReadBarCodes = true; // barcodes included automatically
// Before: three static initializations
LabelRecognizer.InitLicense(mrzKey);
BarcodeReader.InitLicense(barcodeKey);
DocumentNormalizer.InitLicense(documentKey);
// After: one line, all capabilities enabled
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
var ocr = new IronTesseract();
ocr.Configuration.ReadBarCodes = true; // barcodes included automatically
Imports System
' Before: three static initializations
LabelRecognizer.InitLicense(mrzKey)
BarcodeReader.InitLicense(barcodeKey)
DocumentNormalizer.InitLicense(documentKey)
' After: one line, all capabilities enabled
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
Dim ocr As New IronTesseract()
ocr.Configuration.ReadBarCodes = True ' barcodes included automatically
Existing Dynamsoft Dispose calls in service classes should be replaced with standard using blocks on IronTesseract instances, or a single reused instance registered in the DI container. The IronTesseract setup guide covers both patterns.
Adding PDF Support
The most common new capability teams acquire during migration is native PDF input — something Dynamsoft never provided. After removing the PDF-to-image conversion loop, native PDF reading requires no code changes beyond the input path:
// Before: PDF rendering loop (50+ lines with external library)
var pdfDoc = PdfDocument.Load(pdfPath);
foreach (var page in pdfDoc.Pages)
{
var bitmap = page.RenderAsBitmap(150);
var results = _labelRecognizer.RecognizeFile(SaveBitmapToTemp(bitmap));
// aggregate...
}
// After: native PDF — no loop, no external library
var result = new IronTesseract().Read(pdfPath);
string fullText = result.Text;
result.SaveAsSearchablePdf("searchable-output.pdf");
// Before: PDF rendering loop (50+ lines with external library)
var pdfDoc = PdfDocument.Load(pdfPath);
foreach (var page in pdfDoc.Pages)
{
var bitmap = page.RenderAsBitmap(150);
var results = _labelRecognizer.RecognizeFile(SaveBitmapToTemp(bitmap));
// aggregate...
}
// After: native PDF — no loop, no external library
var result = new IronTesseract().Read(pdfPath);
string fullText = result.Text;
result.SaveAsSearchablePdf("searchable-output.pdf");
Imports IronOcr
' Before: PDF rendering loop (50+ lines with external library)
Dim pdfDoc = PdfDocument.Load(pdfPath)
For Each page In pdfDoc.Pages
Dim bitmap = page.RenderAsBitmap(150)
Dim results = _labelRecognizer.RecognizeFile(SaveBitmapToTemp(bitmap))
' aggregate...
Next
' After: native PDF — no loop, no external library
Dim result = New IronTesseract().Read(pdfPath)
Dim fullText As String = result.Text
result.SaveAsSearchablePdf("searchable-output.pdf")
For teams that also need to produce searchable PDF archives from scanned inputs, SaveAsSearchablePdf is a single method call. The searchable PDF how-to details the output options.
Preprocessing for Industrial Label Quality
Dynamsoft's template engine is optimized for controlled label conditions. For degraded images — worn labels, low-contrast packaging, skewed industrial scans — IronOCR's preprocessing pipeline fills the gap. The image quality correction guide covers each filter. For label-specific workflows, Deskew and Contrast are the most useful:
using var input = new OcrInput();
input.LoadImage(labelImagePath);
input.Deskew(); // correct rotation from handheld scanner
input.Contrast(); // recover faded label text
input.DeNoise(); // remove packaging texture interference
var labelText = new IronTesseract().Read(input).Text;
Console.WriteLine($"Confidence: {new IronTesseract().Read(input).Confidence}%");
using var input = new OcrInput();
input.LoadImage(labelImagePath);
input.Deskew(); // correct rotation from handheld scanner
input.Contrast(); // recover faded label text
input.DeNoise(); // remove packaging texture interference
var labelText = new IronTesseract().Read(input).Text;
Console.WriteLine($"Confidence: {new IronTesseract().Read(input).Confidence}%");
Imports IronOcr
Using input As New OcrInput()
input.LoadImage(labelImagePath)
input.Deskew() ' correct rotation from handheld scanner
input.Contrast() ' recover faded label text
input.DeNoise() ' remove packaging texture interference
Dim labelText = New IronTesseract().Read(input).Text
Console.WriteLine($"Confidence: {New IronTesseract().Read(input).Confidence}%")
End Using
Additional IronOCR Capabilities
Features not covered in the sections above that teams frequently use after migration:
- Handwriting recognition: Process handwritten notes and annotations alongside printed text — a capability Dynamsoft does not offer
- Scanned document processing: Multi-page scanned PDFs with automatic preprocessing per page
- Table extraction: Detect and extract tabular data from invoices, manifests, and data sheets
- hOCR export: Export recognition results as HTML with bounding box coordinates for downstream layout analysis
- Async OCR: Non-blocking recognition for ASP.NET and high-throughput server applications
- Progress tracking: Monitor multi-page batch jobs with progress callbacks
- 125+ languages index: Full list of supported language NuGet packs including non-Latin scripts
- MICR/cheque reading: Magnetic ink character recognition for financial document processing — another specialist use case handled in one package
- Confidence scores per word: Fine-grained quality signals for automated document review pipelines
.NET Compatibility and Future Readiness
IronOCR targets .NET 8 and .NET 9 as first-class supported runtimes, with full backward compatibility to .NET Framework 4.6.2 and .NET Core 3.1. The library ships as a single NuGet package that resolves the correct platform binary for Windows x64, Windows x86, Linux x64, macOS x64, and macOS ARM automatically through NuGet's runtime identifier graph — no conditional package references, no platform-specific project files. Dynamsoft Label Recognizer similarly supports modern .NET runtimes, but its multi-product model means each product's .NET compatibility must be verified and updated independently. IronOCR's active development cadence maintains NuGet package updates aligned with each .NET release cycle, and the single-package model means .NET 10 compatibility, expected in late 2026, will apply uniformly across all features without per-product tracking.
Conclusion
Dynamsoft Label Recognizer is a technically capable specialist. For a kiosk that processes only passport MRZ, or an assembly line station that reads only VIN codes, its template-driven recognition engine performs the narrow task reliably. The problem is that real applications rarely stay narrow. Passports need their full data pages OCR'd. Shipping labels arrive as PDFs. Inventory systems need barcode and text in the same pass. Each expansion of scope triggers another Dynamsoft product, another annual license, and another API surface to maintain.
The cost model makes this concrete. Multi-year totals for MRZ plus barcode reading across a development team using Dynamsoft's annual subscription model compound significantly. IronOCR covers both capabilities — plus native PDF, searchable PDF output, full document OCR, 125+ languages, and preprocessing — at $999 one-time. The migration itself is largely mechanical: replace RecognizeFile with ocr.Read, delete the manual TD3 MRZ parser, enable ReadBarCodes = true, and remove the external PDF rendering loop.
The architectural difference is not just cost. Dynamsoft's design forces teams to think in terms of products rather than capabilities — to ask "which Dynamsoft product handles this?" before writing any code. IronOCR's design inverts that: one instance, one configuration, one result object regardless of what the document contains. That difference compounds over the life of a project as requirements grow.
For teams building greenfield applications that need any combination of MRZ recognition, barcode reading, general document OCR, or PDF processing, IronOCR's all-in-one model eliminates the multi-product coordination problem from the start. For teams currently running multiple Dynamsoft products alongside a separate OCR library, the migration path consolidates that surface into a single dependency. The IronOCR documentation hub covers every feature discussed here with working code examples and deployment guides.
Frequently Asked Questions
What is Dynamsoft OCR SDK?
Dynamsoft OCR SDK is an OCR solution used by developers and enterprises to extract text from images and documents. It is one of several OCR options evaluated alongside IronOCR for .NET application development.
How does IronOCR compare to Dynamsoft OCR SDK for .NET developers?
IronOCR is a NuGet-native .NET OCR library using IronTesseract as its core engine. Compared to Dynamsoft OCR SDK, it offers simpler deployment (no SDK installers), flat-rate pricing, and a clean C# API without COM interop or cloud dependencies.
Is IronOCR easier to set up than Dynamsoft OCR SDK?
IronOCR installs via a single NuGet package. There are no SDK installers, license files to copy, COM components to register, or separate runtime binaries to manage. The entire OCR engine is bundled in the package.
What accuracy differences exist between Dynamsoft OCR SDK and IronOCR?
IronOCR achieves high recognition accuracy for standard business documents, invoices, receipts, and scanned forms. For highly degraded documents or uncommon scripts, accuracy varies by source quality. IronOCR includes image preprocessing filters to improve recognition on low-quality inputs.
Does IronOCR support PDF text extraction?
Yes. IronOCR extracts text from both native PDFs and scanned PDF images in a single call. It also supports multi-page TIFF files, images, and streams. For scanned PDFs, OCR is applied page-by-page with per-page result objects.
How does Dynamsoft OCR SDK licensing compare to IronOCR?
IronOCR uses a flat-rate perpetual license with no per-page or per-scan charges. Organizations processing high document volumes pay the same license cost regardless of volume. Details and volume pricing are on the IronOCR licensing page.
What languages does IronOCR support?
IronOCR supports 127 languages via separate NuGet language packs. Adding a language requires a single 'dotnet add package IronOcr.Languages.{Language}' command. No manual file placement or path configuration is needed.
How do I install IronOCR in a .NET project?
Install via NuGet: 'Install-Package IronOcr' in Package Manager Console or 'dotnet add package IronOcr' in the CLI. Additional language packs are installed the same way. No native SDK installer is required.
Is IronOCR suitable for Docker and containerized deployments, unlike Dynamsoft OCR?
Yes. IronOCR works in Docker containers via its NuGet package. The license key is set via an environment variable. No license files, SDK paths, or volume mounts are required for the OCR engine itself.
Can I try IronOCR before purchasing, compared to Dynamsoft OCR?
Yes. IronOCR trial mode processes documents and returns OCR results with a watermark overlay on output. You can verify accuracy on your own documents before purchasing a license.
Does IronOCR support barcode reading alongside text extraction?
IronOCR focuses on text extraction and OCR. For barcode reading, Iron Software provides IronBarcode as a companion library. Both are available individually or as part of the Iron Suite bundle.
Is it easy to migrate from Dynamsoft OCR SDK to IronOCR?
Migration from Dynamsoft OCR SDK to IronOCR typically involves replacing initialization sequences with IronTesseract instantiation, removing COM lifecycle management, and updating API calls. Most migrations reduce code complexity significantly.

