Saltar al pie de página
COMPARAR CON OTROS COMPONENTES

Alternativas a Nanonets OCR para España: IronOCR con cumplimiento AEAT, Facturae y LOPDGDD

El modelo de precios por página de Texto de AWS puede parecer económico a bajo volumen, pero los costos se acumulan indefinidamente a escala. Cada documento que procesa su aplicación sale de su red, viaja a un centro de datos de Amazon, es procesado por la infraestructura de Amazon y la factura se acumula indefinidamente. Para los equipos que evalúan opciones de OCR en .NET, la cuestión no es solo si Textract produce resultados precisos —lo hace—, sino si el modelo de coste por página, la transmisión obligatoria a la nube y la arquitectura de sondeo asíncrono para documentos de varias páginas se ajustan a lo que su aplicación realmente necesita.

Comprender AWS Textract

AWS Textract es el servicio de análisis de documentos gestionado por Amazon, accesible a través del SDK de AWS for .NET mediante el paquete AWSSDK.Textract NuGet. Funciona como una API en la nube: su aplicación envía los datos del documento a la infraestructura de Amazon y recibe resultados estructurados. El servicio requiere una cuenta de AWS, credenciales de IAM con permisos de Textract y una conexión a Internet para cada operación de OCR.

Textract ofrece varios modos de análisis distintos, cada uno con un precio independiente:

  • DetectarTextoDocumento: Extracción básica de texto (vea precios de AWS Textract para las tarifas actuales por página)
  • AnalizarDocumento (Tablas): Extracción de tablas estructuradas a una tarifa por página más alta que la extracción de texto básico
  • AnalizarDocumento (Formularios): Extracción de formularios clave-valor a una tarifa por página más alta que la extracción de tabla
  • AnalyzeExpense: Análisis de facturas y recibos a 0,01 $ por página
  • AnalyzeID: Extracción de datos de documentos de identidad a 0,025 $ por página
  • StartDocumentTextDetection / StartDocumentAnalysis: API asíncrona necesaria para cualquier PDF de varias páginas, que requiere un bucket de staging de S3, sondeo de trabajos y paginación de resultados

El modelo de resultado utiliza una lista plana de objetos Block con IDs de relación que deben recorrerse para reconstruir tablas, formularios o cualquier salida estructurada. Una extracción de tabla simple requiere iterar bloques BlockType.TABLE, encontrar bloques hijo BlockType.CELL a través de IDs de relación RelationshipType.CHILD, y luego obtener bloques BlockType.WORD para el texto de cada celda. Este modelo de gráfico de relaciones maneja estructuras de documentos complejas, pero no es ligero.

El canal S3-Async

El OCR de una sola imagen a través de DetectDocumentTextAsync puede pasar bytes de documento directamente en la solicitud. Los PDFs de varias páginas no pueden. Cualquier PDF requiere el proceso asíncrono completo:

// AWS Textract: PDF de varias páginas requires S3 + async job
public async Task<string> ProcessPdfAsync(string pdfPath)
{
    // Step 1: Upload to S3 — credentials for two services required
    var key = $"uploads/{Guid.NewGuid()}.pdf";
    using (var fileStream = File.OpenRead(pdfPath))
    {
        await _s3Client.PutObjectAsync(new PutObjectRequest
        {
            BucketName = _bucketName,
            Key = key,
            InputStream = fileStream
        });
    }

    try
    {
        // Step 2: Start async Textract job
        var startResponse = await _textractClient.StartDocumentTextDetectionAsync(
            new StartDocumentTextDetectionRequest
            {
                DocumentLocation = new DocumentLocation
                {
                    S3Object = new S3Object { Bucket = _bucketName, Name = key }
                }
            });

        var jobId = startResponse.JobId;

        // Step 3: Poll every 5 seconds until complete
        GetDocumentTextDetectionResponse getResponse;
        do
        {
            await Task.Delay(5000);
            getResponse = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest { JobId = jobId });
        } while (getResponse.JobStatus == JobStatus.IN_PROGRESS);

        if (getResponse.JobStatus != JobStatus.SUCCEEDED)
            throw new Exception($"Textract job failed: {getResponse.StatusMessage}");

        // Step 4: Paginate through result blocks
        var allText = new StringBuilder();
        string nextToken = null;
        do
        {
            var pageResponse = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest
                {
                    JobId = jobId,
                    NextToken = nextToken
                });

            foreach (var block in pageResponse.Blocks.Where(b => b.BlockType == BlockType.LINE))
                allText.AppendLine(block.Text);

            nextToken = pageResponse.NextToken;
        } while (nextToken != null);

        return allText.ToString();
    }
    finally
    {
        // Step 5: Siempre clean up S3
        await _s3Client.DeleteObjectAsync(_bucketName, key);
    }
}
// AWS Textract: PDF de varias páginas requires S3 + async job
public async Task<string> ProcessPdfAsync(string pdfPath)
{
    // Step 1: Upload to S3 — credentials for two services required
    var key = $"uploads/{Guid.NewGuid()}.pdf";
    using (var fileStream = File.OpenRead(pdfPath))
    {
        await _s3Client.PutObjectAsync(new PutObjectRequest
        {
            BucketName = _bucketName,
            Key = key,
            InputStream = fileStream
        });
    }

    try
    {
        // Step 2: Start async Textract job
        var startResponse = await _textractClient.StartDocumentTextDetectionAsync(
            new StartDocumentTextDetectionRequest
            {
                DocumentLocation = new DocumentLocation
                {
                    S3Object = new S3Object { Bucket = _bucketName, Name = key }
                }
            });

        var jobId = startResponse.JobId;

        // Step 3: Poll every 5 seconds until complete
        GetDocumentTextDetectionResponse getResponse;
        do
        {
            await Task.Delay(5000);
            getResponse = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest { JobId = jobId });
        } while (getResponse.JobStatus == JobStatus.IN_PROGRESS);

        if (getResponse.JobStatus != JobStatus.SUCCEEDED)
            throw new Exception($"Textract job failed: {getResponse.StatusMessage}");

        // Step 4: Paginate through result blocks
        var allText = new StringBuilder();
        string nextToken = null;
        do
        {
            var pageResponse = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest
                {
                    JobId = jobId,
                    NextToken = nextToken
                });

            foreach (var block in pageResponse.Blocks.Where(b => b.BlockType == BlockType.LINE))
                allText.AppendLine(block.Text);

            nextToken = pageResponse.NextToken;
        } while (nextToken != null);

        return allText.ToString();
    }
    finally
    {
        // Step 5: Siempre clean up S3
        await _s3Client.DeleteObjectAsync(_bucketName, key);
    }
}
Imports System
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
Imports Amazon.S3
Imports Amazon.Textract
Imports Amazon.Textract.Model

