Migración de Windows.Media.Ocr a IronOCR
Esta guía ofrece una ruta de migración paso a paso para los desarrolladores de .NET que cambian de Windows.Media.OCR a IronOCR. Abarca la eliminación de espacios de nombres, los cambios en los archivos de proyecto, ejemplos de migración de código para los patrones que surgen con mayor frecuencia durante la migración y una lista de verificación práctica para validar la transición completada.
¿Por qué migrar desde Windows.Media.OCR (UWP/WinRT OCR)?
Windows.Media.OCR funciona bien dentro de sus límites. Esos límites son estrechos, y los proyectos suelen sobrepasarlos. Las razones por las que los equipos migran se pueden clasificar en categorías predecibles.
El TFM de Windows bloquea cada destino que no sea de Windows. El archivo del proyecto debe declarar un net*-windows* Target Framework Moniker antes de que el Windows.Media.Ocr espacio de nombres incluso se resuelva en tiempo de compilación. Esa declaración no es una bandera de tiempo de ejecución, es una restricción de compilación que se propaga a cada proyecto que hace referencia al tuyo. Una biblioteca de servicios OCR compartida, una API web, un proceso en segundo plano implementado en Linux: todos ellos comparten esta restricción. Eliminarlo significa eliminar Windows.Media.OCR.
La disponibilidad de idiomas se determina en tiempo de ejecución por el SO, no por el desarrollador en tiempo de compilación. OcrEngine.TryCreateFromLanguage devuelve null cuando el paquete de idioma solicitado está ausente en la máquina host. El desarrollador no puede instalar un paquete de idioma desde el código, incluir uno con el binario de la aplicación, ni proporcionar un modelo de reserva. En entornos automatizados —agentes de compilación, ejecutores de CI, máquinas virtuales mínimas en la nube, contenedores— rara vez se instalan paquetes de idiomas. Los fallos de producción causados por la falta de un paquete de idioma no son reproducibles al examinar el código; requieren inspeccionar la configuración del sistema operativo del equipo de destino.
No hay preprocesamiento significa que no hay camino de recuperación para una entrada subóptima. La API acepta un SoftwareBitmap y produce texto. La mejora de la calidad de la imagen entre esos dos puntos es responsabilidad exclusiva del desarrollador, utilizando API independientes de Windows Imaging Component que son exclusivas de Windows. Las fotografías tomadas con el móvil, los escaneos en plano desalineados y los documentos fotocopiados reducen la precisión de forma imperceptible, sin ningún mecanismo integrado para diagnosticar o mejorar el resultado.
El PDF es el formato de documento más común en los flujos de trabajo Enterprise. Windows.Media.OCR no admite archivos PDF como entrada. El procesamiento de un PDF escaneado requiere un renderizador externo, la rasterización página por página y el ensamblaje manual de los resultados. Ese renderizador añade una dependencia, consideraciones de licencia y una superficie de fallo independiente: exactamente la complejidad que se suponía que debía evitar una biblioteca "gratuita e integrada".
La implementación del lado del servidor no es compatible estructuralmente. Windows.Media.OCR está destinado a aplicaciones de cliente. Para ejecutarlo en Windows Server se requiere el paquete de características Desktop Experience, lo que aumenta el coste de la máquina virtual y la complejidad de la infraestructura. La implementación de Docker es imposible. Azure Functions en Linux, AWS Lambda y cualquier carga de trabajo en contenedores basada en Linux simplemente no pueden hacer referencia a la API.
La pila asíncrona de WinRT es incompatible con los patrones estándar de .NET. Se requieren seis o más llamadas encadenadas de await — StorageFile, flujo, BitmapDecoder, SoftwareBitmap, verificación de null, RecognizeAsync — antes de que se lea un solo carácter. Integrar esa cadena en un servicio en segundo plano, un bucle Parallel.ForEach o un controlador ASP.NET estándar resulta complicado. La maquinaria de IAsyncOperation de WinRT se encuentra debajo, y la interacción con el modelo de Task de .NET crea casos extremos sutiles en contextos no UI.
El problema fundamental
La disponibilidad del idioma en Windows.Media.OCR es un error de tiempo de ejecución desconocido que no se puede resolver en el momento de la implementación:
// Windows.Media.Ocr: language availability decided by OS admin, not the developer
// Returns null on any machine without the language pack installed
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("ja-JP"));
if (engine == null)
throw new InvalidOperationException(
"Japanese OCR unavailable — install the Japanese language pack in Windows Settings.");
// No recovery path. No bundled model. No fallback.
// IronOCR: language availability is a NuGet package, not an OS configuration
// dotnet add package IronOcr.Languages.Japanese
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.Japanese;
var result = ocr.Read("invoice.jpg"); // Works on any OS, any machine
Console.WriteLine(result.Text);
##IronOCR frente a Windows.Media.Ocr (OCR de UWP/WinRT): comparación de características
La tabla siguiente recoge todas las capacidades relevantes para las decisiones de migración.
| Característica | Windows.Media.Ocr | IronOCR |
|---|---|---|
| Plataforma: Windows 10/11 | Sí | Sí |
| Plataforma: Windows Server | Limitada (se requiere experiencia en entornos de escritorio) | Sí |
| Plataforma: Linux | No | Sí |
| Plataforma: macOS | No | Sí |
| Plataforma: contenedores Docker | No | Sí |
| Plataforma: Azure Functions (Linux) | No | Sí |
| Plataforma: AWS Lambda | No | Sí |
| Requisitos del proyecto TFM | net*-windows* requerido | Ninguna (TFM estándar) |
| Instalación | Integrado en Windows (sin NuGet) | Paquete de NuGet único (IronOcr) |
| Entrada de imágenes (JPG, PNG, BMP) | Sí (a través de la canalización WinRT) | Sí |
| Entrada de PDF | No | Sí (nativo) |
| Entrada TIFF de varias páginas | No | Sí |
| Entrada de flujos y matrices de bytes | No (solo StorageFile) | Sí |
| Idioma de origen | Paquetes de idioma instalados por el sistema operativo | Más de 125 paquetes NuGet incluidos |
| Portabilidad del lenguaje | No (dependiente del dispositivo) | Sí (implementar con la aplicación) |
| Multilingüe simultáneo | No | Sí |
| Preprocesamiento: corrección de la inclinación | No | Sí (input.Deskew()) |
| Preprocesamiento: eliminación de ruido | No | Sí (input.DeNoise()) |
| Preprocesamiento: contraste | No | Sí (input.Contrast()) |
| Preprocesamiento: binarizar | No | Sí (input.Binarize()) |
| Salida en PDF con capacidad de búsqueda | No | Sí (result.SaveAsSearchablePdf()) |
| Puntuaciones de confianza por palabra | No | Sí (word.Confidence) |
| Salida estructurada (párrafos, líneas, palabras) | Solo líneas | Páginas, párrafos, líneas, palabras, caracteres |
| Lectura de BarCodes durante el OCR | No | Sí |
| OCR basado en regiones | No | Sí (CropRectangle) |
| Ruta de OCR sincrónica | No | Sí |
| Procesamiento paralelo seguro para subprocesos | Limitado | Completo |
| Soporte comercial | No (equipo de la plataforma Windows) | Sí |
| Modelo de licencia | Gratuito (integrado en Windows) | Perpetual ($999 Lite, $1,499 Pro, $2,999 Enterprise) |
Inicio rápido: Migración de Windows.Media.Ocr (OCR de UWP/WinRT) a IronOCR
Paso 1: Sustituir el paquete NuGet
Windows.Media.OCR no tiene paquete NuGet: forma parte del Windows Runtime y se resuelve a través del Windows TFM. Eliminarlo significa eliminar las referencias al espacio de nombres específico de Windows y, cuando sea posible, el TFM de Windows del archivo de proyecto.
Elimina los espacios de nombres Windows.Media.OCR de todos los archivos fuente:
# Audit all files referencing Windows OCR namespaces
grep -r "Windows.Media.Ocr\|Windows.Graphics.Imaging\|Windows.Storage" --include="*.cs" .
Instalar IronOCR:
El paquete de NuGet de IronOCR tiene como objetivo net6.0, net7.0, net8.0 y net9.0 sin TFMs específicos de plataforma. Después de eliminar los espacios de nombres de OCR de Windows, actualice el <TargetFramework> en el archivo del proyecto de net8.0-windows10.0.19041.0 a net8.0 (o la versión apropiada), siempre que no queden otras APIs de WinRT en el proyecto.
Paso 2: Actualizar los espacios de nombres
Sustituya los tres espacios de nombres de OCR de Windows por un único espacio de nombres IronOCR:
// Before (Windows.Media.Ocr)
using Windows.Media.Ocr;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Globalization;
// After (IronOCR)
using IronOcr;
Paso 3: Inicializar licencia
Agregue la llamada de inicialización de licencia una vez al inicio de la aplicación — en Program.cs, Startup.cs o en el generador de host de la aplicación:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"En la página de licencias de IronOCR hay disponible una clave de prueba gratuita que elimina la marca de agua de la versión de prueba con fines de evaluación.
Ejemplos de migración de código
Sustitución de la cadena asíncrona de WinRT en un servicio en segundo plano
Windows.Media.OCR requiere un mínimo de seis operaciones asíncronas encadenadas antes de que comience el reconocimiento. En un servicio en segundo plano que procesa una cola de documentos, esa cadena se ejecuta dentro de un bucle — y la eliminación de SoftwareBitmap, la verificación de null y la interoperabilidad con IAsyncOperation de WinRT añaden fricción en cada iteración.
Enfoque de Windows.Media.OCR:
// Windows.Media.Ocr: full async chain required per document
// Requires net8.0-windows10.0.19041.0 TFM — cannot deploy to Linux workers
public async Task<List<string>> ProcessQueueAsync(IEnumerable<string> imagePaths)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language pack installed on this machine.");
var results = new List<string>();
foreach (var path in imagePaths)
{
// Each document: 4 async steps before RecognizeAsync
var file = await StorageFile.GetFileFromPathAsync(path);
using var stream = await file.OpenAsync(FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var bitmap = await decoder.GetSoftwareBitmapAsync();
var ocrResult = await engine.RecognizeAsync(bitmap);
results.Add(ocrResult.Text);
bitmap.Dispose();
}
return results;
}
Enfoque IronOCR:
// IronOCR: one call per document, no WinRT, no SoftwareBitmap, no null checks
// Runs on Windows, Linux, macOS, Docker — same binary, no TFM change
public List<string> ProcessQueue(IEnumerable<string> imagePaths)
{
var results = new List<string>();
foreach (var path in imagePaths)
{
var result = new IronTesseract().Read(path);
results.Add(result.Text);
}
return results;
}
La versión de IronOCR elimina el viaje de ida y vuelta de StorageFile, el BitmapDecoder, el ciclo de vida de SoftwareBitmap y la verificación de nulos. Para servicios nativos asincrónicos, IronOCR proporciona un camino asincrónico que se integra limpiamente en las canalizaciones basadas en Task sin la sobrecarga de interoperabilidad de WinRT. La guía de configuración de IronTesseract incluye recomendaciones sobre el ciclo de vida de las instancias para escenarios de colas de alto rendimiento.
Eliminación de la conversión de SoftwareBitmap para datos de imagen en memoria
Las aplicaciones que ya tienen datos de imagen en memoria — de una descarga de red, un blob de base de datos o una devolución de llamada de captura de cámara — deben convertir esos datos a un SoftwareBitmap antes de que Windows.Media.Ocr pueda procesarlo. Esa ruta de conversión pasa por BitmapDecoder, que requiere un flujo, lo que significa copiar la matriz de bytes a un MemoryStream.IronOCR acepta matrices de bytes y flujos directamente.
Enfoque de Windows.Media.OCR:
// Windows.Media.Ocr: byte array must travel through WinRT stream → BitmapDecoder → SoftwareBitmap
public async Task<string> RecognizeFromBytesAsync(byte[] imageBytes)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language available.");
// Copy byte array into InMemoryRandomAccessStream (WinRT type)
using var ras = new Windows.Storage.Streams.InMemoryRandomAccessStream();
using var writer = new Windows.Storage.Streams.DataWriter(ras);
writer.WriteBytes(imageBytes);
await writer.StoreAsync();
ras.Seek(0);
var decoder = await BitmapDecoder.CreateAsync(ras);
var bitmap = await decoder.GetSoftwareBitmapAsync();
var result = await engine.RecognizeAsync(bitmap);
bitmap.Dispose();
return result.Text;
}
Enfoque IronOCR:
// IronOCR: byte array loads directly into OcrInput — no conversion, no WinRT types
public string RecognizeFromBytes(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // direct byte array load
var result = new IronTesseract().Read(input);
return result.Text;
}
La ruta de Windows.Media.Ocr requiere InMemoryRandomAccessStream — un tipo WinRT que no se puede instanciar fuera de Windows — además de DataWriter, BitmapDecoder y SoftwareBitmap. La ruta de IronOCR usa OcrInput.LoadImage(byte[]) y produce el resultado en dos líneas. Consulte la guía de entrada de flujo para patrones de carga basados en Stream, que siguen la misma simplicidad que las entradas de matriz de bytes.
Procesamiento de documentos multilingües sin coordinación del sistema operativo
Un proceso de facturación multilingüe que debe reconocer texto en inglés, francés y alemán en una sola pasada se enfrenta a un callejón sin salida arquitectónico con Windows.Media.OCR. La API solo permite un idioma por instancia del motor. El procesamiento de un documento en varios idiomas requiere o bien un motor de un solo idioma que haga la mejor estimación posible, o bien ejecutar el reconocimiento tres veces y fusionar los resultados; ninguna de estas opciones produce un resultado fiable.
Enfoque de Windows.Media.OCR:
// Windows.Media.Ocr: one language per engine, no simultaneous multi-language support
// Each language requires a separate language pack installed on the machine
public async Task<string> RecognizeMultiLanguageAsync(SoftwareBitmap bitmap)
{
// Must pick ONE language — no simultaneous recognition
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("en-US"));
if (engine == null)
throw new InvalidOperationException("English language pack not installed.");
// French and German text on the same document will be misrecognized
var result = await engine.RecognizeAsync(bitmap);
return result.Text;
}
Enfoque IronOCR:
// IronOCR: simultaneous multi-language recognition in a single pass
// Language packs are NuGet packages — no OS coordination required
// dotnet add package IronOcr.Languages.French
// dotnet add package IronOcr.Languages.German
public string RecognizeMultiLanguage(string documentPath)
{
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German;
var result = ocr.Read(documentPath);
// Structured output: walk paragraphs with location data
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"[{paragraph.X},{paragraph.Y}] {paragraph.Text}");
}
}
return result.Text;
}
IronOCR combina modelos de lenguaje en una sola pasada de reconocimiento, lo que elimina la necesidad de adivinar qué idioma utiliza una región determinada. La guía de OCR multilingüe cubre la instalación del paquete de idiomas y los valores de enumeración OcrLanguage para los más de 125 idiomas compatibles. El índice de idiomas incluye el catálogo completo, con las familias de escrituras CJK, árabe, hebreo, devanagari y cirílico.
Habilitación del OCR del lado del servidor con procesamiento paralelo
Windows.Media.OCR no puede ejecutarse en un contexto de servidor en Linux, no puede invocarse desde un controlador de .NET Core estándar en un host multiplataforma y presenta un comportamiento indefinido cuando se invoca desde subprocesos que no pertenecen a la interfaz de usuario en escenarios de servidor. Un equipo que traslada un punto final de OCR de una aplicación de escritorio exclusiva para Windows a una API web escalable se enfrenta a las tres limitaciones simultáneamente.
Enfoque de Windows.Media.OCR:
// Windows.Media.Ocr: cannot run on Linux, Docker, or Azure Functions on Linux
// UWP/WinRT assumptions about thread context cause failures in ASP.NET pipelines
// The entire approach below is non-deployable outside Windows with Desktop Experience
[HttpPost("ocr")]
public async Task<IActionResult> RecognizeDocument(IFormFile file)
{
// WinRT requires STA thread context in some scenarios — not guaranteed in ASP.NET
// Cannot deploy this controller to a Linux App Service plan
using var stream = file.OpenReadStream();
// InMemoryRandomAccessStream is a WinRT type — does not exist on Linux
// var ras = new InMemoryRandomAccessStream(); // compile error on net8.0 TFM
return StatusCode(503, "Windows-only — cannot deploy cross-platform.");
}
Enfoque IronOCR:
// IronOCR: ASP.NET Core controller running on Linux, Docker, or Windows — same code
[HttpPost("ocr")]
public async Task<IActionResult> RecognizeDocument(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file provided.");
using var memoryStream = new MemoryStream();
await file.CopyToAsync(memoryStream);
var imageBytes = memoryStream.ToArray();
using var input = new OcrInput();
input.LoadImage(imageBytes);
input.Deskew(); // straighten uploaded scans automatically
input.DeNoise(); // remove mobile camera noise
var result = new IronTesseract().Read(input);
return Ok(new
{
Text = result.Text,
Confidence = result.Confidence,
Pages = result.Pages.Count
});
}
Este controlador se implementa en Linux App Service, Docker y AWS Lambda sin modificaciones. La guía de implementación de Docker cubre la única dependencia apt-get requerida en la imagen base de Linux. La guía de implementación de Azure y la guía de AWS describen la configuración específica para la nube.
Generación de archivos PDF con capacidad de búsqueda a partir de archivos escaneados
Windows.Media.OCR genera cadenas de texto sin formato. No tiene formato de salida más allá de OcrResult.Text y la geometría de línea en OcrResult.Lines. La conversión de un archivo escaneado en PDF con capacidad de búsqueda —un requisito habitual para los sistemas de gestión de documentos y los flujos de trabajo de cumplimiento normativo— requiere una tercera biblioteca para construir la capa de salida de PDF.IronOCR genera archivos PDF con capacidad de búsqueda de forma nativa.
Enfoque de Windows.Media.OCR:
// Windows.Media.Ocr: plain text output only
// Searchable PDF requires external PDF library + manual text layer construction
public async Task<string> GetTextOnlyAsync(SoftwareBitmap bitmap)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language available.");
var result = await engine.RecognizeAsync(bitmap);
// result.Text is all you get
// Producing a searchable PDF requires an entirely separate library
return result.Text;
}
Enfoque IronOCR:
// IronOCR: searchable PDF output is one method call on OcrResult
public void ProcessScannedArchive(IEnumerable<string> pdfPaths, string outputDirectory)
{
foreach (var sourcePdf in pdfPaths)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(sourcePdf); // native PDF input — no external renderer
input.Deskew(); // correct scan misalignment per page
input.DeNoise(); // remove scanner speckle
var result = ocr.Read(input);
var outputFileName = Path.Combine(
outputDirectory,
Path.GetFileNameWithoutExtension(sourcePdf) + "-searchable.pdf");
result.SaveAsSearchablePdf(outputFileName);
Console.WriteLine($"Processed: {sourcePdf} → {outputFileName} " +
$"({result.Pages.Count} pages, {result.Confidence:F1}% confidence)");
}
}
La llamada SaveAsSearchablePdf inserta una capa de texto sobre la imagen original escaneada, preservando la fidelidad visual mientras habilita la búsqueda de texto completo y Ctrl+F dentro de cualquier visor de PDF. La guía práctica en PDF con función de búsqueda abarca opciones para la incrustación de fuentes, el posicionamiento de capas de texto y la salida de varias páginas. La guía de entrada de PDF abarca los archivos PDF protegidos con contraseña y la selección de rangos de páginas para archivos de gran tamaño.
Extracción de datos estructurados con coordenadas a nivel de WORD
Windows.Media.Ocr expone OcrResult.Lines con texto a nivel de línea y rectángulos delimitadores. La geometría por palabra existe en OcrLine.Words con OcrWord.BoundingRect, pero no hay párrafos, puntuaciones de confianza ni datos a nivel de carácter. Para la extracción de campos de formulario o el análisis de líneas de factura, la geometría de línea es insuficiente: se requieren los límites de párrafo y las puntuaciones de confianza de las palabras para distinguir los campos estructurados del texto circundante.
Enfoque de Windows.Media.OCR:
// Windows.Media.Ocr: line-level geometry, no paragraph grouping, no confidence scores
public async Task<List<string>> ExtractLineTextAsync(SoftwareBitmap bitmap)
{
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("No OCR language available.");
var result = await engine.RecognizeAsync(bitmap);
var lineTexts = new List<string>();
foreach (var line in result.Lines)
{
// Line text + word bounding rects — no paragraph grouping, no confidence
lineTexts.Add(line.Text);
}
return lineTexts;
}
Enfoque IronOCR:
// IronOCR: full hierarchy — pages, paragraphs, lines, words, characters
// Each element carries coordinates and confidence for downstream validation
public void ExtractStructuredData(string documentPath)
{
var result = new IronTesseract().Read(documentPath);
Console.WriteLine($"Overall confidence: {result.Confidence:F1}%");
foreach (var page in result.Pages)
{
Console.WriteLine($"\n--- Page {page.PageNumber} ---");
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"Paragraph at ({paragraph.X},{paragraph.Y}): {paragraph.Text}");
// Filter words below confidence threshold for validation workflows
var lowConfidence = paragraph.Words
.Where(w => w.Confidence < 70)
.ToList();
if (lowConfidence.Any())
{
Console.WriteLine($" Low-confidence words: " +
string.Join(", ", lowConfidence.Select(w => $"'{w.Text}' ({w.Confidence:F0}%)")));
}
}
}
}
El modelo de resultado estructurado — Pages, Paragraphs, Lines, Words, Characters — proporciona los datos de coordenadas y confianza necesarios para la extracción de campos de formulario, el análisis de facturas y el análisis de distribución de documentos. La guía de lectura de resultados documenta el gráfico de objetos completo de OcrResult. La guía de puntuación de confianza explica cómo utilizar los valores de confianza por WORD para marcar las extracciones dudosas para su revisión humana.
Referencia de mapeo de la API Windows.Media.OCR a IronOCR
| Windows.Media.Ocr | IronOCR |
|---|---|
OcrEngine.TryCreateFromLanguage(lang) | new IronTesseract() + ocr.Language = OcrLanguage.X |
OcrEngine.TryCreateFromUserProfileLanguages() | new IronTesseract() (predeterminado en inglés; (sin retorno nulo) |
engine.RecognizeAsync(softwareBitmap) | ocr.Read("image.jpg") o ocr.Read(ocrInput) |
StorageFile.GetFileFromPathAsync(path) | ocr.Read("path") directamente (no se necesita identificador de archivo) |
file.OpenAsync(FileAccessMode.Read) | Eliminado — OcrInput se carga directamente |
BitmapDecoder.CreateAsync(stream) | input.LoadImage(stream) a través de OcrInput |
decoder.GetSoftwareBitmapAsync() | Eliminado — no hay SoftwareBitmap en IronOCR |
SoftwareBitmap (tipo WinRT) | Eliminado — OcrInput acepta bytes, flujos, rutas de archivo |
InMemoryRandomAccessStream (tipo WinRT) | new MemoryStream() + input.LoadImage(stream) |
OcrResult.Text | OcrResult.Text |
OcrResult.Lines | OcrResult.Lines (también Pages, Paragraphs, Words, Characters) |
OcrLine.Text | OcrResult.Lines[i].Text |
OcrLine.Words | OcrResult.Words o page.Paragraphs[i].Words |
OcrWord.BoundingRect | word.X, word.Y, word.Width, word.Height |
| No existe equivalente | result.Confidence (general) / word.Confidence (por palabra) |
| No existe equivalente | result.SaveAsSearchablePdf("output.pdf") |
| No existe equivalente | input.LoadPdf("document.pdf") |
| No existe equivalente | input.Deskew(), input.DeNoise(), input.Contrast() |
| No existe equivalente | ocr.Language = OcrLanguage.A + OcrLanguage.B (simultáneo) |
| No existe equivalente | ocr.Configuration.ReadBarCodes = true |
| No existe equivalente | input.LoadImage(byteArray) |
Problemas comunes de migración y soluciones
Problema 1: El archivo de proyecto sigue requiriendo Windows TFM tras la migración
Windows.Media.Ocr: La declaración de <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework> es necesaria para que los tipos de WinRT se resuelvan. Eliminar las referencias a Windows.Media.OCR sin comprobar otras dependencias de WinRT en el mismo proyecto puede dejar el TFM en su sitio, lo que impediría las compilaciones multiplataforma.
Solución: Tras eliminar las referencias al espacio de nombres OCR de Windows, busque en el proyecto cualquier uso restante de la API WinRT antes de modificar el TFM:
# Find remaining WinRT API usage before removing the Windows TFM
grep -r "Windows\." --include="*.cs" .
grep -r "WinRT\|IAsyncOperation\|StorageFile\|SoftwareBitmap" --include="*.cs" .
Si no quedan referencias a WinRT, actualice el archivo de proyecto:
<!-- Before -->
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<!-- After -->
<TargetFramework>net8.0</TargetFramework>
Si se siguen utilizando otras características de WinRT (notificaciones de Windows, integración con el shell, XAML), abstraiga la llamada al OCR detrás de una interfaz y proporcione implementaciones específicas para cada plataforma, en lugar de eliminar el TFM en todo el proyecto.
Problema 2: Las comprobaciones de motor nulo no tienen equivalente en IronOCR
Windows.Media.Ocr: Cada llamada a TryCreateFromLanguage y TryCreateFromUserProfileLanguages puede devolver nulo. Todo el código existente contiene cláusulas de protección contra valores nulos que lanzan una excepción o se ramifican ante un motor nulo.
**Solución:**IronOCR lanza excepciones estructuradas ante fallos de inicialización en lugar de devolver null. Elimina las cláusulas de protección contra valores nulos. Envuélvelo en un try/catch estándar si necesitas notificar los errores de inicialización al llamante:
// Before: null-check pattern
var engine = OcrEngine.TryCreateFromUserProfileLanguages();
if (engine == null)
throw new InvalidOperationException("OCR unavailable.");
// After: no null — IronTesseract throws if misconfigured
try
{
var result = new IronTesseract().Read("document.jpg");
}
catch (IronOcr.Exceptions.OcrException ex)
{
// structured exception with diagnostic message
logger.LogError("OCR failed: {Message}", ex.Message);
}
Problema 3: Parámetros de SoftwareBitmap en las firmas de métodos existentes
Windows.Media.Ocr: Los métodos utilitarios, servicios y clases de repositorio pueden aceptar SoftwareBitmap como tipo de parámetro. Esas firmas de métodos no se pueden compilar cuando se elimina el TFM de Windows.
Solución: Reemplace los parámetros SoftwareBitmap con byte[] o Stream. El OcrInput de IronOCR acepta ambos directamente. Los sitios de llamada que previamente construyeron un SoftwareBitmap pueden pasar sus datos subyacentes en su lugar:
// Before: SoftwareBitmap parameter — cannot compile cross-platform
public async Task<string> RecognizeAsync(SoftwareBitmap bitmap) { ... }
// After: byte array parameter — compiles on all platforms
public string Recognize(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes);
return new IronTesseract().Read(input).Text;
}
Problema 4: Los llamantes exclusivamente asíncronos no pueden utilizar IronOCR síncrono directamente
Windows.Media.Ocr: Cada llamada de reconocimiento es async. Los llamadores en todo el código usan await y devuelven Task<string>. Cambiar al método sincrónico Read de IronOCR dentro de un método async funciona, pero puede introducir llamadas bloqueantes en contextos donde async era arquitectónico.
**Solución:**IronOCR proporciona una ruta asíncrona para los usuarios que la necesiten. Utilice Task.Run para envolver dependencias del CPU en métodos asincrónicos existentes, o utilice la API asincrónica nativa:
// Option A: wrap synchronous call in Task.Run for async callers
public async Task<string> RecognizeAsync(string imagePath)
{
return await Task.Run(() => new IronTesseract().Read(imagePath).Text);
}
// Option B:IronOCR async path
// See: https://ironsoftware.com/csharp/ocr/how-to/async/
La guía de OCR asíncrono documenta la API asíncrona integrada para contextos en los que se necesitan patrones de "fire-and-forget" o de notificación de progreso.
Problema 5: El formato de la etiqueta de idioma de Windows no se asigna directamente
Windows.Media.Ocr: Los idiomas se especifican utilizando etiquetas de cadena BCP-47 pasadas a Windows.Globalization.Language("fr-FR"). Esas etiquetas de cadena no tienen un equivalente directo en IronOCR.
Solución: Mapea las etiquetas de idioma BCP-47 al enum de OcrLanguage. La correspondencia es sencilla para los idiomas más comunes:
// Before: BCP-47 string tags
var engine = OcrEngine.TryCreateFromLanguage(
new Windows.Globalization.Language("fr-FR"));
// After: OcrLanguage enum
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
// Also: OcrLanguage.German, OcrLanguage.Japanese, OcrLanguage.Arabic, etc.
La correspondencia completa está disponible en el catálogo de idiomas de IronOCR. Para idiomas que no figuran en el enum principal, el soporte para paquetes de idioma personalizados cubre la carga de archivos .traineddata directamente.
Problema 6: FileAccessMode.Read no tiene sustituto
Windows.Media.Ocr: file.OpenAsync(FileAccessMode.Read) es un patrón específico de WinRT para abrir archivos. El enum FileAccessMode no existe en el estándar .NET.
Solución: Reemplace con System.IO.File.ReadAllBytes estándar o FileStream. OcrInput acepta ambos:
// Before: WinRT file access
using var stream = await file.OpenAsync(FileAccessMode.Read);
// After: standard .NET
var imageBytes = File.ReadAllBytes(imagePath);
using var input = new OcrInput();
input.LoadImage(imageBytes);
Lista de verificación para la migración de Windows.Media.OCR (OCR de UWP/WinRT)
Pre-Migración
Revisar el código antes de realizar cambios:
# Find all Windows OCR namespace usages
grep -rn "using Windows.Media.Ocr" --include="*.cs" .
grep -rn "using Windows.Graphics.Imaging" --include="*.cs" .
grep -rn "using Windows.Storage" --include="*.cs" .
grep -rn "using Windows.Globalization" --include="*.cs" .
# Find WinRT type usages
grep -rn "OcrEngine\|SoftwareBitmap\|BitmapDecoder\|StorageFile" --include="*.cs" .
grep -rn "TryCreateFromLanguage\|TryCreateFromUserProfileLanguages\|RecognizeAsync" --include="*.cs" .
grep -rn "InMemoryRandomAccessStream\|DataWriter\|FileAccessMode" --include="*.cs" .
# Find project files with Windows TFM
grep -rn "net.*-windows" --include="*.csproj" .
# Count files requiring changes
grep -rl "Windows.Media.Ocr\|Windows.Graphics.Imaging\|SoftwareBitmap" --include="*.cs" . | wc -l
Registre el número de archivos afectados, las etiquetas de idioma en uso ("en-US", "fr-FR", etc.), y si aparecen tipos WinRT en firmas de métodos públicos (estos requieren cambios en el API además de reescrituras internas).
Migración de código
- Instale el paquete NuGet de
IronOcr:dotnet add package IronOcr - Agregue la llamada de inicialización de licencia en
Program.csoStartup.cs:IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; - Elimine
using Windows.Media.Ocr;de todos los archivos fuente - Elimine
using Windows.Graphics.Imaging;de todos los archivos fuente - Elimine
using Windows.Storage;de todos los archivos fuente - Elimine
using Windows.Globalization;de todos los archivos fuente - Agregue
using IronOcr;a todos los archivos que realicen OCR - Reemplace cada llamada
OcrEngine.TryCreateFromLanguage(new Language("xx-XX"))connew IronTesseract()y establezcaocr.Language = OcrLanguage.X - Reemplace cada llamada
OcrEngine.TryCreateFromUserProfileLanguages()connew IronTesseract() - Eliminar todas las cláusulas de protección contra valores nulos en los resultados de la creación del motor
- Reemplace los parámetros
SoftwareBitmapen firmas de métodos conbyte[]oStream - Reemplace las cadenas de construcción de
StorageFile+BitmapDecoder+SoftwareBitmapconOcrInput.LoadImage(path),OcrInput.LoadImage(bytes), oOcrInput.LoadImage(stream) - Reemplace
engine.RecognizeAsync(bitmap)conocr.Read(path)oocr.Read(input) - Reemplace el uso de
InMemoryRandomAccessStreamyDataWriterconMemoryStream - Reemplace las cadenas de etiquetas de idioma BCP-47 de Windows con los valores de enumeración
OcrLanguage; Instalar los paquetes NuGet de lenguaje necesarios - Actualice
<TargetFramework>en los archivos.csprojpara eliminar el sufijo-windowsX.Y.Zdonde no quedan otras APIs de WinRT
Posmigración
- Confirme que el proyecto compila al apuntar a
net8.0(o su versión objetivo) sin el sufijo TFM de Windows - Confirme que el proyecto compila y se ejecuta en un entorno Linux o contenedor de Docker usando
mcr.microsoft.com/dotnet/aspnet:8.0 - Verificar que el texto resultante del OCR coincide con los resultados esperados para cada tipo de documento en la Suite de pruebas
- Verificar que todos los idiomas admitidos anteriormente generen resultados correctos utilizando los paquetes NuGet de IronOCR.
- Verificar que los documentos multilingües produzcan resultados correctos en una sola pasada de reconocimiento
- Confirme que no se produce
NullReferenceExceptionoInvalidOperationExceptionen la inicialización del motor en máquinas sin paquetes de idiomas de Windows instalados - Verifique que los valores de
result.Confidenceestén dentro de los rangos esperados para documentos de entrada limpios y de baja calidad - Si la aplicación genera documentos, verifique que la salida
SaveAsSearchablePdfse abre correctamente en un visor de PDF y admite la búsqueda de texto - Ejecute cualquier ruta de procesamiento paralela o multihilo existente y confirme la seguridad de los subprocesos bajo carga
- Implementar en el entorno de destino (Docker, Azure App Service, AWS, servidor Linux) y ejecutar al menos una operación OCR completa de extremo a extremo
Principales ventajas de migrar a IronOCR
La implementación multiplataforma se convierte en una decisión de configuración, no en una reescritura del código. Tras la migración, el componente OCR funciona de forma idéntica en Windows, Linux, macOS, Docker y todos los principales proveedores de nube. Trasladar una carga de trabajo de OCR de una máquina virtual Windows a un contenedor Linux para reducir los costes de alojamiento es una operación de implementación. La guía de implementación en Linux y la guía de implementación en Docker cubren la adición de una línea de dependencia necesaria en las imágenes base de Linux.
La compatibilidad lingüística se incluye con el binario de la aplicación. Los paquetes de idiomas se instalan como paquetes NuGet y se vinculan a una versión concreta del paquete IronOCR. El conjunto de idiomas que tu aplicación puede reconocer se define en el archivo de proyecto y es idéntico en todas las máquinas: estación de trabajo del desarrollador, ejecutor de CI, servidor de staging y host de producción. Sin coordinación del administrador del sistema operativo, sin excepciones de la Política de Grupo, sin comprobación de valores nulos en tiempo de ejecución.
La precisión de OCR mejora sin herramientas externas. El pipeline de preprocesamiento — Deskew, DeNoise, Contrast, Binarize, Sharpen, Scale — se ejecuta dentro de IronOCR antes de que el motor de reconocimiento vea la imagen. Los documentos que producían resultados de baja calidad con Windows.Media.OCR debido a desalineaciones en el escaneo o al ruido mejoran sin necesidad de añadir dependencias externas de procesamiento de imágenes. La guía de corrección de la calidad de imagen y el asistente de filtros ayudan a identificar la combinación de filtros adecuada para cada tipo de documento.
Los flujos de trabajo de PDF se consolidan en una única biblioteca. Ya no es necesario el renderizador de PDF externo que se requería para conectar Windows.Media.OCR con la entrada de PDF. Los archivos PDF escaneados se procesan a través de la misma llamada IronTesseract.Read que las imágenes. La salida en PDF con capacidad de búsqueda es un método del objeto de resultado. La arquitectura de dos bibliotecas desaparece, junto con su gestión de versiones, los gastos de licencia y la superficie de implementación.
La salida estructurada habilita las canalizaciones de inteligencia documental. La jerarquía de OcrResult — Pages, Paragraphs, Lines, Words, Characters — con coordenadas y puntajes de confianza por elemento proporciona los datos necesarios para la extracción de campos de facturas, el análisis de formularios y la clasificación de documentos. La salida a nivel de línea de Windows.Media.OCR es insuficiente para estos flujos de trabajo. Con IronOCR, la extracción de palabras filtrada por confianza, la detección de límites de párrafos y la asignación de campos basada en coordenadas son funciones de primera clase sin necesidad de bibliotecas adicionales.
Las licencias perpetuas sustituyen a una dependencia ilimitada de la infraestructura. El coste de mantener la instalación de los paquetes de idiomas de Windows en un parque informático heterogéneo, las licencias de Windows Server Desktop Experience y una infraestructura de CI exclusiva para Windows es real, pero difuso: aparece en los tickets de TI y en los presupuestos de infraestructura, no como una partida específica en el presupuesto de OCR. Una licencia Lite de $999IronOCR elimina esa sobrecarga para un proyecto de un solo desarrollador. The Professional License, priced at 1499 $, covers ten developers. Ambas son compras únicas que incluyen un año de actualizaciones.
