Migración de Asprise OCR a IronOCR
Esta guía acompaña a los desarrolladores .NET paso a paso en el proceso de sustitución de OCR Asprise por IronOCR . Abarca el intercambio mecánico de paquetes, los cambios de espacio de nombres y los cuatro patrones de migración de código que representan la mayor parte del uso de Asprise en aplicaciones .NET de producción. El público objetivo son los desarrolladores que ya han decidido migrar y necesitan un plan de acción concreto.
¿Por qué migrar desde Asprise OCR?
Asprise OCR se diseñó inicialmente como un producto Java. La interfaz .NET es una capa que envuelve un motor nativo de origen Java, y ese origen determina todos los aspectos del comportamiento de la biblioteca en .NET , desde la implementación hasta el diseño de la API y las restricciones de licencia.
Dependencia de binario nativo y JRE. OCR Asprise for .NET requiere binarios nativos específicos de la plataforma (aocr.dll, aocr_x64.dll, libaocr.so, libaocr.dylib) que deben estar presentes en cada máquina donde se ejecute la aplicación. Cada archivo binario debe coincidir exactamente con la plataforma de destino y la arquitectura del proceso. Un contenedor de Docker de 64 bits construido con la DLL de 32 bits lanza BadImageFormatException en tiempo de ejecución. Un despliegue de Linux que falta libaocr.so de LD_LIBRARY_PATH lanza DllNotFoundException. Ninguno de los errores se manifiesta durante la compilación. Cada nuevo destino de despliegue (un nuevo servidor, una nueva imagen de contenedor, un agente de CI) se convierte en un ejercicio manual de obtención de binarios.
API de cadena-constante de herencia de Java. Asprise expone constantes enteras para el tipo de reconocimiento y formato de salida: Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT, Ocr.OUTPUT_FORMAT_XML. Estas constantes se corresponden directamente con la API basada en enteros del SDK de Java. Los desarrolladores de .NET no reciben ninguna guía de IntelliSense sobre valores constantes válidos, ni seguridad en tiempo de compilación sobre combinaciones de argumentos, ni objetos de resultado fuertemente tipados. La extracción de resultados estructurados requiere el análisis manual de cadenas XML.
No hay soporte para funciones asíncronas sin soluciones alternativas. Asprise no proporciona una API asíncrona nativa. Encerrar llamadas sincrónicas de Asprise en Task.Run para evitar bloquear hilos de ASP.NET crea presión en el grupo de hilos y no resuelve la restricción de licencia que prohíbe la ejecución concurrente en niveles LITE y STANDARD. Los patrones asíncronos en las aplicaciones .NET modernas (servicios en segundo plano, puntos finales de API mínimos, Azure Functions) no tienen un equivalente claro en Asprise.
El procesamiento de archivos TIFF multifotograma requiere división manual. Asprise funciona con archivos de imagen individuales. El procesamiento de un archivo TIFF de varias páginas requiere código externo para dividir los fotogramas en archivos individuales y, a continuación, procesar cada archivo en un bucle. No se conservan los metadatos de los fotogramas ni la numeración de las páginas en el archivo de salida.
La restricción de subprocesos impide la implementación en producción. Las licencias Lite (~$299) y STANDARD (~$699) restringen contractualmente la ejecución a un solo subproceso y un solo proceso. ASP.NET Core procesa todas las solicitudes HTTP en un grupo de subprocesos. Cada punto final de la API web que llama a Asprise en esos niveles constituye una infracción de licencia desde la primera solicitud simultánea. La actualización a Enterprise elimina la restricción, pero requiere contactar con el departamento de ventas, cuyo precio no está publicado; las estimaciones oscilan entre 2000 y más de 5000 dólares, según el alcance de la implementación.
El manejo del formato de salida requiere análisis de cadenas. Cuando se especifica OUTPUT_FORMAT_XML, Asprise devuelve una cadena XML en bruto. La aplicación se encarga de deserializar esa cadena, validar su estructura y extraer las palabras y sus coordenadas. Las puntuaciones de confianza por palabra están integradas en los atributos XML. No existe un modelo de objetos, solo manipulación de cadenas de texto.
El problema fundamental
Asprise requiere una configuración binaria nativa adyacente a JRE antes de que se pueda ejecutar la primera llamada de OCR.IronOCR no requiere nada más que un paquete NuGet :
// Asprise: native binary must exist in PATH or application directory
// aocr_x64.dll missing → DllNotFoundException at runtime, not at build
Ocr.SetUp(); // Static init — touches native binary
Ocr ocr = new Ocr();
ocr.StartEngine("eng", Ocr.SPEED_FAST); // Allocates native engine memory
string text = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT);
ocr.StopEngine(); // Must call or native memory leaks
// Asprise: native binary must exist in PATH or application directory
// aocr_x64.dll missing → DllNotFoundException at runtime, not at build
Ocr.SetUp(); // Static init — touches native binary
Ocr ocr = new Ocr();
ocr.StartEngine("eng", Ocr.SPEED_FAST); // Allocates native engine memory
string text = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT);
ocr.StopEngine(); // Must call or native memory leaks
' Asprise: native binary must exist in PATH or application directory
' aocr_x64.dll missing → DllNotFoundException at runtime, not at build
Ocr.SetUp() ' Static init — touches native binary
Dim ocr As New Ocr()
ocr.StartEngine("eng", Ocr.SPEED_FAST) ' Allocates native engine memory
Dim text As String = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT)
ocr.StopEngine() ' Must call or native memory leaks
// IronOCR: dotnet add package IronOcr — no binary sourcing, no lifecycle calls
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
string text = new IronTesseract().Read(imagePath).Text;
// IronOCR: dotnet add package IronOcr — no binary sourcing, no lifecycle calls
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
string text = new IronTesseract().Read(imagePath).Text;
' IronOCR: dotnet add package IronOcr — no binary sourcing, no lifecycle calls
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).Text
IronOCR vs Asprise OCR: Comparación de características
La tabla que aparece a continuación resume las funcionalidades más relevantes para los desarrolladores que evalúan esta migración.
| Característica | OCR Asprise | IronOCR |
|---|---|---|
| Plataforma principal | Java (heredado) | .NET nativo |
| Instalación de NuGet | Envoltorio + DLLs nativas de la plataforma | Paquete único (IronOcr) |
| Se requiere un binario nativo en tiempo de ejecución. | Sí (DLL por plataforma) | No |
| Estilo de API de .NET | Constantes enteras, devoluciones de cadena | Clases y enumeraciones fuertemente tipadas |
IDisposable / using patrón |
No implementado | Sí (OcrInput) |
| OCR asíncrono | Sin soporte nativo | Sí (ReadAsync) |
| Multiprocesamiento — Nivel Lite/ESTÁNDAR | Prohibido por licencia | Permitido |
| Multiprocesamiento — todos los niveles | Solo para Enterprise | Todos los niveles |
| Compatibilidad con ASP.NET Core Web API | Se requiere Enterprise | Cualquier nivel |
| Azure Functions / AWS Lambda | Se requiere Enterprise | Cualquier nivel |
| Entrada nativa de PDF | No | Sí |
| Entrada TIFF multifotograma | No (división manual de fotogramas) | Sí (LoadImageFrames) |
| Matriz de bytes y entrada de flujo | Limitado | Sí |
| Preprocesamiento de imágenes integrado | No | Sí (más de 9 filtros) |
| Salida en PDF con capacidad de búsqueda | No | Sí (SaveAsSearchablePdf) |
| Modelo de objeto de resultado estructurado | No (solo cadena XML) | Sí (páginas, párrafos, palabras, caracteres) |
| Puntuaciones de confianza por palabra | No (análisis de atributos XML) | Sí (result.Confidence) |
| Coordenadas de píxeles de la palabra | Análisis de atributos XML | Propiedades fuertemente tipadas |
| Recuento de palabras | Más de 20 años | 125+ |
| Selección de lenguaje fuertemente tipado | No (códigos de cadena) | Sí (OcrLanguage enum) |
| Lectura de códigos de barras | Sí (reconocer tipo por separado) | Sí (indicador de configuración) |
| Exportación hOCR | No | Sí |
| Implementación multiplataforma | Binario manual por plataforma | NuGet admite todas las plataformas. |
| Docker / Linux / macOS | Configuración manual LD_LIBRARY_PATH |
Funcionamiento inmediato |
| Compatibilidad con .NET | Limitado (puente Java) | .NET Framework 4.6.2+, .NET 5-9 |
| Precio de entrada para el uso del servidor | Enterprise (~$2,000+) | $999 (Lite, todas las funciones) |
| Tipo de licencia | Para cada nivel, contacte con el departamento de ventas de Enterprise. | Perpetuo (compra única) |
Inicio rápido: Migración de OCR Asprise a IronOCR
Paso 1: Sustituir el paquete NuGet
Eliminar Asprise OCR:
dotnet remove package asprise-ocr-api
dotnet remove package asprise-ocr-api
Instale IronOCR desde la página del paquete NuGet :
dotnet add package IronOcr
Paso 2: Actualizar los espacios de nombres
Reemplaza espacios de nombres de Asprise con el espacio de nombres IronOCR:
// Before (Asprise)
using asprise.ocr;
// After (IronOCR)
using IronOcr;
// Before (Asprise)
using asprise.ocr;
// After (IronOCR)
using IronOcr;
Imports IronOcr
Paso 3: Inicializar licencia
Añadir la asignación de clave de licencia al inicio de la aplicación — en Program.cs antes de cualquier llamada OCR, en Startup.Configure, o en un constructor estático:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Puede obtener una clave de prueba gratuita en la página de licencias de IronOCR . Durante el desarrollo y la evaluación,IronOCR se ejecuta sin clave y añade una marca de agua de prueba a la salida.
Ejemplos de migración de código
Eliminación de la configuración de la ruta JRE y la inicialización del motor
Las aplicaciones de Asprise que se ejecutan en Linux o macOS suelen incluir código de inicio que establece la ruta de JRE o valida la presencia de binarios nativos antes de que comience cualquier trabajo de OCR. Esta infraestructura no tiene equivalente en IronOCR.
Enfoque OCR de Asprise:
// AppStartup.cs — native binary validation before accepting any requests
public static void InitializeOcr()
{
// Validate native library is reachable before first use
string nativePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Path.Combine(AppContext.BaseDirectory, "aocr_x64.dll")
: RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
? "/usr/lib/libaocr.so"
: "/usr/local/lib/libaocr.dylib";
if (!File.Exists(nativePath))
throw new FileNotFoundException(
$"Asprise native binary not found: {nativePath}. " +
"Deploy the correct platform binary before starting.");
// Static global init — must run before any Ocr instance is created
Ocr.SetUp();
}
// AppStartup.cs — native binary validation before accepting any requests
public static void InitializeOcr()
{
// Validate native library is reachable before first use
string nativePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Path.Combine(AppContext.BaseDirectory, "aocr_x64.dll")
: RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
? "/usr/lib/libaocr.so"
: "/usr/local/lib/libaocr.dylib";
if (!File.Exists(nativePath))
throw new FileNotFoundException(
$"Asprise native binary not found: {nativePath}. " +
"Deploy the correct platform binary before starting.");
// Static global init — must run before any Ocr instance is created
Ocr.SetUp();
}
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
' AppStartup.vb — native binary validation before accepting any requests
Public Module AppStartup
Public Sub InitializeOcr()
' Validate native library is reachable before first use
Dim nativePath As String = If(RuntimeInformation.IsOSPlatform(OSPlatform.Windows),
Path.Combine(AppContext.BaseDirectory, "aocr_x64.dll"),
If(RuntimeInformation.IsOSPlatform(OSPlatform.Linux),
"/usr/lib/libaocr.so",
"/usr/local/lib/libaocr.dylib"))
If Not File.Exists(nativePath) Then
Throw New FileNotFoundException($"Asprise native binary not found: {nativePath}. " &
"Deploy the correct platform binary before starting.")
End If
' Static global init — must run before any Ocr instance is created
Ocr.SetUp()
End Sub
End Module
Enfoque IronOCR:
// Program.cs — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// That is it. No binary validation, no path configuration, no SetUp() call.
// NuGet resolved the correct native runtime during package restore.
// Program.cs — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// That is it. No binary validation, no path configuration, no SetUp() call.
// NuGet resolved the correct native runtime during package restore.
Imports IronOcr
' Program.vb — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
' That is it. No binary validation, no path configuration, no SetUp() call.
' NuGet resolved the correct native runtime during package restore.
El patrón de Asprise es típicamente de 15-30 líneas a través de múltiples archivos — un validador de inicio, un cambio de plataforma, una excepción con un mensaje de despliegue y la llamada SetUp().IronOCR lo reemplaza todo con una sola tarea. La guía de configuración de IronTesseract abarca las opciones de configuración de implementación para entornos que requieren rutas de datos de prueba personalizadas o funcionamiento sin conexión.
Sustitución del formato de salida XML por objetos de resultados estructurados.
Asprise produce una salida estructurada como una cadena XML en bruto cuando se especifica OUTPUT_FORMAT_XML. Para extraer el texto, las coordenadas y el nivel de confianza de esa cadena, se necesita código de análisis XML.IronOCR devuelve un gráfico de objetos tipados.
Enfoque OCR de Asprise:
// Asprise: structured output is an XML string — must parse manually
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
string xmlOutput = ocr.Recognize(
imagePath,
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_XML); // Returns raw XML, not an object
// Parse the XML manually to extract words and coordinates
var doc = System.Xml.Linq.XDocument.Parse(xmlOutput);
var words = doc.Descendants("word")
.Select(w => new
{
Text = (string)w.Attribute("text"),
Confidence = (float)w.Attribute("confidence"),
X = (int)w.Attribute("x"),
Y = (int)w.Attribute("y"),
})
.ToList();
foreach (var word in words)
Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence}");
}
finally
{
ocr.StopEngine();
}
// Asprise: structured output is an XML string — must parse manually
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
string xmlOutput = ocr.Recognize(
imagePath,
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_XML); // Returns raw XML, not an object
// Parse the XML manually to extract words and coordinates
var doc = System.Xml.Linq.XDocument.Parse(xmlOutput);
var words = doc.Descendants("word")
.Select(w => new
{
Text = (string)w.Attribute("text"),
Confidence = (float)w.Attribute("confidence"),
X = (int)w.Attribute("x"),
Y = (int)w.Attribute("y"),
})
.ToList();
foreach (var word in words)
Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence}");
}
finally
{
ocr.StopEngine();
}
Imports System.Xml.Linq
' Asprise: structured output is an XML string — must parse manually
Ocr.SetUp()
Dim ocr As New Ocr()
Try
ocr.StartEngine("eng", Ocr.SPEED_FAST)
Dim xmlOutput As String = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_XML) ' Returns raw XML, not an object
' Parse the XML manually to extract words and coordinates
Dim doc As XDocument = XDocument.Parse(xmlOutput)
Dim words = doc.Descendants("word") _
.Select(Function(w) New With {
.Text = CStr(w.Attribute("text")),
.Confidence = CSng(w.Attribute("confidence")),
.X = CInt(w.Attribute("x")),
.Y = CInt(w.Attribute("y"))
}) _
.ToList()
For Each word In words
Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence}")
Next
Finally
ocr.StopEngine()
End Try
Enfoque IronOCR:
// IronOCR: structured result is a typed object — no XML parsing
var result = new IronTesseract().Read(imagePath);
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
foreach (var word in paragraph.Words)
{
Console.WriteLine(
$"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence:F1}%");
}
}
}
// IronOCR: structured result is a typed object — no XML parsing
var result = new IronTesseract().Read(imagePath);
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
foreach (var word in paragraph.Words)
{
Console.WriteLine(
$"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence:F1}%");
}
}
}
Imports IronOcr
' IronOCR: structured result is a typed object — no XML parsing
Dim result = New IronTesseract().Read(imagePath)
For Each page In result.Pages
For Each paragraph In page.Paragraphs
For Each word In paragraph.Words
Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence:F1}%")
Next
Next
Next
Sin deserialización XML, sin conversión de atributos, sin suposiciones de esquema. El modelo de objeto OcrResult expone páginas, párrafos, líneas, palabras y caracteres con propiedades tipadas. La guía de resultados de lectura abarca la jerarquía completa y el sistema de coordenadas, incluyendo cómo filtrar por umbral de confianza para flujos de trabajo automatizados.
Procesamiento de archivos TIFF multifotograma
Asprise acepta archivos de imagen individuales. Un archivo TIFF multifotograma, habitual en los flujos de trabajo de escaneo de documentos, debe dividirse en archivos de fotogramas individuales antes de que Asprise pueda procesarlo.IronOCR acepta TIFFs de múltiples cuadros directamente a través de LoadImageFrames.
Enfoque OCR de Asprise:
// Asprise: no multi-frame TIFF support — split frames externally first
// Using an external imaging library (e.g., System.Drawing or Magick.NET)
var frameFiles = new List<string>();
using (var tiff = System.Drawing.Image.FromFile("scanned-batch.tiff"))
{
int frameCount = tiff.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
for (int i = 0; i < frameCount; i++)
{
tiff.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
string framePath = $"frame_{i}.png";
tiff.Save(framePath);
frameFiles.Add(framePath);
}
}
// Now process each frame individually — sequential on LITE/STANDARD
var allText = new System.Text.StringBuilder();
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
foreach (var framePath in frameFiles)
{
string pageText = ocr.Recognize(
framePath,
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_PLAINTEXT);
allText.AppendLine(pageText);
}
}
finally
{
ocr.StopEngine();
// Clean up temporary frame files
foreach (var f in frameFiles)
File.Delete(f);
}
Console.WriteLine(allText.ToString());
// Asprise: no multi-frame TIFF support — split frames externally first
// Using an external imaging library (e.g., System.Drawing or Magick.NET)
var frameFiles = new List<string>();
using (var tiff = System.Drawing.Image.FromFile("scanned-batch.tiff"))
{
int frameCount = tiff.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
for (int i = 0; i < frameCount; i++)
{
tiff.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
string framePath = $"frame_{i}.png";
tiff.Save(framePath);
frameFiles.Add(framePath);
}
}
// Now process each frame individually — sequential on LITE/STANDARD
var allText = new System.Text.StringBuilder();
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
foreach (var framePath in frameFiles)
{
string pageText = ocr.Recognize(
framePath,
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_PLAINTEXT);
allText.AppendLine(pageText);
}
}
finally
{
ocr.StopEngine();
// Clean up temporary frame files
foreach (var f in frameFiles)
File.Delete(f);
}
Console.WriteLine(allText.ToString());
Imports System.Drawing
Imports System.Text
Imports System.IO
' Asprise: no multi-frame TIFF support — split frames externally first
' Using an external imaging library (e.g., System.Drawing or Magick.NET)
Dim frameFiles As New List(Of String)()
Using tiff As Image = Image.FromFile("scanned-batch.tiff")
Dim frameCount As Integer = tiff.GetFrameCount(Imaging.FrameDimension.Page)
For i As Integer = 0 To frameCount - 1
tiff.SelectActiveFrame(Imaging.FrameDimension.Page, i)
Dim framePath As String = $"frame_{i}.png"
tiff.Save(framePath)
frameFiles.Add(framePath)
Next
End Using
' Now process each frame individually — sequential on LITE/STANDARD
Dim allText As New StringBuilder()
Ocr.SetUp()
Dim ocr As New Ocr()
Try
ocr.StartEngine("eng", Ocr.SPEED_FAST)
For Each framePath As String In frameFiles
Dim pageText As String = ocr.Recognize(framePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT)
allText.AppendLine(pageText)
Next
Finally
ocr.StopEngine()
' Clean up temporary frame files
For Each f As String In frameFiles
File.Delete(f)
Next
End Try
Console.WriteLine(allText.ToString())
Enfoque IronOCR:
// IronOCR: multi-frame TIFF loads directly — no frame splitting, no temp files
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff"); // All frames, one call
var result = new IronTesseract().Read(input);
// Access each page independently with its page number
foreach (var page in result.Pages)
Console.WriteLine($"Page {page.PageNumber}: {page.Text}");
// IronOCR: multi-frame TIFF loads directly — no frame splitting, no temp files
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff"); // All frames, one call
var result = new IronTesseract().Read(input);
// Access each page independently with its page number
foreach (var page in result.Pages)
Console.WriteLine($"Page {page.PageNumber}: {page.Text}");
Imports IronOcr
' IronOCR: multi-frame TIFF loads directly — no frame splitting, no temp files
Using input As New OcrInput()
input.LoadImageFrames("scanned-batch.tiff") ' All frames, one call
Dim result = New IronTesseract().Read(input)
' Access each page independently with its page number
For Each page In result.Pages
Console.WriteLine($"Page {page.PageNumber}: {page.Text}")
Next
End Using
El método Asprise requiere una dependencia de procesamiento de imágenes externo, gestión de archivos temporales, limpieza manual y procesamiento secuencial por fotograma.IronOCR procesa todos los fotogramas en una sola pasada. La guía de entrada de archivos TIFF y GIF abarca la selección del rango de fotogramas para archivos TIFF grandes en los que solo se necesitan páginas específicas.
Generación de PDF con capacidad de búsqueda
Asprise no ofrece la posibilidad de generar archivos PDF con texto seleccionable en ningún nivel de licencia. Para crear un PDF con texto OCR incrustado a partir de un documento escaneado, se requiere una biblioteca PDF externa, un paso de OCR independiente para obtener las posiciones del texto y la construcción manual de la superposición.IronOCR genera archivos PDF con capacidad de búsqueda directamente a partir del resultado del reconocimiento.
Enfoque OCR de Asprise:
// Asprise: no searchable PDF output — external PDF library required
// Step 1: OCR the document to get text
Ocr.SetUp();
Ocr ocr = new Ocr();
string recognizedText;
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
recognizedText = ocr.Recognize(
"scanned-contract.jpg",
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_PLAINTEXT); // Only plain text — no position data
}
finally
{
ocr.StopEngine();
}
// Step 2: Use an external PDF library to embed text over the image
// (iTextSharp, PdfSharp, or similar — adds another dependency and license)
// Text positioning requires coordinate data Asprise cannot provide in plain text mode
// ... 40-80 lines of PDF construction code
Console.WriteLine("Searchable PDF: not achievable with Asprise alone");
// Asprise: no searchable PDF output — external PDF library required
// Step 1: OCR the document to get text
Ocr.SetUp();
Ocr ocr = new Ocr();
string recognizedText;
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
recognizedText = ocr.Recognize(
"scanned-contract.jpg",
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_PLAINTEXT); // Only plain text — no position data
}
finally
{
ocr.StopEngine();
}
// Step 2: Use an external PDF library to embed text over the image
// (iTextSharp, PdfSharp, or similar — adds another dependency and license)
// Text positioning requires coordinate data Asprise cannot provide in plain text mode
// ... 40-80 lines of PDF construction code
Console.WriteLine("Searchable PDF: not achievable with Asprise alone");
' Asprise: no searchable PDF output — external PDF library required
' Step 1: OCR the document to get text
Ocr.SetUp()
Dim ocr As New Ocr()
Dim recognizedText As String
Try
ocr.StartEngine("eng", Ocr.SPEED_FAST)
recognizedText = ocr.Recognize( _
"scanned-contract.jpg", _
Ocr.RECOGNIZE_TYPE_TEXT, _
Ocr.OUTPUT_FORMAT_PLAINTEXT) ' Only plain text — no position data
Finally
ocr.StopEngine()
End Try
' Step 2: Use an external PDF library to embed text over the image
' (iTextSharp, PdfSharp, or similar — adds another dependency and license)
' Text positioning requires coordinate data Asprise cannot provide in plain text mode
' ... 40-80 lines of PDF construction code
Console.WriteLine("Searchable PDF: not achievable with Asprise alone")
Enfoque IronOCR:
// IronOCR: searchable PDF in two lines — no external PDF library
var result = new IronTesseract().Read("scanned-contract.jpg");
result.SaveAsSearchablePdf("searchable-contract.pdf");
// Batch: convert a folder of scanned images to searchable PDFs
foreach (var imagePath in Directory.GetFiles("scans", "*.jpg"))
{
var batchResult = new IronTesseract().Read(imagePath);
string outputPath = Path.ChangeExtension(imagePath, ".searchable.pdf");
batchResult.SaveAsSearchablePdf(outputPath);
Console.WriteLine($"Converted: {outputPath}");
}
// IronOCR: searchable PDF in two lines — no external PDF library
var result = new IronTesseract().Read("scanned-contract.jpg");
result.SaveAsSearchablePdf("searchable-contract.pdf");
// Batch: convert a folder of scanned images to searchable PDFs
foreach (var imagePath in Directory.GetFiles("scans", "*.jpg"))
{
var batchResult = new IronTesseract().Read(imagePath);
string outputPath = Path.ChangeExtension(imagePath, ".searchable.pdf");
batchResult.SaveAsSearchablePdf(outputPath);
Console.WriteLine($"Converted: {outputPath}");
}
Imports System.IO
Imports IronOcr
' IronOCR: searchable PDF in two lines — no external PDF library
Dim result = New IronTesseract().Read("scanned-contract.jpg")
result.SaveAsSearchablePdf("searchable-contract.pdf")
' Batch: convert a folder of scanned images to searchable PDFs
For Each imagePath In Directory.GetFiles("scans", "*.jpg")
Dim batchResult = New IronTesseract().Read(imagePath)
Dim outputPath As String = Path.ChangeExtension(imagePath, ".searchable.pdf")
batchResult.SaveAsSearchablePdf(outputPath)
Console.WriteLine($"Converted: {outputPath}")
Next
El PDF con capacidad de búsqueda contiene la imagen original como capa visual con texto OCR invisible superpuesto en las coordenadas correctas, el formato estándar para flujos de trabajo de archivo y cumplimiento normativo. Consulte la guía práctica en formato PDF con función de búsqueda y el ejemplo en formato PDF con función de búsqueda para conocer las opciones disponibles, incluida la salida en formato PDF/A para el archivo a largo plazo.
OCR asíncrono en aplicaciones web
Asprise no tiene una API asíncrona. Los desarrolladores lo integran en aplicaciones .NET asíncronas envolviendo llamadas sincrónicas en Task.Run, lo que consume hilos del grupo de hilos y no elimina el bloqueo.IronOCR proporciona una ruta asíncrona nativa.
Enfoque OCR de Asprise:
// Asprise: no async API — must offload to Task.Run
// This blocks a thread pool thread during the entire OCR operation
// On LITE/STANDARD, concurrent Task.Run calls = license violation
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
string tempPath = Path.GetTempFileName();
await using (var fs = new FileStream(tempPath, FileMode.Create))
await fileStream.CopyToAsync(fs);
// Task.Run wraps synchronous Asprise — occupies a thread pool thread
// Two concurrent requests still violate LITE/STANDARD license
return await Task.Run(() =>
{
Ocr ocr = new Ocr();
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
return ocr.Recognize(
tempPath,
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_PLAINTEXT);
}
finally
{
ocr.StopEngine();
File.Delete(tempPath);
}
});
}
// Asprise: no async API — must offload to Task.Run
// This blocks a thread pool thread during the entire OCR operation
// On LITE/STANDARD, concurrent Task.Run calls = license violation
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
string tempPath = Path.GetTempFileName();
await using (var fs = new FileStream(tempPath, FileMode.Create))
await fileStream.CopyToAsync(fs);
// Task.Run wraps synchronous Asprise — occupies a thread pool thread
// Two concurrent requests still violate LITE/STANDARD license
return await Task.Run(() =>
{
Ocr ocr = new Ocr();
try
{
ocr.StartEngine("eng", Ocr.SPEED_FAST);
return ocr.Recognize(
tempPath,
Ocr.RECOGNIZE_TYPE_TEXT,
Ocr.OUTPUT_FORMAT_PLAINTEXT);
}
finally
{
ocr.StopEngine();
File.Delete(tempPath);
}
});
}
Imports System.IO
Imports System.Threading.Tasks
' Asprise: no async API — must offload to Task.Run
' This blocks a thread pool thread during the entire OCR operation
' On LITE/STANDARD, concurrent Task.Run calls = license violation
Public Async Function ProcessUploadAsync(fileStream As Stream, fileName As String) As Task(Of String)
Dim tempPath As String = Path.GetTempFileName()
Await Using fs As New FileStream(tempPath, FileMode.Create)
Await fileStream.CopyToAsync(fs)
End Using
' Task.Run wraps synchronous Asprise — occupies a thread pool thread
' Two concurrent requests still violate LITE/STANDARD license
Return Await Task.Run(Function()
Dim ocr As New Ocr()
Try
ocr.StartEngine("eng", Ocr.SPEED_FAST)
Return ocr.Recognize(tempPath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT)
Finally
ocr.StopEngine()
File.Delete(tempPath)
End Try
End Function)
End Function
Enfoque IronOCR:
// IronOCR: native async, concurrent requests permitted on all tiers
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
using var input = new OcrInput();
input.LoadImage(fileStream); // Stream input directly — no temp file
var ocr = new IronTesseract();
var result = await ocr.ReadAsync(input);
return result.Text;
}
// IronOCR: native async, concurrent requests permitted on all tiers
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
using var input = new OcrInput();
input.LoadImage(fileStream); // Stream input directly — no temp file
var ocr = new IronTesseract();
var result = await ocr.ReadAsync(input);
return result.Text;
}
Imports System.IO
Imports System.Threading.Tasks
' IronOCR: native async, concurrent requests permitted on all tiers
Public Async Function ProcessUploadAsync(fileStream As Stream, fileName As String) As Task(Of String)
Using input As New OcrInput()
input.LoadImage(fileStream) ' Stream input directly — no temp file
Dim ocr As New IronTesseract()
Dim result = Await ocr.ReadAsync(input)
Return result.Text
End Using
End Function
La versión de IronOCR elimina la escritura de archivos temporales, el envoltorio Task.Run, y el comportamiento de bloqueo de hilos. Múltiples solicitudes concurrentes cada una crea su propia instancia de IronTesseract — la clase es sin estado y cada instancia es independiente. La guía de OCR asíncrona cubre patrones ReadAsync y soporte para tokens de cancelación para operaciones por lotes de larga duración en servicios alojados.
Referencia de mapeo de la API OCR de Asprise a IronOCR
| OCR Asprise | Equivalente a IronOCR |
|---|---|
asprise.ocr espacio de nombres |
IronOcr espacio de nombres |
Ocr.SetUp() |
No es necesario |
new Ocr() |
new IronTesseract() |
ocr.StartEngine("eng", Ocr.SPEED_FAST) |
No es necesario |
ocr.StartEngine("eng+fra", speed) |
ocr.Language = OcrLanguage.English + OcrLanguage.French |
ocr.Recognize(path, type, format) |
ocr.Read(path) o ocr.Read(input) |
Ocr.RECOGNIZE_TYPE_TEXT |
Comportamiento por defecto |
Ocr.RECOGNIZE_TYPE_BARCODE |
ocr.Configuration.ReadBarCodes = true |
Ocr.RECOGNIZE_TYPE_ALL |
ocr.Configuration.ReadBarCodes = true |
Ocr.OUTPUT_FORMAT_PLAINTEXT |
result.Text |
Ocr.OUTPUT_FORMAT_XML |
result.Pages / result.Pages[n].Words |
Ocr.OUTPUT_FORMAT_PDF |
result.SaveAsSearchablePdf(path) |
Ocr.SPEED_FASTEST |
ocr.Configuration.TesseractEngineMode sintonización |
Ocr.SPEED_FAST |
Configuración predeterminada |
Ocr.SPEED_SLOW |
Configuración de mayor precisión |
ocr.StopEngine() |
No requerido — OcrInput es IDisposable |
result.StartsWith("ERROR:") chequeo |
Manejo de excepciones estándar de .NET (try/catch) |
| DLL nativa de la plataforma (aocr_x64.dll) | Paquete de tiempo de ejecución NuGet (automático) |
| Archivo temporal manual para la entrada de flujo | input.LoadImage(stream) directamente |
| Biblioteca externa para TIFF multifotograma | input.LoadImageFrames(path) |
| Biblioteca externa para archivos PDF con capacidad de búsqueda. | result.SaveAsSearchablePdf(path) |
Problemas comunes de migración y soluciones
Problema 1: Excepción DllNotFoundException después de eliminar los binarios nativos.
Asprise OCR: Eliminar el paquete NuGet de Asprise pero dejar las referencias de binarios nativos (en reglas de copia de archivos del proyecto, instrucciones de Docker COPY o scripts de despliegue) puede causar que DllNotFoundException resurja desde una configuración obsoleta apuntando a un binario inexistente.
Solución: Buscar artefactos de despliegue para cualquier referencia a configuraciones aocr, libaocr, o LD_LIBRARY_PATH y eliminarlos.IronOCR no tiene ningún requisito de configuración correspondiente. En Dockerfile:
# Remove: COPY aocr_x64.dll /app/
# Remove: ENV LD_LIBRARY_PATH=/app
# IronOCR: nothing to add — NuGet handles native runtime packaging
RUN dotnet restore
RUN dotnet publish -c Release -o /app/publish
Para la implementación multiplataforma, la guía de implementación de Docker cubre los requisitos de imagen base para IronOCR en contenedores Linux.
Problema 2: Falta de eliminación de Ocr.SetUp() interrumpe el inicio
Asprise OCR: Ocr.SetUp() realiza una inicialización nativa global. Algunas bases de código lo llaman en un constructor estático o Startup.Configure. Después de la migración, eliminar el espacio de nombres Asprise elimina el error de compilación, pero si SetUp() está envuelto en un try/catch que suprime la excepción, el código puede compilarse y ejecutarse silenciosamente sin inicializar nada.
Solución: Usar grep para todas las llamadas SetUp() y eliminar todo el bloque de inicialización. Reemplace el gancho de inicio equivalente con la asignación de clave de licencia de IronOCR:
grep -rn "Ocr.SetUp\|StartEngine\|StopEngine" --include="*.cs" .
grep -rn "Ocr.SetUp\|StartEngine\|StopEngine" --include="*.cs" .
// Remove all occurrences of the engine lifecycle pattern:
// Ocr.SetUp();
// ocr.StartEngine(...);
// ocr.StopEngine();
// Replace application startup initialization with:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Remove all occurrences of the engine lifecycle pattern:
// Ocr.SetUp();
// ocr.StartEngine(...);
// ocr.StopEngine();
// Replace application startup initialization with:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
Problema 3: El código de análisis de salida XML no tiene un reemplazo directo.
Asprise OCR: El código que analiza cadenas OUTPUT_FORMAT_XML usando XDocument, XmlReader, o patrones regex no tiene una estructura XML equivalente en IronOCR. El esquema XML que genera Asprise no se corresponde directamente con el modelo de objetos de IronOCR.
Solución: Reemplazar el código de análisis XML con acceso directo a propiedades en OcrResult. El mapeo es:
// Asprise XML parsing (remove)
var words = XDocument.Parse(xmlOutput)
.Descendants("word")
.Select(w => new { Text = (string)w.Attribute("text"), X = (int)w.Attribute("x") });
//IronOCR object model (replace with)
var result = new IronTesseract().Read(imagePath);
var words = result.Pages
.SelectMany(p => p.Paragraphs)
.SelectMany(para => para.Words)
.Select(w => new { w.Text, w.X });
// Asprise XML parsing (remove)
var words = XDocument.Parse(xmlOutput)
.Descendants("word")
.Select(w => new { Text = (string)w.Attribute("text"), X = (int)w.Attribute("x") });
//IronOCR object model (replace with)
var result = new IronTesseract().Read(imagePath);
var words = result.Pages
.SelectMany(p => p.Paragraphs)
.SelectMany(para => para.Words)
.Select(w => new { w.Text, w.X });
Imports System.Xml.Linq
Imports IronOcr
' Asprise XML parsing (remove)
Dim words = XDocument.Parse(xmlOutput) _
.Descendants("word") _
.Select(Function(w) New With {Key .Text = CType(w.Attribute("text"), String), Key .X = CType(w.Attribute("x"), Integer)})
' IronOCR object model (replace with)
Dim result = New IronTesseract().Read(imagePath)
Dim words = result.Pages _
.SelectMany(Function(p) p.Paragraphs) _
.SelectMany(Function(para) para.Words) _
.Select(Function(w) New With {w.Text, w.X})
La guía de resultados de lectura abarca la jerarquía completa de objetos, incluidos los datos a nivel de caracteres con cuadros delimitadores.
Problema 4: Los envoltorios de Task.Run provocan el agotamiento del grupo de subprocesos.
Asprise OCR: Las aplicaciones web de alta concurrencia que envuelven Asprise en Task.Run pueden agotar el grupo de hilos cuando se incrementa el volumen de OCR. Cada Task.Run en cola mantiene un hilo del grupo de hilos durante toda la duración de la operación OCR.
Solución: Reemplazar Task.Run(() => { asprise... }) patrones con llamadas asíncronas nativas de IronOCR. Cada instancia IronTesseract es independiente — crea una por solicitud:
// Remove: await Task.Run(() => { ocr.Recognize(...) });
// Replace with:
using var input = new OcrInput();
input.LoadImage(stream);
var result = await new IronTesseract().ReadAsync(input);
return result.Text;
// Remove: await Task.Run(() => { ocr.Recognize(...) });
// Replace with:
using var input = new OcrInput();
input.LoadImage(stream);
var result = await new IronTesseract().ReadAsync(input);
return result.Text;
Imports IronTesseract
Using input As New OcrInput()
input.LoadImage(stream)
Dim result = Await (New IronTesseract()).ReadAsync(input)
Return result.Text
End Using
Problema 5: Validación de códigos de lenguaje basada en cadenas de texto
Asprise OCR: Los códigos de lenguaje se pasan como cadenas ("eng", "fra", "eng+fra"). Las aplicaciones que validan estas cadenas en tiempo de ejecución — verificando contra una lista codificada, leyendo desde la configuración — necesitan actualizaciones cuando el formato de la cadena cambia al enum OcrLanguage.
Solución: Reemplazar los parámetros de lenguaje de cadena con valores de enum OcrLanguage. La selección de lengua impulsada por configuración se asigna claramente a Enum.Parse:
// Asprise string-based (remove)
string language = config["OcrLanguage"]; // e.g. "eng+fra"
ocr.StartEngine(language, Ocr.SPEED_FAST);
//IronOCR enum-based (replace with)
// For single language from config:
var ocr = new IronTesseract();
ocr.Language = Enum.Parse<OcrLanguage>(config["OcrLanguage"]); // e.g. "English"
var result = ocr.Read(input);
// Asprise string-based (remove)
string language = config["OcrLanguage"]; // e.g. "eng+fra"
ocr.StartEngine(language, Ocr.SPEED_FAST);
//IronOCR enum-based (replace with)
// For single language from config:
var ocr = new IronTesseract();
ocr.Language = Enum.Parse<OcrLanguage>(config["OcrLanguage"]); // e.g. "English"
var result = ocr.Read(input);
Imports System
Imports IronOcr
' Asprise string-based (remove)
Dim language As String = config("OcrLanguage") ' e.g. "eng+fra"
ocr.StartEngine(language, Ocr.SPEED_FAST)
' IronOCR enum-based (replace with)
' For single language from config:
Dim ocr As New IronTesseract()
ocr.Language = [Enum].Parse(Of OcrLanguage)(config("OcrLanguage")) ' e.g. "English"
Dim result = ocr.Read(input)
La guía de múltiples lenguas enumera todos los valores válidos de enum OcrLanguage y sus paquetes de paquetes de lenguaje de NuGet correspondientes.
Problema 6: Ya no es necesaria la lógica de verificación del nivel de licencia.
Asprise OCR: Algunos códigos de producción incluyen comprobaciones en tiempo de ejecución que detectan el nivel de licencia de Asprise y serializan el trabajo de OCR cuando se ejecuta por debajo de Enterprise. Estas medidas evitan infracciones de licencia, pero añaden complejidad y reducen el rendimiento.
Solución: Eliminar todas las protecciones de detección de niveles y serialización.IronOCR no tiene restricciones de subprocesos en ningún nivel. Los patrones ConcurrentQueue, SemaphoreSlim, o el despachador de un solo hilo usados para serializar llamadas de Asprise no sirven después de la migración:
// Remove: SemaphoreSlim _ocrLock = new SemaphoreSlim(1, 1);
// Remove: await _ocrLock.WaitAsync(); ... _ocrLock.Release();
// IronOCR: direct concurrent access, no guards needed
Parallel.ForEach(documentPaths, path =>
{
var text = new IronTesseract().Read(path).Text;
results[path] = text;
});
// Remove: SemaphoreSlim _ocrLock = new SemaphoreSlim(1, 1);
// Remove: await _ocrLock.WaitAsync(); ... _ocrLock.Release();
// IronOCR: direct concurrent access, no guards needed
Parallel.ForEach(documentPaths, path =>
{
var text = new IronTesseract().Read(path).Text;
results[path] = text;
});
Imports System.Threading.Tasks
' IronOCR: direct concurrent access, no guards needed
Parallel.ForEach(documentPaths, Sub(path)
Dim text = (New IronTesseract()).Read(path).Text
results(path) = text
End Sub)
Lista de verificación de migración de OCR de Asprise
Pre-Migración
Antes de escribir cualquier código de reemplazo, revise el código fuente para detectar cualquier uso de Asprise:
# Find all files importing asprise namespace
grep -rn "using asprise" --include="*.cs" .
# Find all engine lifecycle calls
grep -rn "SetUp\|StartEngine\|StopEngine" --include="*.cs" .
# Find all integer constant references
grep -rn "RECOGNIZE_TYPE\|OUTPUT_FORMAT\|SPEED_FAST\|SPEED_SLOW" --include="*.cs" .
# Find native binary references in project files and deployment scripts
grep -rn "aocr\|libaocr" --include="*.csproj" --include="Dockerfile" --include="*.yml" .
# Find XML output parsing code
grep -rn "OUTPUT_FORMAT_XML\|XDocument.Parse\|Descendants.*word" --include="*.cs" .
# Find Task.Run wrappers around OCR calls
grep -rn "Task.Run.*ocr\|Task.Run.*Recognize" --include="*.cs" .
# Find all files importing asprise namespace
grep -rn "using asprise" --include="*.cs" .
# Find all engine lifecycle calls
grep -rn "SetUp\|StartEngine\|StopEngine" --include="*.cs" .
# Find all integer constant references
grep -rn "RECOGNIZE_TYPE\|OUTPUT_FORMAT\|SPEED_FAST\|SPEED_SLOW" --include="*.cs" .
# Find native binary references in project files and deployment scripts
grep -rn "aocr\|libaocr" --include="*.csproj" --include="Dockerfile" --include="*.yml" .
# Find XML output parsing code
grep -rn "OUTPUT_FORMAT_XML\|XDocument.Parse\|Descendants.*word" --include="*.cs" .
# Find Task.Run wrappers around OCR calls
grep -rn "Task.Run.*ocr\|Task.Run.*Recognize" --include="*.cs" .
Inventarie los resultados:
- Cuenta los archivos que importan
asprise.ocr— todos necesitan actualizaciones de espacio de nombres. - Lista cada sitio de llamada de
StartEngine— cada uno se convierte en una llamadaRead. - Identificar el código de análisis de salida XML: cada bloque necesita ser reemplazado por un modelo de objetos.
- Tenga en cuenta cualquier protección de nivel de licencia o envoltorio de serialización; estos se pueden eliminar.
- Localizar los scripts de despliegue binario nativos y la configuración del contenedor.
Migración de código
- Eliminar el paquete NuGet de
asprise-ocr-apide todos los proyectos. - Instalar el paquete NuGet
IronOcren cada proyecto que realice OCR. - Reemplaza
using asprise.ocrconusing IronOcren todos los archivos. - Agregar
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"al inicio de la aplicación. - Eliminar llamadas
Ocr.SetUp()de todo el código de inicio e inicialización. - Reemplazar cada bloque
Ocr.StartEngine/Recognize/StopEngineconnew IronTesseract().Read(path).Text. - Reemplaza bloques de análisis
OUTPUT_FORMAT_XMLcon recorrido de objetosresult.Pages. - Reemplazar soluciones alternativas
OUTPUT_FORMAT_PDFconresult.SaveAsSearchablePdf(path). - Reemplazar código de división de TIFF de múltiples cuadros con
input.LoadImageFrames(tiffPath). - Reemplazar envolturas basadas en flujo
Task.Runconawait ocr.ReadAsync(input). - Eliminar
SemaphoreSlimo guardias de serialización que protegían Asprise del uso concurrente. - Eliminar instrucciones de copia de binarios nativos de archivos
.csprojy Dockerfiles. - Eliminar configuraciones
LD_LIBRARY_PATHde la configuración del entorno y scripts de CI. - Reemplazar códigos de lenguaje de cadena (
"eng","eng+fra") con valores de enumOcrLanguage. - Reemplazar pruebas
result.StartsWith("ERROR:")con bloquestry/catch.
Posmigración
- Verificar que
dotnet buildcompleta sin advertencias sobre bibliotecas nativas faltantes. - Confirmar que no ocurre
DllNotFoundExceptionoBadImageFormatExceptional inicio en todos los entornos objetivo (Windows, Linux, Docker). - Ejecutar el OCR en una imagen representativa y confirmar que el texto resultante coincide con la línea base previa a la migración.
- Pruebe el procesamiento de TIFF multifotograma y verifique que todas las páginas se devuelvan con los números de página correctos.
- Generar un PDF con capacidad de búsqueda y verificar que el texto se pueda seleccionar y buscar en un visor de PDF.
- Enviar solicitudes HTTP simultáneas a cualquier punto final de la API que llame a OCR y confirmar que todas las solicitudes se completen sin errores.
- Verificar que los puntos finales asíncronos devuelvan resultados sin interbloqueo bajo carga concurrente
- Confirmar que la extracción de datos estructurados (coordenadas de palabras y nivel de confianza) produce un resultado correcto en un documento conocido.
- Verificar el uso de memoria de la aplicación a lo largo del tiempo para confirmar que no hay fugas de memoria nativa (anteriormente causadas por llamadas a
StopEngine()olvidadas). - Ejecute la aplicación en Linux o en un contenedor Docker para confirmar que la implementación multiplataforma funciona sin configuración binaria.
Principales ventajas de migrar a IronOCR
La implementación se reduce a una única referencia NuGet . Tras la migración, todos los destinos de implementación (estaciones de trabajo de desarrollo, servidores de prueba, contenedores Linux, agentes de CI) instalan el mismo paquete con el mismo comando. No existe lógica de detección de plataforma, ni selección de binarios específicos de la arquitectura, ni configuración de ruta de ejecución. Una imagen de Docker que antes requería instrucciones de COPY manual de binario nativo ahora no requiere nada más allá de dotnet restore. La guía de implementación de Linux y la guía de implementación de Azure incluyen notas específicas del entorno cuando corresponda.
Todos los niveles de licencia desbloquean la implementación de servidor. La licencia Lite $999 admite ASP.NET Core Web APIs, Servicios de Windows, Funciones de Azure, AWS Lambda y cualquier otra carga de trabajo .NET multi-hilo. La capacidad de subprocesos de nivel EMPRESARIAL por la que Asprise cobra entre 2000 y 5000 dólares o más está incluida en todos los niveles de IronOCR. Los equipos que migran de Asprise Enterprise a IronOCR Lite reducen sus costos de licencias de OCR al tiempo que obtienen capacidades que Enterprise no proporcionaba: PDF nativo, salida estructurada, generación de PDF con capacidad de búsqueda y 125 idiomas.
Resultados de OCR estructurados reemplazan el análisis de cadenas XML. El modelo de objeto OcrResult expone una jerarquía completa de documentos: páginas, párrafos, líneas, palabras y caracteres, cada uno con coordenadas de caja delimitadora precisas en píxeles y puntajes de confianza. El código que anteriormente analizaba las cadenas XML de Asprise con XDocument o expresiones regulares ahora accede directamente a las propiedades. La página de resultados de OCR incluye información sobre sistemas de coordenadas y cómo filtrar los resultados por nivel de confianza para los controles de calidad automatizados.
El preprocesamiento incorporado elimina las dependencias de imagen externas. El pipeline de preprocesamiento disponible a través de OcrInput — Deskew, DeNoise, Contrast, Binarize, Sharpen, Dilate, Erode, Scale, Invert, y DeepCleanBackgroundNoise — elimina la biblioteca de imágenes externa que las integraciones de Asprise requieren. Eliminar esa dependencia elimina una preocupación de licencia, reduce la huella de construcción, y coloca la configuración de preprocesamiento directamente adyacente a la configuración de OCR en el mismo archivo de código. La página de características de preprocesamiento y la guía de corrección de calidad de imagen cubren cuándo aplicar cada filtro y las ganancias de precisión medibles que cada uno proporciona en escaneos de baja calidad.
Async nativo y verdadero paralelismo mejoran el rendimiento. ReadAsync se integra en el patrón estándar async/await sin bloqueo del grupo de hilos. El procesamiento por lotes paralelo con Parallel.ForEach o PLINQ se escala linealmente con los núcleos disponibles. Un lote de documentos que Asprise Lite/STANDARD forzó a ejecutar de forma secuencial (100 documentos a 2 segundos cada uno tardan más de 3 minutos) se ejecuta en aproximadamente 25 segundos en una máquina de 8 núcleos con IronOCR. El ejemplo de multithreading demuestra patrones de rendimiento paralelo y muestra cómo usar ConcurrentBag para la recolección de resultados seguros para hilos.
125+ idiomas sin distribución binaria. Los paquetes de idiomas se instalan como paquetes NuGet — dotnet add package IronOcr.Languages.Arabic, dotnet add package IronOcr.Languages.Japanese — y se despliegan con la aplicación como cualquier otra dependencia. No es necesario rellenar manualmente la carpeta tessdata, localizar el archivo binario del idioma ni configurar la ruta en la máquina de destino. El índice de idiomas incluye los más de 125 paquetes de idiomas disponibles.
Preguntas Frecuentes
¿Por qué debería migrar de Asprise OCR SDK a IronOCR?
Los impulsores comunes incluyen la eliminación de la complejidad de la interoperabilidad COM, la sustitución de la gestión de licencias basada en archivos, la evitación de la facturación por página, la habilitación de la implementación de Docker/contenedores y la adopción de un flujo de trabajo nativo de NuGet que se integre con las herramientas .NET estándar.
¿Cuáles son los principales cambios en el código al migrar de Asprise OCR SDK a IronOCR?
Sustituya las secuencias de inicialización de Asprise OCR por la instanciación de IronTesseract, elimine la gestión del ciclo de vida COM (patrones explícitos Create/Load/Close) y actualice los nombres de las propiedades de los resultados. El resultado es un número significativamente menor de líneas repetitivas.
¿Cómo instalo IronOCR para comenzar la migración?
Ejecute 'Install-Package IronOcr' en la consola del gestor de paquetes o 'dotnet add package IronOcr' en la CLI. Los paquetes de idiomas son paquetes independientes: 'dotnet add package IronOcr.Languages.French' para el francés, por ejemplo.
¿IronOCR ofrece la misma precisión de reconocimiento óptico de caracteres que Asprise OCR SDK para documentos comerciales estándar?
IronOCR consigue una gran precisión para contenido empresarial estándar, como facturas, contratos, recibos y formularios mecanografiados. Los filtros de preprocesamiento de imágenes (eliminación de distorsiones, eliminación de ruido, mejora del contraste) mejoran aún más el reconocimiento en entradas degradadas.
¿Cómo gestiona IronOCR los datos de idioma que Asprise OCR SDK instala por separado?
Los datos de idiomas en IronOCR se distribuyen como paquetes NuGet. dotnet add package IronOcr.Languages.German' instala la compatibilidad con el alemán. No es necesario colocar manualmente los archivos ni las rutas de los directorios.
¿La migración de Asprise OCR SDK a IronOCR requiere cambios en la infraestructura de implementación?
IronOCR requiere menos cambios de infraestructura que Asprise OCR SDK. No hay rutas binarias del SDK, ubicaciones de archivos de licencia ni configuraciones del servidor de licencias. El paquete NuGet contiene el motor OCR completo, y la clave de licencia es una cadena establecida en el código de la aplicación.
¿Cómo configuro las licencias de IronOCR después de la migración?
Asigne IronOcr.License.LicenseKey = "YOUR-KEY" en el código de inicio de la aplicación. En Docker o Kubernetes, almacene la clave como una variable de entorno y léala en el inicio. Utilice License.IsValidLicense para validar antes de aceptar tráfico.
¿Puede IronOCR procesar archivos PDF del mismo modo que Asprise OCR?
Sí, IronOCR lee PDF nativos y escaneados. Instancie IronTesseract, llame a ocr.Read(input) donde input es una ruta PDF u OcrPdfInput, e itere las páginas OcrResult. No es necesario un proceso de renderizado de PDF independiente.
¿Cómo gestiona IronOCR los hilos en el procesamiento de grandes volúmenes?
IronTesseract puede instanciarse de forma segura por subproceso. Gire una instancia por hilo en un Parallel.ForEach o Task pool, ejecute OCR concurrentemente, y disponga de cada instancia cuando termine. No se requiere estado global o bloqueo.
¿Qué formatos de salida admite IronOCR tras la extracción de texto?
IronOCR devuelve resultados estructurados que incluyen texto, coordenadas de palabras, puntuaciones de confianza y estructura de páginas. Las opciones de exportación incluyen texto sin formato, PDF con opción de búsqueda y objetos de resultados estructurados para su procesamiento posterior.
¿Es el precio de IronOCR más predecible que el de Asprise OCR SDK para escalar cargas de trabajo?
IronOCR utiliza licencias perpetuas de tarifa plana sin cargos por página o volumen. Tanto si procesa 10.000 como 10 millones de páginas, el coste de la licencia permanece constante. Las opciones de licencias por volumen y por equipo se encuentran en la página de precios de IronOCR.
¿Qué sucede con mis pruebas existentes después de migrar de Asprise OCR SDK a IronOCR?
Las pruebas que validan el contenido de texto extraído deben seguir superándose tras la migración. Las pruebas que validan patrones de llamada a API o el ciclo de vida de objetos COM deberán actualizarse para reflejar el modelo de inicialización y resultados más sencillo de IronOCR.