Public Class PdfProcessor
    Private _s3Client As IAmazonS3
    Private _textractClient As IAmazonTextract
    Private _bucketName As String

    Public Async Function ProcessPdfAsync(pdfPath As String) As Task(Of String)
        ' Step 1: Upload to S3 — credentials for two services required
        Dim key As String = $"uploads/{Guid.NewGuid()}.pdf"
        Using fileStream As FileStream = File.OpenRead(pdfPath)
            Await _s3Client.PutObjectAsync(New PutObjectRequest With {
                .BucketName = _bucketName,
                .Key = key,
                .InputStream = fileStream
            })
        End Using

        Try
            ' Step 2: Start async Textract job
            Dim startResponse = Await _textractClient.StartDocumentTextDetectionAsync(
                New StartDocumentTextDetectionRequest With {
                    .DocumentLocation = New DocumentLocation With {
                        .S3Object = New S3Object With {.Bucket = _bucketName, .Name = key}
                    }
                })

            Dim jobId As String = startResponse.JobId

            ' Step 3: Poll every 5 seconds until complete
            Dim getResponse As GetDocumentTextDetectionResponse
            Do
                Await Task.Delay(5000)
                getResponse = Await _textractClient.GetDocumentTextDetectionAsync(
                    New GetDocumentTextDetectionRequest With {.JobId = jobId})
            Loop While getResponse.JobStatus = JobStatus.IN_PROGRESS

            If getResponse.JobStatus <> JobStatus.SUCCEEDED Then
                Throw New Exception($"Textract job failed: {getResponse.StatusMessage}")
            End If

            ' Step 4: Paginate through result blocks
            Dim allText As New StringBuilder()
            Dim nextToken As String = Nothing
            Do
                Dim pageResponse = Await _textractClient.GetDocumentTextDetectionAsync(
                    New GetDocumentTextDetectionRequest With {
                        .JobId = jobId,
                        .NextToken = nextToken
                    })

                For Each block In pageResponse.Blocks.Where(Function(b) b.BlockType = BlockType.LINE)
                    allText.AppendLine(block.Text)
                Next

                nextToken = pageResponse.NextToken
            Loop While nextToken IsNot Nothing

            Return allText.ToString()
        Finally
            ' Step 5: Siempre clean up S3
            Await _s3Client.DeleteObjectAsync(_bucketName, key)
        End Try
    End Function
End Class
$vbLabelText   $csharpLabel

Esta es la implementación mínima viable para el procesamiento confiable de PDF — cinco fases distintas, dos clientes de servicio AWS, y lógica de limpieza en un bloque finally. La versión de producción completa, con el tratamiento adecuado de errores, la lógica de reintentos con límite de frecuencia y la gestión de tiempos de espera, tiene una extensión de entre 150 y 300 líneas.

Comprender IronOCR

IronOCR es una biblioteca IronOCR comercial de .NET que se ejecuta íntegramente en su infraestructura. Incorpora un motor Tesseract 5 optimizado con preprocesamiento automático de imágenes, compatibilidad nativa con PDF y una API síncrona que genera resultados directamente sin llamadas a servicios externos ni pasos intermedios.

Características clave de la arquitectura de IronOCR:

  • Solo procesamiento local: ningún dato del documento sale de la máquina en la que se ejecuta la aplicación
  • Un solo paquete NuGet: dotnet add package IronOcr instala todo, incluyendo binarios nativos
  • Preprocesamiento automático: la corrección de la inclinación, la eliminación de ruido, la mejora del contraste, la binarización y el escalado de resolución se realizan automáticamente en entradas de baja calidad
  • Compatibilidad nativa con PDF: lee archivos PDF directamente a través de la ruta del archivo o un flujo sin necesidad de almacenamiento temporal en S3 ni tareas asíncronas
  • Seguro para hilos: Una sola instancia IronTesseract maneja solicitudes concurrentes a través de hilos sin contención
  • Licenciamiento perpetuo: $999 Lite / $1,499 Plus / $2,999 Professional / $5,999 Unlimited — un pago, sin cargos por página, sin medidor de uso
  • Más de 125 paquetes de idiomas: se instalan como paquetes NuGet independientes, se cargan localmente, sin llamadas de red

Comparación de características

Característica Texto de AWS IronOCR
Lugar de procesamiento Amazon Cloud (obligatorio) Local / en las instalaciones
PDF de varias páginas Requiere S3 + trabajo asíncrono Llamada sincrónica directa
Modelo de costes Por página (contacte a AWS para los precios actuales) Licencia perpetua, sin tarifa por página
Se requiere conexión a Internet Siempre Nunca
Configuración de credenciales Usuario/rol de IAM + S3 opcional Cadena de clave de licencia única
Implementación aislada de la red No es posible Totalmente compatible
Compatibilidad con PDF cifrados No soportado Integrado (parámetro de contraseña)

Comparación detallada de características

Característica Texto de AWS IronOCR
Extracción de texto
OCR básico (imágenes) Sí — DetectDocumentTextAsync Sí — ocr.Read(path)
PDF de varias páginas Requiere S3 + sondeo asíncrono Directo input.LoadPdf(path)
PDF protegido con contraseña No soportado input.LoadPdf(path, Password: "x")
Entrada de flujo Sí (matriz de bytes en la solicitud) Sí — input.LoadImage(stream)
Extracción estructurada
Extracción de tablas AnalyzeDocument + recorrido de grafo de bloque Reconstrucción basada en la posición de las palabras WORD
Extracción de campos de formulario AnalyzeDocument + bloques KEY_VALUE_SET Zonas CropRectangle basadas en región
Resultados a nivel de línea Block filtrando por BlockType.LINE result.Lines colección directa
A nivel de WORD con coordenadas Block filtrando por BlockType.WORD result.Words con .X, .Y, .Width
Puntuaciones de confianza Confianza por bloque Por palabra y general result.Confidence
Modelo de procesamiento
Sincrónico (imágenes) Sí (solo una página) Sí (todos los tipos de documentos)
Asíncrono Requisitos para los archivos PDF Opcional — envoltorio Task.Run()
Procesamiento por lotes Requiere gestión de límites de velocidad (5 TPS por defecto) Parallel.ForEach sin restricciones
Preprocesamiento
Corrección automática de la inclinación No expuesto input.Deskew()
Eliminación de ruido Interno (no configurable) input.DeNoise()
Mejora del contraste Interno (no configurable) input.Contrast()
Mejora de la resolución Interno (no configurable) input.EnhanceResolution(300)
Binarización Interno input.Binarize()
Formatos de salida
Texto sin formato
PDF con función de búsqueda No result.SaveAsSearchablePdf(path)
hOCR No result.SaveAsHocrFile(path)
JSON estructurado A través de la serialización de bloques result.Words / result.Lines
Despliegue
Local No
Aislado físicamente No
Docker Sí (con credenciales de AWS inyectadas) Sí (no se requieren credenciales)
AWS Lambda Nativo Se admite
Azure
Linux Sí (gestionado por AWS) Sí — get-started/linux/
Cumplimiento
HIPAA Requiere BAA con AWS Sin procesador externo
RGPD Los datos se transfieren a las regiones de AWS Los datos permanecen dentro de los límites
ITAR Prohibido sin autorización especial Totalmente local
Aislado físicamente / Nivel 3 de CMMC No es posible Se admite

Costo a escala

El modelo de precios por página es la restricción estructural definitoria de AWS Textract. Los costos que parecen pequeños por página se acumulan significativamente a lo largo de un flujo de trabajo de documento real.

Enfoque de AWS Textract

