Ir para o conteúdo do rodapé
USANDO O IRONBARCODE

Criar uma API de leitor de código de barras em C# (Guia do desenvolvedor)

Crie uma API RESTful de scanner de código de barras usando IronBarcode e ASP.NET Core para gerenciar códigos de barras a partir de imagens, PDFs e digitalizações danificadas sem hardware, garantindo desempenho confiável em Windows, Linux e macOS.

IronBarcode permite a digitalização profissional de códigos de barras através de APIs RESTful no ASP.NET Core, processando imagens, PDFs e digitalizações danificadas sem dependências de hardware enquanto oferece suporte a implantações multiplataforma com recursos de segurança e conformidade embutidos.

O que é o Desafio de Código de Barras Enterprise?

Imagine ser o Arquiteto de Enterprise em uma empresa de logística da Fortune 500. Suas equipes de armazém lutam com etiquetas de envio danificadas, seu departamento de finanças precisa processar milhares de PDFs de faturas com códigos de barras incorporados, e sua equipe de segurança de TI exige uma solução que atenda à conformidade SOC2 sem introduzir dependências de hardware em sua infraestrutura global.

Este cenário é comum para equipes empresariais que buscam descobrir as capacidades da API REST do IronBarcode. O que começou como um simples requisito para ler códigos de barras evoluiu para uma solução de digitalização completa que agora processa mais de 2 milhões de códigos de barras mensalmente em toda a organização.

Tradicionalmente, isso teria exigido scanners de hardware caros em cada local, gestão complexa de drivers e avaliações significativas de segurança. Em vez disso, construíram uma central API RESTful que qualquer departamento pode acessar com segurança, seja escaneando etiquetas de armazém danificadas ou extraindo dados de faturas de PDFs de fornecedores.

Este tutorial orienta você na construção dessa mesma API profissional de scanner de código de barras. Você aprenderá a criar endpoints seguros que lidem com desafios do mundo real como etiquetas rasgadas, imagens enviesadas e documentos de várias páginas. Mais importante ainda, você verá como implementar isso com a segurança, escalabilidade e estabilidade de fornecedor que ambientes empresariais exigem.

Como você constrói uma API de Scanner C# Confiável?

Criar uma API de scanner de código de barras empresarial requer abordar várias preocupações críticas antecipadamente. As equipes de segurança precisam de garantias sobre o manuseio de dados. Os responsáveis pela conformidade exigem trilhas de auditoria. As equipes de operações exigem confiabilidade em diferentes plataformas. A documentação completa do IronBarcode aborda cada uma dessas preocupações sistematicamente.

A beleza de uma abordagem RESTful reside em sua simplicidade e segurança. Ao centralizar o processamento de códigos de barras por trás de endpoints de API seguros, você mantém controle completo sobre o fluxo de dados. Nenhum dispositivo cliente precisa de acesso direto à sua lógica de processamento de códigos de barras. Esta arquitetura apoia naturalmente seu modelo de segurança sem confiança, ao mesmo tempo que permite uma integração suave com sistemas empresariais existentes.

Vamos começar com a fundação. Os recursos de leitura do IronBarcode suportam todos os principais formatos de códigos de barras que sua empresa pode encontrar. Desde os tradicionais códigos de barras Code 39 usados na manufatura até os modernos códigos QR em campanhas de marketing, a biblioteca lida com todos eles. O guia de formatos de códigos de barras suportados fornece uma referência completa para planejar sua implementação.

O que torna isso particularmente valioso para cenários empresariais são as capacidades de tolerância a falhas da biblioteca. Os códigos de barras do mundo real não são perfeitos. Eles se danificam, são impressos de forma inadequada, ou escaneados em ângulos. O processamento avançado de imagens do IronBarcode lida com esses desafios automaticamente, reduzindo os tickets de suporte e melhorando a eficiência operacional.

Como você instala e configura a biblioteca de Código de Barras?

Implantações empresariais exigem consideração cuidadosa de dependências e licenciamento. IronBarcode simplifica isso com instalação direta via NuGet e licenciamento transparente. Veja como começar no seu projeto ASP.NET Core:

Install-Package IronBarCode
Install-Package IronBarCode
SHELL

Para ambientes empresariais com requisitos específicos de plataforma, consulte o guia avançado de instalação NuGet. Isso cobre cenários como direcionamento de versões específicas do .NET ou otimização para plataformas particulares.

Após a instalação, verifique sua configuração com um teste simples. Este código demonstra a capacidade da biblioteca de ler códigos de barras com configuração mínima:

using IronBarCode;

// Verify installation with a basic barcode read
public class InstallationTest
{
    public static void VerifySetup()
    {
        try
        {
            // Test with a sample barcode image
            var result = BarcodeReader.Read("test-barcode.png");

            if (result.Any())
            {
                Console.WriteLine($"Success! Detected: {result.First().Value}");
                Console.WriteLine($"Format: {result.First().BarcodeType}");
                Console.WriteLine($"Confidence: {result.First().Confidence}%");
            }
            else
            {
                Console.WriteLine("No barcode detected in test image");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Setup issue: {ex.Message}");
        }
    }
}
using IronBarCode;

// Verify installation with a basic barcode read
public class InstallationTest
{
    public static void VerifySetup()
    {
        try
        {
            // Test with a sample barcode image
            var result = BarcodeReader.Read("test-barcode.png");

            if (result.Any())
            {
                Console.WriteLine($"Success! Detected: {result.First().Value}");
                Console.WriteLine($"Format: {result.First().BarcodeType}");
                Console.WriteLine($"Confidence: {result.First().Confidence}%");
            }
            else
            {
                Console.WriteLine("No barcode detected in test image");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Setup issue: {ex.Message}");
        }
    }
}
$vbLabelText   $csharpLabel

Esta etapa de verificação é crucial para implantações em empresas. Ela confirma que a biblioteca está corretamente instalada, licenciada e pode acessar os recursos necessários do sistema. A saída da pontuação de confiança ajuda a estabelecer expectativas básicas para seus tipos específicos de códigos de barras.

Para implantações de produção, revise cuidadosamente a documentação de licenciamento. As licenças Enterprise suportam implantações ilimitadas dentro da sua organização, crucial para escalabilidade em vários data centers. O guia de configuração da chave de licença explica vários métodos de ativação, incluindo variáveis de ambiente e arquivos de configuração que se alinham com suas práticas DevOps.

Compatibilidade de Plataforma para Empresas

Provavelmente sua empresa opera em um ambiente heterogêneo. O desenvolvimento acontece no Windows, a preparação em contêineres Linux, e algumas equipes podem usar macOS. A compatibilidade multiplataforma do IronBarcode garante um comportamento consistente em todas essas plataformas.

Para implantações em contêineres, o guia de configuração do Docker fornece instruções específicas para contêineres Linux. Isso inclui o tratamento de dependências e a otimização do tamanho da imagem para implantação eficiente na nuvem. Se você está implantando no Azure ou AWS Lambda, guias específicos de plataforma garantem o desempenho ideal nesses ambientes.

A biblioteca até suporta cenários móveis através da integração .NET MAUI, permitindo ampliar suas capacidades de leitura de códigos de barra para dispositivos iOS e Android quando trabalhadores de campo precisam de capacidades de leitura móvel.

Como Construir um Controlador de API de Scanner Completo?

Vamos construir uma API de scanner pronta para produção que atenda às reais necessidades empresariais. Esta implementação inclui tratamento adequado de erros, considerações de segurança e otimizações de desempenho:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using IronBarCode;
using System.Drawing;
using System.ComponentModel.DataAnnotations;

namespace BarcodeScannerAPI.Controllers
{
    [ApiController]
    [Route("api/v1/[controller]")]
    [Authorize] // Require authentication for all endpoints
    public class ScannerController : ControllerBase
    {
        private readonly ILogger<ScannerController> _logger;
        private readonly IConfiguration _configuration;

        public ScannerController(ILogger<ScannerController> logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
        }

        // Enhanced result model with audit fields
        public class ScanResult
        {
            public bool Success { get; set; }
            public List<BarcodeData> Barcodes { get; set; } = new List<BarcodeData>();
            public string RequestId { get; set; } = Guid.NewGuid().ToString();
            public DateTime ProcessedAt { get; set; } = DateTime.UtcNow;
            public long ProcessingTimeMs { get; set; }
            public string ErrorMessage { get; set; }
            public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
        }

        public class BarcodeData
        {
            public string Value { get; set; }
            public string Format { get; set; }
            public double Confidence { get; set; }
            public Rectangle Location { get; set; }
            public int PageNumber { get; set; } // For PDF processing
        }

        // Input validation model
        public class ScanRequest
        {
            [Required]
            public IFormFile File { get; set; }

            [Range(1, 10)]
            public int MaxBarcodes { get; set; } = 5;

            public string[] ExpectedFormats { get; set; }

            public bool EnableImageCorrection { get; set; } = true;
        }

        [HttpPost("scan")]
        [RequestSizeLimit(52428800)] // 50MB limit
        public async Task<ActionResult<ScanResult>> ScanDocument([FromForm] ScanRequest request)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            var result = new ScanResult();

            try
            {
                // Validate file type for security
                var allowedExtensions = new[] { ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".tiff", ".bmp" };
                var fileExtension = Path.GetExtension(request.File.FileName).ToLowerInvariant();

                if (!allowedExtensions.Contains(fileExtension))
                {
                    _logger.LogWarning($"Rejected file type: {fileExtension}");
                    return BadRequest(new ScanResult
                    {
                        Success = false,
                        ErrorMessage = "Unsupported file type. Allowed: PDF, PNG, JPG, GIF, TIFF, BMP"
                    });
                }

                // Process the file
                using var stream = new MemoryStream();
                await request.File.CopyToAsync(stream);
                var fileBytes = stream.ToArray();

                // Log for audit trail
                _logger.LogInformation($"Processing {request.File.FileName} ({fileBytes.Length} bytes) - RequestId: {result.RequestId}");

                // Configure scanner based on requirements
                var options = ConfigureOptions(request);

                // Handle different file types
                BarcodeResults scanResults;
                if (fileExtension == ".pdf")
                {
                    var pdfOptions = new PdfBarcodeReaderOptions
                    {
                        Scale = 3,
                        DPI = 300,
                        MaxThreads = 4
                    };
                    scanResults = BarcodeReader.ReadPdf(fileBytes, pdfOptions);
                }
                else
                {
                    scanResults = BarcodeReader.Read(fileBytes, options);
                }

                // Process results
                if (scanResults.Any())
                {
                    result.Success = true;
                    foreach (var barcode in scanResults.Take(request.MaxBarcodes))
                    {
                        result.Barcodes.Add(new BarcodeData
                        {
                            Value = barcode.Value,
                            Format = barcode.BarcodeType.ToString(),
                            Confidence = barcode.Confidence,
                            Location = barcode.Bounds,
                            PageNumber = barcode.PageNumber
                        });
                    }

                    result.Metadata["TotalFound"] = scanResults.Count();
                    result.Metadata["FileSize"] = fileBytes.Length;
                    result.Metadata["FileName"] = request.File.FileName;

                    _logger.LogInformation($"Successfully scanned {scanResults.Count()} barcodes - RequestId: {result.RequestId}");
                }
                else
                {
                    result.Success = false;
                    result.ErrorMessage = "No barcodes detected in the document";
                    _logger.LogWarning($"No barcodes found - RequestId: {result.RequestId}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Scanning error - RequestId: {result.RequestId}");
                result.Success = false;
                result.ErrorMessage = "An error occurred during processing";

                // Don't expose internal errors to clients
                if (_configuration.GetValue<bool>("DetailedErrors"))
                {
                    result.Metadata["Exception"] = ex.Message;
                }
            }
            finally
            {
                stopwatch.Stop();
                result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds;
            }

            return result;
        }

