Jak zapisywać kody kreskowe Unicode i języków międzynarodowych w C# | IronPDF
Migracja z ZXing.Net do IronBarcode
Niniejszy przewodnik obejmuje kompletną migrację z ZXing.Net do IronBarcode for .NET dla aplikacji .NET, które odczytują i generują kody kreskowe. Dotyczy usuniecia podstawowego pakietu ZXing.Net i pakietow wiazacych, eliminacji obejsc PdfiumViewer tam, gdzie wystepuja, oraz zastapienia kazdego stanu BarcodeReader instancjizacja z uzyciem statycznego API IronBarcode. Każda sekcja zawiera kod "przed" i "po" zaczerpnięty z najczęściej spotykanych wzorców w integracjach ZXing.Net.
Dlaczego warto przejść z ZXing.Net
ZXing.Net od ponad dziesięciu lat służy społeczności .NET jako bezpłatna biblioteka BARCODE na licencji Apache 2.0. Jednak wraz ze wzrostem skali lub złożoności aplikacji niektóre ograniczenia architektoniczne przekładają się na koszty operacyjne.
Bezpieczenstwo w watkach: BarcodeReader z ZXing.Net jest obiektem stanowiskowym. W dokumentacji biblioteki zaznaczono, że instancje nie mogą być współdzielone między wątkami. W praktyce oznacza to, że każda ścieżka przetwarzania współbieżnego — każda akcja kontrolera obsługująca równoczesne żądania, każde zadanie w równoległej partii — musi przydzielić, skonfigurować i odrzucić własny czytnik. Wraz ze wzrostem liczby żądań ten wzorzec alokacji powoduje wymierną presję na pamięć. Alternatywa ThreadLocal<BarcodeReader> zmniejsza czestotliwosc przydzielania, ale wprowadza wlasna zlozonosc przy usuwaniu. W obu przypadkach poprawność w warunkach współbieżności jest problemem wywołującego, a nie gwarancją zapewnianą przez bibliotekę.
Ryzyko specyfikacji formatu: ZXing.Net wymaga, aby reader.Options.PossibleFormats byl wypełniony przed kazdą operacja dekodowania. Kod kreskowy w formacie nieobecnym na tej liście zwraca null — brak wyjątku, brak ostrzeżenia, brak wskazania, że kod kreskowy był obecny, ale nierozpoznany. Dla aplikacji otrzymujących dokumenty od zewnętrznych partnerów, to zachowanie niewidocznego braku jest ryzykiem niezawodności: błędnie wysłane zamówienie, pominięta rejestracja pacjenta lub wpis do audytu, który nigdy się nie zapisze, mogą wywodzić się z listy formatów, która była skonfigurowana dla poprzedniego wymagania i nigdy nie zaktualizowana.
Luka w przetwarzaniu plików PDF: ZXing.Net odczytuje wyłącznie pliki bitmapowe. Gdy dokumenty źródłowe są w formacie PDF — faktury, listy przewozowe, certyfikaty zgodności — użytkownicy muszą zintegrować oddzielną bibliotekę do renderowania plików PDF (najczęściej jest to PdfiumViewer), zaimplementować pętlę wyliczającą strony, skonfigurować DPI, zarządzać plikami tymczasowymi oraz obsługiwać czyszczenie zarówno w przypadku powodzenia, jak i niepowodzenia. Jest to od 30 do 50 wierszy kodu infrastruktury na każdą integrację, który służy wyłącznie do konwersji tego, czego ZXing.Net nie może odczytać (pliki PDF), na to, co może (mapy bitowe). Ta infrastruktura ma swoje własne zależności, własne wymagania dotyczące wdrażania i własne tryby awarii.
Fragmentacja powiązań platformowych: Funkcja ładowania obrazów w ZXing.Net jest podzielona na pakiety powiązań specyficzne dla poszczególnych platform. Wiazanie Windows uzywa System.Drawing.Bitmap; wiazanie wieloplatformowe uzywa SixLabors.ImageSharp z innym parametrem typu generycznego i inna using dyrektywa. Projekt, ktory zaczyna sie na Windows i pozniej jest konteneryzowany na Linux, musi zmienic zarowno swoje odniesienia NuGet, jak i kod ladowania obrazow. Dwie ścieżki kodu dla tej samej operacji zwiększają powierzchnię podatną na błędy i utrudniają wprowadzanie przyszłych zmian w warstwie skanującej.
Podstawowy problem
Najlepszym przykładem architektury ZXing.Net jest różnica między wywołaniem jednowątkowym a współbieżnym. W ZXing.Net przetwarzanie współbieżne wymaga utworzenia pełnego obiektu czytnika dla każdej operacji równoległej:
// ZXing.Net: full reader instantiation and configuration on every parallel task
Parallel.ForEach(files, file =>
{
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.EAN_13
};
using var bitmap = new Bitmap(file);
var result = reader.Decode(bitmap);
if (result != null)
processed[file] = result.Text;
});
// ZXing.Net: full reader instantiation and configuration on every parallel task
Parallel.ForEach(files, file =>
{
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.EAN_13
};
using var bitmap = new Bitmap(file);
var result = reader.Decode(bitmap);
if (result != null)
processed[file] = result.Text;
});
Imports ZXing
Imports System.Drawing
Imports System.Threading.Tasks
Parallel.ForEach(files, Sub(file)
Dim reader As New BarcodeReader()
reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.EAN_13
}
Using bitmap As New Bitmap(file)
Dim result = reader.Decode(bitmap)
If result IsNot Nothing Then
processed(file) = result.Text
End If
End Using
End Sub)
IronBarcode całkowicie usuwa obiekt. Wywołanie statyczne jest takie samo, niezależnie od tego, czy działa na jednym wątku, czy na stu:
// IronBarcode: static call, same code for single-threaded and concurrent use
Parallel.ForEach(files, file =>
{
var result = BarcodeReader.Read(file).FirstOrDefault();
if (result != null)
processed[file] = result.Value;
});
// IronBarcode: static call, same code for single-threaded and concurrent use
Parallel.ForEach(files, file =>
{
var result = BarcodeReader.Read(file).FirstOrDefault();
if (result != null)
processed[file] = result.Value;
});
Imports IronBarCode
Imports System.Threading.Tasks
Parallel.ForEach(files, Sub(file)
Dim result = BarcodeReader.Read(file).FirstOrDefault()
If result IsNot Nothing Then
processed(file) = result.Value
End If
End Sub)
IronBarcode a ZXing.Net: porównanie funkcji
| Funkcja | ZXing.Net | IronBarcode |
|---|---|---|
| Licencja | Apache 2.0 (bezpłatna) | Komercjalne |
| Bezpieczeństwo wątków | Nie jest bezpieczne dla wątków — wymagana nowa instancja na wątek | Bezpieczne dla wątków statyczne API |
| Wykrywanie formatu | Reczenie — wymagane jest PossibleFormats lista |
Automatyczne — ponad 50 formatów |
| Odczytywanie plików PDF | Nie — wymaga PdfiumViewer lub podobnego oprogramowania | Natywny — pojedyncze wywołanie metody |
| Obsługa platform | Oddzielne pakiety wiązania dla każdej platformy | Pojedynczy pakiet, wszystkie platformy |
| Wiele BarCode'ów na jednym obrazie | Tak — DecodeMultiple |
Tak — domyślne zachowanie |
| Generowanie kodów kreskowych | Zwraca Bitmap, wymaga recznego zapisu |
Fluent API z wbudowanym wyjściem |
| Obsługa logo w kodzie QR | Nie | Tak |
| Kontrola kolorów kodów QR | Nie | Tak |
| Odzyskiwanie uszkodzonych kodów BarCode | TryHarder flaga |
Korekcja obrazu wspierana przez ML |
| Dodatkowe zależności Docker | Moze wymagac libgdiplus |
None |
| Komercjalne wsparcie SLA | Nie | Tak |
| Wymagane pakiety NuGet | 2–3 (podstawowe + powiązane + opcjonalne ImageSharp) | 1 |
Szybki start
Krok 1: Usuń pakiety ZXing.Net
Usuń wszystkie pakiety ZXing.Net i powiązane z projektu:
dotnet remove package ZXing.Net
dotnet remove package ZXing.Net.Bindings.Windows.Compatibility
dotnet remove package ZXing.Net.Bindings.ImageSharp
dotnet remove package PdfiumViewer
dotnet remove package ZXing.Net
dotnet remove package ZXing.Net.Bindings.Windows.Compatibility
dotnet remove package ZXing.Net.Bindings.ImageSharp
dotnet remove package PdfiumViewer
Jeśli natywne binaria PdfiumViewer zostały zainstalowane jako osobny pakiet:
dotnet remove package PdfiumViewer.Native.x64.v8-xfa
dotnet remove package PdfiumViewer.Native.x64.v8-xfa
Jesli Dockerfile zawiera apt-get install -y libgdiplus — dodane, aby wspierac System.Drawing przez wiazanie Windows na Linux — ta linia moze zostac usunieta po migracji.
Krok 2: Zainstaluj IronBarcode
dotnet add package IronBarcode
dotnet add package IronBarcode
Nie są wymagane żadne dodatkowe pakiety powiązań ani zależności specyficzne dla platformy. Ten sam pakiet NuGet działa na Windows, Linuksie, macOS i w kontenerach Docker. Dla szczegółów wdrożeniowych, przewodnik po instalacji IronBarcode na Docker i Linuksie obejmuje dokładny wzorzec Dockerfile.
Krok 3: Aktualizuj przestrzenie nazw i inicjalizuj licencję
Usuń wszystkie związane z ZXing przestrzenie nazw z każdego pliku korzystającego z operacji kodów kreskowych:
// Remove all of these:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using ZXing.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using PdfiumViewer;
// Add this single import:
using IronBarCode;
// Remove all of these:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using ZXing.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using PdfiumViewer;
// Add this single import:
using IronBarCode;
Imports IronBarCode
Dodaj inicjalizację licencji przy starcie aplikacji, przed jakimikolwiek operacjami na kodach kreskowych:
// Program.cs or Startup.cs — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// Program.cs or Startup.cs — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
' Program.vb or Startup.vb — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Klucz licencyjny jest simplem łańcuchem znakowym, ktory moze byc zaladowany z zmiennej srodowiskowej, appsettings.json, lub menadzerem tajemnic. Nie ma pliku do zlokalizowania i nie ma ścieżki do skonfigurowania.
Przykłady migracji kodu
Czytanie pojedynczego kodu kreskowego z obrazu
Ten przykład zastępuje najczęstszy wzór użycia ZXing.Net: tworzenie czytnika, konfigurowanie listy formatów, ładowanie bitmapy i dekodowanie.
Podejście ZXing.Net:
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;
public string ReadSingleBarcode(string imagePath)
{
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.EAN_13
};
using var bitmap = new Bitmap(imagePath);
var result = reader.Decode(bitmap);
return result?.Text ?? string.Empty;
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;
public string ReadSingleBarcode(string imagePath)
{
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.EAN_13
};
using var bitmap = new Bitmap(imagePath);
var result = reader.Decode(bitmap);
return result?.Text ?? string.Empty;
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Drawing
Public Function ReadSingleBarcode(imagePath As String) As String
Dim reader = New BarcodeReader()
reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.EAN_13
}
Using bitmap As New Bitmap(imagePath)
Dim result = reader.Decode(bitmap)
Return If(result?.Text, String.Empty)
End Using
End Function
Podejście IronBarcode:
using IronBarCode;
public string ReadSingleBarcode(string imagePath)
{
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
return result?.Value ?? string.Empty;
}
using IronBarCode;
public string ReadSingleBarcode(string imagePath)
{
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
return result?.Value ?? string.Empty;
}
Imports IronBarCode
Public Function ReadSingleBarcode(imagePath As String) As String
Dim result = BarcodeReader.Read(imagePath).FirstOrDefault()
Return If(result?.Value, String.Empty)
End Function
Lista formatow, Bitmap alokacja i using blok sa usuniete.IronBarcode akceptuje bezpośrednią ścieżkę do pliku i automatycznie wykrywa wszystkie obsługiwane formaty. Wlasciwosc, ktora wczesniej zwracala zakodowany łańcuch znakow, byla result.Text w ZXing.Net; jest result.Value w IronBarcode.
Czytanie wszystkich kodów kreskowych z obrazu
Ten przyklad zastepuje DecodeMultiple, ktory w ZXing.Net wymaga wyczerpujacej listy formatow, aby uniknac cichych brakow.
Podejście ZXing.Net:
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;
public List<string> ReadAllBarcodes(string imagePath)
{
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.CODE_39,
BarcodeFormat.EAN_13,
BarcodeFormat.EAN_8,
BarcodeFormat.UPC_A,
BarcodeFormat.DATA_MATRIX,
BarcodeFormat.PDF_417
};
reader.Options.TryHarder = true;
using var bitmap = new Bitmap(imagePath);
var results = reader.DecodeMultiple(bitmap);
return results?.Select(r => r.Text).ToList() ?? new List<string>();
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;
public List<string> ReadAllBarcodes(string imagePath)
{
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.CODE_39,
BarcodeFormat.EAN_13,
BarcodeFormat.EAN_8,
BarcodeFormat.UPC_A,
BarcodeFormat.DATA_MATRIX,
BarcodeFormat.PDF_417
};
reader.Options.TryHarder = true;
using var bitmap = new Bitmap(imagePath);
var results = reader.DecodeMultiple(bitmap);
return results?.Select(r => r.Text).ToList() ?? new List<string>();
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Drawing
Public Function ReadAllBarcodes(imagePath As String) As List(Of String)
Dim reader = New BarcodeReader()
reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.CODE_39,
BarcodeFormat.EAN_13,
BarcodeFormat.EAN_8,
BarcodeFormat.UPC_A,
BarcodeFormat.DATA_MATRIX,
BarcodeFormat.PDF_417
}
reader.Options.TryHarder = True
Using bitmap As New Bitmap(imagePath)
Dim results = reader.DecodeMultiple(bitmap)
Return If(results?.Select(Function(r) r.Text).ToList(), New List(Of String)())
End Using
End Function
Podejście IronBarcode:
using IronBarCode;
public List<string> ReadAllBarcodes(string imagePath)
{
return BarcodeReader.Read(imagePath)
.Select(r => r.Value)
.ToList();
}
using IronBarCode;
public List<string> ReadAllBarcodes(string imagePath)
{
return BarcodeReader.Read(imagePath)
.Select(r => r.Value)
.ToList();
}
Imports IronBarCode
Public Function ReadAllBarcodes(imagePath As String) As List(Of String)
Return BarcodeReader.Read(imagePath) _
.Select(Function(r) r.Value) _
.ToList()
End Function
BarcodeReader.Read zawsze zwraca kolekcje i nigdy nie zwraca null, eliminujac null-guard na wyniku. Aby dostosowac rownowage miedzy dokladnoscia a szybkoscia, zobacz przewodnik po opcjach szybkości odczytu, ktory omawia ReadingSpeed enum bez zawężania zakresu formatu.
Przetwarzanie wsadowe równoległe
Ten przykład pokazuje różnicę w bezpieczeństwie wątków w najbardziej bezpośredni sposób. ZXing.Net wymaga nowego czytnika przy każdej operacji równoległej;IronBarcode używa tego samego wywołania statycznego bez względu na poziom równoległości.
Podejście ZXing.Net:
using ZXing;
using ZXing.Windows.Compatibility;
using System.Collections.Concurrent;
using System.Drawing;
public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
var output = new ConcurrentDictionary<string, string>();
Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = 4 }, file =>
{
// ZXing.Net is not thread-safe — a new reader is required per parallel operation
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128
};
using var bitmap = new Bitmap(file);
var result = reader.Decode(bitmap);
if (result != null)
output[file] = result.Text;
});
return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Collections.Concurrent;
using System.Drawing;
public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
var output = new ConcurrentDictionary<string, string>();
Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = 4 }, file =>
{
// ZXing.Net is not thread-safe — a new reader is required per parallel operation
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128
};
using var bitmap = new Bitmap(file);
var result = reader.Decode(bitmap);
if (result != null)
output[file] = result.Text;
});
return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Collections.Concurrent
Imports System.Drawing
Public Function ProcessBatch(filePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
Dim output = New ConcurrentDictionary(Of String, String)()
Parallel.ForEach(filePaths, New ParallelOptions With {.MaxDegreeOfParallelism = 4}, Sub(file)
' ZXing.Net is not thread-safe — a new reader is required per parallel operation
Dim reader = New BarcodeReader()
reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128
}
Using bitmap As New Bitmap(file)
Dim result = reader.Decode(bitmap)
If result IsNot Nothing Then
output(file) = result.Text
End If
End Using
End Sub)
Return output.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
End Function
Podejście IronBarcode:
using IronBarCode;
using System.Collections.Concurrent;
public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
var output = new ConcurrentDictionary<string, string>();
var options = new BarcodeReaderOptions { MaxParallelThreads = 4 };
Parallel.ForEach(filePaths, file =>
{
var result = BarcodeReader.Read(file, options).FirstOrDefault();
if (result != null)
output[file] = result.Value;
});
return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
using IronBarCode;
using System.Collections.Concurrent;
public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
var output = new ConcurrentDictionary<string, string>();
var options = new BarcodeReaderOptions { MaxParallelThreads = 4 };
Parallel.ForEach(filePaths, file =>
{
var result = BarcodeReader.Read(file, options).FirstOrDefault();
if (result != null)
output[file] = result.Value;
});
return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
Imports IronBarCode
Imports System.Collections.Concurrent
Public Function ProcessBatch(filePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
Dim output = New ConcurrentDictionary(Of String, String)()
Dim options = New BarcodeReaderOptions With {.MaxParallelThreads = 4}
Parallel.ForEach(filePaths, Sub(file)
Dim result = BarcodeReader.Read(file, options).FirstOrDefault()
If result IsNot Nothing Then
output(file) = result.Value
End If
End Sub)
Return output.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
End Function
Nie ma instancji czytnika do ochrony lub izolowania. Dla wzorców asynchronicznych i konfiguracji liczby wątków, zobacz przewodnika po czytaniu kodów kreskowych asynchronicznie i wielowątkowo.
Wyodrębnianie kodów kreskowych z PDF
Ten przykład zastępuje pętlę renderowania PdfiumViewer. Jeśli dotychczasowa integracja używała Ghostscript lub iText zamiast PdfiumViewer, blok przed będzie różnił się szczegółami, ale strukturalnie identyczny: pętla enumeracji stron dostarczająca bitmapy do ZXing.Net.
Podejście ZXing.Net:
using ZXing;
using ZXing.Windows.Compatibility;
using PdfiumViewer;
using System.Drawing;
using System.Drawing.Imaging;
public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
var collected = new List<string>();
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.PDF_417
};
using var document = PdfDocument.Load(pdfPath);
for (int page = 0; page < document.PageCount; page++)
{
string temp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
try
{
using var rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi);
rendered.Save(temp, ImageFormat.Png);
using var bmp = new Bitmap(temp);
var decoded = reader.DecodeMultiple(bmp);
if (decoded != null)
collected.AddRange(decoded.Select(d => d.Text));
}
finally
{
if (File.Exists(temp))
File.Delete(temp);
}
}
return collected;
}
using ZXing;
using ZXing.Windows.Compatibility;
using PdfiumViewer;
using System.Drawing;
using System.Drawing.Imaging;
public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
var collected = new List<string>();
var reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.PDF_417
};
using var document = PdfDocument.Load(pdfPath);
for (int page = 0; page < document.PageCount; page++)
{
string temp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
try
{
using var rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi);
rendered.Save(temp, ImageFormat.Png);
using var bmp = new Bitmap(temp);
var decoded = reader.DecodeMultiple(bmp);
if (decoded != null)
collected.AddRange(decoded.Select(d => d.Text));
}
finally
{
if (File.Exists(temp))
File.Delete(temp);
}
}
return collected;
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports PdfiumViewer
Imports System.Drawing
Imports System.Drawing.Imaging
Public Function ExtractBarcodesFromPdf(pdfPath As String) As List(Of String)
Dim collected As New List(Of String)()
Dim reader As New BarcodeReader()
reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
BarcodeFormat.QR_CODE,
BarcodeFormat.CODE_128,
BarcodeFormat.PDF_417
}
Using document = PdfDocument.Load(pdfPath)
For page As Integer = 0 To document.PageCount - 1
Dim temp As String = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png")
Try
Using rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi)
rendered.Save(temp, ImageFormat.Png)
Using bmp As New Bitmap(temp)
Dim decoded = reader.DecodeMultiple(bmp)
If decoded IsNot Nothing Then
collected.AddRange(decoded.Select(Function(d) d.Text))
End If
End Using
End Using
Finally
If File.Exists(temp) Then
File.Delete(temp)
End If
End Try
Next
End Using
Return collected
End Function
Podejście IronBarcode:
using IronBarCode;
public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
return BarcodeReader.Read(pdfPath)
.Select(r => r.Value)
.ToList();
}
using IronBarCode;
public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
return BarcodeReader.Read(pdfPath)
.Select(r => r.Value)
.ToList();
}
Imports IronBarCode
Public Function ExtractBarcodesFromPdf(pdfPath As String) As List(Of String)
Return BarcodeReader.Read(pdfPath) _
.Select(Function(r) r.Value) _
.ToList()
End Function
Zależność PdfiumViewer, pętla renderowania stron, konfiguracja DPI, tworzenie plików tymczasowych i blok usuwania są usuwane.IronBarcodeczyta kody kreskowe z PDF-ów natywnie, przetwarzając automatycznie wszystkie strony.
Generowanie BarCode
Pisarz ZXing.Net zwraca Bitmap, ktory uzytkownicy musza zapisac uzywajac System.Drawing.Imaging.IronBarcode zwraca GeneratedBarcode z wbudowanymi metodami wyjscia.
Podejście ZXing.Net:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using System.Drawing;
using System.Drawing.Imaging;
public void WriteCode128(string content, string outputPath)
{
var writer = new BarcodeWriter
{
Format = BarcodeFormat.CODE_128,
Options = new EncodingOptions
{
Width = 400,
Height = 120,
Margin = 10
}
};
using var bitmap = writer.Write(content);
bitmap.Save(outputPath, ImageFormat.Png);
}
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using System.Drawing;
using System.Drawing.Imaging;
public void WriteCode128(string content, string outputPath)
{
var writer = new BarcodeWriter
{
Format = BarcodeFormat.CODE_128,
Options = new EncodingOptions
{
Width = 400,
Height = 120,
Margin = 10
}
};
using var bitmap = writer.Write(content);
bitmap.Save(outputPath, ImageFormat.Png);
}
Imports ZXing
Imports ZXing.Common
Imports ZXing.Windows.Compatibility
Imports System.Drawing
Imports System.Drawing.Imaging
Public Sub WriteCode128(content As String, outputPath As String)
Dim writer = New BarcodeWriter With {
.Format = BarcodeFormat.CODE_128,
.Options = New EncodingOptions With {
.Width = 400,
.Height = 120,
.Margin = 10
}
}
Using bitmap = writer.Write(content)
bitmap.Save(outputPath, ImageFormat.Png)
End Using
End Sub
Podejście IronBarcode:
using IronBarCode;
public void WriteCode128(string content, string outputPath)
{
BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128)
.ResizeTo(400, 120)
.SaveAsPng(outputPath);
}
using IronBarCode;
public void WriteCode128(string content, string outputPath)
{
BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128)
.ResizeTo(400, 120)
.SaveAsPng(outputPath);
}
Imports IronBarCode
Public Sub WriteCode128(content As String, outputPath As String)
BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128) _
.ResizeTo(400, 120) _
.SaveAsPng(outputPath)
End Sub
Jesli potrzebne jest wyjscie binarne zamiast zapisu do pliku, ToPngBinaryData() i ToJpegBinaryData() sa dostepne na zwroconym obiekcie GeneratedBarcode bez jakiejkolwiek kanalizacji MemoryStream.
Odniesienie mapowania ZXing.Net API do IronBarcode
| ZXing.Net | IronBarcode | Uwagi |
|---|---|---|
new BarcodeReader() |
Statyczne — brak instancji | BarcodeReader.Read(...) jest statycznym wywołaniem |
reader.Options.PossibleFormats = new List<BarcodeFormat> { ... } |
Nie jest potrzebne | Automatyczne wykrywanie obejmuje wszystkie 50+ formatów |
reader.Options.TryHarder = true |
Speed = ReadingSpeed.Balanced |
Dostrajanie dokladnosci poprzez BarcodeReaderOptions |
reader.Decode(bitmap) |
BarcodeReader.Read(imagePath).FirstOrDefault() |
Przekaz sciezke do pliku — konstrukcja Bitmap nie jest potrzebna |
reader.DecodeMultiple(bitmap) |
BarcodeReader.Read(imagePath) |
Zawsze zwraca kolekcję; never null |
result.Text |
result.Value |
Zmieniono nazwę właściwości |
result.BarcodeFormat |
result.Format |
Zmieniono nazwę właściwości |
BarcodeFormat.QR_CODE |
BarcodeEncoding.QRCode |
Zmiana konwencji nazewnictwa enumów |
BarcodeFormat.CODE_128 |
BarcodeEncoding.Code128 |
Zmiana konwencji nazewnictwa enumów |
BarcodeFormat.EAN_13 |
BarcodeEncoding.EAN13 |
Zmiana konwencji nazewnictwa enumów |
BarcodeFormat.DATA_MATRIX |
BarcodeEncoding.DataMatrix |
Zmiana konwencji nazewnictwa enumów |
BarcodeFormat.PDF_417 |
BarcodeEncoding.PDF417 |
Zmiana konwencji nazewnictwa enumów |
new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... } } |
BarcodeWriter.CreateBarcode(data, encoding) |
Fabryka statyczna, brak obiektu opcji |
writer.Write(data) zwraca Bitmap |
.SaveAsPng(path) / .ToPngBinaryData() |
Wbudowane wyjscie na GeneratedBarcode |
EncodingOptions { Width, Height } |
.ResizeTo(width, height) |
Płytki metod rozmiaru |
| Brak obsługi plików PDF | BarcodeReader.Read("file.pdf") |
Wsparcie natywne PDF, wszystkie strony |
Typowe problemy związane z migracją i ich rozwiązania
Problem 1: Wzorce instancjowania BarcodeReader
ZXing.Net: Uzytkownicy tworza new BarcodeReader(), ustawiaja reader.Options.PossibleFormats, laduja Bitmap, wywoluja reader.Decode(bitmap) lub reader.DecodeMultiple(bitmap) i czytaja result.Text.
Rozwiązanie: Usuń całkowicie instancję. Zamień cały wzorzec na statyczne wywołanie:
// Before: reader creation + format config + bitmap + decode + result.Text
// After:
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
var value = result?.Value ?? string.Empty;
// Before: reader creation + format config + bitmap + decode + result.Text
// After:
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
var value = result?.Value ?? string.Empty;
' Before: reader creation + format config + bitmap + decode + result.Text
' After:
Dim result = BarcodeReader.Read(imagePath).FirstOrDefault()
Dim value = If(result?.Value, String.Empty)
Przeszukaj baze kodu pod katem new BarcodeReader(), aby znalezc kazda instancje. Każda jest usunięta, nie przekształcona.
Problem 2: Usunięcie bloku PossibleFormats
ZXing.Net: Każde wywołanie dekodowania jest poprzedzone przypisaniem reader.Options.PossibleFormats = new List<BarcodeFormat> { ... }. Te listy są często długie i specyficzne dla projektu.
Rozwiazanie: Usun kazdy blok przypisania PossibleFormats w calosci.IronBarcode wykonuje automatyczne wykrywanie formatu; żadna lista formatów nie jest akceptowana ani wymagana. Jesli flaga TryHarder = true byla ustawiona wraz z lista formatow, zastep ja Speed = ReadingSpeed.Balanced na obiekcie BarcodeReaderOptions, jesli potrzebne jest dostrajanie dokladnosci.
Problem 3: Czyszczenie pakietów powiązań
ZXing.Net: Projekty uzywajace ZXing.Net.Bindings.Windows.Compatibility maja kod odwolujacy sie do typu wejscia System.Drawing.Bitmap. Projekty uzywajace ZXing.Net.Bindings.ImageSharp nawoluja sie do SixLabors.ImageSharp.Image<Rgba32>. Oba wzorce przestają działać po usunięciu pakietów powiązań.
Rozwiązanie: Usuń oba pakiety powiązań i zastąp cały kod ładowania obrazów. IronBarcode's BarcodeReader.Read akceptuje lancuch sciezki do pliku, byte[], Stream lub Uri — konstrukcja Bitmap lub Image<t> nie jest potrzebna. Pozostale using System.Drawing; importy, ktore istnialy wylacznie dla ladowania Bitmap, rowniez mozna usunac.
Problem 4: Odniesienie do result.Text na result.Value
ZXing.Net: Odczytana wartosc kodu kreskowego jest uzyskiwana za pomoca result.Text. Format kodu kreskowego jest uzyskiwany za pomoca result.BarcodeFormat.
Rozwiazanie: Zastap result.Text result.Value i result.BarcodeFormat result.Format w calym zakresie baz kodu. Obie zmiany to proste zmiany nazw właściwości bez różnic w zachowaniu.
Lista kontrolna migracji ZXing.Net
Zadania przed migracją
Przeprowadź audyt bazy kodu, aby znaleźć wszystkie odniesienia do ZXing.Net przed wprowadzeniem zmian:
grep -r "using ZXing" --include="*.cs" .
grep -r "new BarcodeReader" --include="*.cs" .
grep -r "PossibleFormats" --include="*.cs" .
grep -r "BarcodeFormat\." --include="*.cs" .
grep -r "reader\.Decode\|reader\.DecodeMultiple" --include="*.cs" .
grep -r "result\.Text\|result\.BarcodeFormat" --include="*.cs" .
grep -r "new BarcodeWriter\|writer\.Write\|EncodingOptions" --include="*.cs" .
grep -r "PdfiumViewer\|PdfDocument\.Load" --include="*.cs" .
grep -r "using System\.Drawing" --include="*.cs" .
grep -r "using ZXing" --include="*.cs" .
grep -r "new BarcodeReader" --include="*.cs" .
grep -r "PossibleFormats" --include="*.cs" .
grep -r "BarcodeFormat\." --include="*.cs" .
grep -r "reader\.Decode\|reader\.DecodeMultiple" --include="*.cs" .
grep -r "result\.Text\|result\.BarcodeFormat" --include="*.cs" .
grep -r "new BarcodeWriter\|writer\.Write\|EncodingOptions" --include="*.cs" .
grep -r "PdfiumViewer\|PdfDocument\.Load" --include="*.cs" .
grep -r "using System\.Drawing" --include="*.cs" .
Udokumentuj, ktore pliki odnosza sie do pakietow wiazacych ZXing (Windows vs ImageSharp) i zanotuj, gdzie System.Drawing.Bitmap jest uzywane wylacznie do wejscia ZXing. Zrecenzuj Dockerfile (jesli obecny) pod katem instalacji libgdiplus.
Zadania związane z aktualizacją kodu
- Usun
ZXing.Net,ZXing.Net.Bindings.Windows.Compatibility,ZXing.Net.Bindings.ImageSharp, iPdfiumViewerpakiety NuGet - Zainstaluj pakiet NuGet
IronBarcode - Dodaj
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";do uruchamiania aplikacji - Zastap wszystkie importy
using ZXing*iusing SixLabors.ImageSharp*zusing IronBarCode; - Usun kazda instancjizacje
new BarcodeReader() - Usun kazdy blok
reader.Options.PossibleFormats = ... - Zastap
reader.Decode(bitmap)BarcodeReader.Read(imagePath).FirstOrDefault() - Zastap
reader.DecodeMultiple(bitmap)BarcodeReader.Read(imagePath) - Zastap
result.Textresult.Value - Zastap
result.BarcodeFormatresult.Format - Zaktualizuj odniesienia enum
BarcodeFormat.Xdo odpowiednikowBarcodeEncoding.X - Replace
new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... } }withBarcodeWriter.CreateBarcode(data, encoding).ResizeTo(w, h) - Zastap
writer.Write(data)+bitmap.Save(...).SaveAsPng(path)lub.ToPngBinaryData() - Usun wszystkie importy
using System.Drawing;, ktore istnialy wylacznie dla ladowania bitmap ZXing.Net - Usuń pętlę renderowania stron PdfiumViewer tam, gdzie była wdrożona jako obejście dla PDF
- Usun
libgdiplusz Dockerfile, jesli zostal dodany, aby wspieracSystem.Drawingna Linux
Testy po migracji
- Zweryfikuj, że każdy format kodu kreskowego, który aplikacja była wcześniej skonfigurowana do wykrycia, jest poprawnie znajdowany
- Przetestuj obrazy zawierajace formaty kodow kreskowych, ktore wczesniej byly wykluczone z listy
PossibleFormats, aby potwierdzic, ze auto-detekcja je wybiera - Uruchom ścieżki przetwarzania równoległego pod obciążeniem i potwierdź brak sytuacji wyścigowych lub wyników zerowych
- Jeśli aplikacja przetworzyła PDF-y za pomocą PdfiumViewer, dostarcz te same dane wejściowe PDF i potwierdź zgodność wartości kodów kreskowych
- Potwierdź, że wygenerowane kody kreskowe (Code 128, QR Code itp.) zapewniają prawidłowy format wyjścia i wymiary
- Na wdrozeniach Linux lub Docker, potwierdz, ze czytanie obrazu i czytanie PDF dzialaja bez
libgdiplus - Uruchom pełny zestaw testów i porównaj wynik z przedmigracyjnym punktem odniesienia
Kluczowe korzyści wynikające z migracji do IronBarcode
Usunięty ciężar bezpieczeństwa wątków: Statyczne API IronBarcode całkowicie usuwa wzorzec instance per wątek. Nie ma czytnika do zinstancjonowania, zadnej listy formatow do skonfigurowania na watku, i zadnego ThreadLocal basenu do zarzadzania. To samo wywołanie jest poprawne zarówno w środowisku jednosesyjnowym, jak i wysoko równoległym, a poprawność współbieżności jest zapewniona przez bibliotekę, a nie delegowana do każdego wywołującego.
Automatyczne wykrywanie formatu: Usuniecie listy PossibleFormats eliminuje kategorie cichych bledow, ktore wystepuja, gdy dokumenty zawieraja formaty kodow kreskowych, o ktorych nie pomyslano podczas rozwoju. Aplikacje, które przetwarzają dokumenty od zewnętrznych partnerów lub działają w ramach ewoluujących standardów kodów kreskowych, nie wymagają już utrzymywania listy formatów, aby pozostały niezawodne.
Natywne przetwarzanie PDF: Pętla renderowania PdfiumViewer — jego enumeracja stron, konfiguracja DPI, cykl życia plików tymczasowych i kod czyszczenia — została całkowicie usunięta. Aplikacje, które wcześniej wymagały dwóch bibliotek (ZXing.Net i renderera PDF) do przetwarzania kodu kreskowego PDF, teraz używają jednej. Zmniejszenie wdrożonych zależności upraszcza zarówno powierzchnię kompilacji, jak i wdrożenia.
Pojedynczy pakiet wieloplatformowy: Wyeliminowano różnicę w pakietach wiążących pomiędzy wdrożeniami Windows i Linux. To samo wywolanie BarcodeReader.Read(path) kompiluje sie i dziala identycznie na wszystkich platformach docelowych, eliminujac potrzebe ochrony platformowej w kodzie ladowania obrazow i upraszczajac procesy rozwoju i konteneryzacji wieloplatformowej.
Zredukowany kod infrastruktury: Najważniejszym rezultatem migracji jest usunięcie otaczającej infrastruktury — bloków ładowania Bitmap, list formatów, pętli renderowania PdfiumViewer, pul ThreadLocal — które istniały w integracjach ZXing.Net, nie w celu pracy z kodami kreskowymi, ale aby spełnić wymagania architektoniczne biblioteki. Co pozostaje po migracji to sama logika kodu kreskowego. Dla dodatkowego kontekstu na temat wskaźników wykrywania i scenariuszy skanowania, porównanie skanerów ZXing.Net i IronBarcode dostarcza szerszej analizy.
Często Zadawane Pytania
Dlaczego warto przejść z ZXing.Net 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 ZXing.Net 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 ZXing.Net 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 ZXing.Net, 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 ZXing.Net?
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 ZXing.Net?
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 ZXing.Net 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ń.