// Every call to this method costs money — per page, permanently
public async Task<string> DetectTextAsync(string imagePath)
{
    var imageBytes = File.ReadAllBytes(imagePath);  // Image leaves your network

    var request = new DetectDocumentTextRequest
    {
        Document = new Document
        {
            Bytes = new MemoryStream(imageBytes)
        }
    };

    var response = await _client.DetectDocumentTextAsync(request);  // per-page charge

    return string.Join("\n", response.Blocks
        .Where(b => b.BlockType == BlockType.LINE)
        .Select(b => b.Text));
}
// Every call to this method costs money — per page, permanently
public async Task<string> DetectTextAsync(string imagePath)
{
    var imageBytes = File.ReadAllBytes(imagePath);  // Image leaves your network

    var request = new DetectDocumentTextRequest
    {
        Document = new Document
        {
            Bytes = new MemoryStream(imageBytes)
        }
    };

    var response = await _client.DetectDocumentTextAsync(request);  // per-page charge

    return string.Join("\n", response.Blocks
        .Where(b => b.BlockType == BlockType.LINE)
        .Select(b => b.Text));
}
Imports System.IO
Imports System.Threading.Tasks

' Every call to this method costs money — per page, permanently
Public Async Function DetectTextAsync(imagePath As String) As Task(Of String)
    Dim imageBytes = File.ReadAllBytes(imagePath)  ' Image leaves your network

    Dim request = New DetectDocumentTextRequest With {
        .Document = New Document With {
            .Bytes = New MemoryStream(imageBytes)
        }
    }

    Dim response = Await _client.DetectDocumentTextAsync(request)  ' per-page charge

    Return String.Join(vbLf, response.Blocks _
        .Where(Function(b) b.BlockType = BlockType.LINE) _
        .Select(Function(b) b.Text))
End Function
$vbLabelText   $csharpLabel

Consulte la página de precios de AWS Textract para conocer las tarifas actuales por página. Las diferentes características del API (detección básica de texto, extracción de tablas, extracción de formularios) tienen diferentes tarifas. Un documento que contiene tablas y campos de formulario incurre en cargos más altos que la detección básica de texto, y los costos aumentan con el volumen sin límite superior y sin posibilidad de pagar por adelantado.

A volúmenes de página altos, los costos totales de tres años pueden ser sustanciales, y el contador sigue corriendo.

Enfoque de IronOCR

// One license. No per-page cost. Same code handles 1 page or 1,000,000.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var text = new IronTesseract().Read("document.jpg").Text;
// One license. No per-page cost. Same code handles 1 page or 1,000,000.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var text = new IronTesseract().Read("document.jpg").Text;
Imports IronOcr

' One license. No per-page cost. Same code handles 1 page or 1,000,000.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim text As String = New IronTesseract().Read("document.jpg").Text
$vbLabelText   $csharpLabel

La licencia Professional $2,999 cubre 10 desarrolladores, proyectos ilimitados y volumen de página ilimitado. Tras el primer año, el coste mensual por las páginas procesadas es cero. Para equipos que procesan volúmenes de página significativos, la licencia IronOCR se paga por sí misma rápidamente en comparación con los cargos continuos por página en la nube.

La página de licencias de IronOCR incluye detalles sobre los niveles de servicio, opciones de suscripción SaaS para escenarios de facturación basada en el uso y condiciones de redistribución para fabricantes de equipos originales (OEM).

Soberanía de datos y cumplimiento normativo

La arquitectura de Texto de AWS hace imposible una garantía: que tus documentos permanezcan dentro de tu infraestructura. Cada operación de OCR transmite el contenido del documento a los servidores de Amazon.

Enfoque de AWS Textract

// This code sends PHI, legal documents, financial records — whatever is in
// the file — to Amazon Web Services infrastructure
public async Task<string> ProcessSensitiveDocumentAsync(string documentPath)
{
    var imageBytes = File.ReadAllBytes(documentPath);

    // Data crosses your security perimeter here
    var request = new DetectDocumentTextRequest
    {
        Document = new Document
        {
            Bytes = new MemoryStream(imageBytes)
        }
    };

    // Amazon processes it; you receive text back
    var response = await _client.DetectDocumentTextAsync(request);

    return string.Join("\n", response.Blocks
        .Where(b => b.BlockType == BlockType.LINE)
        .Select(b => b.Text));
}
// This code sends PHI, legal documents, financial records — whatever is in
// the file — to Amazon Web Services infrastructure
public async Task<string> ProcessSensitiveDocumentAsync(string documentPath)
{
    var imageBytes = File.ReadAllBytes(documentPath);

    // Data crosses your security perimeter here
    var request = new DetectDocumentTextRequest
    {
        Document = new Document
        {
            Bytes = new MemoryStream(imageBytes)
        }
    };

    // Amazon processes it; you receive text back
    var response = await _client.DetectDocumentTextAsync(request);

    return string.Join("\n", response.Blocks
        .Where(b => b.BlockType == BlockType.LINE)
        .Select(b => b.Text));
}
Imports System.IO
Imports System.Threading.Tasks
Imports Amazon.Textract
Imports Amazon.Textract.Model

Public Class DocumentProcessor
    Private _client As AmazonTextractClient

    Public Sub New(client As AmazonTextractClient)
        _client = client
    End Sub

    ' This code sends PHI, legal documents, financial records — whatever is in
    ' the file — to Amazon Web Services infrastructure
    Public Async Function ProcessSensitiveDocumentAsync(documentPath As String) As Task(Of String)
        Dim imageBytes = File.ReadAllBytes(documentPath)

        ' Data crosses your security perimeter here
        Dim request As New DetectDocumentTextRequest With {
            .Document = New Document With {
                .Bytes = New MemoryStream(imageBytes)
            }
        }

        ' Amazon processes it; you receive text back
        Dim response = Await _client.DetectDocumentTextAsync(request)

        Return String.Join(vbLf, response.Blocks _
            .Where(Function(b) b.BlockType = BlockType.LINE) _
            .Select(Function(b) b.Text))
    End Function
End Class
$vbLabelText   $csharpLabel

AWS ofrece un Acuerdo de socio comercial HIPAApara entidades cubiertas, y las regiones de GovCloud proporcionan la autorización FedRAMP High. Estos marcos no modifican la arquitectura fundamental: los documentos salen de su infraestructura para cada operación. En el caso de los datos técnicos sujetos a la normativa ITAR, no se trata de una sutileza de cumplimiento, sino de una prohibición. Para las cargas de trabajo de nivel 3 del CMMC con CUI, la transmisión en la nube requiere autorizaciones específicas que la mayoría de los contratistas de defensa no poseen. Para los sistemas aislados (redes de investigación, entornos de control industrial, instalaciones clasificadas), Textract simplemente no está disponible.

AWS Textract está disponible en seis regiones: us-east-1, us-west-2, eu-west-1, eu-west-2, ap-southeast-1 y ap-southeast-2. Las organizaciones con requisitos de residencia de datos fuera de estas regiones no disponen de ninguna opción que cumpla con la normativa.

Enfoque de IronOCR