        private BarcodeReaderOptions ConfigureOptions(ScanRequest request)
        {
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                ExpectMultipleBarcodes = request.MaxBarcodes > 1,
                RemoveFalsePositive = true,
                Multithreaded = true,
                MaxParallelThreads = Environment.ProcessorCount
            };

            // Apply format filtering if specified
            if (request.ExpectedFormats?.Any() == true)
            {
                var formats = BarcodeEncoding.None;
                foreach (var format in request.ExpectedFormats)
                {
                    if (Enum.TryParse<BarcodeEncoding>(format, true, out var encoding))
                    {
                        formats |= encoding;
                    }
                }
                options.ExpectBarcodeTypes = formats;
            }

            // Enable image correction for damaged barcodes
            if (request.EnableImageCorrection)
            {
                options.ImageFilters = new ImageFilterCollection
                {
                    new SharpenFilter(2),
                    new ContrastFilter(1.5f),
                    new BrightnessFilter(1.1f)
                };
                options.AutoRotate = true;
            }

            return options;
        }

        // Batch processing endpoint for high-volume scenarios
        [HttpPost("scan-batch")]
        [RequestSizeLimit(524288000)] // 500MB for batch operations
        public async Task<ActionResult<List<ScanResult>>> ScanBatch(List<IFormFile> files)
        {
            if (files == null || !files.Any())
            {
                return BadRequest("No files provided");
            }

            if (files.Count > 50)
            {
                return BadRequest("Maximum 50 files per batch");
            }

            var tasks = files.Select(file => ProcessFileAsync(file));
            var results = await Task.WhenAll(tasks);

            _logger.LogInformation($"Batch processed {files.Count} files, {results.Count(r => r.Success)} successful");

            return Ok(results);
        }

        private async Task<ScanResult> ProcessFileAsync(IFormFile file)
        {
            // Reuse the scanning logic
            var request = new ScanRequest 
            { 
                File = file,
                EnableImageCorrection = true 
            };
            var actionResult = await ScanDocument(request);

            if (actionResult.Result is OkObjectResult okResult)
            {
                return okResult.Value as ScanResult;
            }
            else if (actionResult.Result is BadRequestObjectResult badResult)
            {
                return badResult.Value as ScanResult;
            }

            return new ScanResult 
            { 
                Success = false, 
                ErrorMessage = "Processing failed" 
            };
        }
    }
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using IronBarCode;
using System.Drawing;
using System.ComponentModel.DataAnnotations;

namespace BarcodeScannerAPI.Controllers
{
    [ApiController]
    [Route("api/v1/[controller]")]
    [Authorize] // Require authentication for all endpoints
    public class ScannerController : ControllerBase
    {
        private readonly ILogger<ScannerController> _logger;
        private readonly IConfiguration _configuration;

        public ScannerController(ILogger<ScannerController> logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
        }

        // Enhanced result model with audit fields
        public class ScanResult
        {
            public bool Success { get; set; }
            public List<BarcodeData> Barcodes { get; set; } = new List<BarcodeData>();
            public string RequestId { get; set; } = Guid.NewGuid().ToString();
            public DateTime ProcessedAt { get; set; } = DateTime.UtcNow;
            public long ProcessingTimeMs { get; set; }
            public string ErrorMessage { get; set; }
            public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
        }

        public class BarcodeData
        {
            public string Value { get; set; }
            public string Format { get; set; }
            public double Confidence { get; set; }
            public Rectangle Location { get; set; }
            public int PageNumber { get; set; } // For PDF processing
        }

        // Input validation model
        public class ScanRequest
        {
            [Required]
            public IFormFile File { get; set; }

            [Range(1, 10)]
            public int MaxBarcodes { get; set; } = 5;

            public string[] ExpectedFormats { get; set; }

            public bool EnableImageCorrection { get; set; } = true;
        }

        [HttpPost("scan")]
        [RequestSizeLimit(52428800)] // 50MB limit
        public async Task<ActionResult<ScanResult>> ScanDocument([FromForm] ScanRequest request)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            var result = new ScanResult();

            try
            {
                // Validate file type for security
                var allowedExtensions = new[] { ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".tiff", ".bmp" };
                var fileExtension = Path.GetExtension(request.File.FileName).ToLowerInvariant();

                if (!allowedExtensions.Contains(fileExtension))
                {
                    _logger.LogWarning($"Rejected file type: {fileExtension}");
                    return BadRequest(new ScanResult
                    {
                        Success = false,
                        ErrorMessage = "Unsupported file type. Allowed: PDF, PNG, JPG, GIF, TIFF, BMP"
                    });
                }

                // Process the file
                using var stream = new MemoryStream();
                await request.File.CopyToAsync(stream);
                var fileBytes = stream.ToArray();

                // Log for audit trail
                _logger.LogInformation($"Processing {request.File.FileName} ({fileBytes.Length} bytes) - RequestId: {result.RequestId}");

                // Configure scanner based on requirements
                var options = ConfigureOptions(request);

                // Handle different file types
                BarcodeResults scanResults;
                if (fileExtension == ".pdf")
                {
                    var pdfOptions = new PdfBarcodeReaderOptions
                    {
                        Scale = 3,
                        DPI = 300,
                        MaxThreads = 4
                    };
                    scanResults = BarcodeReader.ReadPdf(fileBytes, pdfOptions);
                }
                else
                {
                    scanResults = BarcodeReader.Read(fileBytes, options);
                }

                // Process results
                if (scanResults.Any())
                {
                    result.Success = true;
                    foreach (var barcode in scanResults.Take(request.MaxBarcodes))
                    {
                        result.Barcodes.Add(new BarcodeData
                        {
                            Value = barcode.Value,
                            Format = barcode.BarcodeType.ToString(),
                            Confidence = barcode.Confidence,
                            Location = barcode.Bounds,
                            PageNumber = barcode.PageNumber
                        });
                    }

                    result.Metadata["TotalFound"] = scanResults.Count();
                    result.Metadata["FileSize"] = fileBytes.Length;
                    result.Metadata["FileName"] = request.File.FileName;

                    _logger.LogInformation($"Successfully scanned {scanResults.Count()} barcodes - RequestId: {result.RequestId}");
                }
                else
                {
                    result.Success = false;
                    result.ErrorMessage = "No barcodes detected in the document";
                    _logger.LogWarning($"No barcodes found - RequestId: {result.RequestId}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Scanning error - RequestId: {result.RequestId}");
                result.Success = false;
                result.ErrorMessage = "An error occurred during processing";

                // Don't expose internal errors to clients
                if (_configuration.GetValue<bool>("DetailedErrors"))
                {
                    result.Metadata["Exception"] = ex.Message;
                }
            }
            finally
            {
                stopwatch.Stop();
                result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds;
            }

            return result;
        }

        private BarcodeReaderOptions ConfigureOptions(ScanRequest request)
        {
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                ExpectMultipleBarcodes = request.MaxBarcodes > 1,
                RemoveFalsePositive = true,
                Multithreaded = true,
                MaxParallelThreads = Environment.ProcessorCount
            };

            // Apply format filtering if specified
            if (request.ExpectedFormats?.Any() == true)
            {
                var formats = BarcodeEncoding.None;
                foreach (var format in request.ExpectedFormats)
                {
                    if (Enum.TryParse<BarcodeEncoding>(format, true, out var encoding))
                    {
                        formats |= encoding;
                    }
                }
                options.ExpectBarcodeTypes = formats;
            }

            // Enable image correction for damaged barcodes
            if (request.EnableImageCorrection)
            {
                options.ImageFilters = new ImageFilterCollection
                {
                    new SharpenFilter(2),
                    new ContrastFilter(1.5f),
                    new BrightnessFilter(1.1f)
                };
                options.AutoRotate = true;
            }

            return options;
        }

        // Batch processing endpoint for high-volume scenarios
        [HttpPost("scan-batch")]
        [RequestSizeLimit(524288000)] // 500MB for batch operations
        public async Task<ActionResult<List<ScanResult>>> ScanBatch(List<IFormFile> files)
        {
            if (files == null || !files.Any())
            {
                return BadRequest("No files provided");
            }

            if (files.Count > 50)
            {
                return BadRequest("Maximum 50 files per batch");
            }

            var tasks = files.Select(file => ProcessFileAsync(file));
            var results = await Task.WhenAll(tasks);

            _logger.LogInformation($"Batch processed {files.Count} files, {results.Count(r => r.Success)} successful");

            return Ok(results);
        }

        private async Task<ScanResult> ProcessFileAsync(IFormFile file)
        {
            // Reuse the scanning logic
            var request = new ScanRequest 
            { 
                File = file,
                EnableImageCorrection = true 
            };
            var actionResult = await ScanDocument(request);

            if (actionResult.Result is OkObjectResult okResult)
            {
                return okResult.Value as ScanResult;
            }
            else if (actionResult.Result is BadRequestObjectResult badResult)
            {
                return badResult.Value as ScanResult;
            }

            return new ScanResult 
            { 
                Success = false, 
                ErrorMessage = "Processing failed" 
            };
        }
    }
}
$vbLabelText   $csharpLabel

Esta implementação profissional inclui vários recursos críticos que as implantações de produção exigem. A autenticação garante que apenas usuários autorizados possam acessar o serviço de escaneamento. Limites de tamanho de solicitação previnem ataques de negação de serviço. O registro completo fornece a trilha de auditoria que as equipes de conformidade precisam.

O modelo de resposta estruturada retorna não apenas os valores dos códigos de barras, mas pontuações de confiança e dados de localização. Esses metadados são inestimáveis para processos de garantia de qualidade. Quando o código de barras de um fornecedor é escaneado com baixa confiança, seu sistema pode sinalizá-lo para revisão manual.

Tratamento Profissional de Erros

Percebe como o controlador nunca expõe os detalhes de exceção interna aos clientes? Isso segue as melhores práticas de segurança ao evitar vazamento de informações. O registro detalhado captura tudo o que é necessário para depuração, mantendo as respostas de erro genéricas.

O campo RequestId permite o rastreamento de ponta a ponta em seus sistemas distribuídos. Quando um trabalhador de armazém relata um problema de escaneamento, sua equipe de suporte pode localizar rapidamente a solicitação exata em seu sistema de registro centralizado. Isso reduz drasticamente o tempo médio para resolução (MTTR) de problemas de produção.

O monitoramento de desempenho por meio de ProcessingTimeMs ajuda a identificar gargalos. Se determinados tipos de códigos de barras consistentemente demoram mais para serem processados, você pode ajustar suas configurações de velocidade de leitura de acordo. O exemplo de velocidades de leitura demonstra como diferentes configurações impactam o desempenho.

Como Você Lida com Diferentes Fontes de Entrada?

Sistemas empresariais raramente se padronizam em um único formato. Sua API de scanner precisa lidar com tudo, desde câmeras de armazém de alta resolução até digitalizações em PDF de baixa qualidade de máquinas de fax de décadas atrás. Veja como construir essa flexibilidade:

// Extended controller with multiple input handlers
[ApiController]
[Route("api/v1/[controller]")]
[Authorize]
public class AdvancedScannerController : ControllerBase
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<AdvancedScannerController> _logger;

    public AdvancedScannerController(
        IHttpClientFactory httpClientFactory, 
        ILogger<AdvancedScannerController> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
    }

    // Handle Base64 input (common in web applications)
    [HttpPost("scan-base64")]
    public ActionResult<ScanResult> ScanBase64([FromBody] Base64Request request)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        try
        {
            // Validate Base64 format
            var base64Data = request.ImageData;
            if (base64Data.Contains(","))
            {
                // Handle data URL format: "data:image/png;base64,..."
                base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1);
            }

