IRONSOFTWAREHOME
VIDEOS

Migración de TesseractOcrMaui a IronOCR

Kannaopat Udonpant
Kannapat Udonpant
Updated: 1 de agosto de 2026

Esta guía describe paso a paso una migración completa de TesseractOcrMauia IronOCR, con código práctico de antes y después para cada paso. Está dirigida a desarrolladores que ya han decidido superar las limitaciones de la plataforma MAUI y necesitan una ruta sistemática hacia una biblioteca que funcione de forma idéntica en aplicaciones móviles, API del lado del servidor, procesos en segundo plano y funciones en la nube. No es necesario haber leído previamente el artículo comparativo.

¿Por qué migrar desde TesseractOcrMaui?

TesseractOcrMaui se creó para resolver una carencia real: los envoltorios de Tesseract for .NET existentes no podían resolver por sí solos la interoperabilidad con plataformas móviles. Para un prototipo MAUI puro sin huella de servidor, cubre ese vacío. Los problemas surgen en el momento en que el producto traspasa ese estrecho ámbito.

Las plataformas objetivo solo de MAUI impiden el intercambio de código. TesseractOcrMauise envía con objetivos para net8.0-ios, net8.0-android y net8.0-windows — todos los identificadores de plataforma MAUI. El paquete no contiene net8.0, no netstandard2.1, sin objetivo compatible con el servidor. Al hacer referencia a ella desde una biblioteca de clases, un proyecto de .NET Core o una función de Azure, se produce un error de compilación. No hay solución alternativa: la arquitectura del paquete no permite su ejecución fuera de un host MAUI. Cada vez que surja la necesidad de OCR en un contexto que no sea MAUI, deberá introducirse y mantenerse una segunda biblioteca en paralelo.

Acoplamiento obligatorio de inyección de dependencia MAUI. La llamada AddTesseractOcr() en MauiProgram.cs conecta ITesseract al proveedor de servicios MAUI. No hay ningún método de fábrica, ningún punto de entrada estático ni ningún constructor fuera de ese gráfico de DI. Esto significa que la lógica OCR no se puede extraer en una biblioteca de clases portátiles: cada clase que toma ITesseract en su constructor está bloqueada al host de la aplicación MAUI durante toda su vida útil.

No se admiten archivos PDF en ningún nivel. Los documentos PDF son el formato más común para contratos, facturas y documentos de identidad escaneados. TesseractOcrMauilanza NotSupportedException en cualquier entrada de PDF. El procesamiento de un PDF requiere añadir una biblioteca de renderizado de PDF independiente, escribir código para la extracción de imágenes página por página, gestionar los archivos temporales en la caché del dispositivo y limpiarlos después de cada llamada. Son más de 100 líneas de código de infraestructura antes de que se ejecute una sola llamada de OCR, y aún así solo funciona en MAUI.

Sin preprocesamiento integrado para imágenes del mundo real. Las cámaras de los dispositivos móviles producen imágenes con rotación, ruido del sensor y DPI inconsistente entre los distintos modelos de dispositivos. TesseractOcrMauipasa las imágenes directamente al motor Tesseract sin ningún tipo de preprocesamiento. Los equipos que necesiten una mayor precisión deben añadir SkiaSharp o ImageSharp, implementar manualmente algoritmos de corrección de inclinación y eliminación de ruido, escribir código para la gestión de archivos temporales y probarlo todo en diferentes variantes de dispositivos iOS y Android. La mayoría se lo salta. Como resultado, la precisión en las capturas móviles reales se ve afectada.

Riesgo de mantenimiento por parte de un único desarrollador en una dependencia de producción. TesseractOcrMauies mantenido por un solo desarrollador. No hay ninguna empresa detrás, ni acuerdo de nivel de servicio (SLA), ni compromiso de parches de seguridad, ni vía de escalado más allá de una incidencia en GitHub. Para aplicaciones de producción en sectores regulados —finanzas, sanidad, jurídico—, una biblioteca mantenida por voluntarios con unas 33 900 descargas totales en NuGet no es una dependencia aceptable.

El problema fundamental

TesseractOcrMaui solo se compila dentro de un proyecto MAUI. En el momento en que otro tipo de proyecto necesita OCR, la arquitectura se rompe:

// TesseractOcrMaui: wired to MAUI host — cannot escape to a shared library
// This code compiles only inside a .NET MAUI application
public class OcrService
{
    private readonly ITesseract _tesseract; // resolved from MAUI DI — no other source exists

    public OcrService(ITesseract tesseract) { _tesseract = tesseract; }

    public async Task<string> ReadAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng"); // traineddata must be bundled as MauiAsset
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.Success ? result.RecognizedText : string.Empty;
    }
    // Cannot reference this class from ASP.NET Core, Azure Functions, or Docker
}
C#
// IronOCR: plain instantiable class — compiles in any .NET project type
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract(); // no DI, no MAUI host

    public string Read(string imagePath)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return _ocr.Read(input).Text;
    }
    // Place this in a netstandard2.1 library — reference from MAUI, API, and Functions together
}
C#

##IronOCR frente a TesseractOcrMaui: comparación de características

La tabla siguiente recoge las diferencias de capacidades relevantes para los equipos que evalúan esta migración.