// IronOCR: document bytes never leave this process
public string ProcessSensitiveDocument(string documentPath)
{
    // Processes entirely on local hardware — no network call
    var ocr = new IronTesseract();
    return ocr.Read(documentPath).Text;
}
// IronOCR: document bytes never leave this process
public string ProcessSensitiveDocument(string documentPath)
{
    // Processes entirely on local hardware — no network call
    var ocr = new IronTesseract();
    return ocr.Read(documentPath).Text;
}
' IronOCR: document bytes never leave this process
Public Function ProcessSensitiveDocument(documentPath As String) As String
    ' Processes entirely on local hardware — no network call
    Dim ocr As New IronTesseract()
    Return ocr.Read(documentPath).Text
End Function
$vbLabelText   $csharpLabel

Dado que IronOCR se ejecuta localmente, encaja de forma natural en los flujos de trabajo del sector sanitario que procesan información médica protegida (PHI), en los sistemas de documentos legales que gestionan comunicaciones privilegiadas, en las aplicaciones financieras que manejan imágenes de tarjetas de pago y en los procesos de los contratistas de defensa que procesan información controlada (CUI). No hay ningún procesador externo que auditar, ningún acuerdo de negocios (BAA) que negociar ni ninguna restricción de residencia de datos que cumplir. El ámbito de cumplimiento es la propia infraestructura de su organización.

Para los equipos que implementan en la infraestructura de AWS pero necesitan procesamiento local,IronOCRse ejecuta en AWS (EC2, Lambda) sin ninguna dependencia de Textract: el procesamiento se realiza dentro de los límites de su propia cuenta de AWS en lugar de en el servicio gestionado de Amazon.

Sondeo asíncrono frente a procesamiento síncrono

La división arquitectónica entre las API síncronas (imagen única) y asíncronas (PDF de varias páginas) de Textract no es un detalle menor de la API. Determina cómo se crean los servicios, cómo se gestionan los errores y cuánto código deben leer y analizar los responsables del mantenimiento.

Enfoque de AWS Textract

// Full production-grade async processor for Textract PDF handling
public class TextractAsyncProcessor
{
    private readonly AmazonTextractClient _textractClient;
    private readonly AmazonS3Client _s3Client;
    private readonly string _bucketName;
    private readonly TimeSpan _pollInterval = TimeSpan.FromSeconds(5);
    private readonly TimeSpan _maxWaitTime = TimeSpan.FromMinutes(10);

    public async Task<DocumentResult> ProcessDocumentAsync(
        string localFilePath,
        CancellationToken cancellationToken = default)
    {
        var s3Key = $"textract-uploads/{Guid.NewGuid()}{Path.GetExtension(localFilePath)}";

        try
        {
            // Phase 1: Upload to S3
            await UploadToS3Async(localFilePath, s3Key, cancellationToken);

            // Phase 2: Start Textract job
            var jobId = await StartTextractJobAsync(s3Key, cancellationToken);

            // Phase 3: Poll until complete (up to 10 minutes)
            var pollResult = await PollForCompletionAsync(jobId, cancellationToken);

            if (!pollResult.Success)
                throw new Exception($"Textract job failed: {pollResult.ErrorMessage}");

            // Phase 4: Retrieve paginated results
            return await GetAllResultsAsync(jobId, cancellationToken);
        }
        finally
        {
            // Phase 5: S3 cleanup — must succeed or storage costs accumulate
            await DeleteFromS3Async(s3Key, cancellationToken);
        }
    }

    private async Task<(bool Success, string ErrorMessage)> PollForCompletionAsync(
        string jobId, CancellationToken cancellationToken)
    {
        var startTime = DateTime.UtcNow;
        int pollCount = 0;

        while (DateTime.UtcNow - startTime < _maxWaitTime)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var response = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest { JobId = jobId }, cancellationToken);

            pollCount++;

            switch (response.JobStatus)
            {
                case JobStatus.SUCCEEDED: return (true, null);
                case JobStatus.FAILED: return (false, response.StatusMessage ?? "Unknown error");
                case JobStatus.IN_PROGRESS:
                    await Task.Delay(_pollInterval, cancellationToken);
                    break;
                default:
                    throw new Exception($"Unknown job status: {response.JobStatus}");
            }
        }

        return (false, "Job timed out");
    }
}
// Full production-grade async processor for Textract PDF handling
public class TextractAsyncProcessor
{
    private readonly AmazonTextractClient _textractClient;
    private readonly AmazonS3Client _s3Client;
    private readonly string _bucketName;
    private readonly TimeSpan _pollInterval = TimeSpan.FromSeconds(5);
    private readonly TimeSpan _maxWaitTime = TimeSpan.FromMinutes(10);

    public async Task<DocumentResult> ProcessDocumentAsync(
        string localFilePath,
        CancellationToken cancellationToken = default)
    {
        var s3Key = $"textract-uploads/{Guid.NewGuid()}{Path.GetExtension(localFilePath)}";

        try
        {
            // Phase 1: Upload to S3
            await UploadToS3Async(localFilePath, s3Key, cancellationToken);

            // Phase 2: Start Textract job
            var jobId = await StartTextractJobAsync(s3Key, cancellationToken);

            // Phase 3: Poll until complete (up to 10 minutes)
            var pollResult = await PollForCompletionAsync(jobId, cancellationToken);

            if (!pollResult.Success)
                throw new Exception($"Textract job failed: {pollResult.ErrorMessage}");

            // Phase 4: Retrieve paginated results
            return await GetAllResultsAsync(jobId, cancellationToken);
        }
        finally
        {
            // Phase 5: S3 cleanup — must succeed or storage costs accumulate
            await DeleteFromS3Async(s3Key, cancellationToken);
        }
    }

    private async Task<(bool Success, string ErrorMessage)> PollForCompletionAsync(
        string jobId, CancellationToken cancellationToken)
    {
        var startTime = DateTime.UtcNow;
        int pollCount = 0;

        while (DateTime.UtcNow - startTime < _maxWaitTime)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var response = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest { JobId = jobId }, cancellationToken);

            pollCount++;

            switch (response.JobStatus)
            {
                case JobStatus.SUCCEEDED: return (true, null);
                case JobStatus.FAILED: return (false, response.StatusMessage ?? "Unknown error");
                case JobStatus.IN_PROGRESS:
                    await Task.Delay(_pollInterval, cancellationToken);
                    break;
                default:
                    throw new Exception($"Unknown job status: {response.JobStatus}");
            }
        }

        return (false, "Job timed out");
    }
}
Imports System
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Imports Amazon.Textract
Imports Amazon.S3
Imports Amazon.Textract.Model

