C#でバーコードスキャナーAPIを構築する(開発者ガイド)
IronBarcodeとASP.NET Coreを使用してRESTfulなバーコードスキャナAPIを作成し、ハードウェアを使用せずに画像、PDF、破損したスキャンデータからバーコードを管理することで、Windows、Linux、macOS全体で信頼性の高いパフォーマンスを保証します。
IronBarcodeは、 ASP.NET CoreのRESTful APIを通じてProfessionalバーコードスキャンを可能にし、ハードウェアに依存することなく画像、PDF、破損したスキャンを処理するとともに、組み込みのセキュリティおよびコンプライアンス機能を備えたクロスプラットフォーム展開をサポートします。
Enterpriseバーコード活用の課題とは?
フォーチュン500に名を連ねる物流企業のEnterpriseアーキテクトになった自分を想像してみてください。 倉庫チームは破損した配送ラベルの処理に苦労し、財務部門はバーコードが埋め込まれた何千もの請求書PDFを処理する必要があり、ITセキュリティチームはグローバルインフラストラクチャ全体にハードウェアの依存関係を導入することなくSOC2コンプライアンスを満たすソリューションを求めている。
これは、 IronBarcodeのREST APIの機能を活用しようとするEnterpriseチームにとってよくあるシナリオです。 当初はバーコードを読み取るという単純な要件だったものが、今では組織全体で毎月200万個以上のバーコードを処理する包括的なスキャンソリューションへと発展した。
従来であれば、各拠点に高価なハードウェアスキャナーを設置し、複雑なドライバー管理を行い、大規模なセキュリティレビューを実施する必要があっただろう。 その代わりに、彼らは中央集権型のRESTful APIを構築し、破損した倉庫ラベルのスキャンや、仕入先からのPDFファイルからの請求書データの抽出など、どの部署でも安全にアクセスできるようにした。
このチュートリアルでは、ProfessionalのバーコードスキャナーAPIを構築する手順を解説します。 破れたラベル、歪んだ画像、複数ページの文書など、現実世界で発生する課題に対応できる安全なエンドポイントを作成する方法を学びます。 さらに重要なのは、Enterprise環境が求めるセキュリティ、拡張性、ベンダーの安定性を確保しながら、これをどのように実装するかを学ぶことができる点です。
信頼性の高いC#スキャナAPIを構築するにはどうすればよいでしょうか?
EnterpriseバーコードスキャナーAPIを開発するには、事前にいくつかの重要な課題に対処する必要があります。 セキュリティチームは、データ処理に関する確証を必要としている。 コンプライアンス担当者は監査証跡を必要とする。 運用チームは、様々なプラットフォーム間での信頼性を求めている。 IronBarcodeの包括的なドキュメントは、これらの懸念事項すべてに体系的に対応しています。
RESTfulアプローチの優れた点は、そのシンプルさとセキュリティにある。 安全なAPIエンドポイントの背後でバーコード処理を一元化することで、データフローを完全に制御できます。 クライアントデバイスは、バーコード処理ロジックに直接アクセスする必要はありません。 このアーキテクチャは、ゼロトラストセキュリティモデルを自然にサポートすると同時に、既存のEnterpriseシステムとのスムーズな統合を可能にします。
まずは基礎から始めましょう。 IronBarcodeの読み取り機能は、Enterpriseが遭遇する可能性のある主要なバーコード形式すべてに対応しています。 製造業で使用される従来型のCode 39バーコードから、マーケティングキャンペーンで使用される最新のQRコードまで、当図書館はあらゆる種類のバーコードを取り扱っています。 対応バーコードフォーマットガイドは、実装計画を立てる上での完全な参考資料となります。
Enterprise環境において特に価値があるのは、このライブラリの耐障害性機能です。 現実世界のバーコードは完璧ではない。 それらは破損したり、印刷状態が悪かったり、斜めにスキャンされたりします。 IronBarcodeの高度な画像処理技術は、これらの課題を自動的に処理することで、サポートチケットの削減と業務効率の向上を実現します。
バーコードライブラリのインストールと設定方法を教えてください
Enterprise向け導入においては、依存関係とライセンスについて慎重に検討する必要がある。 IronBarcodeは、 NuGet簡単なインストールと透明性の高いライセンスによって、このプロセスを簡素化します。 ASP.NET Coreプロジェクトを始めるには、以下の手順に従ってください。
Install-Package IronBarCode
Install-Package IronBarCode
特定のプラットフォーム要件を持つEnterprise環境については、高度なNuGetインストール ガイドを参照してください。 これには、特定 for .NETバージョンをターゲットにする場合や、特定のプラットフォーム向けに最適化する場合などのシナリオが含まれます。
インストールが完了したら、簡単なテストで設定を確認してください。このコードは、最小限の設定でバーコードを読み取るライブラリの機能を示しています。
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
この検証手順は、Enterpriseへの導入において非常に重要です。 これは、ライブラリが正しくインストールされ、ライセンスが付与されており、必要なシステムリソースにアクセスできることを確認するものです。 信頼度スコアの出力は、特定のバーコードタイプに対する基準となる期待値を設定するのに役立ちます。
本番環境への導入にあたっては、ライセンスに関するドキュメントをよく確認してください。 Enterpriseライセンスは、組織内での無制限の導入をサポートしており、複数のデータセンターにわたる拡張に不可欠です。 ライセンスキー構成ガイドでは、環境変数や構成ファイルなど、お客様の慣行に合わせたさまざまなアクティベーション方法について説明しています。
企業向けプラットフォーム互換性
Enterpriseは恐らく、多様な環境を運用しているでしょう。 開発はWindows上で行われ、ステージングはLinuxコンテナ上で実行され、一部のチームはmacOSを使用する場合もある。 IronBarcodeのクロスプラットフォーム互換性により、これらのすべてのプラットフォームで一貫した動作が保証されます。
コンテナ化されたデプロイメントの場合、 DockerセットアップガイドにはLinuxコンテナに関する具体的な手順が記載されています。 これには、依存関係の処理や、効率的なクラウド展開のためのイメージサイズの最適化が含まれます。 AzureまたはAWS Lambdaにデプロイする場合は、プラットフォーム固有のガイドを参照することで、これらの環境で最適なパフォーマンスを確保できます。
このライブラリは、 .NET MAUIとの統合を通じてモバイル環境にも対応しており、現場作業員がモバイルでのスキャン機能を必要とする場合に、 iOSおよびAndroidデバイスにもバーコードスキャン機能を拡張できます。
完全なスキャナAPIコントローラを構築するにはどうすればよいですか?
実際のEnterpriseニーズに対応する、実運用可能なスキャナーAPIを構築しましょう。 この実装には、適切なエラー処理、セキュリティ上の考慮事項、およびパフォーマンスの最適化が含まれています。
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
このProfessional実装には、本番環境への導入に必要な重要な機能がいくつか含まれています。認証機能により、許可されたユーザーのみがスキャンサービスにアクセスできます。リクエストサイズの制限により、サービス拒否攻撃を防止します。 完全なログ記録は、コンプライアンスチームが必要とする監査証跡を提供する。
構造化応答モデルは、バーコード値だけでなく、信頼度スコアと位置情報も返します。 このメタデータは、品質保証プロセスにおいて非常に貴重な情報となる。 サプライヤーのバーコードのスキャン結果の信頼性が低い場合、システムはそれを手動レビューの対象としてフラグ付けすることができます。
Professionalエラー処理
コントローラーが内部例外の詳細をクライアントに公開しないことに注目してください。 これは情報漏洩を防ぐことで、セキュリティのベストプラクティスに準拠しています。 詳細なログ記録により、デバッグに必要なすべての情報が記録される一方で、エラー応答は汎用的なものに抑えられます。
RequestId フィールドを使用すると、分散システム全体にわたるエンドツーエンドのトレースが可能になります。 倉庫作業員からスキャンに関する問題が報告された場合、サポートチームは中央ログシステムから該当するリクエストを迅速に特定できます。 これにより、本番環境における問題解決までの平均時間(MTTR)が劇的に短縮されます。
ProcessingTimeMs によるパフォーマンス監視は、ボトルネックの特定に役立ちます。 特定のバーコードの種類によって処理に時間がかかる場合は、読み取り速度の設定を調整してください。 読書速度の例は、さまざまな設定がパフォーマンスにどのように影響するかを示しています。
さまざまな入力ソースをどのように処理しますか?
Enterpriseシステムでは、単一のフォーマットに標準化されることは稀である。 スキャナーAPIは、高解像度の倉庫カメラから数十年前のファックス機でスキャンした低品質のPDFまで、あらゆるものを処理できる必要があります。 その柔軟性を構築する方法は次のとおりです。
// 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
この包括的な実装は、現実世界のEnterpriseシナリオに対応しています。 URLスキャンエンドポイントには、サーバーサイドリクエストフォージェリ(SSRF)攻撃を防ぐためのドメイン検証機能が含まれています。 Base64ハンドラは、Webアプリケーションから画像を受信する際によく見られる、データURLのプレフィックスを削除します。
破損したバーコードのエンドポイントは、IronBarcodeの画像補正機能を示しています。 複数のフィルターを適用し、さまざまな手法を試みることで、著しく劣化した画像からデータを復元することができる。 これは、古い在庫ラベルや天候によって損傷した出荷書類を扱う際に非常に役立ちます。
PDFスキャンと画像スキャンの選択
PDFファイルは、Enterpriseバーコードスキャンにおいて、特有の課題と機会をもたらす。 請求書、出荷明細書、コンプライアンスフォームなど、多くのビジネス文書は、バーコードが埋め込まれたPDFファイルとして届きます。 IronBarcodeのPDFバーコード読み取り機能は、これらのシナリオに適切に対応します。
典型的なEnterpriseシナリオを考えてみましょう。経理部門には毎月何千もの請求書が届き、それぞれの請求書には自動処理用のバーコードが付いています。 ベンダーによっては高品質のPDFを送信するところもあれば、品質にばらつきのあるスキャン文書を送信するところもある。
高度なPDFスキャンエンドポイントは、どちらのシナリオにも対応します。 高品質のPDFを作成する場合、標準設定で十分です。 スキャンした文書の場合、DPIとスケールパラメータを上げると、検出率が向上します。 ページごとの処理機能を使用すると、特定のページからバーコードを抽出できます。これは、請求書のバーコードが必ず最初のページにあることがわかっている場合に便利です。
ページごとにグループ化された結果は、貴重な情報源となります。 ワークフローシステムは、バーコードが含まれているページに基づいて文書をルーティングし、文書の分類を自動化できます。 この構造化された複数ページ文書処理手法は、手作業によるプロセスを効率的な自動化ワークフローへと変革します。
複数のバーコードを効率的に処理する
Enterprise文書には、異なる目的で使用される複数のバーコードが含まれていることがよくあります。 配送ラベルには、追跡用バーコード、商品バーコード、および配送先バーコードが記載されている場合があります。 複数のバーコードシナリオを適切に処理するには、綿密なAPI設計が必要です。
バッチ処理エンドポイントは、大量のデータを効率的に処理する方法を示しています。 複数のファイルを並列処理することで、全体の処理時間を大幅に短縮できます。Task.WhenAll パターンは、システムの安定性を維持しながら、最適なリソース利用を保証します。
IronBarcodeは、アプリケーション内でバーコードを作成する際にも同様に効果的な機能を提供します。 在庫管理システム用の1次元リニアバーコードを生成する場合でも、モバイルアプリケーション用の2次元マトリックスコードを作成する場合でも、同じシンプルなAPIアプローチが適用されます。
パフォーマンスと精度を向上させるにはどうすればよいでしょうか?
Enterpriseにおけるバーコードスキャン性能の最適化は、単に速度を上げるだけではなく、特定のユースケースに最適なバランスを見つけることが重要です。 以下の例では、スキャン性能を劇的に向上させる高度な最適化手法を紹介します。
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
この高度な最適化手法は、いくつかのProfessional技術を示しています。 インテリジェント設定決定機能は、画像特性を分析し、最適な処理パラメータを自動的に選択します。 最新のカメラで撮影された高解像度画像はより高速な処理が可能であり、低品質のスキャン画像は強化されたフィルタリング処理を受けることができる。
領域ベースのスキャンは、特に大判文書に効果的であることが証明されています。 画像を複数の領域に分割し、それらを並列処理することで、大幅なパフォーマンス向上を実現できます。 この手法は、バーコードの位置が予測可能な標準化された用紙に特に効果的です。
適切な設定を選択する ReadingSpeed
適応型画像処理手法は、成功するまで段階的に積極的な処理技術を試行錯誤する。 これにより、高品質のバーコードに対して可能な限り迅速な処理を保証すると同時に、破損したバーコードも適切に処理することが可能になります。 信頼度閾値機能は、機械学習を用いて結果を検証することで、本番環境における誤検出を低減します。
特定の最適化シナリオについては、以下の表に一般的な使用例と推奨設定を対応付けています。
| 使用事例 | 推奨速度 | その他のオプション | 予想されるトレードオフ |
|---|---|---|---|
| 大量バッチ処理 | `Faster` | 想定されるバーコードタイプでフィルタリング | 最速のスループット。劣化したバーコードは見逃す可能性があります。 |
| 品質の異なる文書 | `Balanced` | 適応型強化フォールバック | スピードと精度のバランスが良い |
| 破損または劣化しているバーコード | `ExtremeDetail` | 完全な画像フィルタパイプライン | 最高精度。処理速度は遅い。 |
| リアルタイムAPIエンドポイント | `Balanced` | キャッシング+領域スキャン | 一貫して200ms未満の応答時間 |
| PDF請求書の抽出 | `Balanced` | DPI 300、スケール 3 | テキストレイヤー付きPDFに最適 |
ベンチマークサービスは、データに基づいた構成に関する意思決定を支援します。 実際のバーコードサンプルを使用してベンチマークを実行し、特定の用途における速度と精度の最適なバランスを見つけてください。 Microsoftが提供するASP.NET Coreのパフォーマンスに関するベストプラクティスといった業界標準のガイダンスは、スキャナAPIエンドポイントのチューニングにも直接適用できます。
画像フィルターの影響
画像フィルターは、認識が難しいバーコードの認識率を劇的に向上させることができます。 画像補正に関するドキュメントには、各フィルターの目的が説明されています。 しかし、フィルターを使用すると処理時間も増加するため、慎重に使用してください。
Enterprise環境への導入においては、階層的なアプローチの導入を検討してください。
- 初回試行時はフィルターなしの高速スキャンを実行
- 最初の試行が失敗した場合は、基本フィルターを適用する。
- 必要な場合にのみ積極的なフィルタリングを使用する
- 再処理を避けるために結果をキャッシュする
この戦略は、困難なケースにも適切に対応しながら、平均応答時間を短縮することを可能にする。 向き補正機能は、ユーザーがデバイスをさまざまな角度で保持する可能性があるモバイル撮影画像において、特に有用であることが証明されています。
C#でQRコード画像を生成するにはどうすればよいですか?
スキャンは非常に重要ですが、多くのEnterpriseアプリケーションではバーコードを生成する必要もあります。 IronBarcodeを使えば、作成も読み取りと同じくらい簡単になります。 さまざまなEnterpriseシナリオに対応したQRコードの生成方法をご紹介します。
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
これらの生成例は、企業固有のユースケースを示しています。 資産追跡用QRコードには、保守履歴と資産管理システムへの直接リンクが含まれています。 来訪者用バッジには、セキュリティ基準遵守のため、有効期限とアクセスレベルが設定されています。 配送ラベルは、運送業者の要件を満たすために、複数のバーコード形式を組み合わせて使用します。
セキュアなドキュメントQRコードの実装例は、機密データの暗号化をどのように統合するかを示しています。 この方法により、たとえ誰かがQRコードを読み取りても、適切な復号鍵がなければ情報にアクセスできないことが保証されます。 これは、コンプライアンス文書、財務記録、または機密通信にとって不可欠である。
次のステップは何ですか?
IronBarcodeを使用してEnterpriseバーコードスキャナーAPIを構築することで、デジタルトランスフォーメーションの取り組みのための信頼性の高い基盤が構築されます。 完全なフォーマットサポート、高度な画像処理、そしてクロスプラットフォーム互換性の組み合わせにより、現代企業の複雑なニーズに対応します。 アーキテクチャを最終決定する前に、 GS1バーコード規格のドキュメントを確認することで、サプライチェーンおよび小売業におけるバーコードのエンコード要件を理解するのに役立ちます。 上記のコントローラーの例で使用されているREST API設計パターンについては、 .NETのRESTful API設計ガイドが実用的な参考資料となります。 コンテナ環境にデプロイする場合、 .NETイメージに関するDockerの公式ドキュメントが、ベースイメージの選択に関する信頼できる情報源となります。
導入にあたっての重要なポイント:
1.セキュリティ第一:最初から適切な認証、入力検証、監査ログを実装する 2.パフォーマンスの最適化:使用状況に応じて適切なスキャン速度とキャッシュ戦略を使用してください。 3.エラー処理:エッジケースを適切に処理し、有意義なフィードバックを提供する、回復力のあるシステムを構築する。 4.スケーラビリティ:非同期パターンと効率的なリソース管理を活用し、水平スケーリングを念頭に設計する
本番環境への導入にあたっては、以下の追加リソースも検討してください。
最新の機能や改善点については、変更履歴をご確認ください。
- 特殊なEnterpriseフォーマットを含む、新しいフォーマットのサポートについて検討する
- デスクトップアプリケーション向けにMSIインストーラーの展開を実装する
- 本番環境向けにライセンスキーを適切に設定する
IronBarcodeのEnterprise機能は、基本的なスキャン機能にとどまりません。 ライブラリのスタイルカスタマイズ機能により、ブランドロゴ入りのバーコードを生成できます。 Unicodeバーコードのサポートにより、グローバルな互換性が確保されます。 バーコードの余白やエラー訂正レベルといった高度な機能により、出力品質をきめ細かく制御できます。
Enterpriseサポートとリソース
ミッションクリティカルなバーコードソリューションを導入する際には、信頼できるサポート体制が重要となる。 IronBarcodeが提供するもの:
- SLA保証付きの専用Enterpriseサポート
- カスタム要件に対するエンジニアリングリクエストサポート
- 定期的なセキュリティアップデートとCVE監視
- 一般的なシナリオに対する包括的なトラブルシューティングガイド
手作業によるバーコード処理から、APIを利用した自動処理への移行は、業務効率を劇的に向上させる。 数千件の出荷書類の処理、来訪者のアクセス管理、Enterprise資産の追跡など、どのような業務であっても、 IronBarcodeはEnterprise環境が求める信頼性と機能を提供します。
バーコード処理を変革する準備はできていますか? 無料トライアルで始めて、Professionalバーコード処理がもたらす違いを実感してください。 完全なAPIドキュメントには詳細な実装ガイダンスが記載されており、サンプルセクションには一般的なシナリオに対応したすぐに使えるコードが提供されています。
Enterpriseには、ニーズに合わせて拡張でき、セキュリティコンプライアンスを維持し、あらゆるプラットフォームで一貫した結果を提供するバーコードソリューションが必要です。 IronBarcodeはまさにそれを提供します。長期的なサポートと継続的な改善に尽力する企業によって支えられています。 今すぐスキャナーAPIの構築を開始し、重要なバーコード処理ニーズにおいてIronBarcodeを信頼している数千もの企業に加わりましょう。
よくある質問
C#でスキャナーAPIを構築するためにIronBarcodeを使用する主な利点は何ですか?
IronBarcodeは、開発者が強力で実用的なバーコードスキャナーAPIを迅速に作成できるようにし、複雑さを最小限に抑えます。複雑なスキャナーSDKの統合を排除することで、プロセスを簡素化します。
IronBarcodeは損傷したバーコード入力を処理できますか?
はい、IronBarcodeは、実際のアプリケーションで高信頼性を確保するために、損傷したスキャン入力からのバーコードデータでも処理するように設計されています。
C#スキャナーAPIでIronBarcodeが処理できる入力タイプは何ですか?
IronBarcode は、画像や PDF などのさまざまな入力からバーコードデータを処理でき、異なるスキャンニーズに対応する柔軟なソリューションを提供します。
IronBarcodeを使用してバーコードスキャナーAPIを構築するためのチュートリアルはありますか?
はい、このウェブページには、IronBarcodeを使用してRESTfulバーコードスキャンエンドポイントを構築するためのコード例を含む包括的なチュートリアルが提供されています。
IronBarcodeを使用してバーコードスキャナーAPIをどのくらい早く設定できますか?
IronBarcodeを使用することで、開発者は数分でバーコードスキャナーAPIを設定でき、開発時間と労力を合理化できます。
IronBarcodeは複雑なSDK統合を必要としますか?
いいえ、IronBarcodeは、複雑なスキャナーSDKの統合を排除し、開発者がバーコードスキャン機能を実装しやすくします。
IronBarcodeを使用してスキャナーAPIを構築する言語は何ですか?
IronBarcodeは、.NETフレームワークを活用して堅牢なパフォーマンスを実現するために、C#で使用されます。