            var imageBytes = Convert.FromBase64String(base64Data);

            // Implement size validation
            if (imageBytes.Length > 10 * 1024 * 1024) // 10MB limit
            {
                return BadRequest(new ScanResult
                {
                    Success = false,
                    ErrorMessage = "Image size exceeds 10MB limit"
                });
            }

            // Configure for web-uploaded images (often lower quality)
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Detailed,
                ImageFilters = new ImageFilterCollection
                {
                    new SharpenFilter(3),
                    new ContrastFilter(2),
                    new DeNoise()
                },
                TryInvertColor = true, // Handle inverted barcodes
                AutoRotate = true
            };

            var results = BarcodeReader.Read(imageBytes, options);
            return ProcessResults(results, "base64", request.FileName);
        }
        catch (FormatException)
        {
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Invalid Base64 format"
            });
        }
    }

    // Handle URL input (for cloud storage integration)
    [HttpPost("scan-url")]
    public async Task<ActionResult<ScanResult>> ScanFromUrl([FromBody] UrlScanRequest request)
    {
        if (!Uri.TryCreate(request.Url, UriKind.Absolute, out var uri))
        {
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Invalid URL format"
            });
        }

        // Validate URL domain (security measure)
        var allowedDomains = _configuration.GetSection("AllowedDomains").Get<string[]>() 
            ?? new[] { "blob.core.windows.net", "s3.amazonaws.com" };

        if (!allowedDomains.Any(domain => uri.Host.EndsWith(domain)))
        {
            _logger.LogWarning($"Rejected URL from unauthorized domain: {uri.Host}");
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "URL domain not authorized"
            });
        }

        try
        {
            using var httpClient = _httpClientFactory.CreateClient("BarcodeScanner");
            httpClient.Timeout = TimeSpan.FromSeconds(30);

            // Add headers to avoid being blocked
            httpClient.DefaultRequestHeaders.Add("User-Agent", "BarcodeScannerAPI/2.0");

            var response = await httpClient.GetAsync(uri);
            response.EnsureSuccessStatusCode();

            // Check content type
            var contentType = response.Content.Headers.ContentType?.MediaType;
            if (!IsValidContentType(contentType))
            {
                return BadRequest(new ScanResult
                {
                    Success = false,
                    ErrorMessage = $"Unsupported content type: {contentType}"
                });
            }

            var imageBytes = await response.Content.ReadAsByteArrayAsync();

            // Use async processing for better scalability
            var results = await BarcodeReader.ReadAsync(imageBytes);
            return ProcessResults(results, "url", uri.ToString());
        }
        catch (HttpRequestException ex)
        {
            _logger.LogError(ex, $"Failed to download from URL: {uri}");
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Failed to download image from URL"
            });
        }
        catch (TaskCanceledException)
        {
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Download timeout - file too large or slow connection"
            });
        }
    }

    // Handle multi-page PDFs with page-specific processing
    [HttpPost("scan-pdf-advanced")]
    public async Task<ActionResult<PdfScanResult>> ScanPdfAdvanced([FromForm] PdfScanRequest request)
    {
        using var stream = new MemoryStream();
        await request.File.CopyToAsync(stream);

        var pdfOptions = new PdfBarcodeReaderOptions
        {
            Scale = request.Scale ?? 3,
            DPI = request.DPI ?? 300,
            PageNumbers = request.PageNumbers,
            Password = request.Password,
            MaxThreads = Math.Min(request.MaxThreads ?? 4, Environment.ProcessorCount)
        };

        // For large PDFs, process in chunks
        if (stream.Length > 50 * 1024 * 1024) // 50MB
        {
            _logger.LogInformation($"Large PDF detected ({stream.Length / 1024 / 1024}MB), using chunked processing");
            pdfOptions.MaxThreads = 2; // Reduce memory pressure
        }

        var results = BarcodeReader.ReadPdf(stream.ToArray(), pdfOptions);

        // Group results by page
        var pageResults = results.GroupBy(r => r.PageNumber)
            .OrderBy(g => g.Key)
            .Select(g => new PageBarcodeResult
            {
                PageNumber = g.Key,
                BarcodeCount = g.Count(),
                Barcodes = g.Select(b => new BarcodeData
                {
                    Value = b.Value,
                    Format = b.BarcodeType.ToString(),
                    Confidence = b.Confidence,
                    Location = b.Bounds
                }).ToList()
            }).ToList();

        return Ok(new PdfScanResult
        {
            Success = true,
            TotalPages = pageResults.Count,
            TotalBarcodes = results.Count(),
            PageResults = pageResults,
            RequestId = Guid.NewGuid().ToString()
        });
    }

    // Handle damaged or low-quality barcodes
    [HttpPost("scan-damaged")]
    public async Task<ActionResult<ScanResult>> ScanDamagedBarcode([FromForm] IFormFile file)
    {
        using var stream = new MemoryStream();
        await file.CopyToAsync(stream);

        // Aggressive image correction for damaged barcodes
        var options = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.ExtremeDetail,
            ImageFilters = new ImageFilterCollection
            {
                new SharpenFilter(4),
                new ContrastFilter(3),
                new BrightnessFilter(1.5f),
                new BinaryThresholdFilter(128),
                new DeNoise(3)
            },
            TryInvertColor = true,
            AutoRotate = true,
            UseCode39ExtendedMode = true,
            RemoveFalsePositive = false, // Accept lower confidence
            Confidence = ConfidenceLevel.Low
        };

        var results = BarcodeReader.Read(stream.ToArray(), options);

        // If still no results, try with different threshold
        if (!results.Any())
        {
            options.ImageFilters = new ImageFilterCollection
            {
                new AdaptiveThresholdFilter(9),
                new MedianFilter(3),
                new Dilate(1)
            };

            results = BarcodeReader.Read(stream.ToArray(), options);
        }

        return ProcessResults(results, "damaged", file.FileName);
    }

    private bool IsValidContentType(string contentType)
    {
        var validTypes = new[]
        {
            "image/jpeg", "image/jpg", "image/png", "image/gif",
            "image/tiff", "image/bmp", "application/pdf"
        };
        return validTypes.Contains(contentType?.ToLower());
    }

    private ActionResult<ScanResult> ProcessResults(BarcodeResults results, string source, string identifier)
    {
        var scanResult = new ScanResult
        {
            Metadata = new Dictionary<string, object>
            {
                ["Source"] = source,
                ["Identifier"] = identifier,
                ["ProcessedAt"] = DateTime.UtcNow
            }
        };

        if (results.Any())
        {
            scanResult.Success = true;
            scanResult.Barcodes = results.Select(r => new BarcodeData
            {
                Value = r.Value,
                Format = r.BarcodeType.ToString(),
                Confidence = r.Confidence,
                Location = r.Bounds
            }).ToList();

            // Log low confidence results for quality monitoring
            var lowConfidence = results.Where(r => r.Confidence < 70).ToList();
            if (lowConfidence.Any())
            {
                _logger.LogWarning($"Low confidence barcodes detected: {lowConfidence.Count} of {results.Count()} from {identifier}");
            }
        }
        else
        {
            scanResult.Success = false;
            scanResult.ErrorMessage = "No barcodes detected";
        }

        return Ok(scanResult);
    }
}

// Request models
public class Base64Request
{
    [Required]
    public string ImageData { get; set; }
    public string FileName { get; set; }
}

public class UrlScanRequest
{
    [Required]
    [Url]
    public string Url { get; set; }
}

public class PdfScanRequest
{
    [Required]
    public IFormFile File { get; set; }
    public int? Scale { get; set; }
    public int? DPI { get; set; }
    public int[] PageNumbers { get; set; }
    public string Password { get; set; }
    public int? MaxThreads { get; set; }
}

// Response models
public class PdfScanResult : ScanResult
{
    public int TotalPages { get; set; }
    public int TotalBarcodes { get; set; }
    public List<PageBarcodeResult> PageResults { get; set; }
}

