Migrando do Dynamsoft OCR para o IronOCR
Este guia fornece um caminho de migração completo para desenvolvedores .NET que estão migrando do Reconhecedor de rótulos Dynamsoft para o IronOCR . Abrange a substituição de pacotes NuGet , atualizações de namespace, inicialização de licenças e exemplos práticos de migração de código para cenários distintos das comparações gerais de recursos — incluindo a eliminação da configuração de modelos, a remoção de configurações JSON de tempo de execução, a migração da definição de região e a simplificação da análise de resultados.
Por que migrar do Dynamsoft OCR?
O Reconhecedor de rótulos Dynamsoft é um especialista desenvolvido para um propósito específico. Essa precisão funciona bem para implementações restritas, mas cria atrito no momento em que o escopo da aplicação se expande além do caso de uso original de MRZ ou VIN.
A configuração de tempo de execução em JSON é uma superfície de manutenção. Todo fluxo de trabalho de reconhecimento Dynamsoft começa com AppendSettingsFromString, carregando um documento JSON que declara matrizes de parâmetros, modelos de caracteres e referências de região. Esses modelos JSON são artefatos de implantação separados — não são compilados no seu binário. Eles exigem controle de versão, gerenciamento de pipeline de implantação e atualizações manuais quando a Dynamsoft altera os esquemas de modelo entre as versões do SDK.IronOCR não requer arquivos de configuração: instancie IronTesseract, chame .Read(), e o motor seleciona as configurações apropriadas automaticamente.
Preços de assinatura anual do Compounds. Licenças do Reconhecedor de rótulos Dynamsoft a partir de US$ 599 por dispositivo por ano. Não existe opção perpétua. Um cluster de processamento com cinco dispositivos custa mais de US$ 2.995 por ano — e esse orçamento cobre apenas o reconhecimento de MRZ e de rótulos estruturados. Adicione o Dynamsoft Barcode Reader para códigos de barras ou o Dynamsoft Document Normalizer para correção de bordas, e a fatura anual se multiplica pela quantidade de produtos. A licença Lite do IronOCR é $999 única e cobre OCR geral, rótulos estruturados, códigos de barras, PDF nativo, saída PDF pesquisável, e mais de 125 idiomas em um único pacote.
A definição de região requer templates JSON. Definir uma região de reconhecimento no Dynamsoft significa criar um bloco JSON ReferenceRegionArray, referenciá-lo em um LabelRecognizerParameterArray e carregar o documento inteiro antes de começar qualquer processamento de imagem.IronOCR usa um único construtor CropRectangle(x, y, width, height) passado diretamente para OcrInput.LoadImage. Alterar uma região requer apenas a edição de um número, não a análise completa de um documento JSON.
A análise de resultados é inteiramente sua responsabilidade. RecognizeFile e RecognizeByFile retornam matrizes LineResult contendo cadeias de texto bruto. Cada estrutura necessária — deslocamentos de campo, conversões de data, validação de dígito verificador, tratamento de separadores de nome — requer código de análise personalizado além da saída bruta.IronOCR retorna um OcrResult com .Pages, .Lines, .Words e .Characters como coleções tipadas com coordenadas de caixa delimitadora, pontuações de confiança e metadados de fonte já preenchidos.
A ausência de suporte nativo para PDF cria uma dependência oculta. O Reconhecedor de rótulos Dynamsoft não possui capacidade de entrada de PDF. Qualquer PDF que chegue ao seu pipeline de processamento requer uma biblioteca externa para renderizar cada página em um bitmap, um loop de iteração de página e uma etapa de agregação de resultados antes da primeira chamada ao Dynamsoft.IronOCR lê PDFs nativamente: new IronTesseract().Read("document.pdf") processa todas as páginas sem uma dependência secundária, loop de renderização ou pasta de imagens temporária.
Os blocos de inicialização multiproduto crescem com o escopo. Um aplicativo Dynamsoft que lida com rótulos estruturados, códigos de barras e normalização de documentos possui três chamadas InitLicense estáticas na inicialização, três cadeias de descarte e três dependências de versão de SDK independentes. A atualização do SDK implica em coordenação entre todos os produtos. O IronOCR possui uma única linha de inicialização e uma única versão de pacote, independentemente dos recursos que o aplicativo utilize.
O problema fundamental
O Dynamsoft exige que um arquivo de configuração JSON seja carregado em tempo de execução para que o reconhecimento possa ser iniciado:
// Dynamsoft: JSON template required before any image processing
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
string settings = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""VIN_Label"",
""ReferenceRegionNameArray"": [""VinRegion""],
""CharacterModelName"": ""VIN""
}],
""ReferenceRegionArray"": [{
""Name"": ""VinRegion"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [5, 40],
""SecondPoint"": [95, 40],
""ThirdPoint"": [95, 60],
""FourthPoint"": [5, 60]
}
}]
}";
recognizer.AppendSettingsFromString(settings); // fails silently if JSON is malformed
var results = recognizer.RecognizeFile(imagePath);
// Dynamsoft: JSON template required before any image processing
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
string settings = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""VIN_Label"",
""ReferenceRegionNameArray"": [""VinRegion""],
""CharacterModelName"": ""VIN""
}],
""ReferenceRegionArray"": [{
""Name"": ""VinRegion"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [5, 40],
""SecondPoint"": [95, 40],
""ThirdPoint"": [95, 60],
""FourthPoint"": [5, 60]
}
}]
}";
recognizer.AppendSettingsFromString(settings); // fails silently if JSON is malformed
var results = recognizer.RecognizeFile(imagePath);
' Dynamsoft: JSON template required before any image processing
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
Dim settings As String = "{
""LabelRecognizerParameterArray"": [{
""Name"": ""VIN_Label"",
""ReferenceRegionNameArray"": [""VinRegion""],
""CharacterModelName"": ""VIN""
}],
""ReferenceRegionArray"": [{
""Name"": ""VinRegion"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [5, 40],
""SecondPoint"": [95, 40],
""ThirdPoint"": [95, 60],
""FourthPoint"": [5, 60]
}
}]
}"
recognizer.AppendSettingsFromString(settings) ' fails silently if JSON is malformed
Dim results = recognizer.RecognizeFile(imagePath)
// IronOCR: no JSON, no template files — region is a constructor argument
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var region = new CropRectangle(x: 50, y: 400, width: 900, height: 200);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
// IronOCR: no JSON, no template files — region is a constructor argument
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var region = new CropRectangle(x: 50, y: 400, width: 900, height: 200);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
Imports IronOcr
' IronOCR: no JSON, no template files — region is a constructor argument
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim region As New CropRectangle(x:=50, y:=400, width:=900, height:=200)
Using input As New OcrInput()
input.LoadImage(imagePath, region)
Dim result = New IronTesseract().Read(input)
Console.WriteLine(result.Text)
End Using
IronOCR vs Dynamsoft OCR: Comparação de Recursos
A tabela abaixo mostra a diferença total de funcionalidades entre as duas bibliotecas.
| Recurso | Reconhecedor de rótulos Dynamsoft | IronOCR |
|---|---|---|
| OCR de documentos gerais | Não suportado | Suporte total |
| reconhecimento MRZ | Especializado (saída de texto bruto) | Integrado com campos estruturados |
| reconhecimento de VIN | Especializado (modelo necessário) | OCR padrão com segmentação regional |
| Leitura de rótulos industriais | Especializado (modelo necessário) | Sim, via CropRectangle |
| Configuração das definições de tempo de execução | Necessário (JSON via AppendSettingsFromString) |
Não é necessário |
| Artefatos de implantação de modelo | Obrigatório (arquivos JSON) | None |
| Entrada nativa de PDF | Não suportado | Sim |
| PDF protegido por senha | Não suportado | Sim |
| Entrada TIFF de várias páginas | Iteração da página do manual | Nativo (LoadImageFrames) |
| Saída em PDF pesquisável | Não suportado | Sim (SaveAsSearchablePdf) |
| Leitura de código de barras | Produto separado (Leitor de código de barras Dynamsoft) | Integrado (ReadBarCodes = true) |
| Pré-processamento automático | Limitado | Sim (Corrigir distorção, Reduzir ruído, Contraste, Binarizar, Nitidez, Dilatação, Erosão) |
| Saída estruturada (Palavras, Linhas, Parágrafos) | Cadeias de texto bruto LineResult |
Totalmente digitado com coordenadas e confiança. |
| Suporte linguístico | Limitado (Latin MRZ) | Mais de 125 idiomas, agrupados como pacotes NuGet. |
| Simultaneidade multilíngue | Não suportado | Sim (OcrLanguage.French + OcrLanguage.German) |
| Pontuações de confiança | Somente por linha | Por palavra, linha, página |
| Exportação hOCR | Não suportado | Sim |
| Modelo de licenciamento | Assinatura anual (a partir de US$ 599 por dispositivo por ano) | Perpétuo ($999 único, nível Lite) |
| Vários produtos necessários | Sim (3+ para cobertura completa) | Não (um pacote) |
| Suporte ao .NET Framework | .NET Framework 4.x+ | .NET Framework 4.6.2+, .NET 5/6/7/8/9 |
| Implantação multiplataforma | Sim | Sim (Windows, Linux, macOS, Docker, Azure, AWS) |
| Pacote NuGet | Dynamsoft.LabelRecognizer |
IronOcr |
Guia rápido: Migração do Dynamsoft OCR para o IronOCR
Passo 1: Substitua o pacote NuGet
Remova o pacote Dynamsoft:
dotnet remove package Dynamsoft.LabelRecognizer
dotnet remove package Dynamsoft.LabelRecognizer
Instale o IronOCR a partir da galeria NuGet :
dotnet add package IronOcr
Etapa 2: Atualizar Namespaces
// Before (Dynamsoft)
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;
// After (IronOCR)
using IronOcr;
// Before (Dynamsoft)
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;
// After (IronOCR)
using IronOcr;
Imports IronOcr
Etapa 3: Inicializar a licença
Substitua cada chamada estática InitLicense do Dynamsoft por uma única atribuição de licença IronOCR na inicialização do aplicativo:
// Before (Dynamsoft — one call per product)
LabelRecognizer.InitLicense("DYNAMSOFT-LICENSE-KEY");
// After (IronOCR — one line, all features)
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Before (Dynamsoft — one call per product)
LabelRecognizer.InitLicense("DYNAMSOFT-LICENSE-KEY");
// After (IronOCR — one line, all features)
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
' Before (Dynamsoft — one call per product)
LabelRecognizer.InitLicense("DYNAMSOFT-LICENSE-KEY")
' After (IronOCR — one line, all features)
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Exemplos de migração de código
Reconhecimento baseado em modelos para mecanismo de configuração zero
O sistema de modelos JSON da Dynamsoft fornece ao SDK instruções detalhadas sobre modelos de personagens, especificações de região e parâmetros de reconhecimento antes que qualquer imagem seja processada. Para a maioria das cargas de trabalho de OCR do mundo real, essa configuração adiciona complexidade de configuração sem benefícios de reconhecimento, porque o mecanismo Tesseract subjacente lida com a detecção de layout automaticamente.
Abordagem da Dynamsoft:
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;
// JSON template required before recognition
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
string invoiceTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""Invoice_Header"",
""ReferenceRegionNameArray"": [""HeaderRegion""],
""CharacterModelName"": ""NumberLetter""
}],
""ReferenceRegionArray"": [{
""Name"": ""HeaderRegion"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [0, 0],
""SecondPoint"": [100, 0],
""ThirdPoint"": [100, 20],
""FourthPoint"": [0, 20]
}
}]
}";
recognizer.AppendSettingsFromString(invoiceTemplate);
var results = recognizer.RecognizeFile("invoice.jpg");
var headerText = new StringBuilder();
foreach (var result in results)
foreach (var line in result.LineResults)
headerText.AppendLine(line.Text);
Console.WriteLine(headerText.ToString());
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
using Dynamsoft.Core;
// JSON template required before recognition
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
string invoiceTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""Invoice_Header"",
""ReferenceRegionNameArray"": [""HeaderRegion""],
""CharacterModelName"": ""NumberLetter""
}],
""ReferenceRegionArray"": [{
""Name"": ""HeaderRegion"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [0, 0],
""SecondPoint"": [100, 0],
""ThirdPoint"": [100, 20],
""FourthPoint"": [0, 20]
}
}]
}";
recognizer.AppendSettingsFromString(invoiceTemplate);
var results = recognizer.RecognizeFile("invoice.jpg");
var headerText = new StringBuilder();
foreach (var result in results)
foreach (var line in result.LineResults)
headerText.AppendLine(line.Text);
Console.WriteLine(headerText.ToString());
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
Imports Dynamsoft.Core
Imports System.Text
' JSON template required before recognition
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
Dim invoiceTemplate As String = "{
""LabelRecognizerParameterArray"": [{
""Name"": ""Invoice_Header"",
""ReferenceRegionNameArray"": [""HeaderRegion""],
""CharacterModelName"": ""NumberLetter""
}],
""ReferenceRegionArray"": [{
""Name"": ""HeaderRegion"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [0, 0],
""SecondPoint"": [100, 0],
""ThirdPoint"": [100, 20],
""FourthPoint"": [0, 20]
}
}]
}"
recognizer.AppendSettingsFromString(invoiceTemplate)
Dim results = recognizer.RecognizeFile("invoice.jpg")
Dim headerText As New StringBuilder()
For Each result In results
For Each line In result.LineResults
headerText.AppendLine(line.Text)
Next
Next
Console.WriteLine(headerText.ToString())
recognizer.Dispose()
Abordagem IronOCR:
using IronOcr;
// No template file — region specified inline, engine auto-configures
var region = new CropRectangle(x: 0, y: 0, width: 1200, height: 200);
using var input = new OcrInput();
input.LoadImage("invoice.jpg", region);
input.Deskew();
var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
Console.WriteLine($"Confidence: {result.Confidence}%");
using IronOcr;
// No template file — region specified inline, engine auto-configures
var region = new CropRectangle(x: 0, y: 0, width: 1200, height: 200);
using var input = new OcrInput();
input.LoadImage("invoice.jpg", region);
input.Deskew();
var result = new IronTesseract().Read(input);
Console.WriteLine(result.Text);
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr
' No template file — region specified inline, engine auto-configures
Dim region As New CropRectangle(x:=0, y:=0, width:=1200, height:=200)
Using input As New OcrInput()
input.LoadImage("invoice.jpg", region)
input.Deskew()
Dim result = New IronTesseract().Read(input)
Console.WriteLine(result.Text)
Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
A abordagem da Dynamsoft exige a criação, validação e implementação de um modelo JSON antes que qualquer imagem seja processada. Um erro de digitação em AppendSettingsFromString retorna resultados vazios em tempo de execução — não há validação em tempo de compilação. CropRectangle do IronOCR é um construtor simples: verificação de tipo em tempo de compilação, sem arquivos externos, sem artefato de implantação. Consulte o guia de OCR baseado em região para todos os padrões de segmentação.
Leitura do código VIN com migração de região
A extração do número de identificação do veículo é uma especialidade do Dynamsoft Label Recognizer. Seu modelo de VIN é otimizado para o formato alfanumérico específico de 17 caracteres. A migração para o IronOCR substitui o modelo de template por um pipeline de pré-processamento e direcionamento regional, que lida com as mesmas condições da placa VIN sem exigir uma configuração de modelo de caracteres.
Abordagem da Dynamsoft:
using Dynamsoft.LabelRecognizer;
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
// VIN requires a specific character model and region configuration
string vinTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""VIN_Scan"",
""ReferenceRegionNameArray"": [""VIN_Zone""],
""CharacterModelName"": ""VIN""
}],
""ReferenceRegionArray"": [{
""Name"": ""VIN_Zone"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [10, 35],
""SecondPoint"": [90, 35],
""ThirdPoint"": [90, 65],
""FourthPoint"": [10, 65]
}
}]
}";
recognizer.AppendSettingsFromString(vinTemplate);
var results = recognizer.RecognizeFile("vehicle-vin.jpg");
string rawVin = results
.SelectMany(r => r.LineResults)
.Select(l => l.Text)
.FirstOrDefault() ?? string.Empty;
Console.WriteLine($"Raw VIN text: {rawVin}"); // still requires validation
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
// VIN requires a specific character model and region configuration
string vinTemplate = @"{
""LabelRecognizerParameterArray"": [{
""Name"": ""VIN_Scan"",
""ReferenceRegionNameArray"": [""VIN_Zone""],
""CharacterModelName"": ""VIN""
}],
""ReferenceRegionArray"": [{
""Name"": ""VIN_Zone"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [10, 35],
""SecondPoint"": [90, 35],
""ThirdPoint"": [90, 65],
""FourthPoint"": [10, 65]
}
}]
}";
recognizer.AppendSettingsFromString(vinTemplate);
var results = recognizer.RecognizeFile("vehicle-vin.jpg");
string rawVin = results
.SelectMany(r => r.LineResults)
.Select(l => l.Text)
.FirstOrDefault() ?? string.Empty;
Console.WriteLine($"Raw VIN text: {rawVin}"); // still requires validation
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
' VIN requires a specific character model and region configuration
Dim vinTemplate As String = "{
""LabelRecognizerParameterArray"": [{
""Name"": ""VIN_Scan"",
""ReferenceRegionNameArray"": [""VIN_Zone""],
""CharacterModelName"": ""VIN""
}],
""ReferenceRegionArray"": [{
""Name"": ""VIN_Zone"",
""Localization"": {
""SourceType"": ""LST_MANUAL_SPECIFICATION"",
""FirstPoint"": [10, 35],
""SecondPoint"": [90, 35],
""ThirdPoint"": [90, 65],
""FourthPoint"": [10, 65]
}
}]
}"
recognizer.AppendSettingsFromString(vinTemplate)
Dim results = recognizer.RecognizeFile("vehicle-vin.jpg")
Dim rawVin As String = results _
.SelectMany(Function(r) r.LineResults) _
.Select(Function(l) l.Text) _
.FirstOrDefault() OrElse String.Empty
Console.WriteLine($"Raw VIN text: {rawVin}") ' still requires validation
recognizer.Dispose()
Abordagem IronOCR:
using IronOcr;
using System.Text.RegularExpressions;
// Target the VIN plate region directly — no template file
var vinRegion = new CropRectangle(x: 100, y: 350, width: 800, height: 300);
using var input = new OcrInput();
input.LoadImage("vehicle-vin.jpg", vinRegion);
input.Contrast(); // recover faded stamped digits
input.Sharpen(); // clarify character boundaries on embossed plates
var result = new IronTesseract().Read(input);
// VIN: 17 chars, no I/O/Q
var vinMatch = Regex.Match(result.Text, @"\b[A-HJ-NPR-Z0-9]{17}\b");
string vin = vinMatch.Success ? vinMatch.Value : result.Text.Trim();
Console.WriteLine($"VIN: {vin}");
Console.WriteLine($"Confidence: {result.Confidence}%");
using IronOcr;
using System.Text.RegularExpressions;
// Target the VIN plate region directly — no template file
var vinRegion = new CropRectangle(x: 100, y: 350, width: 800, height: 300);
using var input = new OcrInput();
input.LoadImage("vehicle-vin.jpg", vinRegion);
input.Contrast(); // recover faded stamped digits
input.Sharpen(); // clarify character boundaries on embossed plates
var result = new IronTesseract().Read(input);
// VIN: 17 chars, no I/O/Q
var vinMatch = Regex.Match(result.Text, @"\b[A-HJ-NPR-Z0-9]{17}\b");
string vin = vinMatch.Success ? vinMatch.Value : result.Text.Trim();
Console.WriteLine($"VIN: {vin}");
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr
Imports System.Text.RegularExpressions
' Target the VIN plate region directly — no template file
Dim vinRegion As New CropRectangle(x:=100, y:=350, width:=800, height:=300)
Using input As New OcrInput()
input.LoadImage("vehicle-vin.jpg", vinRegion)
input.Contrast() ' recover faded stamped digits
input.Sharpen() ' clarify character boundaries on embossed plates
Dim result = New IronTesseract().Read(input)
' VIN: 17 chars, no I/O/Q
Dim vinMatch = Regex.Match(result.Text, "\b[A-HJ-NPR-Z0-9]{17}\b")
Dim vin As String = If(vinMatch.Success, vinMatch.Value, result.Text.Trim())
Console.WriteLine($"VIN: {vin}")
Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
As coordenadas CropRectangle usam o mesmo quadro de referência de pixel da especificação baseada em porcentagem do Dynamsoft SecondPoint — converta multiplicando os valores de porcentagem do Dynamsoft pelas dimensões da sua imagem. O pipeline de pré-processamento (Contrast, Sharpen) substitui a otimização de modelo de caracteres que o Dynamsoft incorpora em seu template VIN. O guia de correção da qualidade da imagem aborda a seleção de filtros para superfícies em relevo e de baixo contraste.
Processamento em lote de TIFF de várias páginas
O Reconhecedor de rótulos Dynamsoft processa imagens individuais. Documentos TIFF com várias páginas — comuns em sistemas de gerenciamento de documentos, arquivos de imagens médicas e fluxos de fax — exigem iteração externa: carregar cada quadro, passá-lo individualmente pelo reconhecedor e agregar os resultados.IronOCR lida com TIFF de múltiplos quadros nativamente através de LoadImageFrames.
Abordagem da Dynamsoft:
using Dynamsoft.LabelRecognizer;
// Requires an external TIFF library to extract frames
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(genericTemplate);
// External library needed to iterate TIFF frames
var tiffImage = System.Drawing.Image.FromFile("scanned-batch.tiff");
int frameCount = tiffImage.GetFrameCount(
System.Drawing.Imaging.FrameDimension.Page);
var allText = new StringBuilder();
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
string tempPath = $"frame_{i}.jpg";
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Jpeg);
var results = recognizer.RecognizeFile(tempPath);
foreach (var r in results)
foreach (var line in r.LineResults)
allText.AppendLine(line.Text);
System.IO.File.Delete(tempPath); // clean up temp files
}
Console.WriteLine(allText.ToString());
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
// Requires an external TIFF library to extract frames
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(genericTemplate);
// External library needed to iterate TIFF frames
var tiffImage = System.Drawing.Image.FromFile("scanned-batch.tiff");
int frameCount = tiffImage.GetFrameCount(
System.Drawing.Imaging.FrameDimension.Page);
var allText = new StringBuilder();
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
string tempPath = $"frame_{i}.jpg";
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Jpeg);
var results = recognizer.RecognizeFile(tempPath);
foreach (var r in results)
foreach (var line in r.LineResults)
allText.AppendLine(line.Text);
System.IO.File.Delete(tempPath); // clean up temp files
}
Console.WriteLine(allText.ToString());
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Text
' Requires an external TIFF library to extract frames
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
recognizer.AppendSettingsFromString(genericTemplate)
' External library needed to iterate TIFF frames
Dim tiffImage As Image = Image.FromFile("scanned-batch.tiff")
Dim frameCount As Integer = tiffImage.GetFrameCount(FrameDimension.Page)
Dim allText As New StringBuilder()
For i As Integer = 0 To frameCount - 1
tiffImage.SelectActiveFrame(FrameDimension.Page, i)
Dim tempPath As String = $"frame_{i}.jpg"
tiffImage.Save(tempPath, Imaging.ImageFormat.Jpeg)
Dim results = recognizer.RecognizeFile(tempPath)
For Each r In results
For Each line In r.LineResults
allText.AppendLine(line.Text)
Next
Next
File.Delete(tempPath) ' clean up temp files
Next
Console.WriteLine(allText.ToString())
recognizer.Dispose()
Abordagem IronOCR:
using IronOcr;
// No frame iteration, no temp files, no external TIFF library
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff"); // loads all frames natively
input.Deskew();
input.DeNoise();
var ocr = new IronTesseract();
var result = ocr.Read(input);
// Results organized per page
foreach (var page in result.Pages)
{
Console.WriteLine($"Frame {page.PageNumber}: {page.Lines.Count} lines");
Console.WriteLine(page.Text);
}
// Save entire batch as a single searchable PDF
result.SaveAsSearchablePdf("batch-searchable.pdf");
using IronOcr;
// No frame iteration, no temp files, no external TIFF library
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff"); // loads all frames natively
input.Deskew();
input.DeNoise();
var ocr = new IronTesseract();
var result = ocr.Read(input);
// Results organized per page
foreach (var page in result.Pages)
{
Console.WriteLine($"Frame {page.PageNumber}: {page.Lines.Count} lines");
Console.WriteLine(page.Text);
}
// Save entire batch as a single searchable PDF
result.SaveAsSearchablePdf("batch-searchable.pdf");
Imports IronOcr
' No frame iteration, no temp files, no external TIFF library
Using input As New OcrInput()
input.LoadImageFrames("scanned-batch.tiff") ' loads all frames natively
input.Deskew()
input.DeNoise()
Dim ocr As New IronTesseract()
Dim result = ocr.Read(input)
' Results organized per page
For Each page In result.Pages
Console.WriteLine($"Frame {page.PageNumber}: {page.Lines.Count} lines")
Console.WriteLine(page.Text)
Next
' Save entire batch as a single searchable PDF
result.SaveAsSearchablePdf("batch-searchable.pdf")
End Using
A abordagem Dynamsoft requer System.Drawing para extração de quadros, um arquivo temporário no disco por quadro e uma limpeza manual após cada execução. LoadImageFrames do IronOCR lê todos os quadros em uma única chamada — sem arquivos temporários, sem rastreamento de índice de quadro. Após o OCR, SaveAsSearchablePdf arquiva todo o lote como um documento pesquisável em uma chamada de método. O guia de TIFF com múltiplos quadros e o guia de saída em PDF pesquisável abordam ambas as funcionalidades em detalhes.
Análise estruturada de resultados em nível de palavra
Dynamsoft RecognizeFile retorna uma matriz DLRResult. Cada DLRResult contém uma coleção LineResults de objetos DLRLineResult com uma propriedade Text e uma propriedade Location que mantém o quadrilátero delimitador. Extrair as posições das palavras requer dividir o texto da linha em espaços em branco e dividir proporcionalmente a caixa delimitadora da linha — uma aproximação que falha em fontes proporcionais.IronOCR disponibiliza caixas delimitadoras a nível de palavra como propriedades tipadas em cada objeto OcrResult.Word.
Abordagem da Dynamsoft:
using Dynamsoft.LabelRecognizer;
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(settingsJson);
var results = recognizer.RecognizeFile("form-scan.jpg");
foreach (var dlrResult in results)
{
foreach (var lineResult in dlrResult.LineResults)
{
// Line-level data only — word boundaries are not provided
Console.WriteLine($"Text: {lineResult.Text}");
Console.WriteLine($"Confidence: {lineResult.Confidence}");
// Location is a quadrilateral — four corner points
var loc = lineResult.Location;
Console.WriteLine($"Top-left: ({loc.Points[0].X}, {loc.Points[0].Y})");
// To get word positions: split text and divide bounding box manually
var words = lineResult.Text.Split(' ');
int approxWidth = (loc.Points[1].X - loc.Points[0].X) / words.Length;
for (int i = 0; i < words.Length; i++)
{
int wordX = loc.Points[0].X + (i * approxWidth);
Console.WriteLine($" Word '{words[i]}' approx at x={wordX}");
}
}
}
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(settingsJson);
var results = recognizer.RecognizeFile("form-scan.jpg");
foreach (var dlrResult in results)
{
foreach (var lineResult in dlrResult.LineResults)
{
// Line-level data only — word boundaries are not provided
Console.WriteLine($"Text: {lineResult.Text}");
Console.WriteLine($"Confidence: {lineResult.Confidence}");
// Location is a quadrilateral — four corner points
var loc = lineResult.Location;
Console.WriteLine($"Top-left: ({loc.Points[0].X}, {loc.Points[0].Y})");
// To get word positions: split text and divide bounding box manually
var words = lineResult.Text.Split(' ');
int approxWidth = (loc.Points[1].X - loc.Points[0].X) / words.Length;
for (int i = 0; i < words.Length; i++)
{
int wordX = loc.Points[0].X + (i * approxWidth);
Console.WriteLine($" Word '{words[i]}' approx at x={wordX}");
}
}
}
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer As New LabelRecognizer()
recognizer.AppendSettingsFromString(settingsJson)
Dim results = recognizer.RecognizeFile("form-scan.jpg")
For Each dlrResult In results
For Each lineResult In dlrResult.LineResults
' Line-level data only — word boundaries are not provided
Console.WriteLine($"Text: {lineResult.Text}")
Console.WriteLine($"Confidence: {lineResult.Confidence}")
' Location is a quadrilateral — four corner points
Dim loc = lineResult.Location
Console.WriteLine($"Top-left: ({loc.Points(0).X}, {loc.Points(0).Y})")
' To get word positions: split text and divide bounding box manually
Dim words = lineResult.Text.Split(" "c)
Dim approxWidth As Integer = (loc.Points(1).X - loc.Points(0).X) \ words.Length
For i As Integer = 0 To words.Length - 1
Dim wordX As Integer = loc.Points(0).X + (i * approxWidth)
Console.WriteLine($" Word '{words(i)}' approx at x={wordX}")
Next
Next
Next
recognizer.Dispose()
Abordagem IronOCR:
using IronOcr;
var result = new IronTesseract().Read("form-scan.jpg");
// Word-level positions are first-class properties — no manual division
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");
foreach (var line in paragraph.Lines)
{
foreach (var word in line.Words)
{
Console.WriteLine(
$" Word: '{word.Text}' " +
$"at ({word.X},{word.Y}) " +
$"size {word.Width}x{word.Height} " +
$"confidence {word.Confidence}%");
}
}
}
}
using IronOcr;
var result = new IronTesseract().Read("form-scan.jpg");
// Word-level positions are first-class properties — no manual division
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");
foreach (var line in paragraph.Lines)
{
foreach (var word in line.Words)
{
Console.WriteLine(
$" Word: '{word.Text}' " +
$"at ({word.X},{word.Y}) " +
$"size {word.Width}x{word.Height} " +
$"confidence {word.Confidence}%");
}
}
}
}
Imports IronOcr
Dim result = New IronTesseract().Read("form-scan.jpg")
' Word-level positions are first-class properties — no manual division
For Each page In result.Pages
For Each paragraph In page.Paragraphs
Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}")
For Each line In paragraph.Lines
For Each word In line.Words
Console.WriteLine(
$" Word: '{word.Text}' " &
$"at ({word.X},{word.Y}) " &
$"size {word.Width}x{word.Height} " &
$"confidence {word.Confidence}%")
Next
Next
Next
Next
O IronOCR fornece uma hierarquia verdadeira: as páginas contêm parágrafos, os parágrafos contêm linhas, as linhas contêm palavras e as palavras contêm caracteres. Cada nível expõe .X, .Y, .Width, .Height, e .Confidence como propriedades inteiras e duplas tipadas — sem necessidade de aritmética de coordenadas de quadrilátero. O guia de resultados estruturados documenta todas as propriedades acessíveis, e o guia de pontuação de confiança explica a definição de limites de confiança para fluxos de trabalho automatizados de revisão de documentos.
Processamento paralelo assíncrono para digitalização de etiquetas em alto volume
O reconhecedor de rótulos do Dynamsoft é seguro para threads, mas sua chamada RecognizeFile é síncrona. Envolvê-lo em Task.Run produz processamento paralelo, mas cada chamada compartilha o estado de configuração através de AppendSettingsFromString — carregar templates em múltiplos threads requer uma sequência de inicialização cuidadosa. As instâncias IronTesseract do IronOCR são independentes: crie uma por tarefa, chame Read, e o modelo de thread é direto.
Abordagem da Dynamsoft:
using Dynamsoft.LabelRecognizer;
using System.Threading.Tasks;
// InitLicense must be called once before parallel work begins
LabelRecognizer.InitLicense(licenseKey);
// Each thread needs its own recognizer instance with its own template load
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
await Task.WhenAll(imagePaths.Select(async path =>
{
// Cannot share recognizer instances safely across tasks
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(templateJson); // reload JSON per instance
await Task.Run(() =>
{
var dlrResults = recognizer.RecognizeFile(path);
var text = string.Join("\n",
dlrResults.SelectMany(r => r.LineResults).Select(l => l.Text));
results.Add(text);
});
recognizer.Dispose();
}));
Console.WriteLine($"Processed {results.Count} images");
using Dynamsoft.LabelRecognizer;
using System.Threading.Tasks;
// InitLicense must be called once before parallel work begins
LabelRecognizer.InitLicense(licenseKey);
// Each thread needs its own recognizer instance with its own template load
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
await Task.WhenAll(imagePaths.Select(async path =>
{
// Cannot share recognizer instances safely across tasks
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(templateJson); // reload JSON per instance
await Task.Run(() =>
{
var dlrResults = recognizer.RecognizeFile(path);
var text = string.Join("\n",
dlrResults.SelectMany(r => r.LineResults).Select(l => l.Text));
results.Add(text);
});
recognizer.Dispose();
}));
Console.WriteLine($"Processed {results.Count} images");
Imports Dynamsoft.LabelRecognizer
Imports System.Threading.Tasks
Imports System.Collections.Concurrent
' InitLicense must be called once before parallel work begins
LabelRecognizer.InitLicense(licenseKey)
' Each thread needs its own recognizer instance with its own template load
Dim results As New ConcurrentBag(Of String)()
Await Task.WhenAll(imagePaths.Select(Async Function(path)
' Cannot share recognizer instances safely across tasks
Dim recognizer As New LabelRecognizer()
recognizer.AppendSettingsFromString(templateJson) ' reload JSON per instance
Await Task.Run(Sub()
Dim dlrResults = recognizer.RecognizeFile(path)
Dim text = String.Join(vbLf, dlrResults.SelectMany(Function(r) r.LineResults).Select(Function(l) l.Text))
results.Add(text)
End Sub)
recognizer.Dispose()
End Function))
Console.WriteLine($"Processed {results.Count} images")
Abordagem IronOCR:
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;
var extractedTexts = new ConcurrentDictionary<string, string>();
// Each IronTesseract instance is independent — no shared state
Parallel.ForEach(imagePaths, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
extractedTexts[imagePath] = result.Text;
});
foreach (var (path, text) in extractedTexts)
Console.WriteLine($"{System.IO.Path.GetFileName(path)}: {text.Length} characters");
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;
var extractedTexts = new ConcurrentDictionary<string, string>();
// Each IronTesseract instance is independent — no shared state
Parallel.ForEach(imagePaths, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
extractedTexts[imagePath] = result.Text;
});
foreach (var (path, text) in extractedTexts)
Console.WriteLine($"{System.IO.Path.GetFileName(path)}: {text.Length} characters");
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
Dim extractedTexts As New ConcurrentDictionary(Of String, String)()
' Each IronTesseract instance is independent — no shared state
Parallel.ForEach(imagePaths, Sub(imagePath)
Dim ocr As New IronTesseract()
Dim result = ocr.Read(imagePath)
extractedTexts(imagePath) = result.Text
End Sub)
For Each kvp In extractedTexts
Dim path = kvp.Key
Dim text = kvp.Value
Console.WriteLine($"{System.IO.Path.GetFileName(path)}: {text.Length} characters")
Next
O IronOCR não requer nenhuma sequência de inicialização antes do início do trabalho em paralelo. Uma atribuição IronOcr.License.LicenseKey na inicialização do aplicativo ativa todas as instâncias. Sem recarregamento de modelo por thread, sem validação JSON por instância. Para cenários não-bloqueantes no lado do servidor, o guia de OCR assíncrono cobre padrões baseados em await para ASP.NET Core e Funções Azure.
Saída em PDF pesquisável a partir de arquivos de etiquetas digitalizadas.
O Dynamsoft não possui nenhum recurso de geração de PDF. Os arquivos de etiquetas digitalizadas processados pelo Dynamsoft permanecem como arquivos somente de imagem — não pesquisáveis, não indexáveis por sistemas de gerenciamento de documentos e não compatíveis com os padrões de arquivamento PDF/A.IronOCR adiciona saída PDF pesquisável como uma única chamada de método no objeto OcrResult.
Abordagem da Dynamsoft:
using Dynamsoft.LabelRecognizer;
// Process scanned label — extract text into a string
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(labelTemplate);
var results = recognizer.RecognizeFile("scanned-labels.jpg");
var extractedText = new StringBuilder();
foreach (var r in results)
foreach (var line in r.LineResults)
extractedText.AppendLine(line.Text);
// Cannot create a searchable PDF — save text to a sidecar .txt file instead
System.IO.File.WriteAllText("scanned-labels.txt", extractedText.ToString());
// The original image remains unsearchable
Console.WriteLine("No PDF output available in Dynamsoft Label Recognizer.");
recognizer.Dispose();
using Dynamsoft.LabelRecognizer;
// Process scanned label — extract text into a string
LabelRecognizer.InitLicense(licenseKey);
var recognizer = new LabelRecognizer();
recognizer.AppendSettingsFromString(labelTemplate);
var results = recognizer.RecognizeFile("scanned-labels.jpg");
var extractedText = new StringBuilder();
foreach (var r in results)
foreach (var line in r.LineResults)
extractedText.AppendLine(line.Text);
// Cannot create a searchable PDF — save text to a sidecar .txt file instead
System.IO.File.WriteAllText("scanned-labels.txt", extractedText.ToString());
// The original image remains unsearchable
Console.WriteLine("No PDF output available in Dynamsoft Label Recognizer.");
recognizer.Dispose();
Imports Dynamsoft.LabelRecognizer
Imports System.IO
Imports System.Text
' Process scanned label — extract text into a string
LabelRecognizer.InitLicense(licenseKey)
Dim recognizer = New LabelRecognizer()
recognizer.AppendSettingsFromString(labelTemplate)
Dim results = recognizer.RecognizeFile("scanned-labels.jpg")
Dim extractedText = New StringBuilder()
For Each r In results
For Each line In r.LineResults
extractedText.AppendLine(line.Text)
Next
Next
' Cannot create a searchable PDF — save text to a sidecar .txt file instead
File.WriteAllText("scanned-labels.txt", extractedText.ToString())
' The original image remains unsearchable
Console.WriteLine("No PDF output available in Dynamsoft Label Recognizer.")
recognizer.Dispose()
Abordagem IronOCR:
using IronOcr;
// Read, preprocess, and produce a searchable PDF archive in one pipeline
using var input = new OcrInput();
input.LoadImage("scanned-labels.jpg");
input.Deskew();
input.Contrast();
var ocr = new IronTesseract();
var result = ocr.Read(input);
// Searchable PDF: original image layer preserved, invisible text layer added
result.SaveAsSearchablePdf("scanned-labels-searchable.pdf");
Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%");
Console.WriteLine($"Extracted text preview: {result.Text.Substring(0, 100)}");
using IronOcr;
// Read, preprocess, and produce a searchable PDF archive in one pipeline
using var input = new OcrInput();
input.LoadImage("scanned-labels.jpg");
input.Deskew();
input.Contrast();
var ocr = new IronTesseract();
var result = ocr.Read(input);
// Searchable PDF: original image layer preserved, invisible text layer added
result.SaveAsSearchablePdf("scanned-labels-searchable.pdf");
Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%");
Console.WriteLine($"Extracted text preview: {result.Text.Substring(0, 100)}");
Imports IronOcr
' Read, preprocess, and produce a searchable PDF archive in one pipeline
Using input As New OcrInput()
input.LoadImage("scanned-labels.jpg")
input.Deskew()
input.Contrast()
Dim ocr As New IronTesseract()
Dim result = ocr.Read(input)
' Searchable PDF: original image layer preserved, invisible text layer added
result.SaveAsSearchablePdf("scanned-labels-searchable.pdf")
Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%")
Console.WriteLine($"Extracted text preview: {result.Text.Substring(0, 100)}")
End Using
O PDF pesquisável preserva a imagem digitalizada original em resolução total e adiciona uma camada invisível de texto OCR por cima. Sistemas de gerenciamento de documentos, índices de pesquisa e visualizadores de PDF agora podem pesquisar o conteúdo da etiqueta. O guia prático em PDF com função de busca e o guia de processamento de documentos digitalizados abrangem arquivos com várias páginas e fluxos de trabalho de conversão em lote.
Referência de mapeamento da API OCR da Dynamsoft para o IronOCR
| Reconhecedor de rótulos Dynamsoft | Equivalente de IronOCR |
|---|---|
LabelRecognizer.InitLicense(key) |
IronOcr.License.LicenseKey = key |
new LabelRecognizer() |
new IronTesseract() |
recognizer.AppendSettingsFromString(json) |
Não é necessário — configurado automaticamente |
recognizer.RecognizeFile(path) |
ocr.Read(path) |
recognizer.RecognizeByFile(path, templateName) |
ocr.Read(path) |
recognizer.RecognizeBuffer(buffer, width, height, ...) |
input.LoadImage(imageBytes) então ocr.Read(input) |
DLRResult[] (matriz de resultados) |
OcrResult (objeto único de resultado) |
DLRResult.LineResults |
OcrResult.Lines |
DLRLineResult.Text |
OcrResult.Line.Text |
DLRLineResult.Confidence |
OcrResult.Line.Words[i].Confidence |
DLRLineResult.Location.Points[i] |
OcrResult.Line.X, .Y, .Width, .Height |
ReferenceRegionArray (JSON) |
new CropRectangle(x, y, w, h) |
LabelRecognizerParameterArray (JSON) |
Não é necessário |
CharacterModelName no template |
Não é necessário |
recognizer.Dispose() |
using var ocr = new IronTesseract() |
| Sem suporte para entrada de PDF | input.LoadPdf(path) |
| Não há saída em PDF pesquisável. | result.SaveAsSearchablePdf(path) |
| Sem entrada TIFF de várias páginas | input.LoadImageFrames(path) |
| Leitura de código de barras (produto separado) | ocr.Configuration.ReadBarCodes = true |
Múltiplas chamadas InitLicense (por produto) |
Atribuição única IronOcr.License.LicenseKey |
Problemas e soluções comuns em migrações
Problema 1: AppendSettingsFromString retorna resultados vazios após a migração
Dynamsoft: O reconhecimento retorna serenamente matrizes DLRResult vazias quando AppendSettingsFromString recebe uma string JSON malformada. Nenhuma exceção foi lançada. Equipes que migram do Dynamsoft às vezes adicionam verificações de nulos defensivas em todo o código de análise de resultados para se protegerem contra essa falha silenciosa.
Solução: Remova completamente AppendSettingsFromString. O IronOCR não requer nenhuma configuração de modelo. Se for necessário direcionamento de região específico, substitua o JSON ReferenceRegionArray por um CropRectangle:
// Remove all AppendSettingsFromString calls
// Replace region JSON with a CropRectangle constructor
var region = new CropRectangle(x: 0, y: 400, width: 1200, height: 300);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
var result = new IronTesseract().Read(input);
// Remove all AppendSettingsFromString calls
// Replace region JSON with a CropRectangle constructor
var region = new CropRectangle(x: 0, y: 400, width: 1200, height: 300);
using var input = new OcrInput();
input.LoadImage(imagePath, region);
var result = new IronTesseract().Read(input);
Imports System
' Remove all AppendSettingsFromString calls
' Replace region JSON with a CropRectangle constructor
Dim region As New CropRectangle(x:=0, y:=400, width:=1200, height:=300)
Using input As New OcrInput()
input.LoadImage(imagePath, region)
Dim result = New IronTesseract().Read(input)
End Using
O guia de configuração do IronTesseract documenta todas as opções de configuração do mecanismo que podem ser definidas como propriedades em vez de strings JSON.
Problema 2: Múltiplas chamadas InitLicense na inicialização do aplicativo
Dynamsoft: Um aplicativo que usa o Reconhecedor de Rótulos, Leitor de Códigos de Barras e Normalizador de Documento chama três métodos InitLicense separados na inicialização, cada um exigindo sua própria chave de licença. As equipes armazenam três variáveis de ambiente, rotacionam três chaves independentemente e depuram três falhas de inicialização distintas.
Solução: Remover todas as chamadas InitLicense do Dynamsoft. Substitua por uma linha do IronOCR:
// Remove:
// LabelRecognizer.InitLicense(mrzKey);
// BarcodeReader.InitLicense(barcodeKey);
// DocumentNormalizer.InitLicense(docKey);
// Add once, at application startup:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
// Remove:
// LabelRecognizer.InitLicense(mrzKey);
// BarcodeReader.InitLicense(barcodeKey);
// DocumentNormalizer.InitLicense(docKey);
// Add once, at application startup:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
' Remove:
' LabelRecognizer.InitLicense(mrzKey)
' BarcodeReader.InitLicense(barcodeKey)
' DocumentNormalizer.InitLicense(docKey)
' Add once, at application startup:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
Uma única variável de ambiente ativa todas as funcionalidades do IronOCR— OCR, códigos de barras, processamento de PDF e todos os mais de 125 idiomas — sem necessidade de inicialização individual para cada recurso.
Problema 3: A agregação de texto LineResult produz resultados ilegíveis
Dynamsoft: RecognizeFile retorna um DLRResult por região de rótulo detectada. Aplicações que concatenam lineResult.Text em todos os resultados com separadores \n produzem saídas que misturam linhas de diferentes zonas de rótulo na página — porque a ordem dos objetos DLRResult é de detecção de região, não de leitura.
Solução: A hierarquia de resultados do IronOCR organiza a saída na ordem de leitura. Use a estrutura Pages → Paragraphs → Lines para acessar o texto na ordem natural do documento:
var result = new IronTesseract().Read(imagePath);
// Reading-order text — no manual aggregation
Console.WriteLine(result.Text);
// Or access paragraph-level groupings
foreach (var paragraph in result.Pages[0].Paragraphs)
Console.WriteLine(paragraph.Text);
var result = new IronTesseract().Read(imagePath);
// Reading-order text — no manual aggregation
Console.WriteLine(result.Text);
// Or access paragraph-level groupings
foreach (var paragraph in result.Pages[0].Paragraphs)
Console.WriteLine(paragraph.Text);
Imports IronOcr
Dim result = New IronTesseract().Read(imagePath)
' Reading-order text — no manual aggregation
Console.WriteLine(result.Text)
' Or access paragraph-level groupings
For Each paragraph In result.Pages(0).Paragraphs
Console.WriteLine(paragraph.Text)
Next
Problema 4: Arquivos JSON de modelo ausentes no servidor de implantação
Dynamsoft: Os arquivos JSON de modelo são artefatos de implantação separados. Quando um arquivo de template está ausente ou tem um caminho incorreto em um novo servidor, AppendSettingsFromString falha — às vezes silenciosamente, às vezes com uma exceção em tempo de execução — e a implantação quebra o reconhecimento sem tocar no código do aplicativo.
Solução: O IronOCR não possui arquivos de modelo. Após substituir o pacote NuGet e atualizar os namespaces, a lista de artefatos de implantação se reduz aos binários do aplicativo e a uma variável de ambiente. Adicione uma verificação de validação de inicialização, se necessário:
// Validate license at startup — no template files to check
if (!IronOcr.License.IsValidLicense)
throw new InvalidOperationException("IronOCR license key is invalid or missing.");
var ocr = new IronTesseract();
// Ready to process — no file dependencies
// Validate license at startup — no template files to check
if (!IronOcr.License.IsValidLicense)
throw new InvalidOperationException("IronOCR license key is invalid or missing.");
var ocr = new IronTesseract();
// Ready to process — no file dependencies
Imports IronOcr
' Validate license at startup — no template files to check
If Not IronOcr.License.IsValidLicense Then
Throw New InvalidOperationException("IronOCR license key is invalid or missing.")
End If
Dim ocr As New IronTesseract()
' Ready to process — no file dependencies
Edição 5: Gestão da Cadeia de Descarte de Múltiplos Produtos
Dynamsoft: Cada instância de produto Dynamsoft (LabelRecognizer, BarcodeReader, DocumentNormalizer) implementa IDisposable. Classes de serviço que agregam múltiplos produtos possuem implementações de múltiplos níveis Dispose, e a falta de uma chamada Dispose em qualquer instância de produto causa vazamentos de recursos nativos que se manifestam como crescimento de memória sob carga.
Solução: IronTesseract e OcrInput do IronOCR implementam ambos IDisposable, mas o modelo de descarte é mais simples — uma classe, um padrão. Registre uma instância IronTesseract única no contêiner DI como um singleton, ou use blocos using para instâncias de curta duração:
// Short-lived pattern
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = new IronTesseract().Read(input);
// Long-lived singleton (register in Program.cs)
builder.Services.AddSingleton<IronTesseract>();
// Short-lived pattern
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = new IronTesseract().Read(input);
// Long-lived singleton (register in Program.cs)
builder.Services.AddSingleton<IronTesseract>();
Imports IronOcr
' Short-lived pattern
Using input As New OcrInput()
input.LoadImage(imagePath)
Dim result = (New IronTesseract()).Read(input)
End Using
' Long-lived singleton (register in Program.vb)
builder.Services.AddSingleton(Of IronTesseract)()
O guia de acompanhamento de progresso aborda o gerenciamento do ciclo de vida de trabalhos em lote de longa duração, e o guia de OCR assíncrono mostra padrões singleton no ASP.NET Core.
Problema 6: Modelo de caractere não disponível para formato de etiqueta personalizada
Dynamsoft: O campo CharacterModelName em um template refere-se a um arquivo de modelo que deve existir no diretório de instalação do SDK Dynamsoft. Os modelos de personagens personalizados exigem o download de arquivos de modelo adicionais do portal da Dynamsoft e a sua colocação no caminho correto do SDK. A ausência de um modelo faz com que o reconhecimento falhe, resultando em um erro de tempo de execução enigmático.
Solução: O IronOCR não utiliza arquivos de modelo de caracteres. Para fontes personalizadas ou especializadas, utilize o treinamento de idioma personalizado:
// No character model files needed
// For specialized fonts, use a custom language pack
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English; // or load a custom trained pack
using var input = new OcrInput();
input.LoadImage(specializedFontImage);
input.Binarize(); // helps with specialized font clarity
var result = ocr.Read(input);
// No character model files needed
// For specialized fonts, use a custom language pack
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English; // or load a custom trained pack
using var input = new OcrInput();
input.LoadImage(specializedFontImage);
input.Binarize(); // helps with specialized font clarity
var result = ocr.Read(input);
Imports IronTesseract
' No character model files needed
' For specialized fonts, use a custom language pack
Dim ocr As New IronTesseract()
ocr.Language = OcrLanguage.English ' or load a custom trained pack
Using input As New OcrInput()
input.LoadImage(specializedFontImage)
input.Binarize() ' helps with specialized font clarity
Dim result = ocr.Read(input)
End Using
O guia de treinamento de fontes personalizadas aborda o treinamento de um pacote de idiomas personalizado para fontes de rótulos proprietárias sem qualquer configuração de caminho de arquivo.
Lista de verificação para migração do OCR da Dynamsoft
Pré-migração
Audite o código-fonte em busca de todas as referências ao Dynamsoft:
# Find all Dynamsoft using statements
grep -r "using Dynamsoft" --include="*.cs" .
# Find InitLicense calls (one per product)
grep -r "InitLicense" --include="*.cs" .
# Find AppendSettingsFromString calls (template loads)
grep -r "AppendSettingsFromString" --include="*.cs" .
# Find template JSON strings (inline or file references)
grep -r "LabelRecognizerParameterArray\|ReferenceRegionArray\|CharacterModelName" --include="*.cs" .
# Find RecognizeFile and RecognizeByFile calls
grep -r "RecognizeFile\|RecognizeByFile\|RecognizeBuffer" --include="*.cs" .
# Find LineResult result parsing patterns
grep -r "LineResults\|DLRResult\|DLRLineResult" --include="*.cs" .
# Identify any JSON template files in the project
find . -name "*.json" | xargs grep -l "LabelRecognizerParameterArray" 2>/dev/null
# Find all Dynamsoft using statements
grep -r "using Dynamsoft" --include="*.cs" .
# Find InitLicense calls (one per product)
grep -r "InitLicense" --include="*.cs" .
# Find AppendSettingsFromString calls (template loads)
grep -r "AppendSettingsFromString" --include="*.cs" .
# Find template JSON strings (inline or file references)
grep -r "LabelRecognizerParameterArray\|ReferenceRegionArray\|CharacterModelName" --include="*.cs" .
# Find RecognizeFile and RecognizeByFile calls
grep -r "RecognizeFile\|RecognizeByFile\|RecognizeBuffer" --include="*.cs" .
# Find LineResult result parsing patterns
grep -r "LineResults\|DLRResult\|DLRLineResult" --include="*.cs" .
# Identify any JSON template files in the project
find . -name "*.json" | xargs grep -l "LabelRecognizerParameterArray" 2>/dev/null
Resultados do inventário:
- Conte os locais de chamada
InitLicense(um por produto Dynamsoft em uso) - Conte os locais de chamada
AppendSettingsFromString(um por template de reconhecimento) - Liste todos os arquivos de modelo JSON que serão excluídos após a migração.
- Identifique qualquer definição
ReferenceRegionArray(converta paraCropRectangle) - Observe quais funcionalidades são cobertas por produtos separados (códigos de barras, normalização de documentos)
Migração de código
- Remova o pacote NuGet
Dynamsoft.LabelRecognizer(e quaisquer outros pacotes Dynamsoft) - Instale o pacote NuGet
IronOcr(dotnet add package IronOcr) - Substitua todos
using Dynamsoft.LabelRecognizer;eusing Dynamsoft.Core;porusing IronOcr; - Substitua todas as chamadas
LabelRecognizer.InitLicense(key)por uma únicaIronOcr.License.LicenseKey = keyna inicialização do aplicativo - Remova todas as chamadas
AppendSettingsFromString(json)— não é necessário equivalente - Substitua coordenadas JSON
ReferenceRegionArraypor construtoresnew CropRectangle(x, y, width, height) - Substitua a instanciação
new LabelRecognizer()pornew IronTesseract() - Substitua
recognizer.RecognizeFile(path)porocr.Read(path) - Substitua a iteração de resultados
DLRLineResultpor hierarquia.Words - Substitua a agregação manual de cadeias
lineResult.Textporresult.Textou enumeração de páginas estruturadas - Substitua
BarcodeReader.InitLicense+BarcodeReader.DecodeFileporocr.Configuration.ReadBarCodes = true - Remova cadeias multiproduto
Disposee substitua porusing var ocr = new IronTesseract() - Exclua os arquivos de modelo JSON dos artefatos do projeto e da implantação.
- Substitua loops de iteração de quadro sobre arquivos TIFF por
input.LoadImageFrames(path) - Adicione
result.SaveAsSearchablePdf(outputPath)onde quer que saídas digitalizadas precisem ser arquivadas
Pós-migração
- Verificar se
IronOcr.License.IsValidLicenseretornatruena inicialização do aplicativo - Confirme se todos os resultados de reconhecimento retornam
result.Textnão vazios para entradas que anteriormente funcionavam - Verifique
result.Confidenceem amostras representativas — valores acima de 80% indicam boa qualidade de reconhecimento - Teste a precisão do direcionamento de região comparando as saídas
CropRectanglecom os resultados de região anteriores do Dynamsoft - Valide a leitura de código de barras executando
ocr.Configuration.ReadBarCodes = trueem entradas que anteriormente exigiam o Leitor de Código de Barras Dynamsoft - Verifique se o processamento de TIFF de múltiplas páginas produz um
OcrResult.Pagepor quadro - Confirme se o PDF pesquisável permite a busca de texto em um visualizador de PDF.
- Execute testes de processamento paralelo com
Parallel.ForEache verifique se não há contenção de thread - Teste todos os destinos de implantação (Linux, Docker, Azure) para confirmar se a implantação de pacote único funciona sem arquivos de modelo JSON.
- Confirme se não restam variáveis de ambiente da chave de licença da Dynamsoft na configuração de implantação.
Principais benefícios da migração para o IronOCR
Um único pacote elimina o imposto de coordenação multiproduto. Toda capacidade — OCR geral, extração MRZ, leitura de código de barras, entrada PDF nativa, saída PDF pesquisável, pré-processamento e mais de 125 idiomas — é enviada como um único pacote NuGet IronOcr. Atualizações de versão afetam uma entrada de pacote em um arquivo .csproj. A rotação da chave de licença é uma variável de ambiente. O inventário de artefatos de implantação se reduz aos binários do aplicativo, sem arquivos de modelo JSON e sem diretórios de modelos de caracteres.
Sem dependências de arquivos de configuração. O sistema de modelos da Dynamsoft exige que os arquivos JSON estejam presentes e com o caminho correto em tempo de execução. O IronOCR não possui dependências de arquivos em tempo de execução além do próprio pacote NuGet . As imagens do Docker tornam-se determinísticas: o que passa pela integração contínua é exatamente o que é executado em produção. O guia de implantação Docker mostra um Dockerfile completo que requer apenas uma linha apt-get install para Linux.
A saída estruturada reduz o código de integração. O Dynamsoft retorna cadeias de texto LineResult brutas. A extração de dados estruturados — posições de campos, limites de palavras, confiança por token — requer pós-processamento que seu código possui e testa. A hierarquia de resultados do IronOCR expõe páginas, parágrafos, linhas, palavras e caracteres como coleções digitadas com coordenadas e pontuações de confiança em cada nível. As equipes que migram do Dynamsoft normalmente removem de 30 a 50% do código de processamento de resultados, porque o IronOCR fornece a estrutura que elas estavam construindo manualmente. A página de resultados do OCR documenta o modelo de saída completo.
O licenciamento perpétuo elimina a incerteza do orçamento anual. O Reconhecedor de rótulos Dynamsoft não possui opção de licenciamento perpétuo. Um cluster de processamento em funcionamento por cinco anos custa mais de US$ 2.995 por ano apenas para reconhecimento de etiquetas, antes de adicionar produtos de código de barras ou normalização de documentos. A licença Lite do IronOCR$999 é uma compra única que cobre todos os recursos indefinidamente. Para governos, Enterprise e implantações de produção de longa duração, remover as dependências de renovação anual de um componente central de processamento de documentos reduz a complexidade do processo de aquisição e elimina o risco de cancelamento da assinatura no meio do projeto. A página de licenciamento do IronOCR lista todos os níveis e o que cada um inclui.
Compatível com várias plataformas sem necessidade de configuração específica. O IronOCR identifica o binário de tempo de execução correto para Windows x64, Linux x64, macOS x64 e macOS ARM por meio do gráfico de identificadores de tempo de execução do NuGet. Sem blocos <PackageReference> condicionais, sem código de detecção de plataforma, sem configuração de caminho binário nativo. O mesmo código using IronOcr; é compilado e executado no Windows, Linux, AWS Lambda, e Azure App Service sem modificação.
A cobertura de idiomas se adapta às necessidades da aplicação. O Reconhecedor de rótulos Dynamsoft foi projetado para formatos MRZ com caracteres latinos. Os alfabetos não latinos — árabe, chinês, japonês, coreano, hebraico — estão fora do escopo do seu projeto.IronOCR suporta mais de 125 idiomas instalados como pacotes NuGet individuais: dotnet add package IronOcr.Languages.Arabic adiciona suporte ao Árabe sem mudança de código no pipeline de reconhecimento. O índice de idiomas lista todos os pacotes de idiomas disponíveis. Para aplicações que processam documentos de identidade internacionais, etiquetas de envio multilíngues ou faturas internacionais, essa abrangência significa que uma única biblioteca cobre todos os tipos de documentos que uma aplicação em crescimento pode encontrar.
Perguntas frequentes
Por que devo migrar do SDK de OCR da Dynamsoft para o IronOCR?
Entre os principais motivos, incluem-se a eliminação da complexidade da interoperabilidade COM, a substituição do gerenciamento de licenças baseado em arquivos, a eliminação da cobrança por página, a viabilização da implantação em Docker/contêineres e a adoção de um fluxo de trabalho nativo do NuGet que se integra às ferramentas padrão do .NET.
Quais são as principais alterações de código ao migrar do SDK de OCR da Dynamsoft para o IronOCR?
Substitua as sequências de inicialização do Dynamsoft OCR pela instanciação do IronTesseract, remova o gerenciamento do ciclo de vida COM (padrões explícitos de Criação/Carregamento/Fechamento) e atualize os nomes das propriedades de resultado. O resultado é uma redução significativa no número de linhas de código repetitivo.
Como faço para instalar o IronOCR para iniciar a migração?
Execute 'Install-Package IronOcr' no Console do Gerenciador de Pacotes ou 'dotnet add package IronOcr' na CLI. Os pacotes de idiomas são pacotes separados: 'dotnet add package IronOcr.Languages.French' para francês, por exemplo.
O IronOCR atinge a mesma precisão de OCR que o SDK de OCR da Dynamsoft para documentos comerciais padrão?
O IronOCR alcança alta precisão para conteúdo comercial padrão, incluindo faturas, contratos, recibos e formulários digitados. Filtros de pré-processamento de imagem (correção de distorção, remoção de ruído, aprimoramento de contraste) melhoram ainda mais o reconhecimento em entradas de baixa qualidade.
Como o IronOCR lida com os dados de idioma que o SDK OCR da Dynamsoft instala separadamente?
Os dados de idioma no IronOCR são distribuídos como pacotes NuGet. O comando 'dotnet add package IronOcr.Languages.German' instala o suporte ao alemão. Não é necessário inserir arquivos manualmente nem configurar caminhos de diretório.
A migração do SDK de OCR da Dynamsoft para o IronOCR requer alterações na infraestrutura de implantação?
O IronOCR requer menos alterações de infraestrutura do que o SDK de OCR da Dynamsoft. Não há caminhos binários do SDK, necessidade de instalar arquivos de licença ou configurar servidores de licença. O pacote NuGet contém o mecanismo de OCR completo e a chave de licença é uma string definida no código do aplicativo.
Como configuro o licenciamento do IronOCR após a migração?
Atribua `IronOcr.License.LicenseKey = "YOUR-KEY"` no código de inicialização do aplicativo. No Docker ou Kubernetes, armazene a chave como uma variável de ambiente e leia-a na inicialização. Use `License.IsValidLicense` para validar a licença antes de aceitar o tráfego.
O IronOCR consegue processar PDFs da mesma forma que o Dynamsoft OCR?
Sim. O IronOCR lê PDFs nativos e digitalizados. Instancie o IronTesseract, chame ocr.Read(input) onde input é um caminho para um PDF ou OcrPdfInput, e itere pelas páginas do OcrResult. Não é necessário um pipeline de renderização de PDF separado.
Como o IronOCR lida com multithreading em processamento de alto volume?
O IronTesseract pode ser instanciado com segurança por thread. Crie uma instância por thread em um Parallel.ForEach ou pool de Tasks, execute o OCR simultaneamente e descarte cada instância ao terminar. Não é necessário nenhum estado global ou bloqueio.
Quais formatos de saída o IronOCR suporta após a extração de texto?
O IronOCR retorna resultados estruturados, incluindo texto, coordenadas de palavras, níveis de confiança e estrutura da página. As opções de exportação incluem texto simples, PDF pesquisável e objetos de resultados estruturados para processamento posterior.
O preço do IronOCR é mais previsível do que o do SDK OCR da Dynamsoft para dimensionamento de cargas de trabalho?
O IronOCR utiliza licenciamento perpétuo com preço fixo, sem cobranças por página ou volume. Independentemente de você processar 10.000 ou 10 milhões de páginas, o custo da licença permanece constante. As opções de licenciamento por volume e para equipes estão disponíveis na página de preços do IronOCR.
O que acontece com meus testes existentes após a migração do SDK de OCR da Dynamsoft para o IronOCR?
Os testes que verificam o conteúdo de texto extraído devem continuar a ser aprovados após a migração. Os testes que validam padrões de chamadas de API ou o ciclo de vida de objetos COM precisarão ser atualizados para refletir o modelo de inicialização e resultados mais simples do IronOCR.