' Full production-grade async processor for Textract PDF handling
Public Class TextractAsyncProcessor
    Private ReadOnly _textractClient As AmazonTextractClient
    Private ReadOnly _s3Client As AmazonS3Client
    Private ReadOnly _bucketName As String
    Private ReadOnly _pollInterval As TimeSpan = TimeSpan.FromSeconds(5)
    Private ReadOnly _maxWaitTime As TimeSpan = TimeSpan.FromMinutes(10)

    Public Async Function ProcessDocumentAsync(localFilePath As String, Optional cancellationToken As CancellationToken = Nothing) As Task(Of DocumentResult)
        Dim s3Key = $"textract-uploads/{Guid.NewGuid()}{Path.GetExtension(localFilePath)}"

        Try
            ' Phase 1: Upload to S3
            Await UploadToS3Async(localFilePath, s3Key, cancellationToken)

            ' Phase 2: Start Textract job
            Dim jobId = Await StartTextractJobAsync(s3Key, cancellationToken)

            ' Phase 3: Poll until complete (up to 10 minutes)
            Dim pollResult = Await PollForCompletionAsync(jobId, cancellationToken)

            If Not pollResult.Success Then
                Throw New Exception($"Textract job failed: {pollResult.ErrorMessage}")
            End If

            ' Phase 4: Retrieve paginated results
            Return Await GetAllResultsAsync(jobId, cancellationToken)
        Finally
            ' Phase 5: S3 cleanup — must succeed or storage costs accumulate
            Await DeleteFromS3Async(s3Key, cancellationToken)
        End Try
    End Function

    Private Async Function PollForCompletionAsync(jobId As String, cancellationToken As CancellationToken) As Task(Of (Success As Boolean, ErrorMessage As String))
        Dim startTime = DateTime.UtcNow
        Dim pollCount As Integer = 0

        While DateTime.UtcNow - startTime < _maxWaitTime
            cancellationToken.ThrowIfCancellationRequested()

            Dim response = Await _textractClient.GetDocumentTextDetectionAsync(New GetDocumentTextDetectionRequest With {.JobId = jobId}, cancellationToken)

            pollCount += 1

            Select Case response.JobStatus
                Case JobStatus.SUCCEEDED
                    Return (True, Nothing)
                Case JobStatus.FAILED
                    Return (False, If(response.StatusMessage, "Unknown error"))
                Case JobStatus.IN_PROGRESS
                    Await Task.Delay(_pollInterval, cancellationToken)
                Case Else
                    Throw New Exception($"Unknown job status: {response.JobStatus}")
            End Select
        End While

        Return (False, "Job timed out")
    End Function
End Class
$vbLabelText   $csharpLabel

No se trata de un texto estándar que se pueda generar y olvidar. Cuando un trabajo de Textract falla en medio de la ejecución, la limpieza de S3 debe seguir ejecutándose. Cuando un trabajo agota el tiempo de espera tras 10 minutos, el autor de la llamada necesita un error claro. Cuando se produce una caída de la red durante el sondeo, la estrategia de reintento no debe crear trabajos duplicados. Cada uno de estos modos de fallo requiere un tratamiento explícito; la estructura mostrada anteriormente es la implementación mínima responsable.

El procesamiento por lotes añade otra capa: el límite TPS por defecto de Textract StartDocumentTextDetection es de 5 solicitudes por segundo. Procesar 100 documentos requiere una limitación SemaphoreSlim, un temporizador de reposición de tasa, y lógica de reintento para ProvisionedThroughputExceededException.

Enfoque de IronOCR

// IronOCR: same synchronous API regardless of document type or size
public string ProcessDocument(string filePath)
{
    using var input = new OcrInput();

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

    return new IronTesseract().Read(input).Text;
}
// IronOCR: same synchronous API regardless of document type or size
public string ProcessDocument(string filePath)
{
    using var input = new OcrInput();

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

    return new IronTesseract().Read(input).Text;
}
Imports System.IO

' IronOCR: same synchronous API regardless of document type or size
Public Function ProcessDocument(filePath As String) As String
    Using input As New OcrInput()
        If Path.GetExtension(filePath).Equals(".pdf", StringComparison.OrdinalIgnoreCase) Then
            input.LoadPdf(filePath)
        Else
            input.LoadImage(filePath)
        End If

        Return New IronTesseract().Read(input).Text
    End Using
End Function
$vbLabelText   $csharpLabel

No hay bucle de sondeo, ni seguimiento de ID de trabajo, ni bucket de S3, ni paginación de resultados. El mismo código gestiona tanto un único archivo JPEG como un PDF de 200 páginas. El procesamiento se completa o genera un error; no hay un estado intermedio de "en curso" que gestionar. Para el procesamiento por lotes, IronOCR es seguro para hilos y una sola instancia IronTesseract maneja Parallel.ForEach sin bloqueos o semáforos.

La guía de instalación de IronTesseract cubre la configuración, y la guía de entrada de PDF documenta la selección de rangos de páginas, los PDF protegidos con contraseña y la entrada basada en flujos para PDF recuperados de bases de datos o respuestas HTTP.

Sobrecarga de la gestión de credenciales

Para iniciar una operación de OCR con Texto de AWS es necesario configurar IAM antes de procesar una sola página.

Enfoque de AWS Textract

Antes de llamar a DetectDocumentTextAsync, un desarrollador debe:

  1. Crea una cuenta de AWS u obtén acceso a una ya existente
  2. Crear un usuario o rol IAM con permisos textract:DetectDocumentText y textract:AnalyzeDocument
  3. Generar y almacenar de forma segura el ID de la clave de acceso y la clave de acceso secreta
  4. Configurar la resolución de credenciales: variables de entorno, archivo de credenciales de AWS o perfil de instancia de EC2
  5. Si se procesan PDFs: crear un bucket S3, configurar la política del bucket, añadir permisos s3:PutObject y s3:DeleteObject
  6. Implementar políticas de rotación de credenciales para cumplir con los estándares de seguridad
  7. Almacene las credenciales de forma segura en cada entorno de implementación: secretos de Docker, secretos de Kubernetes, AWS Secrets Manager o variables del canal de CI/CD
// Every environment needs these configured before this constructor succeeds
public TextractOcrService()
{
    // Reads credentials from environment, ~/.aws/credentials, or IAM role
    _client = new AmazonTextractClient(Amazon.RegionEndpoint.USEast1);
}
// Every environment needs these configured before this constructor succeeds
public TextractOcrService()
{
    // Reads credentials from environment, ~/.aws/credentials, or IAM role
    _client = new AmazonTextractClient(Amazon.RegionEndpoint.USEast1);
}
' Every environment needs these configured before this constructor succeeds
Public Sub New()
    ' Reads credentials from environment, ~/.aws/credentials, or IAM role
    _client = New AmazonTextractClient(Amazon.RegionEndpoint.USEast1)
End Sub
$vbLabelText   $csharpLabel

Cuando las credenciales expiran, rotan o están mal configuradas, cada llamada de OCR falla con AmazonTextractException portando ErrorCode == "AccessDeniedException". En un sistema de producción, esto implica implementar bloques catch específicos para los errores de credenciales y supervisar las desviaciones de las políticas de IAM.

Enfoque de IronOCR

// One-time setup at application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Or from environment — recommended for deployments
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
// One-time setup at application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Or from environment — recommended for deployments
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
' One-time setup at application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

' Or from environment — recommended for deployments
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
$vbLabelText   $csharpLabel

La clave de licencia es una cadena estática. No caduca durante su funcionamiento, no requiere rotación y no conlleva permisos que gestionar. Un contenedor Dockerque procesa documentos no necesita credenciales de AWS inyectadas, un rol de IAM vinculado a un contexto de ejecución ni acceso de red a AWS STS para la actualización de tokens.

