How to Read Barcodes from Multi-Page Gif and Tiff Images in C#
从Scanbot SDK迁移到 IronBarcode
本指南是为将条形码处理从Scanbot SDK迁移到IronBarcode 的.NET开发团队编写的,适用于服务器端、桌面端或扩展的基于文件的场景。 这并非完全替代:Scanbot SDK 是一个移动摄像头扫描组件,而IronBarcode是一个文件和文档处理库。 此次迁移是由于仅使用摄像头的模型无法满足某些需求而导致的范围变更。 如果团队要替换现有的移动摄像头扫描用户界面,且不增加其他需求,则应在进行迁移之前评估迁移是否合适。
对于最初使用 Scanbot 开发 MAUI 移动应用程序,现在需要在ASP.NET Core、桌面构建或文档管道中进行条形码处理的团队来说,机械迁移非常简单。 核心更改是将source是文件路径、流、字节数组或PDF。
为什么要从Scanbot SDK迁移
服务器端处理要求:Scanbot SDK无法在ASP.NET Core、控制台应用程序、Azure Functions 或任何非 MAUI 项目中编译。 当移动应用程序需要一个服务器端配套程序来处理条形码时——例如从上传的 PDF 中提取条形码或验证传入文档中的条形码值——Scanbot 就无法跨越这个界限。 IronBarcode在所有这些上下文中运行的都是相同的BarcodeReader.Read() API。
桌面MAUI支持:Scanbot的包针对net10.0-ios。 一个MAUI项目如果在其net10.0-maccatalyst,将无法构建桌面目标,因为Scanbot包不为这些平台提供程序集。 IronBarcode除了支持 iOS 和 Android 之外,还支持 Windows 和 macOS MAUI ,这意味着同一个软件包可以在多目标 MAUI 项目中运行,而无需特定于平台的排除或条件引用。
PDF文档工作流程:Scanbot中没有BarcodeScanner.Read(filePath)。 当工作流程发展到需要读取文档上传、扫描图像存档或 PDF 发票中的条形码时,Scanbot 的架构就无法满足需求了。 IronBarcode直接读取 PDF 和图像,每个结果都带有找到条形码的页码。
定价模式可预测性: Scanbot 采用年度固定费用制。 对于某些组织,年度续约是评估替代方案的触发器——尤其是当项目范围已扩大到服务器端或桌面目标,不在Scanbot覆盖范围内。 IronBarcode采用一次性永久购买模式,免去了每年续费的义务。
基本问题
Scanbot SDK 需要实时摄像头画面。 当需求扩展到移动端以外时,现有依赖项中没有等效路径:
// Scanbot SDK: camera-only — no file or server equivalent exists
var configuration = new BarcodeScannerScreenConfiguration
{
BarcodeFormats = new[] { BarcodeFormat.Code128, BarcodeFormat.QrCode }
};
// This call requires iOS or Android hardware and a MAUI camera UI
// It cannot be redirected to a file path, stream, or server context
var result = await ScanbotSDKMain.Barcode.StartScannerAsync(configuration);
// Scanbot SDK: camera-only — no file or server equivalent exists
var configuration = new BarcodeScannerScreenConfiguration
{
BarcodeFormats = new[] { BarcodeFormat.Code128, BarcodeFormat.QrCode }
};
// This call requires iOS or Android hardware and a MAUI camera UI
// It cannot be redirected to a file path, stream, or server context
var result = await ScanbotSDKMain.Barcode.StartScannerAsync(configuration);
Imports System.Threading.Tasks
' Scanbot SDK: camera-only — no file or server equivalent exists
Dim configuration As New BarcodeScannerScreenConfiguration With {
.BarcodeFormats = {BarcodeFormat.Code128, BarcodeFormat.QrCode}
}
' This call requires iOS or Android hardware and a MAUI camera UI
' It cannot be redirected to a file path, stream, or server context
Dim result = Await ScanbotSDKMain.Barcode.StartScannerAsync(configuration)
IronBarcode在任何项目上下文中都接受相同的源类型——文件、流、字节数组或 PDF:
// IronBarcode: the same call works in MAUI, ASP.NET Core, console, WPF, Azure Functions
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// From a file — works on any platform
var results = BarcodeReader.Read("invoice.pdf");
foreach (var result in results)
Console.WriteLine($"Page {result.PageNumber}: {result.Value} ({result.BarcodeType})");
// IronBarcode: the same call works in MAUI, ASP.NET Core, console, WPF, Azure Functions
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// From a file — works on any platform
var results = BarcodeReader.Read("invoice.pdf");
foreach (var result in results)
Console.WriteLine($"Page {result.PageNumber}: {result.Value} ({result.BarcodeType})");
Imports IronBarCode
' IronBarcode: the same call works in MAUI, ASP.NET Core, console, WPF, Azure Functions
License.LicenseKey = "YOUR-LICENSE-KEY"
' From a file — works on any platform
Dim results = BarcodeReader.Read("invoice.pdf")
For Each result In results
Console.WriteLine($"Page {result.PageNumber}: {result.Value} ({result.BarcodeType})")
Next
IronBarcode与 Scanbot SDK:功能对比
| 特征 | Scanbot SDK | IronBarcode |
|---|---|---|
| 从文件路径输入 | 否 | 是 |
| 来自流的输入 | 否 | 是 |
| 从字节数组输入 | 否 | 是 |
| PDF条形码提取 | 否 | 是 |
| 实时相机取景器 | 是 | 否(请使用 MediaPicker) |
| 条形码生成 | 否 | 是 |
| iOS 主界面 | 是 | 是 |
| Android MAUI | 是 | 是 |
| Windows MAUI | 否 | 是 |
| macOS MAUI | 否 | 是 |
| ASP.NET Core。 | 否 | 是 |
| 控制台/服务器 | 否 | 是 |
| Azure / Lambda / Docker | 否 | 是 |
| .NET Framework 4.6.2+ | 否 | 是 |
| 机器学习误差校正 | 否 | 是 |
| 条形码损坏恢复 | 否 | 是 |
| 自动格式检测 | 是 | 是 |
| 一维格式 | 20岁以上 | 30+ |
| 二维格式 | QR码、DataMatrix码、PDF417码、Aztec码 | QR码、DataMatrix码、PDF417码、Aztec码、MaxiCode码 |
| 许可模式 | 年度固定费用 | 一次性永久 |
| 公布价格 | 联系销售 | 是的 ($999–$5,999) |
快速入门:Scanbot SDK 到IronBarcode 的迁移
步骤 1:替换 NuGet 软件包
移除 Scanbot 软件包:
dotnet remove package ScanbotBarcodeSDK.MAUI
dotnet remove package ScanbotBarcodeSDK.MAUI
如果项目在.csproj文件中使用条件包引用,也需移除这些条目:
<PackageReference Include="ScanbotBarcodeSDK.MAUI" Version="8.0.0" />
<PackageReference Include="ScanbotBarcodeSDK.MAUI" Version="8.0.0" />
安装IronBarcode:
dotnet add package IronBarcode
dotnet add package IronBarcode
IronBarcode可在NuGet上获取,并支持.NET 6、7、8、9 和.NET Framework 4.6.2+。 对于一个MAUI多目标项目,单个dotnet add package可以跨所有目标使用——无需平台条件包引用。
步骤 2:更新命名空间
将 Scanbot 命名空间替换为IronBarcode命名空间:
// Remove
using ScanbotSDK.MAUI;
// Add
using IronBarCode;
// Remove
using ScanbotSDK.MAUI;
// Add
using IronBarCode;
Imports IronBarCode
步骤 3:初始化许可证
移除 Scanbot 初始化代码块,并将其替换为IronBarcode许可证密钥。 在应用启动时根据项目类型在Program.cs中添加许可证初始化:
// Remove this
ScanbotSDKMain.Initialize(new SdkConfiguration
{
LicenseKey = "YOUR-SCANBOT-LICENSE-KEY",
LoggingEnabled = false
});
// Add this — one line, placed once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// Remove this
ScanbotSDKMain.Initialize(new SdkConfiguration
{
LicenseKey = "YOUR-SCANBOT-LICENSE-KEY",
LoggingEnabled = false
});
// Add this — one line, placed once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
' Remove this
ScanbotSDKMain.Initialize(New SdkConfiguration With {
.LicenseKey = "YOUR-SCANBOT-LICENSE-KEY",
.LoggingEnabled = False
})
' Add this — one line, placed once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
代码迁移示例
毛伊岛照片拍摄
Scanbot 的扫描调用会打开一个全屏相机界面,并在用户扫描条形码或取消时返回。 IronBarcode不提供相机用户界面; 替换使用MAUI的BarcodeReader.Read()。
Scanbot SDK 方法:
using ScanbotSDK.MAUI;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var configuration = new BarcodeScannerScreenConfiguration
{
BarcodeFormats = new[]
{
BarcodeFormat.Code128,
BarcodeFormat.QrCode,
BarcodeFormat.Ean13
},
FinderAspectRatio = new AspectRatio(1, 1),
TopBarBackgroundColor = Colors.DarkBlue
};
var result = await ScanbotSDKMain.Barcode.StartScannerAsync(configuration);
if (result.Status == OperationResult.Ok)
{
foreach (var barcode in result.Barcodes)
ResultLabel.Text = $"{barcode.Format}: {barcode.Text}";
}
}
using ScanbotSDK.MAUI;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var configuration = new BarcodeScannerScreenConfiguration
{
BarcodeFormats = new[]
{
BarcodeFormat.Code128,
BarcodeFormat.QrCode,
BarcodeFormat.Ean13
},
FinderAspectRatio = new AspectRatio(1, 1),
TopBarBackgroundColor = Colors.DarkBlue
};
var result = await ScanbotSDKMain.Barcode.StartScannerAsync(configuration);
if (result.Status == OperationResult.Ok)
{
foreach (var barcode in result.Barcodes)
ResultLabel.Text = $"{barcode.Format}: {barcode.Text}";
}
}
Imports ScanbotSDK.MAUI
Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
Dim configuration = New BarcodeScannerScreenConfiguration With {
.BarcodeFormats = New BarcodeFormat() {
BarcodeFormat.Code128,
BarcodeFormat.QrCode,
BarcodeFormat.Ean13
},
.FinderAspectRatio = New AspectRatio(1, 1),
.TopBarBackgroundColor = Colors.DarkBlue
}
Dim result = Await ScanbotSDKMain.Barcode.StartScannerAsync(configuration)
If result.Status = OperationResult.Ok Then
For Each barcode In result.Barcodes
ResultLabel.Text = $"{barcode.Format}: {barcode.Text}"
Next
End If
End Sub
IronBarcode方法:
// NuGet: dotnet add package IronBarcode
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var first = results.FirstOrDefault();
ResultLabel.Text = first != null
? $"{first.BarcodeType}: {first.Value}"
: "No barcode found";
}
// NuGet: dotnet add package IronBarcode
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var first = results.FirstOrDefault();
ResultLabel.Text = first != null
? $"{first.BarcodeType}: {first.Value}"
: "No barcode found";
}
Imports IronBarCode
Imports System.IO
Imports System.Linq
Imports System.Threading.Tasks
Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using stream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await stream.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray())
Dim first = results.FirstOrDefault()
ResultLabel.Text = If(first IsNot Nothing, $"{first.BarcodeType}: {first.Value}", "No barcode found")
End Using
End Using
End Sub
用户体验的变化在于,用户将看到系统摄像头屏幕,而不是 Scanbot 的嵌入式取景器以及扫描区域叠加层。 对于商业应用——库存、物流、文档工作流程——系统摄像头已经足够用了。 .NET MAUI条形码扫描器教程涵盖了 iOS 和 Android 目标平台的完整集成模式,包括权限处理。
扫描选项和配置
Scanbot的BarcodeScannerScreenConfiguration控制扫描仪接受哪些格式以及相机UI的外观。 IronBarcode的BarcodeReaderOptions控制图像的分析方式——处理速度、多条码检测和类似参数。 配置概念对应不同的关注点,因为底层操作不同。
Scanbot SDK 方法:
var configuration = new BarcodeScannerScreenConfiguration
{
BarcodeFormats = new[] { BarcodeFormat.Code128, BarcodeFormat.QrCode },
FinderAspectRatio = new AspectRatio(1, 1),
FlashEnabled = false,
OrientationLockMode = OrientationLockMode.Portrait
};
var result = await ScanbotSDKMain.Barcode.StartScannerAsync(configuration);
if (result.Status == OperationResult.Ok)
{
foreach (var barcode in result.Barcodes)
Console.WriteLine($"{barcode.Format}: {barcode.Text}");
}
var configuration = new BarcodeScannerScreenConfiguration
{
BarcodeFormats = new[] { BarcodeFormat.Code128, BarcodeFormat.QrCode },
FinderAspectRatio = new AspectRatio(1, 1),
FlashEnabled = false,
OrientationLockMode = OrientationLockMode.Portrait
};
var result = await ScanbotSDKMain.Barcode.StartScannerAsync(configuration);
if (result.Status == OperationResult.Ok)
{
foreach (var barcode in result.Barcodes)
Console.WriteLine($"{barcode.Format}: {barcode.Text}");
}
Imports System
Imports System.Threading.Tasks
Dim configuration As New BarcodeScannerScreenConfiguration With {
.BarcodeFormats = {BarcodeFormat.Code128, BarcodeFormat.QrCode},
.FinderAspectRatio = New AspectRatio(1, 1),
.FlashEnabled = False,
.OrientationLockMode = OrientationLockMode.Portrait
}
Dim result = Await ScanbotSDKMain.Barcode.StartScannerAsync(configuration)
If result.Status = OperationResult.Ok Then
For Each barcode In result.Barcodes
Console.WriteLine($"{barcode.Format}: {barcode.Text}")
Next
End If
IronBarcode方法:
using IronBarCode;
// Format detection is automatic — BarcodeReaderOptions controls processing behavior
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = false
};
// Combined with the MediaPicker capture pattern
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var photoStream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await photoStream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray(), options);
foreach (var result in results)
Console.WriteLine($"{result.BarcodeType}: {result.Value}");
using IronBarCode;
// Format detection is automatic — BarcodeReaderOptions controls processing behavior
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = false
};
// Combined with the MediaPicker capture pattern
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var photoStream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await photoStream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray(), options);
foreach (var result in results)
Console.WriteLine($"{result.BarcodeType}: {result.Value}");
Imports IronBarCode
Imports System.IO
' Format detection is automatic — BarcodeReaderOptions controls processing behavior
Dim options As New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Balanced,
.ExpectMultipleBarcodes = False
}
' Combined with the MediaPicker capture pattern
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using photoStream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await photoStream.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray(), options)
For Each result In results
Console.WriteLine($"{result.BarcodeType}: {result.Value}")
Next
End Using
End Using
无需指定格式IronBarcode会自动检测所有支持的格式。 与Scanbot配置最直接对应的ExpectMultipleBarcodes(在第一次匹配后继续扫描)。
服务器端 PDF 处理
这种情况在 Scanbot 上没有对应的功能。 借助IronBarcode,为 MAUI 移动应用程序安装的同一个软件包可以从服务器端ASP.NET Core端点的 PDF 中提取条形码,从而为团队提供一个可在两种部署环境中工作的单一条形码依赖项。
Scanbot SDK 方法:
//Scanbot SDKcannot be used here — the package does not compile
// in ASP.NET Core, Azure Functions, console apps, or any non-MAUI project.
// There is no server-side Scanbot equivalent for this endpoint.
//Scanbot SDKcannot be used here — the package does not compile
// in ASP.NET Core, Azure Functions, console apps, or any non-MAUI project.
// There is no server-side Scanbot equivalent for this endpoint.
'Scanbot SDK cannot be used here — the package does not compile
' in ASP.NET Core, Azure Functions, console apps, or any non-MAUI project.
' There is no server-side Scanbot equivalent for this endpoint.
IronBarcode方法:
// NuGet: dotnet add package IronBarcode
// Works in ASP.NET Core, console apps, Azure Functions, Docker — the same package as MAUI
using IronBarCode;
[HttpPost("extract-barcodes")]
public async Task<IActionResult> ExtractBarcodes(IFormFile file)
{
using var ms = new MemoryStream();
await file.CopyToAsync(ms);
// Reads all barcodes from all pages of the uploaded PDF
var results = BarcodeReader.Read(ms.ToArray());
var values = results.Select(r => new
{
r.Value,
Format = r.Format.ToString(),
r.PageNumber
});
return Ok(values);
}
// NuGet: dotnet add package IronBarcode
// Works in ASP.NET Core, console apps, Azure Functions, Docker — the same package as MAUI
using IronBarCode;
[HttpPost("extract-barcodes")]
public async Task<IActionResult> ExtractBarcodes(IFormFile file)
{
using var ms = new MemoryStream();
await file.CopyToAsync(ms);
// Reads all barcodes from all pages of the uploaded PDF
var results = BarcodeReader.Read(ms.ToArray());
var values = results.Select(r => new
{
r.Value,
Format = r.Format.ToString(),
r.PageNumber
});
return Ok(values);
}
Imports IronBarCode
Imports Microsoft.AspNetCore.Mvc
Imports System.IO
Imports System.Threading.Tasks
<HttpPost("extract-barcodes")>
Public Async Function ExtractBarcodes(file As IFormFile) As Task(Of IActionResult)
Using ms As New MemoryStream()
Await file.CopyToAsync(ms)
' Reads all barcodes from all pages of the uploaded PDF
Dim results = BarcodeReader.Read(ms.ToArray())
Dim values = results.Select(Function(r) New With {
.Value = r.Value,
.Format = r.Format.ToString(),
.PageNumber = r.PageNumber
})
Return Ok(values)
End Using
End Function
IronBarcode本机处理多页PDF——每个结果都有一个PageNumber属性,指示找到条码的页面。 PDF 条形码提取指南涵盖了 PDF 读取选项的全部范围,包括页面范围选择和针对大型文档批次的性能调优。
ASP.NET Core后台处理
对于 Azure Functions 或 Worker Services 等批量工作流处理已归档的 PDF 文档, IronBarcode提供了与 MAUI 应用和ASP.NET Core控制器中相同的 API。
Scanbot SDK 方法:
//Scanbot SDKdoes not support this deployment context.
// The package will not compile in Azure Functions or Worker Services.
//Scanbot SDKdoes not support this deployment context.
// The package will not compile in Azure Functions or Worker Services.
'Scanbot SDK does not support this deployment context.
' The package will not compile in Azure Functions or Worker Services.
IronBarcode方法:
// NuGet: dotnet add package IronBarcode
using IronBarCode;
// Azure Function or Worker Service batch processing
public void ProcessInvoiceBatch(IEnumerable<string> filePaths)
{
foreach (var filePath in filePaths)
{
var results = BarcodeReader.Read(filePath);
foreach (var result in results)
Console.WriteLine($"File: {filePath} | Page {result.PageNumber}: {result.Value} ({result.BarcodeType})");
}
}
// NuGet: dotnet add package IronBarcode
using IronBarCode;
// Azure Function or Worker Service batch processing
public void ProcessInvoiceBatch(IEnumerable<string> filePaths)
{
foreach (var filePath in filePaths)
{
var results = BarcodeReader.Read(filePath);
foreach (var result in results)
Console.WriteLine($"File: {filePath} | Page {result.PageNumber}: {result.Value} ({result.BarcodeType})");
}
}
Imports IronBarCode
Public Sub ProcessInvoiceBatch(filePaths As IEnumerable(Of String))
For Each filePath In filePaths
Dim results = BarcodeReader.Read(filePath)
For Each result In results
Console.WriteLine($"File: {filePath} | Page {result.PageNumber}: {result.Value} ({result.BarcodeType})")
Next
Next
End Sub
Scanbot SDKAPI 到IronBarcode映射参考
| Scanbot SDK | IronBarcode |
|---|---|
ScanbotSDKMain.Initialize(new SdkConfiguration { LicenseKey = "..." }) |
IronBarCode.License.LicenseKey = "key" |
new BarcodeScannerScreenConfiguration() |
new BarcodeReaderOptions() |
ScanbotSDKMain.Barcode.StartScannerAsync(configuration) |
BarcodeReader.Read(path / stream / bytes) |
result.Status == OperationResult.Ok |
results.FirstOrDefault() != null |
result.Barcodes |
BarcodeReader.Read()的返回值 |
barcode.Format |
result.BarcodeType (IronBarCode.BarcodeEncoding) |
barcode.Text |
result.Value |
BarcodeFormat.Code128 |
BarcodeEncoding.Code128 |
BarcodeFormat.QrCode |
BarcodeEncoding.QRCode |
BarcodeFormat.Ean13 |
BarcodeEncoding.EAN13 |
BarcodeScannerScreenConfiguration.FinderAspectRatio |
没有等效项——图像取景由 MediaPicker 处理 |
BarcodeScannerScreenConfiguration.FlashEnabled |
没有等效选项——请使用 MediaPicker 选项 |
| 摄像头所需输入 | 文件路径、流、字节数组或 PDF |
| iOS 和 Android MAUI 系统 | 所有.NET平台和项目类型 |
常见迁移问题和解决方案
问题一:没有实时取景器
Scanbot SDK:在扫描体验中嵌入实时摄像头取景器,提供扫描区域叠加、触觉反馈和实时视频流中的连续条形码检测。
解决方案:使用MAUI的MediaPicker.CapturePhotoAsync()打开系统相机并捕获静止图像进行处理:
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
Imports System.IO
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using stream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await stream.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray())
End Using
End Using
对于商业应用而言,该系统摄像头已经足够用了。 对于以实时叠加层为用户体验核心的消费者应用,在决定迁移之前,请评估此用户体验变更是否可以接受。
问题二:相机权限差异
Scanbot SDK: Scanbot 软件包在其 UI 流程中处理相机权限请求,因此相机权限由 SDK 初始化和扫描仪启动隐式管理。
解决方案:使用MediaPicker,MAUI通过标准机制处理权限。 验证NSCameraUsageDescription密钥。 这些条目通常存在于已搭建好的 MAUI 项目模板中。 如果该应用之前仅使用 Scanbot 进行摄像头访问,请在测试前确认以下清单条目已存在:
<uses-permission android:name="android.permission.CAMERA" />
<key>NSCameraUsageDescription</key>
<string>This app uses the camera to scan barcodes.</string>
<uses-permission android:name="android.permission.CAMERA" />
<key>NSCameraUsageDescription</key>
<string>This app uses the camera to scan barcodes.</string>
问题 3:Windows 构建错误已清除
Scanbot SDK:TargetFrameworks时构建失败。
解决方法:移除 Scanbot 程序包引用即可解决 Windows 构建失败问题。 IronBarcode在所有 MAUI 目标平台上都能正确解析,无需任何平台相关的配置:
# Verify the build succeeds on all targets after removing Scanbot and adding IronBarcode
dotnet build -f net10.0-windows10.0.19041.0
dotnet build -f net10.0-ios
dotnet build -f net10.0-android
# Verify the build succeeds on all targets after removing Scanbot and adding IronBarcode
dotnet build -f net10.0-windows10.0.19041.0
dotnet build -f net10.0-ios
dotnet build -f net10.0-android
问题 4:枚举命名空间格式更改
Scanbot SDK:使用ScanbotBarcodeSDK.MAUI命名空间。
解决方案:IronBarcode在BarcodeEncoding枚举。 更新所有格式引用以及任何存储、比较或切换格式枚举值的代码:
// Before (Scanbot)
BarcodeFormat.Code128
BarcodeFormat.QrCode
BarcodeFormat.Ean13
// After (IronBarcode)
BarcodeEncoding.Code128
BarcodeEncoding.QRCode
BarcodeEncoding.EAN13
// Before (Scanbot)
BarcodeFormat.Code128
BarcodeFormat.QrCode
BarcodeFormat.Ean13
// After (IronBarcode)
BarcodeEncoding.Code128
BarcodeEncoding.QRCode
BarcodeEncoding.EAN13
' Before (Scanbot)
BarcodeFormat.Code128
BarcodeFormat.QrCode
BarcodeFormat.Ean13
' After (IronBarcode)
BarcodeEncoding.Code128
BarcodeEncoding.QRCode
BarcodeEncoding.EAN13
请注意,IronBarcode默认自动检测所有支持的格式——只有在提前知道预期格式时,为了性能优化才需要通过BarcodeReaderOptions进行显式格式过滤。
Scanbot SDK迁移清单
迁移前任务
审核代码库,找出所有Scanbot SDK的使用情况:
grep -rn "ScanbotSDK.Initialize" --include="*.cs" .
grep -rn "BarcodeScannerScreenConfiguration" --include="*.cs" .
grep -rn "ScanbotSDKMain.Barcode.StartScannerAsync" --include="*.cs" .
grep -rn "result\.Barcodes" --include="*.cs" .
grep -rn "barcode\.Format" --include="*.cs" .
grep -rn "barcode\.Text" --include="*.cs" .
grep -rn "OperationResult\.Ok" --include="*.cs" .
grep -rn "using ScanbotBarcodeSDK" --include="*.cs" .
grep -rn "BarcodeFormat\." --include="*.cs" .
grep -rn "ScanbotSDK.Initialize" --include="*.cs" .
grep -rn "BarcodeScannerScreenConfiguration" --include="*.cs" .
grep -rn "ScanbotSDKMain.Barcode.StartScannerAsync" --include="*.cs" .
grep -rn "result\.Barcodes" --include="*.cs" .
grep -rn "barcode\.Format" --include="*.cs" .
grep -rn "barcode\.Text" --include="*.cs" .
grep -rn "OperationResult\.Ok" --include="*.cs" .
grep -rn "using ScanbotBarcodeSDK" --include="*.cs" .
grep -rn "BarcodeFormat\." --include="*.cs" .
- 记录所有扫描调用点,并注明它们是在共享代码、平台特定代码还是 UI 事件处理程序中。
- 确定是否有任何页面或流程依赖 Scanbot 的实时取景器作为主要用户交互方式。
- 确认
Info.plist中存在相机权限条目 - 查看
.csproj中与Scanbot相关的任何条件包引用
代码更新任务
- 移除
ScanbotSDK.MAUINuGet包 - 从
<PackageReference>条目 - 安装
IronBarcodeNuGet包 - 在所有文件中将
using IronBarCode; - 在应用启动时将
IronBarCode.License.LicenseKey = "key" - 在MAUI相机工作流程中将
BarcodeReader.Read(bytes) - 在服务器端和文件处理环境中将
BarcodeReader.Read(stream) - 将
results.FirstOrDefault() != null - 将
BarcodeReader.Read()的返回值 - 将
result.Value - 将
BarcodeEncoding.</em>等效值 - 在需要处理选项的地方,将
new BarcodeReaderOptions()
迁移后测试
- 验证在所有 MAUI 目标平台上构建是否成功,包括 Windows 和 macOS(如果存在)。
- 在实体iOS设备和实体安卓设备上测试
MediaPicker.CapturePhotoAsync()流程 - 确认IronBarcode解码的条形码值与Scanbot之前对同一物理条形码解码的值一致。
- 如果项目包含文档处理工作流程,请测试多页PDF提取功能
- 验证格式检测涵盖
BarcodeScannerScreenConfiguration.BarcodeFormats中以前配置的所有条码类型 - 确认服务器端端点或后台作业对同一文档样本产生正确的结果
- 验证在 iOS 和 Android 设备上首次启动时,相机权限提示是否正确显示
迁移到IronBarcode的主要优势
跨所有部署目标的统一软件包: IronBarcode安装一次即可在 MAUI 移动应用、MAUI 桌面应用、 ASP.NET Core、Azure Functions、控制台应用和 Windows 桌面应用中运行。 团队不再需要为同一系统的不同部分分别配备条形码。
PDF 和文档处理: IronBarcode可以直接从 PDF 文件中读取条形码,每个结果都带有找到它的页码。 在Scanbot模型中以前不可能的文档工作流程,通过BarcodeReader.Read("document.pdf")变得简单。
Windows 和 macOS 桌面 MAUI 支持:多目标 MAUI 项目,包括 Windows 或 macOS 构建,在移除 Scanbot 后不会出现错误。 IronBarcode在所有四个 MAUI 目标上提供相同的条形码读取 API,消除了 Scanbot 所需的平台条件依赖性管理。
永久许可所有权:一次性购买模式免除了每年续费的义务。 获得授权后, IronBarcode即可在购买的级别上无限期使用,无需支付任何续费。 项目范围超出 Scanbot 移动覆盖范围的团队发现,永久模式更符合长期成本规划。
条形码生成: IronBarcode可以生成所有受支持格式的条形码,例如图像文件、流或嵌入式内容。 既需要读取又需要生成的项目不再需要除了 Scanbot 之外的第二个库。
机器学习辅助读取: IronBarcode应用基于机器学习的错误纠正和损坏条形码恢复技术,用于处理标准检测算法无法解码的复杂真实世界图像(低对比度、部分损坏、打印质量差)。 此功能对于图像质量不稳定的文档处理工作流程尤为重要。
常见问题解答
我为什么要从 Scanbot SDK 迁移到 IronBarcode?
常见原因包括简化许可(消除 SDK + 运行时密钥的复杂性)、消除吞吐量限制、获得原生 PDF 支持、改进 Docker/CI/CD 部署以及减少生产代码中的 API 样板代码。
如何用 IronBarcode 替换 Scanbot API 调用?
用 `IronBarCode.License.LicenseKey = "key"` 替换实例创建和许可相关的样板代码。用 `BarcodeReader.Read(path)` 替换读取器调用,用 `BarcodeWriter.CreateBarcode(data, encoding)` 替换写入器调用。静态方法无需实例管理。
从 Scanbot SDK 迁移到 IronBarcode 时,需要修改多少代码?
大多数迁移都能减少代码行数。许可样板代码、实例构造函数和显式格式配置都被移除。核心读/写操作映射到更简洁的 IronBarcode 等效代码,并生成更清晰的结果对象。
迁移过程中是否需要同时安装 Scanbot SDK 和 IronBarcode?
不。大多数迁移都是直接替换,而不是并行操作。一次迁移一个服务类,替换 NuGet 引用,并更新实例化和 API 调用模式,然后再迁移下一个类。
IronBarcode 的 NuGet 包名称是什么?
该软件包名为“IronBarCode”(B 和 C 大写)。使用“Install-Package IronBarCode”或“dotnet add package IronBarCode”进行安装。代码中的 using 指令为“using IronBarCode;”。
与 Scanbot SDK 相比,IronBarcode 如何简化 Docker 部署?
IronBarcode 是一个 NuGet 包,不包含任何外部 SDK 文件或已挂载的许可证配置。在 Docker 环境中,设置 IRONBARCODE_LICENSE_KEY 环境变量后,该包会在启动时自动处理许可证验证。
从 Scanbot 迁移后,IronBarcode 是否能自动检测所有条形码格式?
是的。IronBarcode 可以自动检测所有支持格式的条码符号,无需显式枚举 BarcodeTypes。如果已知条码格式且性能至关重要,BarcodeReaderOptions 允许缩小搜索范围以进行优化。
IronBarcode 能否在不使用单独库的情况下读取 PDF 中的条形码?
是的。`BarcodeReader.Read("document.pdf")` 可以直接处理 PDF 文件。结果包括每个条形码的页码、格式、值和置信度。无需外部 PDF 渲染步骤。
IronBarcode如何处理并行条码处理?
IronBarcode 的静态方法是无状态且线程安全的。可以直接对文件列表使用 Parallel.ForEach,无需进行线程级实例管理。BarcodeReaderOptions.MaxParallelThreads 控制内部线程预算。
从 Scanbot SDK 迁移到 IronBarcode 时,哪些结果属性会发生变化?
常见重命名:BarcodeValue 变为 Value,BarcodeType 变为 Format。IronBarcode 结果还会添加 Confidence 和 PageNumber。解决方案范围内的查找替换功能会处理现有结果处理代码中的重命名。
如何在 CI/CD 流水线中设置 IronBarcode 许可?
将 IRONBARCODE_LICENSE_KEY 存储为管道密钥,并在应用程序启动代码中赋值 IronBarCode.License.LicenseKey。一个密钥即可覆盖所有环境,包括开发、测试、预发布和生产环境。
IronBarcode是否支持生成自定义样式的二维码?
是的。QRCodeWriter.CreateQrCode() 支持通过 ChangeBarCodeColor() 自定义颜色、通过 AddBrandLogo() 嵌入徽标、可配置纠错级别以及多种输出格式,包括 PNG、JPG、PDF 和流媒体。