CaracterísticaTesseractOcrMauiIronOCR
.NET MAUI (iOS)Sí (IronOcr.iOS)
.NET MAUI (Android)Sí (IronOcr.Android)
.NET MAUI (Windows)
ASP.NET CoreNo
Azure FunctionsNo
AWS LambdaNo
Docker / Contenedores LinuxNo
Aplicaciones de consolaNo
WPF / WinFormsNo
Biblioteca de clases .NET compartidaNo
Entrada de PDF (nativa)No
Entrada de PDF protegida con contraseñaNo
Entrada de flujoNo
Entrada de matriz de bytesNo
Entrada TIFF de varias páginasNo
Salida en PDF con capacidad de búsquedaNo
Exportación hOCRNo
Corrección automática de la inclinaciónNo
Eliminación automática de ruidoNo
Mejora del contrasteNo
BinarizaciónNo
OCR basado en la regiónNo
Lectura de BarCodes durante el OCRNo
Coordenadas a nivel de palabraNo
Multilingüe simultáneoNo
Idiomas compatiblesDatos de entrenamiento agrupados manualmenteMás de 125 paquetes NuGet
Seguridad de los hilosManualIncorporado en
Apoyo comercialNinguno (desarrollador único)Sí (Iron Software)
LicenciasApache 2.0 (gratuito)Perpetuo desde $999
Descargas de NuGet~33.900Más de 5,3 millones

Inicio rápido: Migración de TesseractOcrMauia IronOCR

Paso 1: Sustituir el paquete NuGet

Eliminar TesseractOcrMauidel proyecto MAUI:

dotnet remove package TesseractOcrMaui
SHELL

Instala IronOCR. Para proyectos MAUI, añada los paquetes específicos de la plataforma junto con el paquete principal:

dotnet add package IronOcr, IronOcr.Android, IronOcr.iOS

Para proyectos del lado del servidor (ASP.NET Core, Azure Functions, consola):

dotnet add package IronOcr

La página del paquete NuGet de IronOCR enumera todos los paquetes de plataforma disponibles.

Paso 2: Actualizar los espacios de nombres

Reemplazar espacios de nombres TesseractOcrMauipor el espacio de nombres IronOCR:

// Before (TesseractOcrMaui)
using TesseractOcrMaui;
using TesseractOcrMaui.Results;
using Microsoft.Maui.Storage;

// After (IronOCR)
using IronOcr;
C#

Paso 3: Inicializar licencia

Agrega la inicialización de la licencia al inicio de la aplicación. En una aplicación MAUI, esto va en MauiProgram.cs; en ASP.NET Coreva en Program.cs:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

Ejemplos de migración de código

Sustitución del registro de inyección de dependencias de MAUI

TesseractOcrMaui requiere registrar el motor OCR a través del proveedor de servicios MAUI. Eliminar ese registro es el primer paso arquitectónico, ya que es lo que vincula todo el código OCR posterior al host MAUI.

Enfoque de TesseractOcrMaui:

// MauiProgram.cs — OCR engine registered here; nowhere else resolves it
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // Binds OCR to MAUI DI — no standalone path exists after this
        builder.Services.AddTesseractOcr();

        return builder.Build();
    }
}

// Any class that needs OCR must receive ITesseract from the MAUI container
public class InvoicePageViewModel
{
    private readonly ITesseract _tesseract;

    public InvoicePageViewModel(ITesseract tesseract)
    {
        _tesseract = tesseract; // fails to construct outside MAUI host
    }

    public async Task<string> ScanInvoiceAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.RecognizedText ?? string.Empty;
    }
}
C#

Enfoque IronOCR:

// MauiProgram.cs — license only; no DI registration needed
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // One-line initialization — works for all project types
        IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

        return builder.Build();
    }
}

// No constructor injection needed — IronTesseract instantiates directly
public class InvoicePageViewModel
{
    public string ScanInvoice(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return ocr.Read(input).Text;
    }
}
C#

Eliminar AddTesseractOcr() elimina el acoplamiento DI de MAUI. La clase IronTesseract tiene un constructor público sin parámetros y no lleva dependencia de plataforma: se puede instanciar en cualquier parte. Consulte la guía de configuración de IronTesseract para conocer las opciones de inicialización, incluidos el modo del motor y la configuración del idioma.

Traslado de la lógica OCR a una biblioteca de clases compartida

Con TesseractOcrMaui, compartir la lógica de OCR entre distintos tipos de proyectos es estructuralmente imposible. Con IronOCR, la ruta de migración es sencilla: extrae el servicio en una biblioteca de clases .NET Standard 2.1 o net8.0 y haz referencia a ella desde cada proyecto en la solución.

Enfoque de TesseractOcrMaui:

// This service CANNOT be extracted to a shared library.
// It compiles only in a project that references TesseractOcrMaui,
// which only has MAUI platform targets.
//
// Result: every non-MAUI project must use a different OCR library,
// duplicating language config, error handling, and accuracy tuning.

public class DocumentOcrService
{
    private readonly ITesseract _tesseract; // MAUI DI only

    public DocumentOcrService(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<string> ProcessDocumentAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.Success ? result.RecognizedText : string.Empty;
    }
    // Server team writes their own version using a different library
    // Two codebases, two accuracy profiles, two maintenance tracks
}
C#

Enfoque IronOCR:

// Place this in: MyCompany.OcrCore (net8.0 or netstandard2.1 class library)
// Reference from: MyCompany.MauiApp, MyCompany.Api, MyCompany.BatchWorker

using IronOcr;

namespace MyCompany.OcrCore
{
    public class DocumentOcrService
    {
        private readonly IronTesseract _ocr;

        public DocumentOcrService()
        {
            _ocr = new IronTesseract();
        }

        public string ProcessDocument(string imagePath)
        {
            using var input = new OcrInput();
            input.LoadImage(imagePath);
            input.Deskew();
            input.DeNoise();
            return _ocr.Read(input).Text;
        }

        public string ProcessDocumentFromBytes(byte[] imageData)
        {
            using var input = new OcrInput();
            input.LoadImage(imageData);
            input.Deskew();
            input.DeNoise();
            return _ocr.Read(input).Text;
        }

        public string ProcessDocumentFromStream(Stream imageStream)
        {
            using var input = new OcrInput();
            input.LoadImage(imageStream);
            return _ocr.Read(input).Text;
        }
    }
}
C#

Una biblioteca de clases, un conjunto de pruebas, un perfil de precisión. La aplicación MAUI llama ProcessDocument(photoPath), la API de ASP.NET Corellama ProcessDocumentFromBytes(uploadedBytes) y la función de Azure llama ProcessDocumentFromStream(blobStream) — todos respaldados por la misma implementación. La guía de entrada de flujo y la guía de entrada de imágenes documentan todas las variantes de carga OcrInput.

Habilitar el OCR del lado del servidor en ASP.NET Core

No se puede hacer referencia a TesseractOcrMauidesde un proyecto de .NET Core. Los equipos que añaden un punto final de carga de documentos se ven obligados a recurrir a una biblioteca completamente diferente.IronOCR se ejecuta en ASP.NET Coresin necesidad de cambios de configuración más allá de la clave de licencia.

Enfoque de TesseractOcrMaui:

// ASP.NET CoreWeb API — TesseractOcrMauiCANNOT be used here.
// The package has no net8.0 or netstandard target.
// Referencing it produces: "The given project does not support targeting net8.0-ios/android/windows."
//
// Team is forced to add a second OCR library — Tesseract charlesw wrapper,
// a cloud API, or another solution — creating a split codebase.

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    // Cannot inject ITesseract here — no MAUI host, no MAUI DI container
    // Must use a completely different OCR library for server-side processing
}
C#

Enfoque IronOCR:

// ASP.NET Core—IronOCR works without modification
using IronOcr;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    [HttpPost("extract-text")]
    public async Task<IActionResult> ExtractText(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file uploaded.");

        var ocr = new IronTesseract();
        using var input = new OcrInput();

        // Load directly from the upload stream — no temp files
        using var stream = file.OpenReadStream();

        if (file.ContentType == "application/pdf")
            input.LoadPdf(stream);
        else
            input.LoadImage(stream);

        input.Deskew();
        input.DeNoise();

        var result = ocr.Read(input);

        return Ok(new
        {
            text = result.Text,
            confidence = result.Confidence,
            pageCount = result.Pages.Count()
        });
    }

    [HttpPost("extract-text-batch")]
    public async Task<IActionResult> ExtractTextBatch(List<IFormFile> files)
    {
        var results = new List<object>();

        // Thread-safe: create one IronTesseract per thread
        await Parallel.ForEachAsync(files, async (file, ct) =>
        {
            var ocr = new IronTesseract();
            using var input = new OcrInput();
            using var stream = file.OpenReadStream();
            input.LoadImage(stream);
            var result = ocr.Read(input);

            lock (results)
            {
                results.Add(new { file = file.FileName, text = result.Text });
            }
        });

        return Ok(results);
    }
}
C#

El mismo código se implementa sin cambios en IIS, Kestrel o un contenedor Docker de Linux. La guía OCR de ASP.NET cubre la configuración del middleware y la guía de implementación de Docker documenta la configuración de contenedores Linux.

Eliminación del código de controladores específico de la plataforma

La arquitectura de TesseractOcrMaui, orientada exclusivamente a MAUI, obliga a los desarrolladores a escribir código condicional a la plataforma cuando intentan integrar el OCR en soluciones multiobjetivo.IronOCR elimina la necesidad de condiciones de plataforma, ya que el mismo paquete se resuelve correctamente en todos los destinos.

Enfoque de TesseractOcrMaui:

// Attempting to share OCR logic across MAUI and non-MAUI targets
// requires platform-conditional compilation — a maintenance hazard

#if ANDROID || IOS || WINDOWS
// Only compile this block in MAUI targets
// Non-MAUI targets cannot reference TesseractOcrMauiat all
using TesseractOcrMaui;

public class PlatformOcrHandler
{
    private readonly ITesseract _tesseract;

    public PlatformOcrHandler(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<string> ProcessAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var r = await _tesseract.RecognizeTextAsync(imagePath);
        return r.RecognizedText ?? string.Empty;
    }
}
#else
// Server targets need a completely different implementation
public class PlatformOcrHandler
{
    public string ProcessAsync(string imagePath)
    {
        // Duplicate logic using a different library
        throw new PlatformNotSupportedException("Use server OCR library here");
    }
}
#endif
C#

Enfoque IronOCR:

// One implementation — no conditional compilation, no duplicate logic
using IronOcr;