La reducción total de sobrecarga de credenciales al cambiar de Textract a IronOCR: se han eliminado tres paquetes NuGet (AWSSDK.Textract, AWSSDK.S3, AWSSDK.Core), se han eliminado todas las variables de entorno AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION, y se han desmantelado las configuraciones de roles IAM y buckets S3. La guía de entrada de imágenes y la guía de entrada de flujos cubren toda la gama de métodos de entrada que sustituyen a los modelos de documentos de matriz de bytes y objetos S3 de Textract.

Referencia de mapeo de API

API de Texto de AWS Equivalente a IronOCR
AmazonTextractClient IronTesseract
AmazonS3Client No es necesario
DetectDocumentTextRequest OcrInput
DetectDocumentTextResponse OcrResult
AnalyzeDocumentRequest OcrInput con CropRectangle para zonas
StartDocumentTextDetectionRequest OcrInput — sincrónico, no es necesario iniciar
GetDocumentTextDetectionRequest No es obligatorio — resultados inmediatos
Document.Bytes input.LoadImage(bytes) o input.LoadImage(stream)
S3Object (preparación de documentos) Cadena de ruta de archivo o flujo
Block (BlockType.LINE) result.Lines
Block (BlockType.WORD) result.Words
Block (BlockType.TABLE) Agrupación de posición de palabras a través de result.Words
Block (BlockType.KEY_VALUE_SET) Extracción de región CropRectangle
Block.Confidence word.Confidence / result.Confidence
JobStatus.SUCCEEDED No aplicable — retorno sincrónico
JobStatus.IN_PROGRESS No aplicable — sin estado asíncrono
response.NextToken (paginación) No aplicable — resultados no paginados
ProvisionedThroughputExceededException No aplicable — sin límites de TPS
client.DetectDocumentTextAsync(request) ocr.Read(path)
client.AnalyzeDocumentAsync(request) ocr.Read(input)
client.StartDocumentTextDetectionAsync(request) ocr.Read(input)
client.GetDocumentTextDetectionAsync(request) No procede

Cuando los equipos se plantean pasar de Texto de AWS a IronOCR

Cuando la factura mensual se convierte en una partida presupuestaria

Los equipos que empezaron a utilizar Textract con un volumen reducido suelen encontrarse con una situación concreta: la factura de AWS por el procesamiento OCR aparece en la revisión trimestral del presupuesto y alguien pregunta si este coste es fijo. No lo es. En volúmenes altos de páginas, los costos anuales de Textract pueden ser sustanciales — consulte la página de precios de AWS Textract para tarifas actuales. La licencia Professional de IronOCR en $2,999 un solo pago se paga rápidamente con volúmenes de páginas moderados a altos.

Cuando un requisito de cumplimiento bloquea el procesamiento en la nube

Las organizaciones sanitarias que implementan flujos de trabajo de digitalización de documentos suelen descubrir a mitad del proyecto que la información médica protegida (PHI) según la HIPAAno puede circular a través de servicios en la nube sin un acuerdo de negocios (BAA) y una revisión legal adicional, o que su equipo de seguridad prohíbe por completo la transmisión a la nube. Los contratistas de defensa que manejan planos técnicos, especificaciones o cualquier información clasificada (CUI) se enfrentan a restricciones de ITARy CMMC que excluyen a Texto de AWS de su consideración. Los bufetes de abogados que procesan comunicaciones privilegiadas tienen preocupaciones similares. No se trata de casos extremos teóricos de cumplimiento normativo, sino que aparecen con frecuencia en revisiones de adquisiciones, auditorías de seguridad y negociaciones contractuales.IronOCR procesa los datos localmente, por lo que la cuestión del cumplimiento normativo en relación con los datos de los documentos se reduce a si su propia infraestructura está incluida en el ámbito de aplicación, y no a si la infraestructura de Amazon lo está.

Cuando la complejidad del PDF asíncrono supera su valor

El proceso S3-async de cinco fases —carga, inicio del trabajo, sondeo, paginación de resultados, limpieza— no es técnicamente difícil de implementar. Es difícil de mantener, probar y operar. Cada fase es un punto de fallo. Los errores de carga en S3 requieren una lógica de reintento. Los fallos en las tareas de Textract requieren distinguir entre errores transitorios y permanentes. Los tiempos de espera de las consultas requieren un manejo de los tiempos de espera independiente de la cancelación. La paginación de resultados requiere acumular el estado a lo largo de múltiples llamadas a la API. Los fallos en la limpieza de S3 requieren una alerta, ya que los objetos huérfanos acumulan costes. Los equipos que han implementado este sistema en producción suelen dedicar más tiempo de ingeniería a su mantenimiento que el que invirtieron en su desarrollo. El equivalente de IronOCR— input.LoadPdf(path) seguido de ocr.Read(input) — elimina todas las cinco fases y sus modos de falla asociados.

Cuando los entornos de implementación carecen de acceso a Internet

Los contenedores Dockerque se ejecutan en segmentos de red aislados, los servidores locales sin conexión a Internet saliente, los entornos de investigación aislados físicamente y los sistemas industriales con estrictos controles de red comparten una característica: Texto de AWS no está disponible.IronOCR se instala como un paquete NuGet estándar y funciona sin necesidad de realizar llamadas de red después de la instalación. Los equipos que ejecutan aplicaciones .NET en estos entornos no tienen la opción Textract y necesitan una biblioteca que procese localmente. La guía de implementación de Docker y la guía de implementación de Linux cubren la configuración específica para entornos de contenedores.

Cuando la limitación de velocidad interrumpe los flujos de trabajo por lotes

El límite TPS por defecto StartDocumentTextDetection es de 5 solicitudes por segundo. Las llamadas sincrónicas DetectDocumentText también están limitadas por tasa. Los trabajos por lotes que procesan cientos o miles de documentos deben implementar limitación SemaphoreSlim, retroceso exponencial en ProvisionedThroughputExceededException, y temporizadores de reposición de tasa. AWS admite las solicitudes de aumento del límite de TPS, pero requieren justificación, revisión y no están garantizadas.IronOCR procesa las tareas tan rápido como lo permite la CPU local: un servidor de 32 núcleos procesa 32 documentos simultáneamente sin configuración de limitación de velocidad ni negociación del nivel de servicio.

Consideraciones comunes sobre la migración

Sustitución del gráfico de bloques por colecciones directas

Textract representa todos los resultados como una List<Block> plana donde líneas, palabras, celdas, tablas y pares clave-valor se distinguen por BlockType y se enlazan por matrices de IDs de relación.IronOCR proporciona colecciones de texto directamente escritas.

// Textract: filter flat block list by type
var lines = response.Blocks.Where(b => b.BlockType == BlockType.LINE);
var words = response.Blocks.Where(b => b.BlockType == BlockType.WORD);

// IronOCR: direct access to typed collections
var result = ocr.Read(imagePath);
var lines = result.Lines;   // IEnumerable<OcrResult.OcrResultLine>
var words = result.Words;   // IEnumerable<OcrResult.OcrResultWord>
foreach (var word in result.Words)
    Console.WriteLine($"'{word.Text}' at ({word.X},{word.Y}) confidence {word.Confidence}%");
