Créer une API de scanner de codes-barres en C# (Guide du développeur)
Créez une API de lecteur de codes-barres RESTful utilisant IronBarcode et ASP.NET Core pour gérer les codes-barres à partir d'images, de PDF et de numérisations endommagées sans matériel, garantissant des performances fiables sous Windows, Linux et macOS.
IronBarcode permet la numérisation Professional de codes-barres via des API RESTful dans ASP.NET Core, traitant les images, les PDF et les numérisations endommagées sans dépendance matérielle tout en prenant en charge le déploiement multiplateforme avec des fonctionnalités de sécurité et de conformité intégrées.
Qu'est-ce que le défi des codes-barres Enterprise ?
Imaginez être l'architecte Enterprise d'une société de logistique figurant au classement Fortune 500. Vos équipes d'entrepôt peinent à gérer les étiquettes d'expédition endommagées, votre service financier doit traiter des milliers de factures PDF avec codes-barres intégrés et votre équipe de sécurité informatique exige une solution conforme à la norme SOC2 sans introduire de dépendances matérielles dans votre infrastructure mondiale.
Ce scénario est fréquent pour les équipes Enterprise qui cherchent à découvrir les fonctionnalités de l'API REST d' IronBarcode . Ce qui avait commencé comme un simple besoin de lecture de codes-barres s'est transformé en une solution de numérisation complète qui traite désormais plus de 2 millions de codes-barres par mois au sein de leur organisation.
Traditionnellement, cela aurait nécessité des scanners matériels coûteux sur chaque site, une gestion complexe des pilotes et des analyses de sécurité approfondies. Ils ont donc mis en place une API RESTful centralisée à laquelle n'importe quel service pouvait accéder en toute sécurité, que ce soit pour scanner des étiquettes d'entrepôt endommagées ou extraire des données de factures à partir de fichiers PDF de fournisseurs.
Ce tutoriel vous guide dans la création de cette même API Professional de lecteur de codes-barres. Vous apprendrez à créer des points de terminaison sécurisés capables de gérer des problèmes concrets tels que les étiquettes déchirées, les images déformées et les documents de plusieurs pages. Plus important encore, vous verrez comment mettre cela en œuvre avec la sécurité, l'évolutivité et la stabilité du fournisseur qu'exigent les environnements Enterprise .
Comment créer une API de scanner C# fiable ?
La création d'une API de lecture de codes-barres Enterprise nécessite de répondre à plusieurs préoccupations critiques dès le départ. Les équipes de sécurité ont besoin d'être rassurées quant au traitement des données. Les responsables de la conformité exigent des pistes d'audit. Les équipes opérationnelles exigent une fiabilité sur différentes plateformes. La documentation complète d'IronBarcode aborde systématiquement chacune de ces préoccupations.
La beauté d'une approche RESTful réside dans sa simplicité et sa sécurité. En centralisant le traitement des codes-barres derrière des points de terminaison API sécurisés, vous conservez un contrôle total sur le flux de données. Aucun périphérique client n'a besoin d'un accès direct à votre logique de traitement des codes-barres. Cette architecture prend naturellement en charge votre modèle de sécurité zéro confiance tout en permettant une intégration fluide avec les systèmes Enterprise existants.
Commençons par les fondations. Les fonctionnalités de lecture d'IronBarcode prennent en charge tous les principaux formats de codes-barres que votre Enterprise pourrait rencontrer. Des codes-barres Code 39 traditionnels utilisés dans la fabrication aux codes QR modernes des campagnes marketing, la bibliothèque les gère tous. Le guide des formats de codes-barres pris en charge constitue une référence complète pour la planification de votre mise en œuvre.
Ce qui rend cette bibliothèque particulièrement précieuse pour les scénarios Enterprise , ce sont ses capacités de tolérance aux pannes . Les codes-barres du monde réel ne sont pas parfaits. Ils sont endommagés, mal imprimés ou scannés de travers. Le traitement d'images avancé d'IronBarcode gère automatiquement ces problèmes, réduisant ainsi les demandes d'assistance et améliorant l'efficacité opérationnelle.
Comment installer et configurer la bibliothèque de codes-barres ?
Les déploiements en Enterprise nécessitent une analyse approfondie des dépendances et des licences. IronBarcode simplifie cela grâce à une installation NuGet simple et une licence transparente. Voici comment démarrer votre projet ASP.NET Core :
Install-Package IronBarCode
Install-Package IronBarCode
Pour les environnements Enterprise avec des exigences de plateforme spécifiques, consultez le guide d'installation NuGet avancé . Cela couvre des scénarios tels que le ciblage de versions .NET spécifiques ou l'optimisation pour des plateformes particulières.
Une fois l'installation terminée, vérifiez votre configuration à l'aide d'un test simple. Ce code illustre la capacité de la bibliothèque à lire les codes-barres avec une configuration minimale :
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}");
}
}
}
Imports IronBarCode
' Verify installation with a basic barcode read
Public Class InstallationTest
Public Shared Sub VerifySetup()
Try
' Test with a sample barcode image
Dim result = BarcodeReader.Read("test-barcode.png")
If result.Any() Then
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")
End If
Catch ex As Exception
Console.WriteLine($"Setup issue: {ex.Message}")
End Try
End Sub
End Class
Cette étape de vérification est cruciale pour les déploiements en Enterprise . Cela confirme que la bibliothèque est correctement installée, sous licence et qu'elle peut accéder aux ressources système nécessaires. Le score de confiance fourni permet d'établir des attentes de base pour vos types de codes-barres spécifiques.
Pour les déploiements en production, veuillez examiner attentivement la documentation relative aux licences . Les licences Enterprise permettent un nombre illimité de déploiements au sein de votre organisation, ce qui est essentiel pour une mise à l'échelle sur plusieurs centres de données. Le guide de configuration de la clé de licence explique différentes méthodes d'activation, y compris les variables d'environnement et les fichiers de configuration qui correspondent à vos pratiques DevOps.
Compatibilité de la plateforme pour les entreprises
Votre Enterprise exploite probablement un environnement hétérogène. Le développement se fait sous Windows, la préproduction s'exécute sur des conteneurs Linux, et certaines équipes peuvent utiliser macOS. La compatibilité multiplateforme d'IronBarcode garantit un comportement cohérent sur toutes ces plateformes.
Pour les déploiements conteneurisés, le guide d'installation de Docker fournit des instructions spécifiques pour les conteneurs Linux. Cela inclut la gestion des dépendances et l'optimisation de la taille des images pour un déploiement cloud efficace. Si vous déployez sur Azure ou AWS Lambda , des guides spécifiques à chaque plateforme garantissent des performances optimales dans ces environnements.
La bibliothèque prend même en charge les scénarios mobiles grâce à l'intégration .NET MAUI , vous permettant d'étendre vos capacités de lecture de codes-barres aux appareils iOS et Android lorsque les travailleurs sur le terrain ont besoin de capacités de lecture mobiles.
Comment créer un contrôleur d'API de scanner complet ?
Créons une API de scanner prête pour la production qui réponde aux besoins réels des Enterprise . Cette implémentation comprend une gestion appropriée des erreurs, des considérations de sécurité et des optimisations de performance :
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"
};
}
}
}
Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.AspNetCore.Authorization
Imports IronBarCode
Imports System.Drawing
Imports System.ComponentModel.DataAnnotations
Namespace BarcodeScannerAPI.Controllers
<ApiController>
<Route("api/v1/[controller]")>
<Authorize>
Public Class ScannerController
Inherits ControllerBase
Private ReadOnly _logger As ILogger(Of ScannerController)
Private ReadOnly _configuration As IConfiguration
Public Sub New(logger As ILogger(Of ScannerController), configuration As IConfiguration)
_logger = logger
_configuration = configuration
End Sub
' Enhanced result model with audit fields
Public Class ScanResult
Public Property Success As Boolean
Public Property Barcodes As List(Of BarcodeData) = New List(Of BarcodeData)()
Public Property RequestId As String = Guid.NewGuid().ToString()
Public Property ProcessedAt As DateTime = DateTime.UtcNow
Public Property ProcessingTimeMs As Long
Public Property ErrorMessage As String
Public Property Metadata As Dictionary(Of String, Object) = New Dictionary(Of String, Object)()
End Class
Public Class BarcodeData
Public Property Value As String
Public Property Format As String
Public Property Confidence As Double
Public Property Location As Rectangle
Public Property PageNumber As Integer
End Class
' Input validation model
Public Class ScanRequest
<Required>
Public Property File As IFormFile
<Range(1, 10)>
Public Property MaxBarcodes As Integer = 5
Public Property ExpectedFormats As String()
Public Property EnableImageCorrection As Boolean = True
End Class
<HttpPost("scan")>
<RequestSizeLimit(52428800)>
Public Async Function ScanDocument(<FromForm> request As ScanRequest) As Task(Of ActionResult(Of ScanResult))
Dim stopwatch = System.Diagnostics.Stopwatch.StartNew()
Dim result = New ScanResult()
Try
' Validate file type for security
Dim allowedExtensions = {".pdf", ".png", ".jpg", ".jpeg", ".gif", ".tiff", ".bmp"}
Dim fileExtension = Path.GetExtension(request.File.FileName).ToLowerInvariant()
If Not allowedExtensions.Contains(fileExtension) Then
_logger.LogWarning($"Rejected file type: {fileExtension}")
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "Unsupported file type. Allowed: PDF, PNG, JPG, GIF, TIFF, BMP"
})
End If
' Process the file
Using stream = New MemoryStream()
Await request.File.CopyToAsync(stream)
Dim fileBytes = stream.ToArray()
' Log for audit trail
_logger.LogInformation($"Processing {request.File.FileName} ({fileBytes.Length} bytes) - RequestId: {result.RequestId}")
' Configure scanner based on requirements
Dim options = ConfigureOptions(request)
' Handle different file types
Dim scanResults As BarcodeResults
If fileExtension = ".pdf" Then
Dim pdfOptions = New PdfBarcodeReaderOptions With {
.Scale = 3,
.DPI = 300,
.MaxThreads = 4
}
scanResults = BarcodeReader.ReadPdf(fileBytes, pdfOptions)
Else
scanResults = BarcodeReader.Read(fileBytes, options)
End If
' Process results
If scanResults.Any() Then
result.Success = True
For Each barcode In scanResults.Take(request.MaxBarcodes)
result.Barcodes.Add(New BarcodeData With {
.Value = barcode.Value,
.Format = barcode.BarcodeType.ToString(),
.Confidence = barcode.Confidence,
.Location = barcode.Bounds,
.PageNumber = barcode.PageNumber
})
Next
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}")
End If
End Using
Catch ex As Exception
_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(Of Boolean)("DetailedErrors") Then
result.Metadata("Exception") = ex.Message
End If
Finally
stopwatch.Stop()
result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds
End Try
Return result
End Function
Private Function ConfigureOptions(request As ScanRequest) As BarcodeReaderOptions
Dim options = New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Balanced,
.ExpectMultipleBarcodes = request.MaxBarcodes > 1,
.RemoveFalsePositive = True,
.Multithreaded = True,
.MaxParallelThreads = Environment.ProcessorCount
}
' Apply format filtering if specified
If request.ExpectedFormats?.Any() = True Then
Dim formats = BarcodeEncoding.None
For Each format In request.ExpectedFormats
Dim encoding As BarcodeEncoding
If [Enum].TryParse(format, True, encoding) Then
formats = formats Or encoding
End If
Next
options.ExpectBarcodeTypes = formats
End If
' Enable image correction for damaged barcodes
If request.EnableImageCorrection Then
options.ImageFilters = New ImageFilterCollection From {
New SharpenFilter(2),
New ContrastFilter(1.5F),
New BrightnessFilter(1.1F)
}
options.AutoRotate = True
End If
Return options
End Function
' Batch processing endpoint for high-volume scenarios
<HttpPost("scan-batch")>
<RequestSizeLimit(524288000)>
Public Async Function ScanBatch(files As List(Of IFormFile)) As Task(Of ActionResult(Of List(Of ScanResult)))
If files Is Nothing OrElse Not files.Any() Then
Return BadRequest("No files provided")
End If
If files.Count > 50 Then
Return BadRequest("Maximum 50 files per batch")
End If
Dim tasks = files.Select(Function(file) ProcessFileAsync(file))
Dim results = Await Task.WhenAll(tasks)
_logger.LogInformation($"Batch processed {files.Count} files, {results.Count(Function(r) r.Success)} successful")
Return Ok(results)
End Function
Private Async Function ProcessFileAsync(file As IFormFile) As Task(Of ScanResult)
' Reuse the scanning logic
Dim request = New ScanRequest With {
.File = file,
.EnableImageCorrection = True
}
Dim actionResult = Await ScanDocument(request)
If TypeOf actionResult.Result Is OkObjectResult Then
Return DirectCast(actionResult.Result, OkObjectResult).Value
ElseIf TypeOf actionResult.Result Is BadRequestObjectResult Then
Return DirectCast(actionResult.Result, BadRequestObjectResult).Value
End If
Return New ScanResult With {
.Success = False,
.ErrorMessage = "Processing failed"
}
End Function
End Class
End Namespace
Cette implémentation Professional comprend plusieurs fonctionnalités essentielles requises pour les déploiements en production. L'authentification garantit que seuls les utilisateurs autorisés peuvent accéder au service d'analyse. Les limites de taille des requêtes empêchent les attaques par déni de service. Un enregistrement complet des données fournit la piste d'audit dont les équipes de conformité ont besoin.
Le modèle de réponse structurée renvoie non seulement les valeurs des codes-barres, mais aussi les scores de confiance et les données de localisation. Ces métadonnées s'avèrent inestimables pour les processus d'assurance qualité. Lorsqu'un code-barres provenant d'un fournisseur présente un faible niveau de fiabilité, votre système peut le signaler pour une vérification manuelle.
Gestion Professional des erreurs
Remarquez que le contrôleur ne divulgue jamais les détails des exceptions internes aux clients ? Cela respecte les meilleures pratiques de sécurité en empêchant les fuites d'informations. La journalisation détaillée capture tout ce qui est nécessaire au débogage tout en conservant des réponses d'erreur génériques.
Le champ RequestId permet un traçage de bout en bout à travers vos systèmes distribués. Lorsqu'un employé d'entrepôt signale un problème de numérisation, votre équipe d'assistance peut rapidement localiser la demande exacte dans votre système de journalisation centralisé. Cela réduit considérablement le temps moyen de résolution (MTTR) des problèmes de production.
La surveillance des performances via ProcessingTimeMs permet d'identifier les goulots d'étranglement. Si certains types de codes-barres prennent systématiquement plus de temps à traiter, vous pouvez ajuster vos paramètres de vitesse de lecture en conséquence. L' exemple des vitesses de lecture illustre comment différents paramètres influent sur les performances.
Comment gérez-vous les différentes sources d'entrée ?
Les systèmes Enterprise adoptent rarement un format standardisé unique. Votre API de numérisation doit pouvoir gérer aussi bien les données des caméras d'entrepôt haute résolution que celles des numérisations PDF de basse qualité provenant de télécopieurs vieux de plusieurs décennies. Voici comment développer cette flexibilité :
// 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; }
}
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Net.Http
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Authorization
Imports Microsoft.AspNetCore.Http
Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.Logging
<ApiController>
<Route("api/v1/[controller]")>
<Authorize>
Public Class AdvancedScannerController
Inherits ControllerBase
Private ReadOnly _httpClientFactory As IHttpClientFactory
Private ReadOnly _logger As ILogger(Of AdvancedScannerController)
Private ReadOnly _configuration As IConfiguration
Public Sub New(httpClientFactory As IHttpClientFactory, logger As ILogger(Of AdvancedScannerController), configuration As IConfiguration)
_httpClientFactory = httpClientFactory
_logger = logger
_configuration = configuration
End Sub
' Handle Base64 input (common in web applications)
<HttpPost("scan-base64")>
Public Function ScanBase64(<FromBody> request As Base64Request) As ActionResult(Of ScanResult)
If Not ModelState.IsValid Then
Return BadRequest(ModelState)
End If
Try
' Validate Base64 format
Dim base64Data = request.ImageData
If base64Data.Contains(",") Then
' Handle data URL format: "data:image/png;base64,..."
base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1)
End If
Dim imageBytes = Convert.FromBase64String(base64Data)
' Implement size validation
If imageBytes.Length > 10 * 1024 * 1024 Then ' 10MB limit
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "Image size exceeds 10MB limit"
})
End If
' Configure for web-uploaded images (often lower quality)
Dim options = New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Detailed,
.ImageFilters = New ImageFilterCollection From {
New SharpenFilter(3),
New ContrastFilter(2),
New DeNoise()
},
.TryInvertColor = True, ' Handle inverted barcodes
.AutoRotate = True
}
Dim results = BarcodeReader.Read(imageBytes, options)
Return ProcessResults(results, "base64", request.FileName)
Catch ex As FormatException
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "Invalid Base64 format"
})
End Try
End Function
' Handle URL input (for cloud storage integration)
<HttpPost("scan-url")>
Public Async Function ScanFromUrl(<FromBody> request As UrlScanRequest) As Task(Of ActionResult(Of ScanResult))
Dim uri As Uri = Nothing
If Not Uri.TryCreate(request.Url, UriKind.Absolute, uri) Then
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "Invalid URL format"
})
End If
' Validate URL domain (security measure)
Dim allowedDomains = _configuration.GetSection("AllowedDomains").Get(Of String())() _
?? New String() {"blob.core.windows.net", "s3.amazonaws.com"}
If Not allowedDomains.Any(Function(domain) uri.Host.EndsWith(domain)) Then
_logger.LogWarning($"Rejected URL from unauthorized domain: {uri.Host}")
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "URL domain not authorized"
})
End If
Try
Using httpClient = _httpClientFactory.CreateClient("BarcodeScanner")
httpClient.Timeout = TimeSpan.FromSeconds(30)
' Add headers to avoid being blocked
httpClient.DefaultRequestHeaders.Add("User-Agent", "BarcodeScannerAPI/2.0")
Dim response = Await httpClient.GetAsync(uri)
response.EnsureSuccessStatusCode()
' Check content type
Dim contentType = response.Content.Headers.ContentType?.MediaType
If Not IsValidContentType(contentType) Then
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = $"Unsupported content type: {contentType}"
})
End If
Dim imageBytes = Await response.Content.ReadAsByteArrayAsync()
' Use async processing for better scalability
Dim results = Await BarcodeReader.ReadAsync(imageBytes)
Return ProcessResults(results, "url", uri.ToString())
End Using
Catch ex As HttpRequestException
_logger.LogError(ex, $"Failed to download from URL: {uri}")
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "Failed to download image from URL"
})
Catch ex As TaskCanceledException
Return BadRequest(New ScanResult With {
.Success = False,
.ErrorMessage = "Download timeout - file too large or slow connection"
})
End Try
End Function
' Handle multi-page PDFs with page-specific processing
<HttpPost("scan-pdf-advanced")>
Public Async Function ScanPdfAdvanced(<FromForm> request As PdfScanRequest) As Task(Of ActionResult(Of PdfScanResult))
Using stream = New MemoryStream()
Await request.File.CopyToAsync(stream)
Dim pdfOptions = New PdfBarcodeReaderOptions With {
.Scale = If(request.Scale, 3),
.DPI = If(request.DPI, 300),
.PageNumbers = request.PageNumbers,
.Password = request.Password,
.MaxThreads = Math.Min(If(request.MaxThreads, 4), Environment.ProcessorCount)
}
' For large PDFs, process in chunks
If stream.Length > 50 * 1024 * 1024 Then ' 50MB
_logger.LogInformation($"Large PDF detected ({stream.Length / 1024 / 1024}MB), using chunked processing")
pdfOptions.MaxThreads = 2 ' Reduce memory pressure
End If
Dim results = BarcodeReader.ReadPdf(stream.ToArray(), pdfOptions)
' Group results by page
Dim pageResults = results.GroupBy(Function(r) r.PageNumber) _
.OrderBy(Function(g) g.Key) _
.Select(Function(g) New PageBarcodeResult With {
.PageNumber = g.Key,
.BarcodeCount = g.Count(),
.Barcodes = g.Select(Function(b) New BarcodeData With {
.Value = b.Value,
.Format = b.BarcodeType.ToString(),
.Confidence = b.Confidence,
.Location = b.Bounds
}).ToList()
}).ToList()
Return Ok(New PdfScanResult With {
.Success = True,
.TotalPages = pageResults.Count,
.TotalBarcodes = results.Count(),
.PageResults = pageResults,
.RequestId = Guid.NewGuid().ToString()
})
End Using
End Function
' Handle damaged or low-quality barcodes
<HttpPost("scan-damaged")>
Public Async Function ScanDamagedBarcode(<FromForm> file As IFormFile) As Task(Of ActionResult(Of ScanResult))
Using stream = New MemoryStream()
Await file.CopyToAsync(stream)
' Aggressive image correction for damaged barcodes
Dim options = New BarcodeReaderOptions With {
.Speed = ReadingSpeed.ExtremeDetail,
.ImageFilters = New ImageFilterCollection From {
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
}
Dim results = BarcodeReader.Read(stream.ToArray(), options)
' If still no results, try with different threshold
If Not results.Any() Then
options.ImageFilters = New ImageFilterCollection From {
New AdaptiveThresholdFilter(9),
New MedianFilter(3),
New Dilate(1)
}
results = BarcodeReader.Read(stream.ToArray(), options)
End If
Return ProcessResults(results, "damaged", file.FileName)
End Using
End Function
Private Function IsValidContentType(contentType As String) As Boolean
Dim validTypes = New String() {
"image/jpeg", "image/jpg", "image/png", "image/gif",
"image/tiff", "image/bmp", "application/pdf"
}
Return validTypes.Contains(contentType?.ToLower())
End Function
Private Function ProcessResults(results As BarcodeResults, source As String, identifier As String) As ActionResult(Of ScanResult)
Dim scanResult = New ScanResult With {
.Metadata = New Dictionary(Of String, Object) From {
{"Source", source},
{"Identifier", identifier},
{"ProcessedAt", DateTime.UtcNow}
}
}
If results.Any() Then
scanResult.Success = True
scanResult.Barcodes = results.Select(Function(r) New BarcodeData With {
.Value = r.Value,
.Format = r.BarcodeType.ToString(),
.Confidence = r.Confidence,
.Location = r.Bounds
}).ToList()
' Log low confidence results for quality monitoring
Dim lowConfidence = results.Where(Function(r) r.Confidence < 70).ToList()
If lowConfidence.Any() Then
_logger.LogWarning($"Low confidence barcodes detected: {lowConfidence.Count} of {results.Count()} from {identifier}")
End If
Else
scanResult.Success = False
scanResult.ErrorMessage = "No barcodes detected"
End If
Return Ok(scanResult)
End Function
End Class
' Request models
Public Class Base64Request
<Required>
Public Property ImageData As String
Public Property FileName As String
End Class
Public Class UrlScanRequest
<Required>
<Url>
Public Property Url As String
End Class
Public Class PdfScanRequest
<Required>
Public Property File As IFormFile
Public Property Scale As Integer?
Public Property DPI As Integer?
Public Property PageNumbers As Integer()
Public Property Password As String
Public Property MaxThreads As Integer?
End Class
' Response models
Public Class PdfScanResult
Inherits ScanResult
Public Property TotalPages As Integer
Public Property TotalBarcodes As Integer
Public Property PageResults As List(Of PageBarcodeResult)
End Class
Public Class PageBarcodeResult
Public Property PageNumber As Integer
Public Property BarcodeCount As Integer
Public Property Barcodes As List(Of BarcodeData)
End Class
Cette implémentation complète répond aux besoins réels des Enterprise . Le point de terminaison d'analyse d'URL inclut une validation de domaine afin de prévenir les attaques de type falsification de requête côté serveur (SSRF). Le gestionnaire Base64 supprime les préfixes d'URL des données, ce qui est fréquent lors de la réception d'images provenant d'applications Web.
Le terminal de code-barres endommagé démontre les capacités de correction d'image d'IronBarcode. En appliquant plusieurs filtres et en essayant différentes approches, il peut récupérer des données à partir d'images fortement dégradées. Cela s'avère inestimable lorsqu'il s'agit d'étiquettes d'inventaire anciennes ou de documents d'expédition endommagés par les intempéries.
Choisir entre la numérisation de PDF et d'images
Les fichiers PDF présentent des défis et des opportunités uniques en matière de numérisation de codes-barres en Enterprise . De nombreux documents commerciaux, tels que les factures, les manifestes d'expédition et les formulaires de conformité, arrivent au format PDF avec des codes-barres intégrés. Les fonctionnalités de lecture de codes-barres PDF d' IronBarcode gèrent ces scénarios avec élégance.
Prenons l'exemple d'une Enterprise classique : votre service comptabilité fournisseurs reçoit chaque mois des milliers de factures, chacune contenant un code-barres pour un traitement automatisé. Certains fournisseurs envoient des PDF de haute qualité, d'autres envoient des documents numérisés de qualité variable.
Le terminal de numérisation PDF avancé gère les deux scénarios. Pour les PDF de haute qualité, les paramètres standard fonctionnent parfaitement. Pour les documents numérisés, l'augmentation des paramètres DPI et d'échelle améliore les taux de détection. Le traitement par page permet d'extraire les codes-barres de pages spécifiques, ce qui est utile lorsque vous savez que les factures comportent toujours des codes-barres sur la première page.
Le regroupement des résultats par page apporte un contexte précieux. Votre système de flux de travail peut acheminer les documents en fonction des pages contenant des codes-barres, automatisant ainsi la classification des documents. Cette approche structurée du traitement des documents multipages transforme les processus manuels en flux de travail automatisés et efficaces.
Gestion efficace de plusieurs codes-barres
Les documents Enterprise contiennent souvent plusieurs codes-barres ayant des fonctions différentes. Une étiquette d'expédition peut comporter un code-barres de suivi, un code-barres du produit et un code-barres de destination. La gestion adéquate de plusieurs scénarios de codes-barres nécessite une conception d'API réfléchie.
Le point de terminaison de traitement par lots démontre comment gérer efficacement les scénarios à volume élevé. En traitant plusieurs fichiers en parallèle, vous pouvez réduire considérablement le temps de traitement total. Le modèle Task.WhenAll garantit une utilisation optimale des ressources tout en préservant la stabilité du système.
Pour la création de codes-barres dans vos applications, IronBarcode offre des fonctionnalités tout aussi efficaces. Que vous ayez besoin de générer des codes-barres linéaires 1D pour les systèmes d'inventaire ou de créer des codes matriciels 2D pour les applications mobiles, la même approche API simple s'applique.
Comment améliorer ses performances et sa précision ?
L'optimisation des performances de la lecture des codes-barres en Enterprise ne se résume pas à la vitesse ; il s'agit de trouver le juste équilibre pour votre cas d'utilisation spécifique. Les exemples suivants explorent des techniques d'optimisation avancées qui peuvent transformer vos performances de numérisation :
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; }
}
Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.IO
Imports System.Linq
Imports System.Threading.Tasks
Public Class OptimizedScannerService
Private ReadOnly _logger As ILogger(Of OptimizedScannerService)
Private ReadOnly _cache As IMemoryCache
Public Sub New(logger As ILogger(Of OptimizedScannerService), cache As IMemoryCache)
_logger = logger
_cache = cache
End Sub
' Performance-optimized scanning with caching
Public Async Function ScanWithOptimizationsAsync(imageData As Byte(), Optional cacheKey As String = Nothing) As Task(Of ScanResult)
' Check cache for repeat scans
If Not String.IsNullOrEmpty(cacheKey) Then
Dim cachedResult As ScanResult = Nothing
If _cache.TryGetValue(cacheKey, cachedResult) Then
_logger.LogInformation($"Cache hit for {cacheKey}")
cachedResult.Metadata("CacheHit") = True
Return cachedResult
End If
End If
' Determine optimal settings based on image characteristics
Dim settings = Await DetermineOptimalSettingsAsync(imageData)
' Apply region-specific scanning if applicable
If settings.UseRegionScanning Then
Return Await ScanWithRegionsAsync(imageData, settings)
End If
' Standard optimized scanning
Dim results = Await BarcodeReader.ReadAsync(imageData, settings.Options)
Dim scanResult = BuildScanResult(results)
' Cache successful results
If Not String.IsNullOrEmpty(cacheKey) AndAlso scanResult.Success Then
_cache.Set(cacheKey, scanResult, TimeSpan.FromMinutes(5))
End If
Return scanResult
End Function
' Intelligent settings determination
Private Async Function DetermineOptimalSettingsAsync(imageData As Byte()) As Task(Of ScanSettings)
Dim settings As New ScanSettings()
' Quick analysis of image properties
Using ms As New MemoryStream(imageData)
Using image As Image = Image.FromStream(ms)
Dim width = image.Width
Dim height = image.Height
Dim aspectRatio = CDbl(width) / height
_logger.LogInformation($"Image analysis: {width}x{height}, ratio: {aspectRatio:F2}")
' High-resolution images can use faster scanning
If width > 2000 AndAlso height > 2000 Then
settings.Options.Speed = ReadingSpeed.Faster
settings.Options.ExpectBarcodeTypes = BarcodeEncoding.QRCode Or BarcodeEncoding.Code128
ElseIf width < 800 OrElse height < 800 Then
' Low-resolution needs more processing
settings.Options.Speed = ReadingSpeed.ExtremeDetail
settings.Options.ImageFilters = New ImageFilterCollection From {
New SharpenFilter(3),
New ContrastFilter(2)
}
Else
settings.Options.Speed = ReadingSpeed.Balanced
End If
' Detect if image might contain multiple barcodes based on aspect ratio
If aspectRatio > 2 OrElse aspectRatio < 0.5 Then
settings.Options.ExpectMultipleBarcodes = True
settings.UseRegionScanning = True
End If
' Enable rotation correction for potentially skewed images
settings.Options.AutoRotate = True
End Using
End Using
Return settings
End Function
' Region-based scanning for large images
Private Async Function ScanWithRegionsAsync(imageData As Byte(), settings As ScanSettings) As Task(Of ScanResult)
Dim allResults As New List(Of BarcodeResult)()
Using ms As New MemoryStream(imageData)
Using image As Image = Image.FromStream(ms)
' Define scanning regions for common document layouts
Dim regions = {
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
}
Dim tasks = regions.Select(Async Function(region)
Dim regionOptions As New BarcodeReaderOptions With {
.CropArea = region,
.Speed = ReadingSpeed.Faster,
.ExpectMultipleBarcodes = False
}
Try
Return Await BarcodeReader.ReadAsync(imageData, regionOptions)
Catch ex As Exception
_logger.LogWarning($"Region scan failed: {ex.Message}")
Return New BarcodeResult() {}
End Try
End Function)
Dim regionResults = Await Task.WhenAll(tasks)
' Combine and deduplicate results
Dim uniqueResults = regionResults.
SelectMany(Function(r) r).
GroupBy(Function(r) r.Value).
Select(Function(g) g.OrderByDescending(Function(r) r.Confidence).First()).
ToList()
Return BuildScanResult(uniqueResults)
End Using
End Using
End Function
' Adaptive quality enhancement
Public Async Function ScanWithAdaptiveEnhancementAsync(imageData As Byte()) As Task(Of ScanResult)
Dim attempts = New List(Of Func(Of Task(Of BarcodeResults))) From {
' Attempt 1: Fast scan
Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Faster,
.RemoveFalsePositive = True
}),
' Attempt 2: Standard scan with basic filters
Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Balanced,
.ImageFilters = New ImageFilterCollection From {
New ContrastFilter(1.5F),
New SharpenFilter(1)
},
.TryInvertColor = True
}),
' Attempt 3: Detailed scan with aggressive filtering
Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Detailed,
.ImageFilters = New ImageFilterCollection From {
New AdaptiveThresholdFilter(11),
New DeNoise(2),
New MedianFilter(3)
},
.AutoRotate = True,
.Confidence = ConfidenceLevel.Low
}),
' Attempt 4: Extreme processing for damaged barcodes
Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With {
.Speed = ReadingSpeed.ExtremeDetail,
.ImageFilters = New ImageFilterCollection From {
New BinaryThresholdFilter(100),
New Erode(1),
New Dilate(2),
New SharpenFilter(4)
},
.RemoveFalsePositive = False,
.UseCode39ExtendedMode = True,
.TryInvertColor = True
})
}
For Each attempt In attempts.Select(Function(a, i) (a, i))
Dim stopwatch = Stopwatch.StartNew()
Dim results = Await attempt.a()
stopwatch.Stop()
_logger.LogInformation($"Attempt {attempt.i + 1} took {stopwatch.ElapsedMilliseconds}ms, found {results.Count()} barcodes")
If results.Any() Then
Dim scanResult = BuildScanResult(results)
scanResult.Metadata("AttemptNumber") = attempt.i + 1
scanResult.Metadata("ProcessingStrategy") = GetStrategyName(attempt.i)
Return scanResult
End If
Next
Return New ScanResult With {
.Success = False,
.ErrorMessage = "No barcodes found after all enhancement attempts"
}
End Function
' Machine learning confidence optimization
Public Class MLOptimizedScanner
Private ReadOnly _formatConfidenceThresholds As New Dictionary(Of String, Double) From {
{"QRCode", 85.0},
{"Code128", 90.0},
{"Code39", 88.0},
{"DataMatrix", 87.0},
{"EAN13", 92.0},
{"PDF417", 86.0}
}
Public Async Function ScanWithMLConfidenceAsync(imageData As Byte(), Optional expectedFormat As String = Nothing) As Task(Of ScanResult)
Dim options As New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Balanced,
.Confidence = ConfidenceLevel.Optional
}
' If we know the expected format, improve for it
If Not String.IsNullOrEmpty(expectedFormat) AndAlso
[Enum].TryParse(Of BarcodeEncoding)(expectedFormat, encoding) Then
options.ExpectBarcodeTypes = encoding
End If
Dim results = Await BarcodeReader.ReadAsync(imageData, options)
' Apply ML confidence filtering
Dim confidenceThreshold = If(expectedFormat IsNot Nothing AndAlso
_formatConfidenceThresholds.ContainsKey(expectedFormat),
_formatConfidenceThresholds(expectedFormat),
80.0)
Dim highConfidenceResults = results.
Where(Function(r) r.Confidence >= confidenceThreshold).
ToList()
If highConfidenceResults.Any() Then
Return BuildScanResult(highConfidenceResults)
End If
' If no high-confidence results, include lower confidence with warnings
Dim lowConfidenceResults = results.
Where(Function(r) r.Confidence < confidenceThreshold).
ToList()
If lowConfidenceResults.Any() Then
Dim result = BuildScanResult(lowConfidenceResults)
result.Metadata("Warning") = "Low confidence results - manual verification recommended"
result.Metadata("MinConfidence") = lowConfidenceResults.Min(Function(r) r.Confidence)
Return result
End If
Return New ScanResult With {
.Success = False,
.ErrorMessage = "No barcodes met confidence threshold"
}
End Function
End Class
Private Function BuildScanResult(results As IEnumerable(Of BarcodeResult)) As ScanResult
Dim resultList = results.ToList()
Return New ScanResult With {
.Success = True,
.Barcodes = resultList.Select(Function(r) New BarcodeData With {
.Value = r.Value,
.Format = r.BarcodeType.ToString(),
.Confidence = r.Confidence,
.Location = r.Bounds
}).ToList(),
.Metadata = New Dictionary(Of String, Object) From {
{"TotalFound", resultList.Count},
{"AverageConfidence", resultList.Average(Function(r) r.Confidence)},
{"Formats", resultList.Select(Function(r) r.BarcodeType.ToString()).Distinct().ToArray()}
}
}
End Function
Private Function GetStrategyName(attemptIndex As Integer) As String
Return attemptIndex Select Case {
0 : "FastScan",
1 : "StandardEnhanced",
2 : "DetailedFiltering",
3 : "ExtremeDamageRecovery",
Else : "Unknown"
}
End Function
End Class
' Supporting classes
Public Class ScanSettings
Public Property Options As BarcodeReaderOptions = New BarcodeReaderOptions()
Public Property UseRegionScanning As Boolean
Public Property CustomRegions As List(Of Rectangle)
End Class
' Benchmark service for performance testing
Public Class BenchmarkService
Private ReadOnly _logger As ILogger(Of BenchmarkService)
Public Async Function BenchmarkSettingsAsync(testImage As Byte(), Optional iterations As Integer = 10) As Task(Of BenchmarkResult)
Dim results As New Dictionary(Of String, BenchmarkData)()
Dim testConfigurations = New Dictionary(Of String, BarcodeReaderOptions) From {
{"Fastest", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Faster}},
{"Balanced", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Balanced}},
{"Detailed", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Detailed}},
{"Parallel", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Balanced, .Multithreaded = True, .MaxParallelThreads = 4}},
{"Filtered", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Balanced, .ImageFilters = New ImageFilterCollection From {New SharpenFilter(2), New ContrastFilter(1.5F)}}}
}
For Each config In testConfigurations
Dim times As New List(Of Long)()
Dim successCount = 0
For i = 0 To iterations - 1
Dim sw = Stopwatch.StartNew()
Dim scanResults = Await BarcodeReader.ReadAsync(testImage, config.Value)
sw.Stop()
times.Add(sw.ElapsedMilliseconds)
If scanResults.Any() Then successCount += 1
' Small delay between tests
Await Task.Delay(100)
Next
results(config.Key) = New BenchmarkData With {
.AverageMs = times.Average(),
.MinMs = times.Min(),
.MaxMs = times.Max(),
.SuccessRate = CDbl(successCount) / iterations * 100
}
Next
Return New BenchmarkResult With {.Results = results}
End Function
End Class
Public Class BenchmarkData
Public Property AverageMs As Double
Public Property MinMs As Long
Public Property MaxMs As Long
Public Property SuccessRate As Double
End Class
Public Class BenchmarkResult
Public Property Results As Dictionary(Of String, BenchmarkData)
End Class
Cette approche d'optimisation avancée met en œuvre plusieurs techniques Professional . La détermination intelligente des paramètres analyse les propriétés de l'image afin de sélectionner automatiquement les paramètres de traitement optimaux. Les images haute résolution issues des appareils photo modernes peuvent bénéficier d'un traitement plus rapide, tandis que les numérisations de basse qualité reçoivent un filtrage amélioré.
La numérisation par région s'avère particulièrement efficace pour les documents grand format. En divisant l'image en régions et en les traitant en parallèle, vous pouvez obtenir des gains de performance significatifs. Cette technique fonctionne particulièrement bien pour les formulaires standardisés où l'emplacement des codes-barres est prévisible.
Choisir le bon réglage ReadingSpeed
L'approche d'amélioration adaptative essaie progressivement des techniques de traitement plus agressives jusqu'à ce qu'elles aboutissent. Cela garantit un traitement aussi rapide que possible des codes-barres de bonne qualité, tout en gérant efficacement ceux endommagés. La fonction de seuil de confiance utilise l'apprentissage automatique pour valider les résultats, réduisant ainsi les faux positifs en environnement de production.
Pour des scénarios d'optimisation spécifiques, le tableau ci-dessous associe les cas d'utilisation courants aux paramètres recommandés :
| Cas d'utilisation | Vitesse recommandée | Options supplémentaires | Compromis attendu |
|---|---|---|---|
| Traitement par lots à grand volume | `Faster` | Filtrer par type de code-barres attendu | Débit maximal ; risque de ne pas détecter les codes-barres dégradés. |
| Documents de qualité variable | `Balanced` | repli d'amélioration adaptative | Bon équilibre entre vitesse et précision |
| Codes-barres endommagés ou vétustes | `ExtremeDetail` | pipeline de filtrage d'image complet | Précision maximale ; débit plus lent |
| Points de terminaison d'API en temps réel | `Balanced` | Mise en cache + analyse de région | Temps de réponse constants inférieurs à 200 ms |
| extraction de factures PDF | `Balanced` | DPI 300, Échelle 3 | Idéal pour les PDF contenant du texte |
Le service d'analyse comparative vous aide à prendre des décisions de configuration basées sur les données. Effectuez des tests de performance avec vos propres échantillons de codes-barres afin de trouver le juste équilibre entre vitesse et précision pour votre cas d'utilisation spécifique. Les recommandations sectorielles de Microsoft concernant les meilleures pratiques de performance pour ASP.NET Core s'appliquent également directement lors du réglage des points de terminaison de votre API de scanner.
Impact des filtres d'image
Les filtres d'image peuvent améliorer considérablement les taux de reconnaissance des codes-barres difficiles à lire. La documentation relative à la correction d'image explique le rôle de chaque filtre. Cependant, les filtres augmentent également le temps de traitement, il convient donc de les utiliser avec discernement.
Pour les déploiements en Enterprise , envisagez la mise en œuvre d'une approche par paliers :
- Analyse rapide sans filtres pour la première tentative
- Appliquer des filtres de base si la première tentative échoue.
- N'utilisez le filtrage agressif que lorsque cela est nécessaire.
- Mise en cache des résultats pour éviter un retraitement
Cette stratégie permet de maintenir des temps de réponse moyens rapides tout en gérant efficacement les cas difficiles. La fonction de correction d'orientation s'avère particulièrement précieuse pour les images prises avec un téléphone portable, où les utilisateurs peuvent tenir leurs appareils sous différents angles.
Comment générer des images de code QR en C# ?
Bien que la numérisation soit essentielle, de nombreuses applications Enterprise ont également besoin de générer des codes-barres. IronBarcode , la création est aussi simple que la lecture. Voici comment générer des codes QR pour différents scénarios Enterprise :
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; }
}
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Security.Cryptography
Imports System.Text
Imports System.Text.Json
Imports System.Threading.Tasks
Public Class BarcodeGenerationService
Private ReadOnly _logger As ILogger(Of BarcodeGenerationService)
' Generate QR codes for asset tracking
Public Function GenerateAssetQRCode(asset As AssetInfo) As Byte()
' Create JSON payload with asset information
Dim assetData = JsonSerializer.Serialize(New With {
.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
Dim 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()
End Function
' Generate visitor badges with QR codes
Public Function CreateVisitorBadgeQR(visitor As VisitorInfo) As GeneratedBarcode
' Encode visitor information with expiration
Dim visitorData = New With {
.Name = visitor.Name,
.Company = visitor.Company,
.Host = visitor.HostEmployee,
.ValidFrom = visitor.CheckInTime,
.ValidUntil = visitor.CheckInTime.AddHours(8),
.AccessLevel = visitor.AccessLevel,
.BadgeId = Guid.NewGuid().ToString()
}
Dim qrCode = QRCodeWriter.CreateQrCode(
JsonSerializer.Serialize(visitorData),
400,
QRCodeWriter.QrErrorCorrectionLevel.Medium
)
' Add company logo for professional appearance
If File.Exists("company-logo.png") Then
qrCode.AddLogo("company-logo.png")
End If
' 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
End Function
' Generate shipping labels with multiple barcodes
Public Function GenerateShippingLabel(shipping As ShippingInfo) As Byte()
' Create a PDF with multiple barcodes
Dim pdf = New IronPdf.ChromePdfRenderer()
' Generate tracking barcode (Code 128 for USPS/UPS compatibility)
Dim trackingBarcode = BarcodeWriter.CreateBarcode(
shipping.TrackingNumber,
BarcodeEncoding.Code128
)
trackingBarcode.ResizeTo(300, 75)
trackingBarcode.SetMargins(5)
' Generate postal code barcode
Dim postalBarcode = BarcodeWriter.CreateBarcode(
shipping.PostalCode,
BarcodeEncoding.Code128
)
postalBarcode.ResizeTo(200, 50)
' Generate QR code with complete shipping data
Dim shippingData = JsonSerializer.Serialize(shipping)
Dim qrCode = QRCodeWriter.CreateQrCode(shippingData, 200)
' Combine into shipping label HTML
Dim 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
End Function
' Generate secure document QR codes with encryption
Public Class SecureDocumentQR
Private ReadOnly _encryptionKey As Byte()
Public Sub New(encryptionKey As Byte())
_encryptionKey = encryptionKey
End Sub
Public Function GenerateSecureDocumentQR(document As DocumentInfo) As GeneratedBarcode
' Create document reference with security features
Dim documentRef = New With {
.DocumentId = document.Id,
.Type = document.DocumentType,
.CreatedDate = document.CreatedDate,
.Hash = ComputeDocumentHash(document),
.AccessUrl = "___PROTECTED_URL_46___",
.ValidUntil = DateTime.UtcNow.AddDays(30)
}
' Encrypt sensitive data
Dim jsonData = JsonSerializer.Serialize(documentRef)
Dim encryptedData = EncryptData(jsonData)
' Generate QR with encrypted payload
Dim 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
End Function
Private Function ComputeDocumentHash(document As DocumentInfo) As String
Using sha256 = SHA256.Create()
Dim hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(If(document.Content, document.Id)))
Return BitConverter.ToString(hash).Replace("-", "")
End Using
End Function
Private Function EncryptData(data As String) As Byte()
' Simplified encryption - use proper encryption in production
Using aes = Aes.Create()
aes.Key = _encryptionKey
aes.GenerateIV()
Using encryptor = aes.CreateEncryptor()
Dim dataBytes = Encoding.UTF8.GetBytes(data)
Dim encrypted = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length)
' Prepend IV for decryption
Return aes.IV.Concat(encrypted).ToArray()
End Using
End Using
End Function
End Class
' Batch generation for high-volume scenarios
Public Async Function GenerateBatchQRCodesAsync(data As List(Of String), options As QRCodeOptions) As Task(Of List(Of GeneratedBarcode))
Dim tasks = data.Select(Function(item) Task.Run(Function()
Dim qr = QRCodeWriter.CreateQrCode(
item,
options.Size,
options.ErrorCorrection
)
If options.IncludeMargins Then
qr.SetMargins(options.MarginSize)
End If
If options.CustomColor.HasValue Then
qr.ChangeBarCodeColor(options.CustomColor.Value)
End If
Return qr
End Function))
Return (Await Task.WhenAll(tasks)).ToList()
End Function
End Class
' Supporting models
Public Class AssetInfo
Public Property AssetId As String
Public Property AssetType As String
Public Property CurrentLocation As String
Public Property LastMaintenanceDate As DateTime
End Class
Public Class VisitorInfo
Public Property Name As String
Public Property Company As String
Public Property HostEmployee As String
Public Property CheckInTime As DateTime
Public Property AccessLevel As String
End Class
Public Class ShippingInfo
Public Property TrackingNumber As String
Public Property SenderAddress As String
Public Property RecipientAddress As String
Public Property PostalCode As String
Public Property ServiceType As String
Public Property Weight As Decimal
End Class
Public Class DocumentInfo
Public Property Id As String
Public Property DocumentType As String
Public Property CreatedDate As DateTime
Public Property Content As String
End Class
Public Class QRCodeOptions
Public Property Size As Integer = 400
Public Property ErrorCorrection As QRCodeWriter.QrErrorCorrectionLevel = QRCodeWriter.QrErrorCorrectionLevel.Medium
Public Property IncludeMargins As Boolean = True
Public Property MarginSize As Integer = 10
Public Property CustomColor As Color?
End Class
Ces exemples de génération illustrent des cas d'utilisation spécifiques aux entreprises. Les codes QR de suivi des actifs incluent l'historique de maintenance et des liens directs vers les systèmes de gestion des actifs. Les badges visiteurs comportent des dates d'expiration et des niveaux d'accès pour assurer la conformité aux normes de sécurité. Les étiquettes d'expédition combinent plusieurs formats de codes-barres pour répondre aux exigences des transporteurs.
La mise en œuvre du QR code sécurisé pour les documents montre comment intégrer le chiffrement des données sensibles. Cette approche garantit que même si quelqu'un capture le code QR, il ne pourra pas accéder aux informations sans les clés de décryptage appropriées. Cela s'avère essentiel pour les documents de conformité, les registres financiers ou les communications confidentielles.
Quelles sont vos prochaines étapes ?
La création d'une API de lecture de codes-barres Enterprise avec IronBarcode offre une base fiable pour les initiatives de transformation numérique. La combinaison d'une prise en charge complète des formats, d'un traitement d'image avancé et d'une compatibilité multiplateforme répond aux exigences complexes des entreprises modernes. Avant de finaliser votre architecture, la consultation de la documentation relative aux normes de codes-barres GS1 vous aidera à comprendre les exigences d'encodage pour les codes-barres de la chaîne d'approvisionnement et du commerce de détail. Pour les modèles de conception d'API REST utilisés dans les exemples de contrôleurs ci-dessus, le guide de conception d'API RESTful de .NET constitue une référence pratique. Lors du déploiement dans des environnements conteneurisés, la documentation officielle de Docker sur les images .NET fait foi pour la sélection de l'image de base.
Points clés à retenir pour votre mise en œuvre :
- La sécurité avant tout : Mettez en place dès le départ une authentification appropriée, une validation des entrées et une journalisation des audits.
- Optimisation des performances : Utilisez des vitesses d'analyse et des stratégies de mise en cache adaptées à votre cas d'utilisation.
- Gestion des erreurs : Concevoir des systèmes résilients qui gèrent élégamment les cas limites et fournissent un retour d'information pertinent.
- Évolutivité : Concevoir en tenant compte de l'évolutivité horizontale, en utilisant des modèles asynchrones et une gestion efficace des ressources.
Pour les déploiements en production, tenez compte des ressources supplémentaires suivantes :
- Consultez le journal des modifications pour découvrir les dernières fonctionnalités et améliorations.
- Explorez la prise en charge de nouveaux formats, y compris les formats Enterprise spécialisés.
- Mettre en œuvre le déploiement d'installateurs MSI pour les applications de bureau
- Configurer correctement les clés de licence pour les environnements de production
Les fonctionnalités d'IronBarcode pour Enterprise vont bien au-delà de la simple numérisation. Les fonctionnalités de personnalisation du style de la bibliothèque permettent la génération de codes-barres de marque. La prise en charge des codes-barres Unicode garantit une compatibilité mondiale. Des fonctionnalités avancées telles que les marges des codes-barres et les niveaux de correction d'erreurs offrent un contrôle précis de la qualité de la sortie.
Support et ressources Enterprise
Lors de la mise en œuvre de solutions de codes-barres critiques, disposer d'un support fiable est essentiel. IronBarcode propose :
- Assistance dédiée aux Enterprise avec garanties SLA
- Assistance technique pour les besoins spécifiques
- Mises à jour de sécurité régulières et surveillance des CVE
- Guides de dépannage complets pour les scénarios courants
Le passage de la gestion manuelle des codes-barres au traitement automatisé par API transforme l'efficacité opérationnelle. Que vous traitiez des milliers de documents d'expédition, gériez l'accès des visiteurs ou suiviez les actifs de Enterprise , IronBarcode offre la fiabilité et les fonctionnalités exigées par les environnements Enterprise .
Prêt à transformer votre traitement des codes-barres ? Commencez par un essai gratuit et constatez la différence que peut apporter le traitement Professional des codes-barres. La documentation complète de l'API fournit des instructions d'implémentation détaillées, tandis que la section des exemples propose du code prêt à l'emploi pour les scénarios courants.
Votre Enterprise mérite une solution de codes-barres qui évolue avec vos besoins, garantit la conformité aux normes de sécurité et offre des résultats cohérents sur toutes les plateformes. IronBarcode offre précisément cela, avec le soutien d'une entreprise engagée dans un soutien à long terme et une amélioration continue. Commencez dès aujourd'hui à développer votre API de scanner et rejoignez les milliers d'entreprises qui font confiance à IronBarcode pour leurs besoins critiques en matière de traitement des codes-barres.
Questions Fréquemment Posées
Quel est le principal avantage d'utiliser IronBarcode pour construire une API de scanner en C# ?
IronBarcode permet aux développeurs de créer rapidement une API de scanner de codes-barres puissante et prête pour la production avec une complexité minimale. Il simplifie le processus en éliminant le besoin d'intégrations complexes de SDK de scanner.
IronBarcode peut-il traiter les entrées de codes-barres endommagés ?
Oui, IronBarcode est conçu pour traiter les données de codes-barres même à partir d'entrées de scan endommagées, assurant une fiabilité élevée dans les applications du monde réel.
Quels types d'entrées IronBarcode peut-il traiter dans une API de scanner en C# ?
IronBarcode peut traiter des données de codes-barres provenant de diverses entrées telles que des images et des PDF, offrant des solutions polyvalentes pour différents besoins de numérisation.
Y a-t-il un tutoriel disponible pour construire une API de scanner de codes-barres en utilisant IronBarcode ?
Oui, la page web fournit un tutoriel complet avec des exemples de code pour guider les développeurs dans la construction d'un point de terminaison RESTful de numérisation de codes-barres à l'aide de IronBarcode.
À quelle vitesse une API de scanner de codes-barres peut-elle être configurée en utilisant IronBarcode ?
Avec IronBarcode, les développeurs peuvent configurer une API de scanner de codes-barres en quelques minutes, rationalisant le temps et les efforts de développement.
IronBarcode nécessite-t-il des intégrations complexes de SDK ?
Non, IronBarcode élimine le besoin d'intégrations complexes de SDK de scanner, facilitant l'implémentation de la fonctionnalité de numérisation de codes-barres pour les développeurs.
Quel langage est utilisé avec IronBarcode pour créer une API de scanner ?
IronBarcode est utilisé avec C# pour construire une API de scanner, en s'appuyant sur le cadre .NET pour une performance robuste.