public class PlatformOcrHandler
{
    // This class compiles identically for:
    // net8.0-android, net8.0-ios, net8.0-windows (MAUI targets)
    // net8.0 (server targets)
    // netstandard2.1 (shared library targets)

    public string Process(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        input.Deskew();
        return ocr.Read(input).Text;
    }
}

// Multi-target .csproj — no conditional package references needed
// <TargetFrameworks>net8.0;net8.0-android;net8.0-ios</TargetFrameworks>
// IronOcr resolves correctly for all three targets from one package reference
C#

Las condiciones de plataforma en el código de gestión del OCR indican una división arquitectónica que se agrava con el tiempo. Cada cambio en la configuración del idioma, cada ajuste en el preprocesamiento y cada modificación del umbral de confianza deben aplicarse en ambas ramas.IronOCR hace que la división sea innecesaria. La descripción general de la biblioteca OCR de .NET aborda en detalle la estructura de proyectos con múltiples objetivos.

Extracción de datos estructurados con coordenadas de palabras

TesseractOcrMaui solo expone result.RecognizedText y un puntaje de confianza de alto nivel. No es posible extraer palabras individuales con sus cuadros delimitadores, algo necesario para la validación de campos de formulario, el análisis de documentos o las superposiciones de resaltado.IronOCR expone un modelo de objetos de documento completo: páginas, párrafos, líneas, palabras y caracteres, cada uno con coordenadas de píxeles.

Enfoque de TesseractOcrMaui:

// TesseractOcrMaui: flat text string only — no structure, no coordinates
public class TesseractMauiFormParser
{
    private readonly ITesseract _tesseract;

    public TesseractMauiFormParser(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<Dictionary<string, string>> ParseFormAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);

        // result.RecognizedText is one flat string — no field positions
        // Parsing requires fragile line-splitting and regex heuristics
        var fields = new Dictionary<string, string>();
        var lines = result.RecognizedText?.Split('\n') ?? Array.Empty<string>();

        foreach (var line in lines)
        {
            // Hope the layout stays consistent enough to parse
            var parts = line.Split(':');
            if (parts.Length == 2)
                fields[parts[0].Trim()] = parts[1].Trim();
        }

        return fields;
        // No way to validate against expected field positions
        // No confidence per word — only document-level confidence
    }
}
C#

Enfoque IronOCR:

// IronOCR: full document structure with bounding boxes per word
using IronOcr;

public class IronOcrFormParser
{
    public List<WordLocation> ExtractWordsWithPositions(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);

        var result = ocr.Read(input);
        var wordLocations = new List<WordLocation>();

        foreach (var page in result.Pages)
        {
            foreach (var word in page.Words)
            {
                wordLocations.Add(new WordLocation
                {
                    Text = word.Text,
                    Confidence = word.Confidence,
                    X = word.X,
                    Y = word.Y,
                    Width = word.Width,
                    Height = word.Height
                });
            }
        }

        return wordLocations;
    }

    public FormData ParseStructuredForm(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        input.Deskew();

        var result = ocr.Read(input);
        var form = new FormData();

        foreach (var page in result.Pages)
        {
            foreach (var paragraph in page.Paragraphs)
            {
                // Use Y coordinate to identify form regions
                if (paragraph.Y < 200)
                    form.HeaderText += paragraph.Text + " ";
                else if (paragraph.Y > 800)
                    form.FooterText += paragraph.Text + " ";
                else
                    form.BodyLines.Add(paragraph.Text);
            }
        }

        form.OverallConfidence = result.Confidence;
        return form;
    }
}

public class WordLocation
{
    public string Text { get; set; }
    public float Confidence { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
}

public class FormData
{
    public string HeaderText { get; set; } = string.Empty;
    public string FooterText { get; set; } = string.Empty;
    public List<string> BodyLines { get; set; } = new();
    public float OverallConfidence { get; set; }
}
C#

Las coordenadas de WORD permiten la validación con respecto a plantillas de formulario conocidas, el marcado basado en la confianza para la revisión humana y el resaltado de superposiciones en las interfaces de usuario de los visores de documentos. La guía de resultados estructurados documenta el modelo de objeto OcrResult completo, incluida la accesibilidad a nivel de carácter, y la guía de puntuaciones de confianza cubre patrones de filtro de confianza por palabra.

Procesamiento en segundo plano con asincronización nativa y seguimiento del progreso

TesseractOcrMaui expone una API asincrónica (RecognizeTextAsync) pero solo dentro del contexto de la aplicación MAUI. Los trabajos por lotes de larga duración deben ejecutarse en un servicio en segundo plano, una función de Azure o un proceso de trabajo, ninguno de los cuales puede ser el destino de TesseractOcrMaui.IronOCR ofrece compatibilidad nativa con asíncrono que funciona en cualquier servicio alojado.

Enfoque de TesseractOcrMaui:

// Background processing is impossible with TesseractOcrMaui.
// IHostedService runs in a server context — TesseractOcrMauihas no server target.
// The MAUI async API exists, but there is nowhere to run it outside the MAUI app host.

public class DocumentBatchWorker : BackgroundService
{
    // ITesseract cannot be injected here — no MAUI DI in a hosted service
    // Attempting to reference TesseractOcrMauiwill fail to compile:
    // error: Package TesseractOcrMauidoes not support target net8.0
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        throw new PlatformNotSupportedException(
            "TesseractOcrMaui has no server target. Use a different OCR library.");
    }
}
C#