// Textract: filter flat block list by type
var lines = response.Blocks.Where(b => b.BlockType == BlockType.LINE);
var words = response.Blocks.Where(b => b.BlockType == BlockType.WORD);

// IronOCR: direct access to typed collections
var result = ocr.Read(imagePath);
var lines = result.Lines;   // IEnumerable<OcrResult.OcrResultLine>
var words = result.Words;   // IEnumerable<OcrResult.OcrResultWord>
foreach (var word in result.Words)
    Console.WriteLine($"'{word.Text}' at ({word.X},{word.Y}) confidence {word.Confidence}%");
' Textract: filter flat block list by type
Dim lines = response.Blocks.Where(Function(b) b.BlockType = BlockType.LINE)
Dim words = response.Blocks.Where(Function(b) b.BlockType = BlockType.WORD)

' IronOCR: direct access to typed collections
Dim result = ocr.Read(imagePath)
Dim lines = result.Lines   ' IEnumerable(Of OcrResult.OcrResultLine)
Dim words = result.Words   ' IEnumerable(Of OcrResult.OcrResultWord)
For Each word In result.Words
    Console.WriteLine($"'{word.Text}' at ({word.X},{word.Y}) confidence {word.Confidence}%")
Next
$vbLabelText   $csharpLabel

La guía de resultados estructurados cubre result.Pages, result.Paragraphs, result.Lines, result.Words y el acceso a coordenadas para construir procesamiento de documentos consciente del diseño.

Sustitución del procesamiento de PDF por etapas S3 con Direct LoadPdf

Cualquier código de Textract que se cargue en S3 antes de iniciar una tarea de detección puede sustituirse por una carga directa de PDF. Sin área de preparación, sin sincronización de carga, sin lógica de limpieza.

// Textract: upload to S3 → start job → poll → paginate → cleanup (50+ lines)
//IronOCR equivalent:
public string ProcessPdf(string pdfPath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return ocr.Read(input).Text;
}

// Specific page ranges (no Textract equivalent without async job per range)
public string ProcessPdfPages(string pdfPath, int startPage, int endPage)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadPdfPages(pdfPath, startPage, endPage);
    return ocr.Read(input).Text;
}
// Textract: upload to S3 → start job → poll → paginate → cleanup (50+ lines)
//IronOCR equivalent:
public string ProcessPdf(string pdfPath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return ocr.Read(input).Text;
}

// Specific page ranges (no Textract equivalent without async job per range)
public string ProcessPdfPages(string pdfPath, int startPage, int endPage)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadPdfPages(pdfPath, startPage, endPage);
    return ocr.Read(input).Text;
}
Imports IronOcr

Public Class PdfProcessor
    ' Textract: upload to S3 → start job → poll → paginate → cleanup (50+ lines)
    ' IronOCR equivalent:
    Public Function ProcessPdf(pdfPath As String) As String
        Dim ocr As New IronTesseract()
        Using input As New OcrInput()
            input.LoadPdf(pdfPath)
            Return ocr.Read(input).Text
        End Using
    End Function

    ' Specific page ranges (no Textract equivalent without async job per range)
    Public Function ProcessPdfPages(pdfPath As String, startPage As Integer, endPage As Integer) As String
        Dim ocr As New IronTesseract()
        Using input As New OcrInput()
            input.LoadPdfPages(pdfPath, startPage, endPage)
            Return ocr.Read(input).Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Agregar preprocesamiento para documentos que produjeron baja confianza en Textract

El preprocesamiento de Textract es interno y no configurable. Cuando un documento escaneado produce resultados deficientes, las únicas opciones son volver a intentarlo o aceptar un resultado con baja fiabilidad.IronOCR expone directamente el proceso de preprocesamiento.

// For documents that returned low-confidence results from Textract
using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");

input.Deskew();              // Fix rotation from scanner misalignment
input.DeNoise();             // Remove scanner noise artifacts
input.Contrast();            // Boost faint text
input.EnhanceResolution(300); // Scale to optimal OCR resolution

var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
// For documents that returned low-confidence results from Textract
using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");

input.Deskew();              // Fix rotation from scanner misalignment
input.DeNoise();             // Remove scanner noise artifacts
input.Contrast();            // Boost faint text
input.EnhanceResolution(300); // Scale to optimal OCR resolution

var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr

Dim input As New OcrInput()
input.LoadImage("low-quality-scan.jpg")

input.Deskew()              ' Fix rotation from scanner misalignment
input.DeNoise()             ' Remove scanner noise artifacts
input.Contrast()            ' Boost faint text
input.EnhanceResolution(300) ' Scale to optimal OCR resolution

Dim result = New IronTesseract().Read(input)
Console.WriteLine($"Confidence: {result.Confidence}%")
$vbLabelText   $csharpLabel

La guía de corrección de calidad de imagen y tutorial de filtros de imagen documentan toda la tubería de preprocesamiento y las combinaciones que funcionan mejor para tipos de documentos específicos. Para la interpretación de puntajes de confianza y el acceso a la confianza por elemento, la guía de puntuaciones de confianza cubre la propiedad result.Confidence y los valores de confianza por palabra.

Cómo gestionar el cambio de patrón de asíncrono a síncrono

El código existente de Textract es necesariamente async Task<t> durante todo el proceso porque el SDK es solo asincrónico. Las operaciones de IronOCR son síncronas. Para el código de la aplicación que ya tiene una cadena de llamadas asincrónica, envuelva la llamada IronOCR en Task.Run para mantener el límite asincrónico.

// Preserves async call site for minimal refactoring
public async Task<string> ExtractTextAsync(string path)
{
    return await Task.Run(() => new IronTesseract().Read(path).Text);
}
// Preserves async call site for minimal refactoring
public async Task<string> ExtractTextAsync(string path)
{
    return await Task.Run(() => new IronTesseract().Read(path).Text);
}
Imports System.Threading.Tasks

' Preserves async call site for minimal refactoring
Public Async Function ExtractTextAsync(path As String) As Task(Of String)
    Return Await Task.Run(Function() New IronTesseract().Read(path).Text)
End Function
$vbLabelText   $csharpLabel

Se trata de un envoltorio práctico, no de un requisito. Para el procesamiento del lado del servidor, donde el código que realiza la llamada ya se encuentra en un hilo en segundo plano, se prefiere la llamada síncrona directa.

Funcionalidades adicionales de IronOCR

Más allá de los puntos de comparación mencionados anteriormente,IronOCR ofrece capacidades que no tienen equivalente en AWS Textract:

Compatibilidad con .NET y preparación para el futuro

IronOCR está diseñado para .NET 8 y .NET 9, con compatibilidad activa para proyectos .NET Standard 2.0 y .NET Framework versiones 4.6.2 a 4.8. La biblioteca distribuye binarios nativos para Windows x64, Windows x86, Linuxx64 y macOS a través de un único paquete NuGet , sin necesidad de cambiar el identificador de tiempo de ejecución ni de hacer referencia a paquetes específicos de la plataforma. El paquete AWSSDK.Textract de Texto de AWS admite los mismos objetivos modernos de .NET, pero el modelo de implementación incluye todo el árbol de dependencias del SDK de AWS, infraestructura de credenciales IAM y las restricciones arquitectónicas documentadas a lo largo de este artículo.IronOCR mantiene un desarrollo activo con lanzamientos periódicos que siguen de cerca las actualizaciones del motor Tesseract 5 y los avances del entorno de ejecución .NET , incluida la compatibilidad con .NET 10 cuando se lance.