public class PageBarcodeResult
{
    public int PageNumber { get; set; }
    public int BarcodeCount { get; set; }
    public List<BarcodeData> Barcodes { get; set; }
}
// Extended controller with multiple input handlers
[ApiController]
[Route("api/v1/[controller]")]
[Authorize]
public class AdvancedScannerController : ControllerBase
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<AdvancedScannerController> _logger;

    public AdvancedScannerController(
        IHttpClientFactory httpClientFactory, 
        ILogger<AdvancedScannerController> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
    }

    // Handle Base64 input (common in web applications)
    [HttpPost("scan-base64")]
    public ActionResult<ScanResult> ScanBase64([FromBody] Base64Request request)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        try
        {
            // Validate Base64 format
            var base64Data = request.ImageData;
            if (base64Data.Contains(","))
            {
                // Handle data URL format: "data:image/png;base64,..."
                base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1);
            }

            var imageBytes = Convert.FromBase64String(base64Data);

            // Implement size validation
            if (imageBytes.Length > 10 * 1024 * 1024) // 10MB limit
            {
                return BadRequest(new ScanResult
                {
                    Success = false,
                    ErrorMessage = "Image size exceeds 10MB limit"
                });
            }

            // Configure for web-uploaded images (often lower quality)
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Detailed,
                ImageFilters = new ImageFilterCollection
                {
                    new SharpenFilter(3),
                    new ContrastFilter(2),
                    new DeNoise()
                },
                TryInvertColor = true, // Handle inverted barcodes
                AutoRotate = true
            };

            var results = BarcodeReader.Read(imageBytes, options);
            return ProcessResults(results, "base64", request.FileName);
        }
        catch (FormatException)
        {
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Invalid Base64 format"
            });
        }
    }

    // Handle URL input (for cloud storage integration)
    [HttpPost("scan-url")]
    public async Task<ActionResult<ScanResult>> ScanFromUrl([FromBody] UrlScanRequest request)
    {
        if (!Uri.TryCreate(request.Url, UriKind.Absolute, out var uri))
        {
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Invalid URL format"
            });
        }

        // Validate URL domain (security measure)
        var allowedDomains = _configuration.GetSection("AllowedDomains").Get<string[]>() 
            ?? new[] { "blob.core.windows.net", "s3.amazonaws.com" };

        if (!allowedDomains.Any(domain => uri.Host.EndsWith(domain)))
        {
            _logger.LogWarning($"Rejected URL from unauthorized domain: {uri.Host}");
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "URL domain not authorized"
            });
        }

        try
        {
            using var httpClient = _httpClientFactory.CreateClient("BarcodeScanner");
            httpClient.Timeout = TimeSpan.FromSeconds(30);

            // Add headers to avoid being blocked
            httpClient.DefaultRequestHeaders.Add("User-Agent", "BarcodeScannerAPI/2.0");

            var response = await httpClient.GetAsync(uri);
            response.EnsureSuccessStatusCode();

            // Check content type
            var contentType = response.Content.Headers.ContentType?.MediaType;
            if (!IsValidContentType(contentType))
            {
                return BadRequest(new ScanResult
                {
                    Success = false,
                    ErrorMessage = $"Unsupported content type: {contentType}"
                });
            }

            var imageBytes = await response.Content.ReadAsByteArrayAsync();

            // Use async processing for better scalability
            var results = await BarcodeReader.ReadAsync(imageBytes);
            return ProcessResults(results, "url", uri.ToString());
        }
        catch (HttpRequestException ex)
        {
            _logger.LogError(ex, $"Failed to download from URL: {uri}");
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Failed to download image from URL"
            });
        }
        catch (TaskCanceledException)
        {
            return BadRequest(new ScanResult
            {
                Success = false,
                ErrorMessage = "Download timeout - file too large or slow connection"
            });
        }
    }

    // Handle multi-page PDFs with page-specific processing
    [HttpPost("scan-pdf-advanced")]
    public async Task<ActionResult<PdfScanResult>> ScanPdfAdvanced([FromForm] PdfScanRequest request)
    {
        using var stream = new MemoryStream();
        await request.File.CopyToAsync(stream);

        var pdfOptions = new PdfBarcodeReaderOptions
        {
            Scale = request.Scale ?? 3,
            DPI = request.DPI ?? 300,
            PageNumbers = request.PageNumbers,
            Password = request.Password,
            MaxThreads = Math.Min(request.MaxThreads ?? 4, Environment.ProcessorCount)
        };

        // For large PDFs, process in chunks
        if (stream.Length > 50 * 1024 * 1024) // 50MB
        {
            _logger.LogInformation($"Large PDF detected ({stream.Length / 1024 / 1024}MB), using chunked processing");
            pdfOptions.MaxThreads = 2; // Reduce memory pressure
        }

        var results = BarcodeReader.ReadPdf(stream.ToArray(), pdfOptions);

        // Group results by page
        var pageResults = results.GroupBy(r => r.PageNumber)
            .OrderBy(g => g.Key)
            .Select(g => new PageBarcodeResult
            {
                PageNumber = g.Key,
                BarcodeCount = g.Count(),
                Barcodes = g.Select(b => new BarcodeData
                {
                    Value = b.Value,
                    Format = b.BarcodeType.ToString(),
                    Confidence = b.Confidence,
                    Location = b.Bounds
                }).ToList()
            }).ToList();

        return Ok(new PdfScanResult
        {
            Success = true,
            TotalPages = pageResults.Count,
            TotalBarcodes = results.Count(),
            PageResults = pageResults,
            RequestId = Guid.NewGuid().ToString()
        });
    }

    // Handle damaged or low-quality barcodes
    [HttpPost("scan-damaged")]
    public async Task<ActionResult<ScanResult>> ScanDamagedBarcode([FromForm] IFormFile file)
    {
        using var stream = new MemoryStream();
        await file.CopyToAsync(stream);

        // Aggressive image correction for damaged barcodes
        var options = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.ExtremeDetail,
            ImageFilters = new ImageFilterCollection
            {
                new SharpenFilter(4),
                new ContrastFilter(3),
                new BrightnessFilter(1.5f),
                new BinaryThresholdFilter(128),
                new DeNoise(3)
            },
            TryInvertColor = true,
            AutoRotate = true,
            UseCode39ExtendedMode = true,
            RemoveFalsePositive = false, // Accept lower confidence
            Confidence = ConfidenceLevel.Low
        };

        var results = BarcodeReader.Read(stream.ToArray(), options);

        // If still no results, try with different threshold
        if (!results.Any())
        {
            options.ImageFilters = new ImageFilterCollection
            {
                new AdaptiveThresholdFilter(9),
                new MedianFilter(3),
                new Dilate(1)
            };

            results = BarcodeReader.Read(stream.ToArray(), options);
        }

        return ProcessResults(results, "damaged", file.FileName);
    }

    private bool IsValidContentType(string contentType)
    {
        var validTypes = new[]
        {
            "image/jpeg", "image/jpg", "image/png", "image/gif",
            "image/tiff", "image/bmp", "application/pdf"
        };
        return validTypes.Contains(contentType?.ToLower());
    }

    private ActionResult<ScanResult> ProcessResults(BarcodeResults results, string source, string identifier)
    {
        var scanResult = new ScanResult
        {
            Metadata = new Dictionary<string, object>
            {
                ["Source"] = source,
                ["Identifier"] = identifier,
                ["ProcessedAt"] = DateTime.UtcNow
            }
        };

        if (results.Any())
        {
            scanResult.Success = true;
            scanResult.Barcodes = results.Select(r => new BarcodeData
            {
                Value = r.Value,
                Format = r.BarcodeType.ToString(),
                Confidence = r.Confidence,
                Location = r.Bounds
            }).ToList();

            // Log low confidence results for quality monitoring
            var lowConfidence = results.Where(r => r.Confidence < 70).ToList();
            if (lowConfidence.Any())
            {
                _logger.LogWarning($"Low confidence barcodes detected: {lowConfidence.Count} of {results.Count()} from {identifier}");
            }
        }
        else
        {
            scanResult.Success = false;
            scanResult.ErrorMessage = "No barcodes detected";
        }

        return Ok(scanResult);
    }
}

// Request models
public class Base64Request
{
    [Required]
    public string ImageData { get; set; }
    public string FileName { get; set; }
}

public class UrlScanRequest
{
    [Required]
    [Url]
    public string Url { get; set; }
}

public class PdfScanRequest
{
    [Required]
    public IFormFile File { get; set; }
    public int? Scale { get; set; }
    public int? DPI { get; set; }
    public int[] PageNumbers { get; set; }
    public string Password { get; set; }
    public int? MaxThreads { get; set; }
}

// Response models
public class PdfScanResult : ScanResult
{
    public int TotalPages { get; set; }
    public int TotalBarcodes { get; set; }
    public List<PageBarcodeResult> PageResults { get; set; }
}

public class PageBarcodeResult
{
    public int PageNumber { get; set; }
    public int BarcodeCount { get; set; }
    public List<BarcodeData> Barcodes { get; set; }
}
$vbLabelText   $csharpLabel

Esta implementação completa aborda cenários reais de empresas. O ponto final de escaneamento de URL inclui validação de domínio para prevenir ataques SSRF (Server-Side Request Forgery). O manipulador Base64 remove prefixos de URL de dados, comum ao receber imagens de aplicações web.

O ponto final de código de barras danificado demonstra as capacidades de correção de imagem do IronBarcode. Ao aplicar múltiplos filtros e tentar abordagens diferentes, ele pode recuperar dados de imagens severamente degradadas. Isso prova ser inestimável ao lidar com etiquetas de inventário antigas ou documentos de envio danificados pelo clima.

Escolhendo Entre Escaneamento de PDF e Imagem

Os PDFs apresentam desafios e oportunidades únicos na leitura de códigos de barras empresariais. Muitos documentos comerciais, como faturas, manifestos de envio e formulários de conformidade, chegam como PDFs com códigos de barras embutidos. As capacidades de leitura de códigos de barras em PDF no IronBarcode lidam com esses cenários de maneira elegante.

Considere um cenário típico de empresa: seu departamento de contas a pagar recebe milhares de faturas mensalmente, cada uma contendo códigos de barras para processamento automatizado. Alguns fornecedores enviam PDFs de alta qualidade, outros enviam documentos escaneados com qualidade variável.

O ponto final avançado de escaneamento de PDFs lida com ambos os cenários. Para PDFs de alta qualidade, as configurações padrão funcionam perfeitamente. Para documentos digitalizados, aumentar os parâmetros de DPI e escala melhora as taxas de detecção. O processamento específico por página permite extrair códigos de barras de páginas específicas, útil quando você sabe que faturas sempre têm códigos de barras na primeira página.

Os resultados agrupados por página fornecem contexto valioso. Seu sistema de fluxo de trabalho pode direcionar documentos com base em quais páginas contêm códigos de barras, automatizando a classificação de documentos. Essa abordagem estruturada para processamento de documentos de várias páginas transforma processos manuais em fluxos de trabalho automatizados eficientes.

Manipulação Eficiente de Múltiplos Códigos de Barras

Documentos empresariais frequentemente contêm múltiplos códigos de barras com diferentes propósitos. Um rótulo de envio pode ter um código de barras de rastreamento, um código de barras de produto e um código de barras de destino. O manuseio adequado de cenários de múltiplos códigos de barras requer um design de API cuidadoso.

O endpoint de processamento em lote demonstra como lidar eficientemente com cenários de alto volume. Ao processar vários arquivos em paralelo, você pode reduzir drasticamente o tempo total de processamento. O padrão Task.WhenAll garante a utilização ideal dos recursos enquanto mantém a estabilidade do sistema.

Para criar códigos de barras em suas aplicações, o IronBarcode oferece capacidades igualmente eficazes. Quer você precise gerar códigos de barras lineares 1D para sistemas de inventário ou criar códigos de matriz 2D para aplicativos móveis, a mesma abordagem simples de API se aplica.

Como Melhorar o Desempenho e a Precisão?

A otimização de desempenho na leitura de códigos de barras em empresas não se trata apenas de velocidade -- trata-se de encontrar o equilíbrio certo para seu caso de uso específico. Os exemplos a seguir exploram técnicas avançadas de otimização que podem transformar o desempenho da sua leitura:

public class OptimizedScannerService
{
    private readonly ILogger<OptimizedScannerService> _logger;
    private readonly IMemoryCache _cache;

    public OptimizedScannerService(ILogger<OptimizedScannerService> logger, IMemoryCache cache)
    {
        _logger = logger;
        _cache = cache;
    }

    // Performance-optimized scanning with caching
    public async Task<ScanResult> ScanWithOptimizationsAsync(byte[] imageData, string cacheKey = null)
    {
        // Check cache for repeat scans
        if (!string.IsNullOrEmpty(cacheKey))
        {
            if (_cache.TryGetValue(cacheKey, out ScanResult cachedResult))
            {
                _logger.LogInformation($"Cache hit for {cacheKey}");
                cachedResult.Metadata["CacheHit"] = true;
                return cachedResult;
            }
        }

        // Determine optimal settings based on image characteristics
        var settings = await DetermineOptimalSettingsAsync(imageData);

        // Apply region-specific scanning if applicable
        if (settings.UseRegionScanning)
        {
            return await ScanWithRegionsAsync(imageData, settings);
        }

        // Standard optimized scanning
        var results = await BarcodeReader.ReadAsync(imageData, settings.Options);
        var scanResult = BuildScanResult(results);

        // Cache successful results
        if (!string.IsNullOrEmpty(cacheKey) && scanResult.Success)
        {
            _cache.Set(cacheKey, scanResult, TimeSpan.FromMinutes(5));
        }

        return scanResult;
    }

    // Intelligent settings determination
    private async Task<ScanSettings> DetermineOptimalSettingsAsync(byte[] imageData)
    {
        var settings = new ScanSettings();

        // Quick analysis of image properties
        using var ms = new MemoryStream(imageData);
        using var image = Image.FromStream(ms);

        var width = image.Width;
        var height = image.Height;
        var aspectRatio = (double)width / height;

        _logger.LogInformation($"Image analysis: {width}x{height}, ratio: {aspectRatio:F2}");

        // High-resolution images can use faster scanning
        if (width > 2000 && height > 2000)
        {
            settings.Options.Speed = ReadingSpeed.Faster;
            settings.Options.ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128;
        }
        // Low-resolution needs more processing
        else if (width < 800 || height < 800)
        {
            settings.Options.Speed = ReadingSpeed.ExtremeDetail;
            settings.Options.ImageFilters = new ImageFilterCollection
            {
                new SharpenFilter(3),
                new ContrastFilter(2)
            };
        }
        else
        {
            settings.Options.Speed = ReadingSpeed.Balanced;
        }

        // Detect if image might contain multiple barcodes based on aspect ratio
        if (aspectRatio > 2 || aspectRatio < 0.5)
        {
            settings.Options.ExpectMultipleBarcodes = true;
            settings.UseRegionScanning = true;
        }

        // Enable rotation correction for potentially skewed images
        settings.Options.AutoRotate = true;

        return settings;
    }

    // Region-based scanning for large images
    private async Task<ScanResult> ScanWithRegionsAsync(byte[] imageData, ScanSettings settings)
    {
        var allResults = new List<BarcodeResult>();
        using var ms = new MemoryStream(imageData);
        using var image = Image.FromStream(ms);

        // Define scanning regions for common document layouts
        var regions = new[]
        {
            new Rectangle(0, 0, image.Width / 2, image.Height / 2), // Top-left
            new Rectangle(image.Width / 2, 0, image.Width / 2, image.Height / 2), // Top-right
            new Rectangle(0, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-left
            new Rectangle(image.Width / 2, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-right
            new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2) // Center
        };

        var tasks = regions.Select(async region =>
        {
            var regionOptions = new BarcodeReaderOptions
            {
                CropArea = region,
                Speed = ReadingSpeed.Faster,
                ExpectMultipleBarcodes = false
            };

            try
            {
                return await BarcodeReader.ReadAsync(imageData, regionOptions);
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"Region scan failed: {ex.Message}");
                return new BarcodeResult[0];
            }
        });

        var regionResults = await Task.WhenAll(tasks);

        // Combine and deduplicate results
        var uniqueResults = regionResults
            .SelectMany(r => r)
            .GroupBy(r => r.Value)
            .Select(g => g.OrderByDescending(r => r.Confidence).First())
            .ToList();

        return BuildScanResult(uniqueResults);
    }

    // Adaptive quality enhancement
    public async Task<ScanResult> ScanWithAdaptiveEnhancementAsync(byte[] imageData)
    {
        var attempts = new List<Func<Task<BarcodeResults>>>
        {
            // Attempt 1: Fast scan
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Faster,
                RemoveFalsePositive = true
            }),

            // Attempt 2: Standard scan with basic filters
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                ImageFilters = new ImageFilterCollection
                {
                    new ContrastFilter(1.5f),
                    new SharpenFilter(1)
                },
                TryInvertColor = true
            }),

            // Attempt 3: Detailed scan with aggressive filtering
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Detailed,
                ImageFilters = new ImageFilterCollection
                {
                    new AdaptiveThresholdFilter(11),
                    new DeNoise(2),
                    new MedianFilter(3)
                },
                AutoRotate = true,
                Confidence = ConfidenceLevel.Low
            }),

            // Attempt 4: Extreme processing for damaged barcodes
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.ExtremeDetail,
                ImageFilters = new ImageFilterCollection
                {
                    new BinaryThresholdFilter(100),
                    new Erode(1),
                    new Dilate(2),
                    new SharpenFilter(4)
                },
                RemoveFalsePositive = false,
                UseCode39ExtendedMode = true,
                TryInvertColor = true
            })
        };

        foreach (var (attempt, index) in attempts.Select((a, i) => (a, i)))
        {
            var stopwatch = Stopwatch.StartNew();
            var results = await attempt();
            stopwatch.Stop();

            _logger.LogInformation($"Attempt {index + 1} took {stopwatch.ElapsedMilliseconds}ms, found {results.Count()} barcodes");

            if (results.Any())
            {
                var scanResult = BuildScanResult(results);
                scanResult.Metadata["AttemptNumber"] = index + 1;
                scanResult.Metadata["ProcessingStrategy"] = GetStrategyName(index);
                return scanResult;
            }
        }

        return new ScanResult
        {
            Success = false,
            ErrorMessage = "No barcodes found after all enhancement attempts"
        };
    }

    // Machine learning confidence optimization
    public class MLOptimizedScanner
    {
        private readonly Dictionary<string, double> _formatConfidenceThresholds = new()
        {
            { "QRCode", 85.0 },
            { "Code128", 90.0 },
            { "Code39", 88.0 },
            { "DataMatrix", 87.0 },
            { "EAN13", 92.0 },
            { "PDF417", 86.0 }
        };

        public async Task<ScanResult> ScanWithMLConfidenceAsync(byte[] imageData, string expectedFormat = null)
        {
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                Confidence = ConfidenceLevel.Optional
            };

            // If we know the expected format, improve for it
            if (!string.IsNullOrEmpty(expectedFormat) && 
                Enum.TryParse<BarcodeEncoding>(expectedFormat, out var encoding))
            {
                options.ExpectBarcodeTypes = encoding;
            }

            var results = await BarcodeReader.ReadAsync(imageData, options);

            // Apply ML confidence filtering
            var confidenceThreshold = expectedFormat != null && 
                _formatConfidenceThresholds.ContainsKey(expectedFormat)
                ? _formatConfidenceThresholds[expectedFormat]
                : 80.0;

            var highConfidenceResults = results
                .Where(r => r.Confidence >= confidenceThreshold)
                .ToList();

            if (highConfidenceResults.Any())
            {
                return BuildScanResult(highConfidenceResults);
            }

            // If no high-confidence results, include lower confidence with warnings
            var lowConfidenceResults = results
                .Where(r => r.Confidence < confidenceThreshold)
                .ToList();

            if (lowConfidenceResults.Any())
            {
                var result = BuildScanResult(lowConfidenceResults);
                result.Metadata["Warning"] = "Low confidence results - manual verification recommended";
                result.Metadata["MinConfidence"] = lowConfidenceResults.Min(r => r.Confidence);
                return result;
            }

            return new ScanResult
            {
                Success = false,
                ErrorMessage = "No barcodes met confidence threshold"
            };
        }
    }

    private ScanResult BuildScanResult(IEnumerable<BarcodeResult> results)
    {
        var resultList = results.ToList();
        return new ScanResult
        {
            Success = true,
            Barcodes = resultList.Select(r => new BarcodeData
            {
                Value = r.Value,
                Format = r.BarcodeType.ToString(),
                Confidence = r.Confidence,
                Location = r.Bounds
            }).ToList(),
            Metadata = new Dictionary<string, object>
            {
                ["TotalFound"] = resultList.Count,
                ["AverageConfidence"] = resultList.Average(r => r.Confidence),
                ["Formats"] = resultList.Select(r => r.BarcodeType.ToString()).Distinct().ToArray()
            }
        };
    }

    private string GetStrategyName(int attemptIndex)
    {
        return attemptIndex switch
        {
            0 => "FastScan",
            1 => "StandardEnhanced",
            2 => "DetailedFiltering",
            3 => "ExtremeDamageRecovery",
            _ => "Unknown"
        };
    }
}

// Supporting classes
public class ScanSettings
{
    public BarcodeReaderOptions Options { get; set; } = new BarcodeReaderOptions();
    public bool UseRegionScanning { get; set; }
    public List<Rectangle> CustomRegions { get; set; }
}

// Benchmark service for performance testing
public class BenchmarkService
{
    private readonly ILogger<BenchmarkService> _logger;

    public async Task<BenchmarkResult> BenchmarkSettingsAsync(byte[] testImage, int iterations = 10)
    {
        var results = new Dictionary<string, BenchmarkData>();

        var testConfigurations = new Dictionary<string, BarcodeReaderOptions>
        {
            ["Fastest"] = new() { Speed = ReadingSpeed.Faster },
            ["Balanced"] = new() { Speed = ReadingSpeed.Balanced },
            ["Detailed"] = new() { Speed = ReadingSpeed.Detailed },
            ["Parallel"] = new() { Speed = ReadingSpeed.Balanced, Multithreaded = true, MaxParallelThreads = 4 },
            ["Filtered"] = new() 
            { 
                Speed = ReadingSpeed.Balanced, 
                ImageFilters = new ImageFilterCollection { new SharpenFilter(2), new ContrastFilter(1.5f) } 
            }
        };

        foreach (var config in testConfigurations)
        {
            var times = new List<long>();
            var successCount = 0;

            for (int i = 0; i < iterations; i++)
            {
                var sw = Stopwatch.StartNew();
                var scanResults = await BarcodeReader.ReadAsync(testImage, config.Value);
                sw.Stop();

                times.Add(sw.ElapsedMilliseconds);
                if (scanResults.Any()) successCount++;

                // Small delay between tests
                await Task.Delay(100);
            }

            results[config.Key] = new BenchmarkData
            {
                AverageMs = times.Average(),
                MinMs = times.Min(),
                MaxMs = times.Max(),
                SuccessRate = (double)successCount / iterations * 100
            };
        }

        return new BenchmarkResult { Results = results };
    }
}

public class BenchmarkData
{
    public double AverageMs { get; set; }
    public long MinMs { get; set; }
    public long MaxMs { get; set; }
    public double SuccessRate { get; set; }
}

public class BenchmarkResult
{
    public Dictionary<string, BenchmarkData> Results { get; set; }
}
public class OptimizedScannerService
{
    private readonly ILogger<OptimizedScannerService> _logger;
    private readonly IMemoryCache _cache;

    public OptimizedScannerService(ILogger<OptimizedScannerService> logger, IMemoryCache cache)
    {
        _logger = logger;
        _cache = cache;
    }

    // Performance-optimized scanning with caching
    public async Task<ScanResult> ScanWithOptimizationsAsync(byte[] imageData, string cacheKey = null)
    {
        // Check cache for repeat scans
        if (!string.IsNullOrEmpty(cacheKey))
        {
            if (_cache.TryGetValue(cacheKey, out ScanResult cachedResult))
            {
                _logger.LogInformation($"Cache hit for {cacheKey}");
                cachedResult.Metadata["CacheHit"] = true;
                return cachedResult;
            }
        }

        // Determine optimal settings based on image characteristics
        var settings = await DetermineOptimalSettingsAsync(imageData);

        // Apply region-specific scanning if applicable
        if (settings.UseRegionScanning)
        {
            return await ScanWithRegionsAsync(imageData, settings);
        }

        // Standard optimized scanning
        var results = await BarcodeReader.ReadAsync(imageData, settings.Options);
        var scanResult = BuildScanResult(results);

        // Cache successful results
        if (!string.IsNullOrEmpty(cacheKey) && scanResult.Success)
        {
            _cache.Set(cacheKey, scanResult, TimeSpan.FromMinutes(5));
        }

        return scanResult;
    }

    // Intelligent settings determination
    private async Task<ScanSettings> DetermineOptimalSettingsAsync(byte[] imageData)
    {
        var settings = new ScanSettings();

        // Quick analysis of image properties
        using var ms = new MemoryStream(imageData);
        using var image = Image.FromStream(ms);

        var width = image.Width;
        var height = image.Height;
        var aspectRatio = (double)width / height;

        _logger.LogInformation($"Image analysis: {width}x{height}, ratio: {aspectRatio:F2}");

        // High-resolution images can use faster scanning
        if (width > 2000 && height > 2000)
        {
            settings.Options.Speed = ReadingSpeed.Faster;
            settings.Options.ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128;
        }
        // Low-resolution needs more processing
        else if (width < 800 || height < 800)
        {
            settings.Options.Speed = ReadingSpeed.ExtremeDetail;
            settings.Options.ImageFilters = new ImageFilterCollection
            {
                new SharpenFilter(3),
                new ContrastFilter(2)
            };
        }
        else
        {
            settings.Options.Speed = ReadingSpeed.Balanced;
        }

        // Detect if image might contain multiple barcodes based on aspect ratio
        if (aspectRatio > 2 || aspectRatio < 0.5)
        {
            settings.Options.ExpectMultipleBarcodes = true;
            settings.UseRegionScanning = true;
        }

        // Enable rotation correction for potentially skewed images
        settings.Options.AutoRotate = true;

        return settings;
    }

    // Region-based scanning for large images
    private async Task<ScanResult> ScanWithRegionsAsync(byte[] imageData, ScanSettings settings)
    {
        var allResults = new List<BarcodeResult>();
        using var ms = new MemoryStream(imageData);
        using var image = Image.FromStream(ms);

        // Define scanning regions for common document layouts
        var regions = new[]
        {
            new Rectangle(0, 0, image.Width / 2, image.Height / 2), // Top-left
            new Rectangle(image.Width / 2, 0, image.Width / 2, image.Height / 2), // Top-right
            new Rectangle(0, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-left
            new Rectangle(image.Width / 2, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-right
            new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2) // Center
        };

        var tasks = regions.Select(async region =>
        {
            var regionOptions = new BarcodeReaderOptions
            {
                CropArea = region,
                Speed = ReadingSpeed.Faster,
                ExpectMultipleBarcodes = false
            };

            try
            {
                return await BarcodeReader.ReadAsync(imageData, regionOptions);
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"Region scan failed: {ex.Message}");
                return new BarcodeResult[0];
            }
        });

        var regionResults = await Task.WhenAll(tasks);

        // Combine and deduplicate results
        var uniqueResults = regionResults
            .SelectMany(r => r)
            .GroupBy(r => r.Value)
            .Select(g => g.OrderByDescending(r => r.Confidence).First())
            .ToList();

        return BuildScanResult(uniqueResults);
    }

    // Adaptive quality enhancement
    public async Task<ScanResult> ScanWithAdaptiveEnhancementAsync(byte[] imageData)
    {
        var attempts = new List<Func<Task<BarcodeResults>>>
        {
            // Attempt 1: Fast scan
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Faster,
                RemoveFalsePositive = true
            }),

            // Attempt 2: Standard scan with basic filters
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                ImageFilters = new ImageFilterCollection
                {
                    new ContrastFilter(1.5f),
                    new SharpenFilter(1)
                },
                TryInvertColor = true
            }),

            // Attempt 3: Detailed scan with aggressive filtering
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Detailed,
                ImageFilters = new ImageFilterCollection
                {
                    new AdaptiveThresholdFilter(11),
                    new DeNoise(2),
                    new MedianFilter(3)
                },
                AutoRotate = true,
                Confidence = ConfidenceLevel.Low
            }),

            // Attempt 4: Extreme processing for damaged barcodes
            async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.ExtremeDetail,
                ImageFilters = new ImageFilterCollection
                {
                    new BinaryThresholdFilter(100),
                    new Erode(1),
                    new Dilate(2),
                    new SharpenFilter(4)
                },
                RemoveFalsePositive = false,
                UseCode39ExtendedMode = true,
                TryInvertColor = true
            })
        };

        foreach (var (attempt, index) in attempts.Select((a, i) => (a, i)))
        {
            var stopwatch = Stopwatch.StartNew();
            var results = await attempt();
            stopwatch.Stop();

            _logger.LogInformation($"Attempt {index + 1} took {stopwatch.ElapsedMilliseconds}ms, found {results.Count()} barcodes");

            if (results.Any())
            {
                var scanResult = BuildScanResult(results);
                scanResult.Metadata["AttemptNumber"] = index + 1;
                scanResult.Metadata["ProcessingStrategy"] = GetStrategyName(index);
                return scanResult;
            }
        }

        return new ScanResult
        {
            Success = false,
            ErrorMessage = "No barcodes found after all enhancement attempts"
        };
    }

    // Machine learning confidence optimization
    public class MLOptimizedScanner
    {
        private readonly Dictionary<string, double> _formatConfidenceThresholds = new()
        {
            { "QRCode", 85.0 },
            { "Code128", 90.0 },
            { "Code39", 88.0 },
            { "DataMatrix", 87.0 },
            { "EAN13", 92.0 },
            { "PDF417", 86.0 }
        };

        public async Task<ScanResult> ScanWithMLConfidenceAsync(byte[] imageData, string expectedFormat = null)
        {
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                Confidence = ConfidenceLevel.Optional
            };

            // If we know the expected format, improve for it
            if (!string.IsNullOrEmpty(expectedFormat) && 
                Enum.TryParse<BarcodeEncoding>(expectedFormat, out var encoding))
            {
                options.ExpectBarcodeTypes = encoding;
            }

            var results = await BarcodeReader.ReadAsync(imageData, options);

            // Apply ML confidence filtering
            var confidenceThreshold = expectedFormat != null && 
                _formatConfidenceThresholds.ContainsKey(expectedFormat)
                ? _formatConfidenceThresholds[expectedFormat]
                : 80.0;

            var highConfidenceResults = results
                .Where(r => r.Confidence >= confidenceThreshold)
                .ToList();

            if (highConfidenceResults.Any())
            {
                return BuildScanResult(highConfidenceResults);
            }

            // If no high-confidence results, include lower confidence with warnings
            var lowConfidenceResults = results
                .Where(r => r.Confidence < confidenceThreshold)
                .ToList();

            if (lowConfidenceResults.Any())
            {
                var result = BuildScanResult(lowConfidenceResults);
                result.Metadata["Warning"] = "Low confidence results - manual verification recommended";
                result.Metadata["MinConfidence"] = lowConfidenceResults.Min(r => r.Confidence);
                return result;
            }

            return new ScanResult
            {
                Success = false,
                ErrorMessage = "No barcodes met confidence threshold"
            };
        }
    }

    private ScanResult BuildScanResult(IEnumerable<BarcodeResult> results)
    {
        var resultList = results.ToList();
        return new ScanResult
        {
            Success = true,
            Barcodes = resultList.Select(r => new BarcodeData
            {
                Value = r.Value,
                Format = r.BarcodeType.ToString(),
                Confidence = r.Confidence,
                Location = r.Bounds
            }).ToList(),
            Metadata = new Dictionary<string, object>
            {
                ["TotalFound"] = resultList.Count,
                ["AverageConfidence"] = resultList.Average(r => r.Confidence),
                ["Formats"] = resultList.Select(r => r.BarcodeType.ToString()).Distinct().ToArray()
            }
        };
    }

    private string GetStrategyName(int attemptIndex)
    {
        return attemptIndex switch
        {
            0 => "FastScan",
            1 => "StandardEnhanced",
            2 => "DetailedFiltering",
            3 => "ExtremeDamageRecovery",
            _ => "Unknown"
        };
    }
}

// Supporting classes
public class ScanSettings
{
    public BarcodeReaderOptions Options { get; set; } = new BarcodeReaderOptions();
    public bool UseRegionScanning { get; set; }
    public List<Rectangle> CustomRegions { get; set; }
}

// Benchmark service for performance testing
public class BenchmarkService
{
    private readonly ILogger<BenchmarkService> _logger;

    public async Task<BenchmarkResult> BenchmarkSettingsAsync(byte[] testImage, int iterations = 10)
    {
        var results = new Dictionary<string, BenchmarkData>();

        var testConfigurations = new Dictionary<string, BarcodeReaderOptions>
        {
            ["Fastest"] = new() { Speed = ReadingSpeed.Faster },
            ["Balanced"] = new() { Speed = ReadingSpeed.Balanced },
            ["Detailed"] = new() { Speed = ReadingSpeed.Detailed },
            ["Parallel"] = new() { Speed = ReadingSpeed.Balanced, Multithreaded = true, MaxParallelThreads = 4 },
            ["Filtered"] = new() 
            { 
                Speed = ReadingSpeed.Balanced, 
                ImageFilters = new ImageFilterCollection { new SharpenFilter(2), new ContrastFilter(1.5f) } 
            }
        };

        foreach (var config in testConfigurations)
        {
            var times = new List<long>();
            var successCount = 0;

            for (int i = 0; i < iterations; i++)
            {
                var sw = Stopwatch.StartNew();
                var scanResults = await BarcodeReader.ReadAsync(testImage, config.Value);
                sw.Stop();

                times.Add(sw.ElapsedMilliseconds);
                if (scanResults.Any()) successCount++;

                // Small delay between tests
                await Task.Delay(100);
            }

            results[config.Key] = new BenchmarkData
            {
                AverageMs = times.Average(),
                MinMs = times.Min(),
                MaxMs = times.Max(),
                SuccessRate = (double)successCount / iterations * 100
            };
        }

        return new BenchmarkResult { Results = results };
    }
}

public class BenchmarkData
{
    public double AverageMs { get; set; }
    public long MinMs { get; set; }
    public long MaxMs { get; set; }
    public double SuccessRate { get; set; }
}

public class BenchmarkResult
{
    public Dictionary<string, BenchmarkData> Results { get; set; }
}
$vbLabelText   $csharpLabel

Esta abordagem avançada de otimização demonstra várias técnicas profissionais. A determinação inteligente de configurações analisa as propriedades da imagem para selecionar automaticamente os parâmetros de processamento mais adequados. Imagens de alta resolução de câmeras modernas podem usar processamento mais rápido, enquanto digitalizações de baixa qualidade recebem filtragem aprimorada.

A leitura baseada em regiões é particularmente eficaz para documentos de grande formato. Dividindo a imagem em regiões e processando-as em paralelo, é possível alcançar melhorias significativas de desempenho. Essa técnica funciona especialmente bem para formulários padronizados onde a localização dos códigos de barras é previsível.

Escolhendo a Configuração ReadingSpeed Correta

A abordagem adaptativa de aprimoramento tenta técnicas de processamento progressivamente mais agressivas até ser bem sucedida. Isso garante o processamento mais rápido possível para códigos de barras de boa qualidade, enquanto ainda lida com aqueles danificados com sucesso. O recurso de limiar de confiança usa aprendizado de máquina para validar resultados, reduzindo falsos positivos em ambientes de produção.

Para cenários específicos de otimização, a tabela abaixo mapeia casos de uso comuns para configurações recomendadas:

Configurações de Velocidade de Leitura por Caso de Uso
Caso de uso Velocidade Recomendada Opções Adicionais Compensações Esperadas
Processamento em lote de alto volume `Mais rápido` Filtro por tipo de código de barras esperado Maior produtividade; pode perder códigos de barras degradados
Documentos de qualidade mista `Equilibrado` Fallback de aprimoramento adaptativo Bom equilíbrio de velocidade e precisão
Códigos de barras danificados ou envelhecidos `DetalheExtremo` Pipeline de filtro de imagem completo Maior precisão; rendimento mais lento
Endpoints de API em tempo real `Equilibrado` Cache + leitura por região Tempos de resposta consistentes abaixo de 200ms
Extração de faturas em PDF `Equilibrado` DPI 300, Escala 3 Melhor para PDFs com camada de texto

O serviço de benchmark ajuda você a tomar decisões baseadas em dados sobre configuração. Execute benchmarks com suas amostras reais de código de barras para encontrar o equilíbrio ideal entre velocidade e precisão para seu caso de uso específico. A orientação do setor das melhores práticas de desempenho da Microsoft para ASP.NET Core também se aplica diretamente ao ajustar seus endpoints de API de scanner.

Impacto dos Filtros de Imagem

Filtros de imagem podem melhorar drasticamente as taxas de reconhecimento para códigos de barras desafiadores. A documentação sobre correção de imagem explica o propósito de cada filtro. No entanto, os filtros também aumentam o tempo de processamento, então use-os com discernimento.

Para implantações em nível empresarial, considere implementar uma abordagem em camadas:

  1. Verificação rápida sem filtros na tentativa inicial
  2. Aplique filtros básicos se a primeira tentativa falhar
  3. Use filtragem agressiva apenas quando necessário
  4. Armazene em cache os resultados para evitar reprocessamento

Esta estratégia mantém tempos de resposta médios rápidos, enquanto ainda lida com casos difíceis com sucesso. O recurso de correção de orientação é particularmente valioso para imagens capturadas por dispositivos móveis, onde os usuários podem segurar os dispositivos em vários ângulos.

Como Você Gera Imagens de Código QR em C#?

Embora a varredura seja crucial, muitas aplicações empresariais também precisam gerar códigos de barras. IronBarcode torna a criação tão simples quanto a leitura. Veja como gerar códigos QR para vários cenários empresariais:

public class BarcodeGenerationService
{
    private readonly ILogger<BarcodeGenerationService> _logger;

    // Generate QR codes for asset tracking
    public byte[] GenerateAssetQRCode(AssetInfo asset)
    {
        // Create JSON payload with asset information
        var assetData = JsonSerializer.Serialize(new
        {
            Id = asset.AssetId,
            Type = asset.AssetType,
            Location = asset.CurrentLocation,
            LastMaintenance = asset.LastMaintenanceDate,
            Url = "___PROTECTED_URL_45___"
        });

        // Generate QR code with high error correction for durability
        var qrCode = QRCodeWriter.CreateQrCode(assetData, 500, QRCodeWriter.QrErrorCorrectionLevel.High);

        // Add company branding
        qrCode.AddAnnotationTextAboveBarcode($"ASSET: {asset.AssetId}");
        qrCode.AddAnnotationTextBelowBarcode(asset.AssetType);
        qrCode.SetMargins(10);

        // Style for printing on asset labels
        qrCode.ChangeBarCodeColor(Color.Black);
        qrCode.ChangeBackgroundColor(Color.White);

        return qrCode.ToStream().ToArray();
    }

    // Generate visitor badges with QR codes
    public GeneratedBarcode CreateVisitorBadgeQR(VisitorInfo visitor)
    {
        // Encode visitor information with expiration
        var visitorData = new
        {
            Name = visitor.Name,
            Company = visitor.Company,
            Host = visitor.HostEmployee,
            ValidFrom = visitor.CheckInTime,
            ValidUntil = visitor.CheckInTime.AddHours(8),
            AccessLevel = visitor.AccessLevel,
            BadgeId = Guid.NewGuid().ToString()
        };

        var qrCode = QRCodeWriter.CreateQrCode(
            JsonSerializer.Serialize(visitorData), 
            400, 
            QRCodeWriter.QrErrorCorrectionLevel.Medium
        );

        // Add company logo for professional appearance
        if (File.Exists("company-logo.png"))
        {
            qrCode.AddLogo("company-logo.png");
        }

        // Style for badge printing
        qrCode.SetMargins(15);
        qrCode.ChangeBarCodeColor(Color.FromArgb(0, 48, 135)); // Company blue

        // Add visible text for security personnel
        qrCode.AddAnnotationTextAboveBarcode($"VISITOR: {visitor.Name}");
        qrCode.AddAnnotationTextBelowBarcode($"Expires: {visitor.CheckInTime.AddHours(8):HH:mm}");

        _logger.LogInformation($"Generated visitor badge for {visitor.Name}, BadgeId: {visitorData.BadgeId}");

        return qrCode;
    }

    // Generate shipping labels with multiple barcodes
    public byte[] GenerateShippingLabel(ShippingInfo shipping)
    {
        // Create a PDF with multiple barcodes
        var pdf = new IronPdf.ChromePdfRenderer();

        // Generate tracking barcode (Code 128 for USPS/UPS compatibility)
        var trackingBarcode = BarcodeWriter.CreateBarcode(
            shipping.TrackingNumber, 
            BarcodeEncoding.Code128
        );
        trackingBarcode.ResizeTo(300, 75);
        trackingBarcode.SetMargins(5);

        // Generate postal code barcode
        var postalBarcode = BarcodeWriter.CreateBarcode(
            shipping.PostalCode,
            BarcodeEncoding.Code128
        );
        postalBarcode.ResizeTo(200, 50);

        // Generate QR code with complete shipping data
        var shippingData = JsonSerializer.Serialize(shipping);
        var qrCode = QRCodeWriter.CreateQrCode(shippingData, 200);

        // Combine into shipping label HTML
        var labelHtml = $@
        <html>
        <body style='font-family: Arial, sans-serif;'>
            <div style='border: 2px solid black; padding: 20px; width: 4in; height: 6in;'>
                <h2>SHIPPING LABEL</h2>
                <hr/>
                <p><strong>From:</strong><br/>{shipping.SenderAddress}</p>
                <p><strong>To:</strong><br/>{shipping.RecipientAddress}</p>
                <hr/>
                <div style='text-align: center;'>
                    <img src='{trackingBarcode.ToDataUrl()}' alt='Tracking barcode'/>
                    <p>Tracking: {shipping.TrackingNumber}</p>
                </div>
                <div style='margin-top: 20px;'>
                    <img src='{postalBarcode.ToDataUrl()}' alt='Postal barcode' style='float: left;'/>
                    <img src='{qrCode.ToDataUrl()}' alt='Shipping QR code' style='float: right; width: 100px;'/>
                </div>
                <div style='clear: both; margin-top: 20px; font-size: 10px;'>
                    <p>Service: {shipping.ServiceType} | Weight: {shipping.Weight}lbs</p>
                </div>
            </div>
        </body>
        </html>";

        return pdf.RenderHtmlAsPdf(labelHtml).BinaryData;
    }

    // Generate secure document QR codes with encryption
    public class SecureDocumentQR
    {
        private readonly byte[] _encryptionKey;

        public SecureDocumentQR(byte[] encryptionKey)
        {
            _encryptionKey = encryptionKey;
        }

        public GeneratedBarcode GenerateSecureDocumentQR(DocumentInfo document)
        {
            // Create document reference with security features
            var documentRef = new
            {
                DocumentId = document.Id,
                Type = document.DocumentType,
                CreatedDate = document.CreatedDate,
                Hash = ComputeDocumentHash(document),
                AccessUrl = "___PROTECTED_URL_46___",
                ValidUntil = DateTime.UtcNow.AddDays(30)
            };

            // Encrypt sensitive data
            var jsonData = JsonSerializer.Serialize(documentRef);
            var encryptedData = EncryptData(jsonData);

            // Generate QR with encrypted payload
            var qrCode = QRCodeWriter.CreateQrCode(
                Convert.ToBase64String(encryptedData),
                500,
                QRCodeWriter.QrErrorCorrectionLevel.High
            );

            // Add visual security indicators
            qrCode.ChangeBarCodeColor(Color.DarkGreen);
            qrCode.AddAnnotationTextAboveBarcode("SECURE DOCUMENT");
            qrCode.AddAnnotationTextBelowBarcode($"Expires: {documentRef.ValidUntil:yyyy-MM-dd}");

            return qrCode;
        }

        private string ComputeDocumentHash(DocumentInfo document)
        {
            using var sha256 = SHA256.Create();
            var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(document.Content ?? document.Id));
            return BitConverter.ToString(hash).Replace("-", "");
        }

        private byte[] EncryptData(string data)
        {
            // Simplified encryption - use proper encryption in production
            using var aes = Aes.Create();
            aes.Key = _encryptionKey;
            aes.GenerateIV();

            using var encryptor = aes.CreateEncryptor();
            var dataBytes = Encoding.UTF8.GetBytes(data);
            var encrypted = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length);

            // Prepend IV for decryption
            return aes.IV.Concat(encrypted).ToArray();
        }
    }

    // Batch generation for high-volume scenarios
    public async Task<List<GeneratedBarcode>> GenerateBatchQRCodesAsync(List<string> data, QRCodeOptions options)
    {
        var tasks = data.Select(item => Task.Run(() =>
        {
            var qr = QRCodeWriter.CreateQrCode(
                item, 
                options.Size, 
                options.ErrorCorrection
            );

            if (options.IncludeMargins)
                qr.SetMargins(options.MarginSize);

            if (options.CustomColor.HasValue)
                qr.ChangeBarCodeColor(options.CustomColor.Value);

            return qr;
        }));

        return (await Task.WhenAll(tasks)).ToList();
    }
}

// Supporting models
public class AssetInfo
{
    public string AssetId { get; set; }
    public string AssetType { get; set; }
    public string CurrentLocation { get; set; }
    public DateTime LastMaintenanceDate { get; set; }
}

public class VisitorInfo
{
    public string Name { get; set; }
    public string Company { get; set; }
    public string HostEmployee { get; set; }
    public DateTime CheckInTime { get; set; }
    public string AccessLevel { get; set; }
}

public class ShippingInfo
{
    public string TrackingNumber { get; set; }
    public string SenderAddress { get; set; }
    public string RecipientAddress { get; set; }
    public string PostalCode { get; set; }
    public string ServiceType { get; set; }
    public decimal Weight { get; set; }
}

public class DocumentInfo
{
    public string Id { get; set; }
    public string DocumentType { get; set; }
    public DateTime CreatedDate { get; set; }
    public string Content { get; set; }
}

public class QRCodeOptions
{
    public int Size { get; set; } = 400;
    public QRCodeWriter.QrErrorCorrectionLevel ErrorCorrection { get; set; } = QRCodeWriter.QrErrorCorrectionLevel.Medium;
    public bool IncludeMargins { get; set; } = true;
    public int MarginSize { get; set; } = 10;
    public Color? CustomColor { get; set; }
}
public class BarcodeGenerationService
{
    private readonly ILogger<BarcodeGenerationService> _logger;

    // Generate QR codes for asset tracking
    public byte[] GenerateAssetQRCode(AssetInfo asset)
    {
        // Create JSON payload with asset information
        var assetData = JsonSerializer.Serialize(new
        {
            Id = asset.AssetId,
            Type = asset.AssetType,
            Location = asset.CurrentLocation,
            LastMaintenance = asset.LastMaintenanceDate,
            Url = "___PROTECTED_URL_45___"
        });

        // Generate QR code with high error correction for durability
        var qrCode = QRCodeWriter.CreateQrCode(assetData, 500, QRCodeWriter.QrErrorCorrectionLevel.High);

        // Add company branding
        qrCode.AddAnnotationTextAboveBarcode($"ASSET: {asset.AssetId}");
        qrCode.AddAnnotationTextBelowBarcode(asset.AssetType);
        qrCode.SetMargins(10);

        // Style for printing on asset labels
        qrCode.ChangeBarCodeColor(Color.Black);
        qrCode.ChangeBackgroundColor(Color.White);

        return qrCode.ToStream().ToArray();
    }

    // Generate visitor badges with QR codes
    public GeneratedBarcode CreateVisitorBadgeQR(VisitorInfo visitor)
    {
        // Encode visitor information with expiration
        var visitorData = new
        {
            Name = visitor.Name,
            Company = visitor.Company,
            Host = visitor.HostEmployee,
            ValidFrom = visitor.CheckInTime,
            ValidUntil = visitor.CheckInTime.AddHours(8),
            AccessLevel = visitor.AccessLevel,
            BadgeId = Guid.NewGuid().ToString()
        };

        var qrCode = QRCodeWriter.CreateQrCode(
            JsonSerializer.Serialize(visitorData), 
            400, 
            QRCodeWriter.QrErrorCorrectionLevel.Medium
        );

        // Add company logo for professional appearance
        if (File.Exists("company-logo.png"))
        {
            qrCode.AddLogo("company-logo.png");
        }

        // Style for badge printing
        qrCode.SetMargins(15);
        qrCode.ChangeBarCodeColor(Color.FromArgb(0, 48, 135)); // Company blue

        // Add visible text for security personnel
        qrCode.AddAnnotationTextAboveBarcode($"VISITOR: {visitor.Name}");
        qrCode.AddAnnotationTextBelowBarcode($"Expires: {visitor.CheckInTime.AddHours(8):HH:mm}");

        _logger.LogInformation($"Generated visitor badge for {visitor.Name}, BadgeId: {visitorData.BadgeId}");

        return qrCode;
    }

    // Generate shipping labels with multiple barcodes
    public byte[] GenerateShippingLabel(ShippingInfo shipping)
    {
        // Create a PDF with multiple barcodes
        var pdf = new IronPdf.ChromePdfRenderer();

        // Generate tracking barcode (Code 128 for USPS/UPS compatibility)
        var trackingBarcode = BarcodeWriter.CreateBarcode(
            shipping.TrackingNumber, 
            BarcodeEncoding.Code128
        );
        trackingBarcode.ResizeTo(300, 75);
        trackingBarcode.SetMargins(5);

        // Generate postal code barcode
        var postalBarcode = BarcodeWriter.CreateBarcode(
            shipping.PostalCode,
            BarcodeEncoding.Code128
        );
        postalBarcode.ResizeTo(200, 50);

        // Generate QR code with complete shipping data
        var shippingData = JsonSerializer.Serialize(shipping);
        var qrCode = QRCodeWriter.CreateQrCode(shippingData, 200);

        // Combine into shipping label HTML
        var labelHtml = $@
        <html>
        <body style='font-family: Arial, sans-serif;'>
            <div style='border: 2px solid black; padding: 20px; width: 4in; height: 6in;'>
                <h2>SHIPPING LABEL</h2>
                <hr/>
                <p><strong>From:</strong><br/>{shipping.SenderAddress}</p>
                <p><strong>To:</strong><br/>{shipping.RecipientAddress}</p>
                <hr/>
                <div style='text-align: center;'>
                    <img src='{trackingBarcode.ToDataUrl()}' alt='Tracking barcode'/>
                    <p>Tracking: {shipping.TrackingNumber}</p>
                </div>
                <div style='margin-top: 20px;'>
                    <img src='{postalBarcode.ToDataUrl()}' alt='Postal barcode' style='float: left;'/>
                    <img src='{qrCode.ToDataUrl()}' alt='Shipping QR code' style='float: right; width: 100px;'/>
                </div>
                <div style='clear: both; margin-top: 20px; font-size: 10px;'>
                    <p>Service: {shipping.ServiceType} | Weight: {shipping.Weight}lbs</p>
                </div>
            </div>
        </body>
        </html>";

        return pdf.RenderHtmlAsPdf(labelHtml).BinaryData;
    }

    // Generate secure document QR codes with encryption
    public class SecureDocumentQR
    {
        private readonly byte[] _encryptionKey;

        public SecureDocumentQR(byte[] encryptionKey)
        {
            _encryptionKey = encryptionKey;
        }

        public GeneratedBarcode GenerateSecureDocumentQR(DocumentInfo document)
        {
            // Create document reference with security features
            var documentRef = new
            {
                DocumentId = document.Id,
                Type = document.DocumentType,
                CreatedDate = document.CreatedDate,
                Hash = ComputeDocumentHash(document),
                AccessUrl = "___PROTECTED_URL_46___",
                ValidUntil = DateTime.UtcNow.AddDays(30)
            };

            // Encrypt sensitive data
            var jsonData = JsonSerializer.Serialize(documentRef);
            var encryptedData = EncryptData(jsonData);

            // Generate QR with encrypted payload
            var qrCode = QRCodeWriter.CreateQrCode(
                Convert.ToBase64String(encryptedData),
                500,
                QRCodeWriter.QrErrorCorrectionLevel.High
            );

            // Add visual security indicators
            qrCode.ChangeBarCodeColor(Color.DarkGreen);
            qrCode.AddAnnotationTextAboveBarcode("SECURE DOCUMENT");
            qrCode.AddAnnotationTextBelowBarcode($"Expires: {documentRef.ValidUntil:yyyy-MM-dd}");

            return qrCode;
        }

        private string ComputeDocumentHash(DocumentInfo document)
        {
            using var sha256 = SHA256.Create();
            var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(document.Content ?? document.Id));
            return BitConverter.ToString(hash).Replace("-", "");
        }

        private byte[] EncryptData(string data)
        {
            // Simplified encryption - use proper encryption in production
            using var aes = Aes.Create();
            aes.Key = _encryptionKey;
            aes.GenerateIV();

            using var encryptor = aes.CreateEncryptor();
            var dataBytes = Encoding.UTF8.GetBytes(data);
            var encrypted = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length);

            // Prepend IV for decryption
            return aes.IV.Concat(encrypted).ToArray();
        }
    }

    // Batch generation for high-volume scenarios
    public async Task<List<GeneratedBarcode>> GenerateBatchQRCodesAsync(List<string> data, QRCodeOptions options)
    {
        var tasks = data.Select(item => Task.Run(() =>
        {
            var qr = QRCodeWriter.CreateQrCode(
                item, 
                options.Size, 
                options.ErrorCorrection
            );

            if (options.IncludeMargins)
                qr.SetMargins(options.MarginSize);

            if (options.CustomColor.HasValue)
                qr.ChangeBarCodeColor(options.CustomColor.Value);

            return qr;
        }));

        return (await Task.WhenAll(tasks)).ToList();
    }
}

// Supporting models
public class AssetInfo
{
    public string AssetId { get; set; }
    public string AssetType { get; set; }
    public string CurrentLocation { get; set; }
    public DateTime LastMaintenanceDate { get; set; }
}

public class VisitorInfo
{
    public string Name { get; set; }
    public string Company { get; set; }
    public string HostEmployee { get; set; }
    public DateTime CheckInTime { get; set; }
    public string AccessLevel { get; set; }
}

public class ShippingInfo
{
    public string TrackingNumber { get; set; }
    public string SenderAddress { get; set; }
    public string RecipientAddress { get; set; }
    public string PostalCode { get; set; }
    public string ServiceType { get; set; }
    public decimal Weight { get; set; }
}

public class DocumentInfo
{
    public string Id { get; set; }
    public string DocumentType { get; set; }
    public DateTime CreatedDate { get; set; }
    public string Content { get; set; }
}

public class QRCodeOptions
{
    public int Size { get; set; } = 400;
    public QRCodeWriter.QrErrorCorrectionLevel ErrorCorrection { get; set; } = QRCodeWriter.QrErrorCorrectionLevel.Medium;
    public bool IncludeMargins { get; set; } = true;
    public int MarginSize { get; set; } = 10;
    public Color? CustomColor { get; set; }
}
$vbLabelText   $csharpLabel

Esses exemplos de geração demonstram casos de uso específicos de empresas. Códigos QR de rastreamento de ativos incluem histórico de manutenção e links diretos para sistemas de gestão de ativos. Cracha de visitantes incorpora tempos de expiração e níveis de acesso para conformidade de segurança. Etiquetas de remessa combinam vários formatos de código de barras para atender aos requisitos da transportadora.

A implementação segura de documento QR mostra como integrar criptografia para dados sensíveis. Esta abordagem garante que mesmo se alguém capturar o código QR, não consiga acessar as informações sem as chaves de decodificação adequadas. Isso se mostra essencial para documentos de conformidade, registros financeiros ou comunicações confidenciais.

Quais são os seus próximos passos?

Construir uma API de scanner de código de barras empresarial com IronBarcode fornece uma base confiável para iniciativas de transformação digital. A combinação de suporte completo a formatos, processamento avançado de imagens e compatibilidade entre plataformas atende aos complexos requisitos das empresas modernas. Antes de finalizar sua arquitetura, rever a documentação dos padrões de código de barras GS1 ajuda você a entender os requisitos de codificação para códigos de barras de cadeia de suprimentos e varejo. Para padrões de design de API REST usados nos exemplos de controle acima, o guia de Design de API RESTful do restfulapi.net fornece uma referência prática. Ao implantar em ambientes de contêiner, a documentação oficial da Docker sobre imagens .NET é a fonte autorizada para seleção de imagem base.

Itens chave para sua implementação:

  1. Segurança em Primeiro Lugar: Implemente autenticação adequada, validação de entrada e registro de auditoria desde o início
  2. Otimização de Desempenho: Use velocidades de varredura e estratégias de cache adequadas para seu caso de uso
  3. Tratamento de Erros: Construa sistemas resilientes que lidam graciosamente com casos extremos e forneçam feedback significativo
  4. Escalabilidade: Projete pensando em escalabilidade horizontal, utilizando padrões assíncronos e gerenciamento eficiente de recursos

Para implantações em produção, considere esses recursos adicionais:

Os recursos empresariais do IronBarcode vão além da varredura básica. As capacidades de personalização de estilo da biblioteca permitem a geração de códigos de barras de marca. O suporte a códigos de barras Unicode garante compatibilidade global. Recursos avançados como margens de código de barras e níveis de correção de erros oferecem controle detalhado sobre a qualidade do resultado.

Suporte e Recursos Empresariais

Ao implementar soluções de código de barras críticas para o negócio, ter suporte confiável é importante. IronBarcode oferece:

O processo da manipulação manual de códigos de barras para o processamento automatizado orientado por API transforma a eficiência operacional. Quer você esteja processando milhares de documentos de envio, gerenciando acesso de visitantes ou rastreando ativos da empresa, o IronBarcode oferece a confiabilidade e os recursos que os ambientes empresariais exigem.

Pronto para transformar o processamento de seus códigos de barras? Comece com uma avaliação gratuita e experimente a diferença que o processamento profissional de códigos de barras pode fazer. A documentação completa da API fornece orientações detalhadas de implementação, enquanto a seção de exemplos oferece código pronto para uso em cenários comuns.

Sua empresa merece uma solução de código de barras que se adapte às suas necessidades, mantenha a conformidade de segurança e forneça resultados consistentes em todas as plataformas. O IronBarcode oferece exatamente isso -- apoiado por uma empresa comprometida com o suporte a longo prazo e melhoria contínua. Comece a construir sua API de scanner hoje e junte-se a milhares de empresas que confiam no IronBarcode para suas necessidades críticas de processamento de códigos de barras.

Perguntas frequentes

Qual é a principal vantagem de usar o IronBarcode para criar uma API de scanner em C#?

O IronBarcode permite que os desenvolvedores criem rapidamente uma API de leitor de código de barras poderosa e pronta para produção com complexidade mínima. Ele simplifica o processo eliminando a necessidade de integrações complexas de SDKs de leitores.

O IronBarcode consegue lidar com códigos de barras danificados?

Sim, o IronBarcode foi projetado para processar dados de código de barras mesmo a partir de entradas de leitura danificadas, garantindo alta confiabilidade em aplicações do mundo real.

Que tipos de entrada o IronBarcode pode processar em uma API de scanner C#?

O IronBarcode consegue processar dados de código de barras de diversas fontes, como imagens e PDFs, oferecendo soluções versáteis para diferentes necessidades de digitalização.

Existe algum tutorial disponível para criar uma API de leitor de código de barras usando o IronBarcode?

Sim, a página da web oferece um tutorial completo com exemplos de código para orientar os desenvolvedores na criação de um endpoint RESTful para leitura de código de barras usando o IronBarcode.

Com que rapidez é possível configurar uma API de leitor de código de barras usando o IronBarcode?

Com o IronBarcode, os desenvolvedores podem configurar uma API de leitor de código de barras em minutos, otimizando o tempo e o esforço de desenvolvimento.

O IronBarcode requer alguma integração complexa de SDK?

Não, o IronBarcode elimina a necessidade de integrações complexas de SDKs de scanners, facilitando a implementação da funcionalidade de leitura de código de barras pelos desenvolvedores.

Qual linguagem de programação é usada com o IronBarcode para construir uma API de scanner?

O IronBarcode é usado com C# para construir uma API de scanner, aproveitando o framework .NET para um desempenho robusto.

Curtis Chau
Redator Técnico

Curtis Chau é bacharel em Ciência da Computação (Universidade Carleton) e se especializa em desenvolvimento front-end, com experiência em Node.js, TypeScript, JavaScript e React. Apaixonado por criar interfaces de usuário intuitivas e esteticamente agradáveis, Curtis gosta de trabalhar com frameworks modernos e criar manuais ...

Leia mais

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me