Enfoque IronOCR:

// IronOCR: hosted service background batch processor
using IronOcr;
using Microsoft.Extensions.Hosting;

public class DocumentBatchWorker : BackgroundService
{
    private readonly ILogger<DocumentBatchWorker> _logger;
    private readonly string _inputFolder;
    private readonly string _outputFolder;

    public DocumentBatchWorker(ILogger<DocumentBatchWorker> logger, IConfiguration config)
    {
        _logger = logger;
        _inputFolder = config["Ocr:InputFolder"];
        _outputFolder = config["Ocr:OutputFolder"];
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var pendingFiles = Directory.GetFiles(_inputFolder, "*.pdf")
                .Concat(Directory.GetFiles(_inputFolder, "*.jpg"))
                .ToList();

            if (pendingFiles.Count > 0)
            {
                _logger.LogInformation("Processing {Count} documents.", pendingFiles.Count);

                // Thread-safe parallel processing — one IronTesseract per thread
                await Parallel.ForEachAsync(pendingFiles,
                    new ParallelOptions { MaxDegreeOfParallelism = 4, CancellationToken = stoppingToken },
                    async (filePath, ct) =>
                    {
                        await ProcessDocumentAsync(filePath, ct);
                    });
            }

            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
        }
    }

    private async Task ProcessDocumentAsync(string filePath, CancellationToken ct)
    {
        try
        {
            var ocr = new IronTesseract();
            using var input = new OcrInput();

            if (Path.GetExtension(filePath).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
                input.LoadPdf(filePath);
            else
                input.LoadImage(filePath);

            input.Deskew();
            input.DeNoise();

            var result = await Task.Run(() => ocr.Read(input), ct);

            // Produce searchable PDF from the same OCR pass
            var outputPath = Path.Combine(_outputFolder,
                Path.GetFileNameWithoutExtension(filePath) + "_searchable.pdf");
            result.SaveAsSearchablePdf(outputPath);

            File.Delete(filePath); // move from input queue
            _logger.LogInformation("Processed {File}: {Confidence:F1}% confidence.", filePath, result.Confidence);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process {File}.", filePath);
        }
    }
}
C#

El trabajador se registra en Program.cs con builder.Services.AddHostedService<DocumentBatchWorker>() y se ejecuta en cualquier host de .NET 8: Windows Service, unidad systemd de Linux, contenedor Docker o aplicación de contenedor de Azure. La guía OCR asincrónica cubre patrones asincrónicos y la guía de PDF buscables documenta las opciones de salida SaveAsSearchablePdf.

Referencia de mapeo de la API de TesseractOcrMauia IronOCR

TesseractOcrMauiEquivalente a IronOCR
dotnet add package TesseractOcrMauidotnet add package IronOcr
builder.Services.AddTesseractOcr()Eliminar por completo — no es necesario registrarse
ITesseract (inyectado)new IronTesseract() (instanciación directa)
_tesseract.InitAsync("eng")ocr.Language = OcrLanguage.English; (o omitir para inglés predeterminado)
_tesseract.RecognizeTextAsync(imagePath)ocr.Read(input)
result.RecognizedTextresult.Text
result.SuccessBasado en excepciones; sin bandera booleana
result.Statusmensaje catch (Exception ex)
result.Confidenceresult.Confidence (también por palabra)
TesseractOcrMaui.Results.RecognitionResultIronOcr.OcrResult
paquete de datos entrenados <MauiAsset>dotnet add package IronOcr.Languages.French
Resources/Raw/tessdata/eng.traineddataEliminar — los datos de idioma se encuentran dentro del paquete NuGet
FileSystem.OpenAppPackageFileAsync() (para datos entrenados)Eliminar — no es necesario
Sin soporte para PDFinput.LoadPdf(path) o input.LoadPdf(stream)
Sin preprocesamientoinput.Deskew(), input.DeNoise(), input.Binarize(), input.Contrast()
No se genera un archivo PDF con capacidad de búsqueda.result.SaveAsSearchablePdf(outputPath)
Sin coordenadas de WORDresult.Pages[0].Words[i].X, .Y, .Width, .Height
Sin confianza por palabraresult.Pages[0].Words[i].Confidence
net8.0-ios solo objetivonet8.0 + paquete IronOcr.iOS
net8.0-android solo objetivonet8.0 + paquete IronOcr.Android

Problemas comunes de migración y soluciones

Problema 1: AddTesseractOcr no se puede eliminar sin romper las clases dependientes

TesseractOcrMaui: Cada clase que realiza OCR recibe ITesseract a través de la inyección de constructor. Eliminar AddTesseractOcr() rompe inmediatamente esos constructores con una excepción de resolución DI.

Solución: Elimina el parámetro del constructor y reemplázalo con una instanciación directa de IronTesseract. Si el proyecto utiliza un contenedor DI y deseas mantener el patrón inyectable, registra IronTesseract manualmente:

// Option A: Direct instantiation (recommended for most cases)
public class ScanPageViewModel
{
    public string ScanDocument(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return ocr.Read(input).Text;
    }
}

// Option B: Register IronTesseract in DI if your architecture requires it
// In MauiProgram.cs or Program.cs:
builder.Services.AddSingleton<IronTesseract>();