Conclusión

AWS Textract e IronOCR resuelven el mismo problema —extraer texto de documentos en aplicaciones .NET con supuestos arquitectónicos fundamentalmente incompatibles. Textract parte de la base de que los documentos pueden salir de su red, que los costes del servicio en la nube aumentan linealmente con el volumen y que los PDF de varias páginas justifican una canalización asíncrona de cinco fases con almacenamiento temporal en S3.IronOCR parte de la base de que los documentos permanecen donde se procesan, que los costes de las licencias deben desvincularse del volumen y que el procesamiento de PDF debe requerir las mismas tres líneas de código que el procesamiento de imágenes.

La aritmética de costos es la línea divisoria más clara. A volúmenes bajos, las tarifas por página de Textract son manejables. A medida que el volumen crece, los costos anuales se componen de manera significativa. A grandes volúmenes de páginas con extracción de tablas, los costos multianuales de Textract pueden superar en gran medida incluso la Licencia Unlimited de IronOCR en $5,999. La matemática inicial se mantiene: el modelo por página se acumula rápidamente, y nunca se detiene.

La soberanía de los datos es la segunda restricción estructural. En lo que respecta a la carga de trabajo en los sectores sanitario, jurídico, financiero y gubernamental, la cuestión de dónde se procesan los documentos no es una cuestión de preferencia, sino un requisito de cumplimiento.IronOCR realiza los procesos localmente por diseño, no por configuración. No hay ningún "modo local" que se pueda activar; El procesamiento local es el único modo de funcionamiento. Eso simplifica la respuesta en materia de cumplimiento normativo: sus documentos permanecen en su infraestructura porque no hay otro lugar adonde puedan ir.

Para los equipos que evalúan el OCR a gran escala o que operan en entornos donde los datos de los documentos no pueden salir de la infraestructura interna, la documentación de IronOCR proporciona la referencia completa de la API, guías de implementación para Docker, AWS, Azurey Linux, y tutoriales que cubren toda la gama de casos de uso de OCR, desde la lectura básica de imágenes hasta la generación de PDF con capacidad de búsqueda y la extracción multilingüe.

(

Por favor notaAWS Textract y Tesseract son marcas registradas de sus respectivos propietarios. Este sitio no está afiliado, aprobado ni patrocinado por Amazon Web Services o Google. 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.

Preguntas Frecuentes

¿Qué es Amazon Textract?

Amazon Textract es una solución de OCR utilizada por desarrolladores y empresas para extraer texto de imágenes y documentos. Es una de las diversas opciones de OCR evaluadas junto con IronOCR for .NET para el desarrollo de aplicaciones.

¿Cómo se compara IronOCR con Amazon Textract para desarrolladores .NET?

IronOCR es una biblioteca de OCR .NET nativa de NuGet que utiliza IronTesseract como motor principal. En comparación con Amazon Textract, ofrece una implementación más sencilla (sin instaladores de SDK), precios de tarifa plana y una API de C# limpia sin interoperabilidad COM ni dependencias de la nube.

¿Es IronOCR más fácil de configurar que Amazon Textract?

IronOCR se instala mediante un único paquete NuGet. No hay instaladores de SDK, archivos de licencia que copiar, componentes COM que registrar ni binarios de ejecución independientes que gestionar. Todo el motor de OCR está incluido en el paquete.

¿Qué diferencias de precisión existen entre Amazon Textract e IronOCR?

IronOCR logra una alta precisión de reconocimiento para documentos comerciales estándar, facturas, recibos y formularios escaneados. Para documentos muy degradados o escrituras poco comunes, la precisión varía en función de la calidad de la fuente. IronOCR incluye filtros de preprocesamiento de imágenes para mejorar el reconocimiento en entradas de baja calidad.

¿Es IronOCR compatible con la extracción de texto en PDF?

Sí. IronOCR extrae texto tanto de PDF nativos como de imágenes PDF escaneadas en una sola llamada. También admite archivos TIFF de varias páginas, imágenes y secuencias. En el caso de los PDF escaneados, el OCR se aplica página a página con objetos de resultado por página.

¿Qué diferencia hay entre las licencias de Amazon Textract y las de IronOCR?

IronOCR utiliza una licencia perpetua de tarifa plana sin cargos por página o por escaneo. Las organizaciones que procesan grandes volúmenes de documentos pagan el mismo coste de licencia independientemente del volumen. Encontrará más información y precios por volumen en la página de licencias de IronOCR.

¿Qué idiomas admite IronOCR?

IronOCR es compatible con 127 idiomas a través de paquetes de idiomas NuGet independientes. Para añadir un idioma, basta con ejecutar el comando 'dotnet add package IronOcr.Languages.{Language}'. No es necesaria la colocación manual de archivos ni la configuración de rutas.

¿Cómo instalo IronOCR en un proyecto .NET ?

Instalación a través de NuGet: install-Package IronOcr' en la consola del gestor de paquetes o 'dotnet add package IronOcr' en la CLI. Los paquetes de idiomas adicionales se instalan del mismo modo. No se requiere ningún instalador nativo del SDK.

¿Es IronOCR adecuado para Docker y las implementaciones en contenedores, a diferencia de Amazon Textract?

Sí. IronOCR funciona en contenedores Docker a través de su paquete NuGet. La clave de licencia se establece mediante una variable de entorno. No se requieren archivos de licencia, rutas de SDK ni montajes de volumen para el propio motor de OCR.

¿Puedo probar IronOCR antes de comprarlo, en comparación con Amazon Textract?

Sí. El modo de prueba de IronOCR procesa documentos y devuelve resultados de OCR con una marca de agua superpuesta en la salida. Puede verificar la precisión en sus propios documentos antes de adquirir una licencia.

¿Admite IronOCR la lectura de códigos de barras junto con la extracción de texto?

IronOCR se centra en la extracción de texto y el reconocimiento óptico de caracteres. Para la lectura de códigos de barras, Iron Software ofrece IronBarcode como biblioteca complementaria. Ambas están disponibles por separado o como parte del paquete Iron Suite.

¿Es fácil migrar de Amazon Textract a IronOCR?

La migración de Amazon Textract a IronOCR suele implicar la sustitución de las secuencias de inicialización por la instanciación de IronTesseract, la eliminación de la gestión del ciclo de vida de COM y la actualización de las llamadas a la API. La mayoría de las migraciones reducen significativamente la complejidad del código.

Kannaopat Udonpant
Ingeniero de Software
Antes de convertirse en Ingeniero de Software, Kannapat completó un doctorado en Recursos Ambientales de la Universidad de Hokkaido en Japón. Mientras perseguía su grado, Kannapat también se convirtió en miembro del Laboratorio de Robótica de Vehículos, que es parte del Departamento de Ingeniería ...
Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame