Przejdź do treści stopki
FILMY

Jak odczytywać BarCodes z plików PDF w języku C#

Migrating from BarcodeScanning.Native.Maui to IronBarcode

Niniejszy przewodnik przedstawia kompletną ścieżkę migracji z BarcodeScanning.Native.Maui do IronBarcode, obejmującą zastąpienie wzorca zdarzeń kamery, zmiany przestrzeni nazw, przykłady migracji kodu oraz obsługę scenariuszy, których BarcodeScanning.Native.Maui nie jest w stanie obsłużyć — Windows MAUI, wprowadzanie plików i PDF, przetwarzanie po stronie serwera oraz generowanie kodów kreskowych.

Dlaczego warto przejść z BarcodeScanning.MAUI

Zespoły migrujące z BarcodeScanning.Native.Maui zgłaszają następujące wyzwałącze:

Wymagany cel Windows MAUI: BarcodeScanning.Native.Maui obsługuje natywne interfejsy API systemów iOS i Android. Nie ma implementacji dla systemu Windows i nie jest ona planowana. Jeśli Twoja aplikacja MAUI jest przeznaczona dla systemów Windows, iOS i Android, potrzebujesz biblioteki, która działa na wszystkich trzech platformach bez konieczności tworzenia odgałęzień specyficznych dla danej platformy.

Dodano plik lub dane wejściowe w formacie PDF do wymagań: BarcodeScanning.Native.Maui akceptuje wyłącznie klatki z kamery na żywo. Gdy użytkownicy muszą przesłać obraz z galerii lub gdy punkt końcowy po stronie serwera musi wyodrębnić BARCODE-y z plików PDF, biblioteka nie oferuje żadnej ścieżki kodu. Każdy scenariusz dotyczący plików lub BarCodes w formacie PDF wymaga innego narzędzia.

Dane UPC-A w systemie iOS były błędne w środowisku produkcyjnym: framework Apple Vision zwraca 13 cyfr dla BARCODE-ów UPC-A (kodowanie EAN-13). BarcodeScanning.Native.Maui przekazuje to bez poprawek. Gdyby kody UPC-A były przechowywane z zerem na początku, mogłoby to spowodować niepostrzeżone zakłócenia w rejestrach zapasów, wyszukiwaniu w punktach sprzedaży lub integracji łańcucha dostaw.IronBarcode zwraca prawidłową 12-cyfrową wartość UPC-A bez konieczności ręcznej normalizacji.

Skanowanie PDF417 było zawodne: W dokumentacji biblioteki na GitHubie PDF417 jest opisany jako "bardzo problematyczny — większość skanów nigdy nie dochodzi do skutku". W przypadku etykiet wysyłkowych, praw jazdy i kart pokładowych stanowi to bezpośrednią przeszkodę.

Wymagane generowanie: BarcodeScanning.Native.Maui nie może generować kodów kreskowych.IronBarcode generuje kody Code128, QR, DataMatrix i inne formaty jako pliki graficzne lub tablice bajtów.

Wprowadzenie przetwarzania po stronie serwera: BarcodeScanning.Native.Maui to kontrolka interfejsu użytkownika kamery — nie może działać w procesie serwera. Gdy oprócz skanowania mobilnego wymagane jest odczytywanie kodów kreskowych po stronie serwera,IronBarcode obsługuje obie strony za pomocą tego samego pakietu i tego samego interfejsu API.

Podstawowy problem

BarCodeScanning.Native.Maui całkowicie wiąże odczyt kodów kreskowych z modelem zdarzeń na żywo z kamery. W momencie, gdy jakikolwiek wymóg wykracza poza ten model, biblioteka nie oferuje nic:

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        ResultLabel.Text = barcode.DisplayValue;
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        ResultLabel.Text = barcode.DisplayValue;
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    Dim barcode = e.BarcodeResults.FirstOrDefault()
    If barcode IsNot Nothing Then
        ResultLabel.Text = barcode.DisplayValue
    End If
End Sub
$vbLabelText   $csharpLabel

IronBarcode akceptuje dowolne dane wejściowe — zdjęcia z aparatu, pliki, PDF, tablice bajtów — i działa na każdej platformie:

using IronBarCode;

private async void ScanBarcodeButton_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());
    ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
using IronBarCode;

private async void ScanBarcodeButton_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());
    ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
Imports IronBarCode

Private Async Sub ScanBarcodeButton_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())
            ResultLabel.Text = If(results.FirstOrDefault()?.Value, "No barcode found")
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

IronBarcode a BarcodeScanning.MAUI: Porównanie funkcji