// Then inject normally:
public class ScanPageViewModel
{
    private readonly IronTesseract _ocr;
    public ScanPageViewModel(IronTesseract ocr) { _ocr = ocr; }

    public string ScanDocument(string imagePath)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return _ocr.Read(input).Text;
    }
}
C#

Problema 2: Faltan archivos de datos entrenados tras la eliminación del paquete

TesseractOcrMaui: La carpeta Resources/Raw/tessdata/, los archivos .traineddata dentro de ella y las declaraciones <MauiAsset> en el .csproj deben ser eliminados. Dejarlos provoca advertencias de compilación e infla el paquete de la aplicación con archivos no utilizados.

Solución: Elimina la carpeta de datos entrenados, elimina las entradas <MauiAsset> y desinstala cualquier idioma que se haya descargado manualmente. Instala en su lugar el paquete de idioma equivalente de IronOCR:

# Delete traineddata assets
rm -rf Resources/Raw/tessdata

# Remove from .csproj (delete the MauiAsset ItemGroup):
# <ItemGroup>
#   <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" />
# </ItemGroup>

# Install IronOCR language pack (if non-English language was needed)
dotnet add package IronOcr.Languages.French
dotnet add package IronOcr.Languages.German
SHELL

Los paquetes de idiomas de IronOCR se resuelven en tiempo de compilación y se empaquetan sin necesidad de gestión manual de archivos. La guía multilingüe documenta todos los paquetes disponibles y la configuración multilingüe simultánea.

Problema 3: InitAsync debe llamarse antes de cada RecognizeTextAsync

TesseractOcrMaui: La llamada ITesseract.InitAsync(language) debe preceder a cada llamada RecognizeTextAsync. Los equipos a menudo añaden banderas de protección _isInitialized, bloqueo verificado doble o semáforos para evitar la inicialización repetida. Todo ese código se convierte en código muerto tras la migración.

Solución: IronTesseract no tiene paso de inicialización. El idioma se establece una vez en la instancia. Elimina todas las llamadas InitAsync, todas las banderas _isInitialized y toda la lógica de protección de inicialización:

// Before: initialization guard required before every OCR call
private bool _isInitialized = false;
private readonly SemaphoreSlim _initLock = new SemaphoreSlim(1, 1);

public async Task<string> GetTextAsync(string imagePath)
{
    await _initLock.WaitAsync();
    try
    {
        if (!_isInitialized)
        {
            await _tesseract.InitAsync("eng");
            _isInitialized = true;
        }
    }
    finally { _initLock.Release(); }

    var result = await _tesseract.RecognizeTextAsync(imagePath);
    return result.RecognizedText ?? string.Empty;
}

// After: no initialization, no guard, no semaphore
public string GetText(string imagePath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    return ocr.Read(input).Text;
}
C#

Problema 4: el patrón de comprobación result.Success debe sustituirse

TesseractOcrMaui: El valor de retorno RecognizeTextAsync lleva un booleano Success y una cadena Status. El código que verifica if (!result.Success) y lee result.Status para información de error necesita ser reescrito.

**Solución:**IronOCR utiliza la semántica de excepciones estándar de .NET. Sustituya las comprobaciones de success-flag por try/catch. En caso de éxito, .Text siempre está poblado (cadena vacía si no se encontró texto):

// Before: success-flag pattern
var result = await _tesseract.RecognizeTextAsync(imagePath);
if (!result.Success)
{
    logger.LogError("OCR failed: {Status}", result.Status);
    return string.Empty;
}
return result.RecognizedText ?? string.Empty;

// After: exception pattern
try
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    var result = ocr.Read(input);
    return result.Text; // empty string if no text found — never null
}
catch (Exception ex)
{
    logger.LogError(ex, "OCR failed for {Path}.", imagePath);
    return string.Empty;
}
C#

N.º 5: Marco de destino exclusivo de MAUI en proyectos de bibliotecas compartidas

TesseractOcrMaui: Una biblioteca de clases que hace referencia a TesseractOcrMaui hereda automáticamente su restricción de plataforma. El <TargetFramework> de la biblioteca debe establecerse en un identificador MAUI (net8.0-android, net8.0-ios o net8.0-windows), lo cual impide que sea referenciado por proyectos de servidor.

Solución: Cambia el objetivo de la biblioteca de clases a net8.0 o netstandard2.1 y haz referencia a IronOcr en su lugar. La biblioteca ahora se resuelve correctamente desde cualquier proyecto que la utilice:

<!-- Before: locked to MAUI target because TesseractOcrMauihas no net8.0 target -->
<TargetFramework>net8.0-android</TargetFramework>
<PackageReference Include="TesseractOcrMaui" Version="*" />

<!-- After: universal target — referenced from MAUI, API, worker, and Functions -->
<TargetFramework>net8.0</TargetFramework>
<PackageReference Include="IronOcr" Version="*" />
XML

Problema 6: El procesamiento de PDF requiere la eliminación de una segunda biblioteca

TesseractOcrMaui: Los equipos que implementaron soporte para PDF agregaron una segunda biblioteca (PDFium, PdfPig o un renderizador en la nube) para convertir páginas PDF a imágenes antes de pasarlas a RecognizeTextAsync. Tras la migración a IronOCR, esa segunda biblioteca y todo su código de renderización de páginas se pueden eliminar.

Solución: Elimina la biblioteca de renderizado de PDF y reemplaza todo el canal de extracción de páginas con input.LoadPdf():

// Before: PDF library + manual temp file management (50+ lines)
using var pdfDoc = PdfDocument.Open(pdfPath);
var results = new List<string>();
foreach (var page in pdfDoc.GetPages())
{
    var tempImagePath = Path.Combine(FileSystem.CacheDirectory, $"page_{page.Number}.png");
    RenderPageToImage(page, tempImagePath, dpi: 300);
    await _tesseract.InitAsync("eng");
    var r = await _tesseract.RecognizeTextAsync(tempImagePath);
    results.Add(r.RecognizedText ?? string.Empty);
    File.Delete(tempImagePath);
}
return string.Join("\n", results);

// After: native PDF support — 5 lines
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(pdfPath);
var result = ocr.Read(input);
return result.Text;
C#

La guía de entrada de PDF abarca la selección de rangos de páginas, los PDF protegidos con contraseña y la carga basada en flujos.

Lista de verificación para la migración de TesseractOcrMaui

Pre-Migración

Revisa el código fuente para hacer un inventario de todos los usos de TesseractOcrMauiantes de modificar cualquier código:

# Find all files that reference TesseractOcrMauinamespaces
grep -r "TesseractOcrMaui" --include="*.cs" .

# Find all ITesseract injection points
grep -r "ITesseract" --include="*.cs" .

# Find all AddTesseractOcr registrations
grep -r "AddTesseractOcr" --include="*.cs" .

# Find all InitAsync calls
grep -r "InitAsync" --include="*.cs" .

# Find all RecognizeTextAsync calls
grep -r "RecognizeTextAsync" --include="*.cs" .

# Find traineddata asset declarations in project files
grep -r "tessdata" --include="*.csproj" .

# Find MauiAsset traineddata declarations
grep -r "MauiAsset" --include="*.csproj" .

# Identify projects with MAUI-only target frameworks that hold OCR logic
grep -r "net8.0-android\|net8.0-ios\|net8.0-windows" --include="*.csproj" .
SHELL

Nota cada clase que toma ITesseract en un constructor: esos constructores cambiarán. Nota cada archivo de proyecto que declara <MauiAsset> para datos entrenados: esas declaraciones serán eliminadas. Determina si hay una biblioteca de renderización de PDF y si se utiliza exclusivamente para el preprocesamiento de OCR.

Migración de código

  1. Ejecuta dotnet remove package TesseractOcrMaui en cada proyecto que lo haga referencia
  2. Ejecuta dotnet add package IronOcr en cada proyecto que realizará OCR
  3. Ejecuta dotnet add package IronOcr.Android en proyectos MAUI que apunten a Android
  4. Ejecuta dotnet add package IronOcr.iOS en proyectos MAUI que apunten a iOS
  5. Ejecuta dotnet add package IronOcr.Languages.* para cualquier idioma que no sea inglés y que previamente se haya incluido como datos entrenados
  6. Agrega IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; al inicio de la aplicación en cada proyecto de punto de entrada
  7. Elimina Resources/Raw/tessdata/ y todos los archivos .traineddata de los proyectos MAUI
  8. Elimina todas las líneas <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" /> de los archivos .csproj
  9. Elimina builder.Services.AddTesseractOcr() de todos los archivos MauiProgram.cs
  10. Reemplaza todos using TesseractOcrMaui; y using TesseractOcrMaui.Results; con using IronOcr;
  11. Elimina los parámetros del constructor ITesseract de todas las clases de servicio y modelo de vista
  12. Reemplaza las llamadas await _tesseract.InitAsync("eng") con ocr.Language = OcrLanguage.English; si es necesario (el predeterminado es inglés)
  13. Reemplaza await _tesseract.RecognizeTextAsync(imagePath) con ocr.Read(input) usando una instancia OcrInput
  14. Reemplaza result.RecognizedText con result.Text
  15. Reemplaza las verificaciones if (!result.Success) con bloques try/catch
  16. Si se agregó una biblioteca de renderizado de PDF únicamente para soportar TesseractOcrMaui, elimínala y reemplaza el código de extracción de páginas con input.LoadPdf()
  17. Cambia cualquier marco de trabajo objetivo solo de MAUI en bibliotecas de clases que contengan lógica OCR a net8.0 o netstandard2.1

Posmigración

  • Verificar que el OCR genere texto a partir de una imagen JPEG capturada por la cámara del dispositivo tanto en dispositivos iOS como Android
  • Verifica que OCR produzca texto de la misma imagen cargada a través de byte[] en el punto final de API del lado del servidor
  • Confirme que la biblioteca de clases compartida se compila y se ejecuta de forma idéntica cuando se hace referencia a ella desde proyectos MAUI y .NET Core
  • Comprueba que la entrada de PDF funciona de principio a fin sin crear ningún archivo temporal
  • Verifica que el SaveAsSearchablePdf de salida sea indexable en un visor de PDF
  • Confirma que las puntuaciones de confianza estén presentes en result.Confidence y en page.Words[i].Confidence
  • Comprueba que la aplicación MAUI genere un registro de inicio sin errores y sin excepciones de "archivo de datos de entrenamiento no encontrado".
  • Verifica que la carpeta Resources/Raw/tessdata/ esté ausente del paquete de aplicaciones MAUI en las versiones de compilación
  • Ejecute un trabajo por lotes en paralelo con 10 o más documentos para confirmar la seguridad de los subprocesos
  • Confirma que la eliminación de InitAsync no haya dejado semáforos huérfanos o variables de estado _isInitialized en ninguna clase de servicio

Principales ventajas de migrar a IronOCR

Un código base en todo el producto. Después de la migración, cada proyecto en la solución — aplicación móvil MAUI, API de ASP.NET Core, función de Azure, trabajador en segundo plano — llama a la misma clase DocumentOcrService de la misma biblioteca compartida. La configuración del idioma, los ajustes de preprocesamiento y el ajuste de la precisión se realizan en un solo lugar. Cuando un nuevo tipo de documento requiere un nuevo filtro de preprocesamiento, el cambio se realiza una sola vez y surte efecto en todas partes.

**Implementación del lado del servidor sin necesidad de reescribir.**IronOCR se implementa en contenedores Linux, Windows Server, Azure App Service, AWS Lambday cualquier otro entorno de ejecución de .NET 8 sin modificaciones. La misma instancia de IronTesseract que procesa capturas de cámara móvil procesa cargas de PDF del lado del servidor. La guía de implementación de Azure y la guía de implementación de AWS documentan los pasos de configuración específicos de cada plataforma.

Procesamiento de PDF sin una segunda biblioteca. La entrada nativa de PDF a través de input.LoadPdf() elimina la biblioteca de renderizado de PDF, el ciclo de extracción de imágenes página por página, la gestión de archivos temporales y el código de limpieza que requería la arquitectura de TesseractOcrMaui. Los contratos PDF escaneados, facturas y documentos de identidad se cargan en una sola línea. La misma pasada de OCR que extrae el texto puede producir un PDF buscable con result.SaveAsSearchablePdf() - una capacidad que TesseractOcrMauino puede proporcionar a ningún nivel.

Preprocesamiento que maneja imágenes móviles reales. input.Deskew(), input.DeNoise(), input.Binarize() y input.Sharpen() son llamadas de método único que aplican correcciones de imagen calibradas antes de que el motor Tesseract vea los datos. Los equipos que aceptaban una precisión del 40-60 % en capturas móviles con poca luz sin preprocesamiento suelen obtener un 85-90 % o más tras añadir un proceso de tres filtros. No se necesita SkiaSharp, ni ImageSharp, ni implementar ningún algoritmo. La guía de corrección de la calidad de la imagen documenta todos los filtros disponibles y cuándo aplicarlos.

Asistencia comercial con una vía de escalación definida. Iron Software ofrece soporte por correo electrónico para todos los niveles de licencia de IronOCR y asistencia prioritaria por teléfono y chat en los niveles Professional y Enterprise. Cuando una actualización de la plataforma interrumpe la resolución de la biblioteca nativa en un nivel específico de la API de Android —el tipo de fallo que la cola de incidencias de GitHub de TesseractOcrMauigestiona en su tiempo libre—, existe un equipo de ingeniería real con la obligación de dar una respuesta. La licencia perpetua comienza en $999 para el nivel Lite; La página de licencias enumera todos los niveles y los servicios de asistencia incluidos en cada uno de ellos.

Más de 125 idiomas a través de NuGet sin aumentar el tamaño del paquete de la aplicación. TesseractOcrMauiincluye archivos de datos entrenados dentro de la aplicación MAUI; cada idioma añade entre 10 y 50 MB al tamaño de descarga de la aplicación. Los paquetes de idiomas de IronOCR se instalan a través de NuGet y solo se incluyen en compilaciones del lado del servidor o en compilaciones de plataforma donde se hacen referencia explícita a ellos. Los paquetes de aplicaciones móviles se mantienen ligeros; Las compilaciones del lado del servidor obtienen el conjunto completo de idiomas. Agregar un nuevo idioma es un comando dotnet add package sin cambios en el archivo del proyecto y sin gestión de archivos. El catálogo completo de idiomas incluye los más de 125 paquetes disponibles.

Por favor nota: PDFium, PdfPig y Tesseract son marcas registradas de sus respectivos propietarios. Este sitio no está afiliado, respaldado, ni patrocinado por Chromium Project, Google, o UglyToad. Todos los nombres de producto, logotipos y marcas son propiedad de sus respectivos dueños. Las comparaciones son solo para fines informativos y reflejan información públicamente disponible en el momento de la redacción.

Artículos Relacionados

Key in blue circle

Obtenga su clave de prueba gratuita de 30 días al instante.

Your trial license will be sent to your email address

Sin limitaciones. 100 % desbloqueado. Sin tarjeta de crédito.

bullet_checkedNo se requiere tarjeta de crédito ni creación de cuentaSin limitaciones. 100 % desbloqueado. Sin tarjeta de crédito.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Obtén tu Consulta Sin Compromiso
Completa el formulario a continuación o envía un correo a sales@ironsoftware.com
Tus detalles siempre serán mantenidos confidenciales.
Confiado por millones de ingenieros en todo el mundo
Logos de clientes de Iron Software
Obtenga su Clave de Prueba de 30 días gratis al instante.
No se requiere tarjeta de crédito ni creación de cuenta