Funkcja BarcodeScanning.MAUI IronBarcode
Odczytywanie klatek z kamery na żywo Tak — kontrolka CameraView Nie (użyj MediaPicker do przechwycenia, a następnie odczytania)
Wizjer aparatu w aplikacji Tak — w czasie rzeczywistym, w sposób ciągły Nie — korzysta z interfejsu użytkownika aparatu systemowego za pośrednictwem MediaPicker
Odczyt z pliku graficznego Nie Tak — BarcodeReader.Read(path)
Odczyt z tablicy bajtów Nie Tak — BarcodeReader.Read(bytes)
Odczyt z strumienia Nie Tak — BarcodeReader.Read(stream)
Czytaj z pliku PDF Nie Tak — BarcodeReader.Read(pdf)
Generowanie BarCode Nie Tak — BarcodeWriter + QRCodeWriter
Obsługa Windows MAUI Nie Tak
Obsługa iOS MAUI Tak Tak
Obsługa MAUI w systemie Android Tak Tak
Obsługa macOS MAUI Brak dokumentacji Tak
Po stronie serwera / ASP.NET Nie Tak
Docker / Azure / AWS Lambda Nie Tak
Dokładność iOS UPC-A Zwraca 13 cyfr (błąd), wymaga ręcznej normalizacji Zwraca poprawny 12-cyfrowy kod UPC-A
Niezawodność PDF417 "Większość skanów nigdy nie ma miejsca" (zgłoszenia na GitHubie) Obsługiwane
Wykrywanie wielu kodów BarCode Tak (wiele na ramkę za pomocą e.BarcodeResults) Tak (opcja ExpectMultipleBarcodes)
Kontrola prędkości czytania None ReadingSpeed.Faster / Balanced / Detailed / ExtremeDetail
Licencja MIT (open source, bezpłatne) Wersja komercyjna — Lite 749 USD, Plus 1499 USD, Professional 2999 USD, Unlimited 5999 USD
Obsługa platformy .NET Framework Nie (tylko MAUI) Tak — .NET Framework 4.6.2+

Szybki start: Migracja z BarcodeScanning.MAUI do IronBarcode

Krok 1: Zastąp pakiet NuGet

Usuń BarcodeScanning.Native.Maui:

dotnet remove package BarcodeScanning.Native.Maui
dotnet remove package BarcodeScanning.Native.Maui
SHELL

Zainstaluj IronBarcode:

dotnet add package IronBarcode
dotnet add package IronBarcode
SHELL

Krok 2: Aktualizacja przestrzeni nazw

Usuń przestrzeń nazw BarcodeScanning ze wszystkich plików:

// Remove
using BarcodeScanning;
// Remove
using BarcodeScanning;
Imports BarcodeScanning
$vbLabelText   $csharpLabel

Dodaj przestrzeń nazw IronBarcode:

// Add
using IronBarCode;
// Add
using IronBarCode;
Imports IronBarCode
$vbLabelText   $csharpLabel

W plikach XAML usuń deklarację przestrzeni nazw XML scanner::


xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui"

xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui"
XML

Krok 3: Inicjalizacja licencji

Dodaj inicjalizację licencji przy starcie aplikacji — w MauiProgram.cs lub App.xaml.cs:

IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode

IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Przykłady migracji kodu

Skanowanie kamerą: CameraView do MediaPicker

Kontrola CameraView zapewniał celownik o rzeczywistym podglądzie z ciągłym wykrywaniem ramek. Zamiennik IronBarcode używa MediaPicker MAUI do otwarcia systemowej kamery, zrobienia zdjęcia i przetworzenia wynikowego obrazu.

Podejście BarcodeScanning.MAUI — XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui">
    <StackLayout>
        <scanner:CameraView x:Name="CameraView"
                            OnDetectionFinished="OnBarcodeDetected"
                            CameraEnabled="True"
                            BarcodeFormats="All"
                            VerticalOptions="FillAndExpand" />
        <Label x:Name="ResultLabel" Text="Waiting for scan..." />
    </StackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui">
    <StackLayout>
        <scanner:CameraView x:Name="CameraView"
                            OnDetectionFinished="OnBarcodeDetected"
                            CameraEnabled="True"
                            BarcodeFormats="All"
                            VerticalOptions="FillAndExpand" />
        <Label x:Name="ResultLabel" Text="Waiting for scan..." />
    </StackLayout>
</ContentPage>
XML

Podejście BarcodeScanning.MAUI — kod źródłowy:

using BarcodeScanning;

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = barcode.DisplayValue);
}
using BarcodeScanning;

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = barcode.DisplayValue);
}
Imports BarcodeScanning

Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    Dim barcode = e.BarcodeResults.FirstOrDefault()
    If barcode IsNot Nothing Then
        MainThread.BeginInvokeOnMainThread(Sub()
                                               ResultLabel.Text = barcode.DisplayValue
                                           End Sub)
    End If
End Sub
$vbLabelText   $csharpLabel

Podejście IronBarcode— XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
    <StackLayout>
        <Button Text="Scan Barcode" Clicked="ScanButton_Clicked" />
        <Label x:Name="ResultLabel" Text="Tap to scan..." />
    </StackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
    <StackLayout>
        <Button Text="Scan Barcode" Clicked="ScanButton_Clicked" />
        <Label x:Name="ResultLabel" Text="Tap to scan..." />
    </StackLayout>
</ContentPage>
XML

Podejście IronBarcode— kod źródłowy:

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?.Value ?? "No barcode found";
}
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?.Value ?? "No barcode found";
}
Imports IronBarCode
Imports System.IO
Imports System.Linq

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?.Value, "No barcode found")
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

Ten kod działa na systemach iOS, Android i Windows MAUI bez żadnych rozgałęzień specyficznych dla danej platformy. Doświadczenie użytkownika zmienia się z podglądu na żywo w aplikacji na natywny ekran aparatu platformy — odpowiedni dla większości aplikacji biznesowych. Przewodnik użytkownika IronBarcode MAUI zawiera informacje o dodatkowych opcjach konfiguracyjnych.

Obsługa wielu BarCodes w jednym skanowaniu

Podejście BarcodeScanning.MAUI:

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    foreach (var barcode in e.BarcodeResults)
    {
        MainThread.BeginInvokeOnMainThread(() =>
            Console.WriteLine($"Found: {barcode.DisplayValue}"));
    }
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    foreach (var barcode in e.BarcodeResults)
    {
        MainThread.BeginInvokeOnMainThread(() =>
            Console.WriteLine($"Found: {barcode.DisplayValue}"));
    }
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    For Each barcode In e.BarcodeResults
        MainThread.BeginInvokeOnMainThread(Sub()
                                               Console.WriteLine($"Found: {barcode.DisplayValue}")
                                           End Sub)
    Next
End Sub
$vbLabelText   $csharpLabel

Podejście 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 options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    var results = BarcodeReader.Read(ms.ToArray(), options);
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
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 options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    var results = BarcodeReader.Read(ms.ToArray(), options);
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
Imports IronBarCode
Imports System.IO

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 options As New BarcodeReaderOptions With {
                .Speed = ReadingSpeed.Balanced,
                .ExpectMultipleBarcodes = True
            }

            Dim results = BarcodeReader.Read(ms.ToArray(), options)
            For Each result In results
                Console.WriteLine($"{result.Format}: {result.Value}")
            Next
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

ExpectMultipleBarcodes = true mówi użytkownikowi, aby kontynuował skanowanie po znalezieniu pierwszego kodu kreskowego. Bez tej opcji wywołanie zwraca wynik przy pierwszym dopasowaniu, co jest szybsze w przypadku scenariuszy z jednym BARCODE-em.

Poprawka iOS UPC-A: Usunięcie obejścia normalizacji

Jeśli w Twoim kodzie występuje obejście dotyczące zer wiodących w kodach UPC-A, usuń je całkowicie.IronBarcode zwraca prawidłową 12-cyfrową wartość bez żadnej ręcznej interwencji.

Podejście BarcodeScanning.MAUI — zastosowane obejście:

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode == null) return;

    var value = barcode.DisplayValue;

    // Workaround: Apple Vision returns 13 digits for UPC-A
    if (barcode.BarcodeFormat == BarcodeFormats.Upca && value.Length == 13)
        value = value.Substring(1);

    ProcessBarcode(value, barcode.BarcodeFormat.ToString());
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode == null) return;

    var value = barcode.DisplayValue;

    // Workaround: Apple Vision returns 13 digits for UPC-A
    if (barcode.BarcodeFormat == BarcodeFormats.Upca && value.Length == 13)
        value = value.Substring(1);

    ProcessBarcode(value, barcode.BarcodeFormat.ToString());
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    Dim barcode = e.BarcodeResults.FirstOrDefault()
    If barcode Is Nothing Then Return

    Dim value = barcode.DisplayValue

    ' Workaround: Apple Vision returns 13 digits for UPC-A
    If barcode.BarcodeFormat = BarcodeFormats.Upca AndAlso value.Length = 13 Then
        value = value.Substring(1)
    End If

    ProcessBarcode(value, barcode.BarcodeFormat.ToString())
End Sub
$vbLabelText   $csharpLabel

Podejście IronBarcode— nie wymaga żadnych obejść:

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();
    if (first == null) return;

    // result.Value is the correct 12-digit UPC-A — no normalization needed
    ProcessBarcode(first.Value, first.Format.ToString());
}
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();
    if (first == null) return;

    // result.Value is the correct 12-digit UPC-A — no normalization needed
    ProcessBarcode(first.Value, first.Format.ToString());
}
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()
            If first Is Nothing Then Return

            ' result.Value is the correct 12-digit UPC-A — no normalization needed
            ProcessBarcode(first.Value, first.Format.ToString())
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

Usuń wszelkie dopasowania dla BarcodeFormats.Upca sparowanego z Substring(1) — ten kod jest nieaktywny po migracji.

Dodanie obsługi plików i formatu PDF

BarcodeScanning.Native.Maui nie ma odpowiednika dla plików lub danych wejściowych w formacie PDF. Jeśli jest to nowe wymaganie, które ma zostać spełnione w momencie migracji:

Podejście BarcodeScanning.MAUI:

// Nie equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
// Nie equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
' No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
$vbLabelText   $csharpLabel

Podejście IronBarcode:

using IronBarCode;

// Read from a file the user picked with FilePicker
private async void ReadFileButton_Clicked(object sender, EventArgs e)
{
    var file = await FilePicker.PickAsync(new PickOptions
    {
        PickerTitle = "Select image or PDF"
    });
    if (file == null) return;

    var results = BarcodeReader.Read(file.FullPath);
    foreach (var result in results)
        ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}

// Read barcodes from a PDF directly — no intermediate image step
private void ReadPdfBarcodes()
{
    var results = BarcodeReader.Read("shipment-manifest.pdf");
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
using IronBarCode;

// Read from a file the user picked with FilePicker
private async void ReadFileButton_Clicked(object sender, EventArgs e)
{
    var file = await FilePicker.PickAsync(new PickOptions
    {
        PickerTitle = "Select image or PDF"
    });
    if (file == null) return;

    var results = BarcodeReader.Read(file.FullPath);
    foreach (var result in results)
        ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}

// Read barcodes from a PDF directly — no intermediate image step
private void ReadPdfBarcodes()
{
    var results = BarcodeReader.Read("shipment-manifest.pdf");
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
Imports IronBarCode

' Read from a file the user picked with FilePicker
Private Async Sub ReadFileButton_Clicked(sender As Object, e As EventArgs)
    Dim file = Await FilePicker.PickAsync(New PickOptions With {
        .PickerTitle = "Select image or PDF"
    })
    If file Is Nothing Then Return

    Dim results = BarcodeReader.Read(file.FullPath)
    For Each result In results
        ResultLabel.Text &= vbCrLf & $"{result.Format}: {result.Value}"
    Next
End Sub

' Read barcodes from a PDF directly — no intermediate image step
Private Sub ReadPdfBarcodes()
    Dim results = BarcodeReader.Read("shipment-manifest.pdf")
    For Each result In results
        Console.WriteLine($"{result.Format}: {result.Value}")
    Next
End Sub
$vbLabelText   $csharpLabel

Dokumentacja dotycząca odczytu plików PDF w IronBarcode obejmuje obsługę wielostronicowych plików PDF oraz wybór zakresu stron.

Przetwarzanie BarCodes po stronie serwera

Jeśli twoja aplikacja ma backend API ASP.NET, który również wymaga przetwarzania kodów kreskowych, to samo wywołanie BarcodeReader.Read() działa tam bez modyfikacji. BarcodeScanning.Native.Maui nie ma odpowiednika po stronie serwera.

Podejście BarcodeScanning.MAUI:

// Nie equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
// and cannot run in a server process
// Nie equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
// and cannot run in a server process
' No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
' and cannot run in a server process
$vbLabelText   $csharpLabel

Podejście IronBarcode:

using IronBarCode;

// ASP.NET endpoint — reads barcodes from an uploaded file
[HttpPost("scan")]
public async Task<IActionResult> ScanBarcode(IFormFile file)
{
    using var ms = new MemoryStream();
    await file.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var values = results.Select(r => new { r.Value, Format = r.Format.ToString() });
    return Ok(values);
}
using IronBarCode;

// ASP.NET endpoint — reads barcodes from an uploaded file
[HttpPost("scan")]
public async Task<IActionResult> ScanBarcode(IFormFile file)
{
    using var ms = new MemoryStream();
    await file.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var values = results.Select(r => new { r.Value, Format = r.Format.ToString() });
    return Ok(values);
}
Imports IronBarCode
Imports Microsoft.AspNetCore.Mvc
Imports System.IO
Imports System.Threading.Tasks

' ASP.NET endpoint — reads barcodes from an uploaded file
<HttpPost("scan")>
Public Async Function ScanBarcode(file As IFormFile) As Task(Of IActionResult)
    Using ms As New MemoryStream()
        Await file.CopyToAsync(ms)

        Dim results = BarcodeReader.Read(ms.ToArray())
        Dim values = results.Select(Function(r) New With {Key .Value = r.Value, Key .Format = r.Format.ToString()})
        Return Ok(values)
    End Using
End Function
$vbLabelText   $csharpLabel

Ten sam pakiet, to samo API, to samo działanie — na urządzeniach mobilnych i serwerach.

Generowanie BarCodes

BarcodeScanning.Native.Maui nie posiada API do generowania.IronBarcode generuje wiele formatów.

Podejście BarcodeScanning.MAUI:

// Nie equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
// Nie equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
$vbLabelText   $csharpLabel

Podejście IronBarcode:

using IronBarCode;

// QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500)
    .SaveAsPng("qr.png");

// Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ResizeTo(400, 100)
    .SaveAsPng("label.png");

// Get bytes for returning from an API or storing in a database
byte[] barcodeBytes = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ToPngBinaryData();
using IronBarCode;

// QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500)
    .SaveAsPng("qr.png");

// Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ResizeTo(400, 100)
    .SaveAsPng("label.png");

// Get bytes for returning from an API or storing in a database
byte[] barcodeBytes = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ToPngBinaryData();
Imports IronBarCode

' QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500) _
    .SaveAsPng("qr.png")

' Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128) _
    .ResizeTo(400, 100) _
    .SaveAsPng("label.png")

' Get bytes for returning from an API or storing in a database
Dim barcodeBytes As Byte() = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128) _
    .ToPngBinaryData()
$vbLabelText   $csharpLabel

Dokumentacja dotycząca generowania kodów kreskowych IronBarcode obejmuje wszystkie obsługiwane formaty i opcje stylizacji.

BarcodeScanning.MAUI API do dokumentacji IronBarcode Mapping Reference

BarcodeScanning.Native.Maui IronBarcode
CameraView kontrola XAML Usuń — użyj Button + MediaPicker.CapturePhotoAsync()
OnDetectionFinished zdarzenie BarcodeReader.Read(imageBytes) wartość zwracana
OnDetectionFinishedEventArg e IEnumerable wynik z BarcodeReader.Read()
e.BarcodeResults Wartość zwrotna BarcodeReader.Read()
e.BarcodeResults.FirstOrDefault() results.FirstOrDefault()
barcode.DisplayValue result.Value
barcode.BarcodeFormat result.Format
BarcodeFormats="All" Wykrywane automatycznie — nie wymaga konfiguracji
CameraEnabled="True" await MediaPicker.CapturePhotoAsync()
Tylko iOS + Android iOS, Android, Windows, macOS MAUI
Brak pliku wejściowego BarcodeReader.Read(filePath)
Brak pliku PDF BarcodeReader.Read("document.pdf")
Brak generacji BarcodeWriter.CreateBarcode() / QRCodeWriter.CreateQrCode()
iOS UPC-A zwraca 13 cyfr Zwraca prawidłowe 12 cyfr — nie jest wymagana normalizacja
PDF417 zawodny Obsługiwane

Typowe problemy związane z migracją i ich rozwiązania

Problem 1: Utrata funkcji podglądu na żywo

BarcodeScanning.MAUI: Kontrola CameraView osadzała podgląd kamery bezpośrednio w stronie MAUI. Użytkownicy mogli zobaczyć obraz z kamery i skierować ją na BarCode — wykrywanie odbywało się automatycznie, bez konieczności naciskania przycisku.

Rozwiązanie: MediaPicker.CapturePhotoAsync() pokazuje ekran kamery platformy zamiast tego. W przypadku większości procesów biznesowych jest to dopuszczalne. W aplikacjach konsumenckich, które wymagają ciągłego podglądu na żywo, ramki z kamery mogą być przekazywane bezpośrednio do BarcodeReader.Read():

using IronBarCode;

// Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
// (frame capture depends on your MAUI camera frame source)
private void ProcessCameraFrame(byte[] frameBytes)
{
    var results = BarcodeReader.Read(frameBytes);
    if (results.Any())
    {
        var first = results.First();
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = first.Value);
    }
}
using IronBarCode;

// Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
// (frame capture depends on your MAUI camera frame source)
private void ProcessCameraFrame(byte[] frameBytes)
{
    var results = BarcodeReader.Read(frameBytes);
    if (results.Any())
    {
        var first = results.First();
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = first.Value);
    }
}
Imports IronBarCode

' Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
' (frame capture depends on your MAUI camera frame source)
Private Sub ProcessCameraFrame(frameBytes As Byte())
    Dim results = BarcodeReader.Read(frameBytes)
    If results.Any() Then
        Dim first = results.First()
        MainThread.BeginInvokeOnMainThread(Sub()
                                               ResultLabel.Text = first.Value
                                           End Sub)
    End If
End Sub
$vbLabelText   $csharpLabel

Wymaga to podłączenia źródła klatek z kamery oddzielnie od IronBarcode. Zanim zdecydujesz się na tę opcję, zastanów się, czy podgląd na żywo jest naprawdę potrzebny, czy wystarczy interfejs użytkownika kamery systemowej.

Problem 2: Zmiany nazw właściwości i enumów w e.BarcodeResults

BarcodeScanning.MAUI: barcode.DisplayValue zwraca rozszyfrowany ciąg znaków; barcode.BarcodeFormat zwraca wartość wyliczania z biblioteki BarcodeScanning.

Rozwiązanie: Zamień DisplayValue na result.Value i barcode.BarcodeFormat na result.Format. Schemat iteracji jest taki sam:

// Before
foreach (var barcode in e.BarcodeResults)
    Console.WriteLine(barcode.DisplayValue);

// After
var results = BarcodeReader.Read(imageBytes);
foreach (var result in results)
    Console.WriteLine(result.Value);
// Before
foreach (var barcode in e.BarcodeResults)
    Console.WriteLine(barcode.DisplayValue);

// After
var results = BarcodeReader.Read(imageBytes);
foreach (var result in results)
    Console.WriteLine(result.Value);
' Before
For Each barcode In e.BarcodeResults
    Console.WriteLine(barcode.DisplayValue)
Next

' After
Dim results = BarcodeReader.Read(imageBytes)
For Each result In results
    Console.WriteLine(result.Value)
Next
$vbLabelText   $csharpLabel

Problem 3: Marshaling wątków dla aktualizacji interfejsu użytkownika

BarcodeScanning.MAUI: OnDetectionFinished działa w tle, więc wszystkie aktualizacje interfejsu użytkownika wymagają MainThread.BeginInvokeOnMainThread().

Rozwiązanie: Z wzorcem MediaPicker + async, kontynuacja po await zwraca się w kontekście wywołania — zazwyczaj na głównym wątku. Opakowania MainThread.BeginInvokeOnMainThread() wokół wyświetlania wyników można zazwyczaj usunąć, upraszczając kod obsługi.

Problem 4: Uprawnienia kamery MAUI

BarcodeScanning.MAUI: Pakiet dodaje automatycznie uprawnienia do kamer do AndroidManifest.xml i Info.plist jako część konfiguracji.

Rozwiązanie: Przy użyciu IronBarcode z MediaPicker, standardowe uprawnienia do kamer MAUI muszą być obecne ręcznie. Są to te same uprawnienia, których potrzebuje każda aplikacja MAUI dla MediaPicker.CapturePhotoAsync() i zazwyczaj są już ustawione. Zweryfikuj, że android.permission.CAMERA jest zadeklarowane w AndroidManifest.xml i NSCameraUsageDescription jest ustawione w Info.plist przed testowaniem na urządzeniu.

Lista kontrolna migracji BarcodeScanning.MAUI

Zadania przed migracją

Przed wprowadzeniem jakichkolwiek zmian należy przeprowadzić następujące wyszukiwania, aby znaleźć wszystkie wystąpienia BarcodeScanning.Native.Maui:

grep -rn "using BarcodeScanning" --include="*.cs" .
grep -rn "using BarcodeScanning" --include="*.xaml" .
grep -rn "CameraView" --include="*.cs" .
grep -rn "CameraView" --include="*.xaml" .
grep -rn "OnDetectionFinished" --include="*.cs" .
grep -rn "OnDetectionFinishedEventArg" --include="*.cs" .
grep -rn "e\.BarcodeResults" --include="*.cs" .
grep -rn "DisplayValue" --include="*.cs" .
grep -rn "BarcodeFormats\.Upca" --include="*.cs" .
grep -rn "scanner:" --include="*.xaml" .
grep -rn "using BarcodeScanning" --include="*.cs" .
grep -rn "using BarcodeScanning" --include="*.xaml" .
grep -rn "CameraView" --include="*.cs" .
grep -rn "CameraView" --include="*.xaml" .
grep -rn "OnDetectionFinished" --include="*.cs" .
grep -rn "OnDetectionFinishedEventArg" --include="*.cs" .
grep -rn "e\.BarcodeResults" --include="*.cs" .
grep -rn "DisplayValue" --include="*.cs" .
grep -rn "BarcodeFormats\.Upca" --include="*.cs" .
grep -rn "scanner:" --include="*.xaml" .
SHELL

Dokumentuj każde trafienie. Zauważ, które pliki zawierają użycie XAML CameraView (wymagają zmian w XAML) w porównaniu do tych, które zawierają tylko zmiany w kodzie. Zidentyfikuj wszelkie obejścia normalizacji UPC-A, które należy usunąć po migracji.

Zadania związane z aktualizacją kodu

  1. Usuń pakiet BarcodeScanning.Native.Maui NuGet
  2. Zainstaluj pakiet IronBarcode NuGet
  3. Dodaj IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"; w MauiProgram.cs lub App.xaml.cs
  4. Zamień using BarcodeScanning; na using IronBarCode; we wszystkich plikach .cs
  5. Usuń deklaracje przestrzeni nazw xmlns:scanner="..." z wszystkich plików XAML
  6. Zamień kontrolki scanner:CameraView w XAML na Button uruchamiający MediaPicker.CapturePhotoAsync()
  7. Usuń połączenia zdarzeń OnDetectionFinished="..." z XAML
  8. Zamień obsługę zdarzeń OnDetectionFinished na obsługę przycisków kliknięcia async używając BarcodeReader.Read()
  9. Zamień barcode.DisplayValue na result.Value wszędzie
  10. Zamień barcode.BarcodeFormat na result.Format wszędzie
  11. Usuń wszystkie obejścia normalizacji BarcodeFormats.Upca + Substring(1)
  12. Dodaj ExpectMultipleBarcodes = true do BarcodeReaderOptions, gdzie wcześniej wykrywanie wielokrotnego kodu kreskowego polegało na e.BarcodeResults zwracającym wiele elementów
  13. Usuń opakowania MainThread.BeginInvokeOnMainThread() z kodu wyświetlania wyników, gdzie asynchroniczny wzorzec czyni je zbędnymi
  14. Zweryfikuj uprawnienia kamer AndroidManifest.xml i Info.plist są obecne

Testy po migracji

  • Sprawdź, czy skanowanie BarCode w systemie iOS działa, a wartości UPC-A są zwracane jako 12-cyfrowe ciągi znaków bez zer wiodących
  • Sprawdź, czy skanowanie BarCode'ów w systemie Android generuje prawidłowe wartości dla wszystkich formatów używanych w aplikacji
  • Sprawdź, czy skanowanie BarCode w Windows MAUI działa, jeśli Windows jest celem kompilacji
  • Przetestuj skanowanie kodów PDF417 na prawdziwych etykietach wysyłkowych, prawach jazdy lub kartach pokładowych, jeśli są one używane
  • Przetestuj scenariusze z wieloma kodami kreskowymi z ExpectMultipleBarcodes = true i potwierdź, że wszystkie kody kreskowe na obrazie są zwracane
  • Zweryfikuj, czy skanowanie wybieracza plików (BarcodeReader.Read(filePath)) działa na wszystkich celach MAUI
  • Sprawdź odczyt BarCode z plików PDF, jeśli była to nowa funkcja dodana wraz z migracją
  • Potwierdź, że serwerowa BarcodeReader.Read() produkuje poprawne wyniki, jeśli dodano komponent backendowy
  • Uruchom wszystkie istniejące testy automatyczne i porównaj wyniki wartości BarCode z wartościami bazowymi sprzed migracji

Kluczowe korzyści wynikające z migracji do IronBarcode

Pełna obsługa Windows MAUI:IronBarcode działa na wszystkich czterech platformach MAUI — iOS, Android, Windows i macOS — przy użyciu tego samego kodu i tego samego pakietu. Żadne specyficzne dla platformy wdrożenie kodu kreskowego nie jest potrzebne dla Windows, i żadne bloki #if WINDOWS nie są wymagane w kodzie aplikacji.

Każde Źródło Wejściowe: BarcodeReader.Read() akceptuje ścieżki plików, tablice bajtów, strumienie i dokumenty PDF. Każdy scenariusz związany z kodami kreskowymi — przechwytywanie przez kamerę, przesyłanie plików, obraz z galerii, przetwarzanie plików PDF po stronie serwera — wykorzystuje tę samą metodę statyczną z tym samym typem wyniku.

Prawidłowe wartości UPC-A:IronBarcode zwraca prawidłową 12-cyfrową wartość UPC-A na iOS bez żadnego kodu normalizującego w aplikacji. Historyczne dane UPC-A zapisane z zerem wiodącym z powodu działania BarcodeScanning.Native.Maui nie wpływają na dokładność wartości odczytanych po migracji.

Niezawodny PDF417: PDF417 jest w pełni obsługiwany i odczytywany w sposób niezawodny. Etykiety wysyłkowe, prawa jazdy i karty pokładowe są skanowane bez ograniczenia "większość skanów nigdy nie ma miejsca", opisanego w zgłoszeniach na GitHubie dotyczących BarcodeScanning.Native.Maui.

Generowanie Kodów Kreskowych: BarcodeWriter.CreateBarcode() i QRCodeWriter.CreateQrCode() generują Code128, QR, DataMatrix i inne formaty jako pliki PNG lub tablice bajtów. Generowanie i odczyt są dostępne w tym samym pakiecie bez dodatkowych zależności.

Wdrożenie Serwerowe: To samo wywołanie BarcodeReader.Read() działa w ASP.NET, Azure Functions, kontenerach Docker i AWS Lambda. Logika kodów kreskowych na urządzeniach mobilnych i serwerach może korzystać z tego samego interfejsu API, obsługiwać ten sam format i generować ten sam typ wyników bez konieczności utrzymywania dwóch oddzielnych implementacji kodów kreskowych.

Często Zadawane Pytania

Dlaczego warto przejść z BarcodeScanning.MAUI na IronBarcode?

Typowe powody to uproszczenie licencjonowania (eliminacja złożoności związanej z SDK i kluczem uruchomieniowym), zniesienie limitów przepustowości, uzyskanie natywnej obsługi plików PDF, usprawnienie wdrażania w środowisku Docker/CI/CD oraz ograniczenie powtarzalnego kodu API w kodzie produkcyjnym.

Jak zastąpić wywołania API BarcodeScanning.MAUI za pomocą IronBarcode?

Zastąp standardowe fragmenty kodu dotyczące tworzenia instancji i licencjonowania wyrażeniem IronBarCode.License.LicenseKey = "key". Zastąp wywołania czytnika wyrażeniem BarcodeReader.Read(path), a wywołania zapisu wyrażeniem BarcodeWriter.CreateBarcode(data, encoding). Metody statyczne nie wymagają zarządzania instancjami.

Jak bardzo zmienia się kod podczas migracji z BarcodeScanning.MAUI do IronBarcode?

Większość migracji skutkuje zmniejszeniem liczby linii kodu. Usuwane są standardowe fragmenty dotyczące licencji, konstruktory instancji oraz jawna konfiguracja formatów. Podstawowe operacje odczytu/zapisu są mapowane na krótsze odpowiedniki w IronBarcode z bardziej przejrzystymi obiektami wynikowymi.

Czy podczas migracji muszę mieć zainstalowane zarówno BarcodeScanning.MAUI, jak i IronBarcode?

Nie. Większość migracji polega na bezpośredniej wymianie, a nie na równoległym działaniu. Należy migrować po jednej klasie usługowej na raz, zastąpić odwołanie do NuGet oraz zaktualizować wzorce instancjonowania i wywoływania API przed przejściem do kolejnej klasy.

Jaka jest nazwa pakietu NuGet dla IronBarcode?

Pakiet nosi nazwę „IronBarcode” (z wielkimi literami B i C). Zainstaluj go za pomocą polecenia „Install-Package IronBarcode” lub „dotnet add package IronBarcode”. Dyrektywa using w kodzie to „using IronBarcode;”.

W jaki sposób IronBarcode upraszcza wdrażanie Docker w porównaniu z BarcodeScanning.MAUI?

IronBarcode to pakiet NuGet bez zewnętrznych plików SDK ani konfiguracji licencji. W Dockerze należy ustawić zmienną środowiskową IRONBARCODE_LICENSE_KEY, a pakiet zajmie się weryfikacją licencji podczas uruchamiania.

Czy IronBarcode automatycznie wykrywa wszystkie formaty kodów kreskowych po migracji z BarcodeScanning.MAUI?

Tak. IronBarcode automatycznie wykrywa symbole we wszystkich obsługiwanych formatach. Wyraźne wyliczenie typów kodów kreskowych nie jest wymagane. Jeśli format jest już znany, a wydajność ma znaczenie, BarcodeReaderOptions pozwala ograniczyć obszar wyszukiwania w celu optymalizacji.

Czy IronBarcode może odczytywać BarCodes z plików PDF bez oddzielnej biblioteki?

Tak. BarCodeReader.Read("document.pdf") przetwarza pliki PDF natywnie. Wyniki obejmują PageNumber, Format, Value i Confidence dla każdego znalezionego kodu kreskowego. Nie jest wymagany żaden zewnętrzny etap renderowania pliku PDF.

W jaki sposób IronBarcode obsługuje równoległe przetwarzanie kodów kreskowych?

Metody statyczne IronBarcode są bezstanowe i bezpieczne dla wątków. Użyj Parallel.ForEach bezpośrednio na listach plików bez zarządzania instancjami dla poszczególnych wątków. BarcodeReaderOptions.MaxParallelThreads kontroluje wewnętrzny limit wątków.

Jakie właściwości wyników ulegają zmianie podczas migracji z BarcodeScanning.MAUI do IronBarcode?

Typowe zmiany nazw: BarcodeValue staje się Value, BarcodeType staje się Format. Wyniki IronBarcode zawierają również Confidence i PageNumber. Funkcja wyszukiwania i zamiany w całym rozwiązaniu obsługuje zmiany nazw w istniejącym kodzie przetwarzania wyników.

Jak skonfigurować licencjonowanie IronBarcode w potoku CI/CD?

Zapisz IronBarcode_LICENSE_KEY jako sekret potoku i przypisz IronBarCode.License.LicenseKey w kodzie uruchamiającym aplikację. Jeden sekret obejmuje wszystkie środowiska, w tym środowisko programistyczne, testowe, przejściowe i produkcyjne.

Czy IronBarcode obsługuje generowanie kodów QR z niestandardowym stylem?

Tak. Funkcja QRCodeWriter.CreateQrCode() obsługuje niestandardowe kolory za pomocą ChangeBarCodeColor(), osadzanie logo za pomocą AddBrandLogo(), konfigurowalne poziomy korekcji błędów oraz wiele formatów wyjściowych, w tym PNG, JPG, PDF i strumień.

Curtis Chau
Autor tekstów technicznych

Curtis Chau posiada tytuł licencjata z informatyki (Uniwersytet Carleton) i specjalizuje się w front-endowym rozwoju, z ekspertką w Node.js, TypeScript, JavaScript i React. Pasjonuje się tworzeniem intuicyjnych i estetycznie przyjemnych interfejsów użytkownika, Curtis cieszy się pracą z nowoczesnymi frameworkami i tworzeniem dobrze zorganizowanych, atrakcyjnych wizualnie podrę...

Czytaj więcej

Zespół wsparcia Iron

Jesteśmy online 24 godziny, 5 dni w tygodniu.
Czat
E-mail
Zadzwoń do mnie