Migrating from BarcodeLib to IronBarcode
This guide provides a complete migration path from BarcodeLib to IronBarcode for .NET developers. It covers the reasons teams make this transition, step-by-step package replacement, code migration examples for every common BarcodeLib pattern, a full API mapping reference, and a structured checklist for managing the migration across a codebase.
Why Migrate from BarcodeLib
Teams migrating from BarcodeLib to IronBarcode report these triggers:
No Reading API: BarcodeLib has never included a reading or decoding capability. When a project that was generating barcode images receives a new requirement to also scan barcodes — from uploaded images, warehouse scanners, or supplier documents — BarcodeLib cannot fulfill it. The only option is adding a second library such as ZXing.Net, which introduces a second dependency graph and second API surface to maintain alongside BarcodeLib.
SkiaSharp Version Conflict: BarcodeLib 3.x introduced SkiaSharp as a graphics backend to replace System.Drawing.Common. The library pins to a specific SkiaSharp version range. In MAUI projects, Blazor projects, and any project where another dependency also pulls in SkiaSharp, the resolved version frequently falls outside BarcodeLib's expected range. This produces NU1608 warnings during restore and, in the worst cases, runtime assembly binding failures on device.
No PDF Support: Applications that generate PDF documents with embedded barcodes — invoices, work orders, shipping manifests — sometimes need to read those barcodes back during downstream processing. BarcodeLib generates barcode images but has no PDF support on either end. Extracting barcodes from a PDF with BarcodeLib requires rendering the PDF pages to images with a separate PDF library and then passing those images to a separate reading library.
Stream-Encoding Step for Byte Array Output: BarcodeLib 3.x returns SKImage, which requires a SkiaSharp encode step into a MemoryStream to produce the byte[] output that HTTP responses, database BLOB columns, and most downstream consumers actually need. IronBarcode provides .ToPngBinaryData() directly on the generation chain.
The Fundamental Problem
BarcodeLib's generation-only architecture means that adding any scan capability forces a second library into the stack:
// BarcodeLib: generation only — reading requires a completely separate library
using BarcodeStandard;
using SkiaSharp;
var b = new Barcode();
SKImage img = b.Encode(Type.Code128, "PRODUCT-12345", 300, 100);
using var stream = File.OpenWrite("barcode.png");
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream);
// To read it back, a separate scanning library such as ZXing.Net is required —
// separate API, separate dependency graph to maintain alongside BarcodeLib.
// BarcodeLib: generation only — reading requires a completely separate library
using BarcodeStandard;
using SkiaSharp;
var b = new Barcode();
SKImage img = b.Encode(Type.Code128, "PRODUCT-12345", 300, 100);
using var stream = File.OpenWrite("barcode.png");
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream);
// To read it back, a separate scanning library such as ZXing.Net is required —
// separate API, separate dependency graph to maintain alongside BarcodeLib.
Imports BarcodeStandard
Imports SkiaSharp
Dim b = New Barcode()
Dim img As SKImage = b.Encode(Type.Code128, "PRODUCT-12345", 300, 100)
Using stream = File.OpenWrite("barcode.png")
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream)
End Using
IronBarcode handles both in the same package with the same using statement:
// IronBarcode: generation and reading — no second library needed
using IronBarCode;
// Generate
BarcodeWriter.CreateBarcode("PRODUCT-12345", BarcodeEncoding.Code128)
.ResizeTo(300, 100)
.SaveAsPng("barcode.png");
// Read back — same package, same namespace
var result = BarcodeReader.Read("barcode.png").First().Value;
Console.WriteLine(result); // "PRODUCT-12345"
// IronBarcode: generation and reading — no second library needed
using IronBarCode;
// Generate
BarcodeWriter.CreateBarcode("PRODUCT-12345", BarcodeEncoding.Code128)
.ResizeTo(300, 100)
.SaveAsPng("barcode.png");
// Read back — same package, same namespace
var result = BarcodeReader.Read("barcode.png").First().Value;
Console.WriteLine(result); // "PRODUCT-12345"
Imports IronBarCode
' Generate
BarcodeWriter.CreateBarcode("PRODUCT-12345", BarcodeEncoding.Code128) _
.ResizeTo(300, 100) _
.SaveAsPng("barcode.png")
' Read back — same package, same namespace
Dim result = BarcodeReader.Read("barcode.png").First().Value
Console.WriteLine(result) ' "PRODUCT-12345"
IronBarcode vs BarcodeLib: Feature Comparison
| Feature | BarcodeLib | IronBarcode |
|---|---|---|
| Barcode generation | Yes | Yes |
| Barcode reading / scanning | No | Yes (BarcodeReader.Read()) |
| QR code generation | No (1D only) | Yes (advanced, with logo embedding) |
| PDF barcode reading | No | Yes (native, no extra library) |
| PDF barcode generation output | No | Yes |
| SkiaSharp dependency | Yes (version conflict risk) | No |
| MAUI project compatibility | Conflict risk (NU1608) | No conflict |
| Fluent chainable API | No | Yes |
byte[] output directly |
Manual (via MemoryStream) |
.ToPngBinaryData() |
| Multi-barcode detection | No | Yes (ExpectMultipleBarcodes) |
| Reading speed tuning | N/A | Yes (ReadingSpeed enum) |
| Linux / macOS support | Partial (SkiaSharp-dependent) | Full |
| Docker / container support | Configuration required | Yes |
| Active maintenance | Yes (community) | Yes (commercial) |
| Commercial support / SLA | No | Yes |
| License | Apache 2.0 (free) | $749–$5,999 perpetual |
Quick Start: BarcodeLib to IronBarcode Migration
The migration can begin immediately with these foundational steps.
Step 1: Replace NuGet Package
Remove the BarcodeLib package first:
dotnet remove package BarcodeLib
dotnet remove package BarcodeLib
If you are not sure how it is referenced, check the .csproj file:
grep -n "BarcodeLib" YourProject.csproj
grep -n "BarcodeLib" YourProject.csproj
Remove all BarcodeLib-related <PackageReference> entries. If you added explicit <PackageReference Include="SkiaSharp"> overrides to work around NU1608 warnings from BarcodeLib, remove those too — after installing IronBarcode, evaluate whether SkiaSharp is still needed for other reasons. Then install IronBarcode:
dotnet add package IronBarcode
dotnet add package IronBarcode
Step 2: Update Namespaces
Replace the BarcodeLib using directives in each file that referenced them:
// Before
using BarcodeStandard;
using SkiaSharp;
// After
using IronBarCode;
// Before
using BarcodeStandard;
using SkiaSharp;
// After
using IronBarCode;
Imports IronBarCode
Imports SkiaSharp
Step 3: Initialize License
Add license initialization at application startup:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
For ASP.NET Core applications, put this in Program.cs before builder.Build(). For console applications, put it at the top of Main(). For class libraries called from other apps, initialize it wherever the host application starts.
Code Migration Examples
Basic Code128 Generation
The most common BarcodeLib pattern: create an instance, set properties, call Encode().
BarcodeLib Approach:
using BarcodeStandard;
using SkiaSharp;
public void GenerateShippingLabel(string trackingNumber, string outputPath)
{
var b = new Barcode();
b.IncludeLabel = true;
SKImage img = b.Encode(Type.Code128, trackingNumber, 400, 120);
using var stream = File.OpenWrite(outputPath);
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream);
}
using BarcodeStandard;
using SkiaSharp;
public void GenerateShippingLabel(string trackingNumber, string outputPath)
{
var b = new Barcode();
b.IncludeLabel = true;
SKImage img = b.Encode(Type.Code128, trackingNumber, 400, 120);
using var stream = File.OpenWrite(outputPath);
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream);
}
Imports BarcodeStandard
Imports SkiaSharp
Public Sub GenerateShippingLabel(trackingNumber As String, outputPath As String)
Dim b As New Barcode()
b.IncludeLabel = True
Dim img As SKImage = b.Encode(Type.Code128, trackingNumber, 400, 120)
Using stream = File.OpenWrite(outputPath)
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream)
End Using
End Sub
IronBarcode Approach:
// NuGet: dotnet add package IronBarcode
using IronBarCode;
public void GenerateShippingLabel(string trackingNumber, string outputPath)
{
BarcodeWriter.CreateBarcode(trackingNumber, BarcodeEncoding.Code128)
.ResizeTo(400, 120)
.AddAnnotationTextBelowBarcode(trackingNumber)
.SaveAsPng(outputPath);
}
// NuGet: dotnet add package IronBarcode
using IronBarCode;
public void GenerateShippingLabel(string trackingNumber, string outputPath)
{
BarcodeWriter.CreateBarcode(trackingNumber, BarcodeEncoding.Code128)
.ResizeTo(400, 120)
.AddAnnotationTextBelowBarcode(trackingNumber)
.SaveAsPng(outputPath);
}
Imports IronBarCode
Public Sub GenerateShippingLabel(trackingNumber As String, outputPath As String)
BarcodeWriter.CreateBarcode(trackingNumber, BarcodeEncoding.Code128) _
.ResizeTo(400, 120) _
.AddAnnotationTextBelowBarcode(trackingNumber) _
.SaveAsPng(outputPath)
End Sub
The property-setter block collapses into a fluent chain. .AddAnnotationTextBelowBarcode() replaces b.IncludeLabel = true — it accepts the label string explicitly so you control what text appears below the bars. .ResizeTo() replaces the width/height arguments. For advanced generation options, see the IronBarcode barcode generation documentation.
Returning byte[] — the Common Web API Pattern
BarcodeLib 3.x returns an SKImage. Getting bytes out of it requires encoding through SkiaSharp into a MemoryStream. IronBarcode provides .ToPngBinaryData() directly.
BarcodeLib Approach:
using BarcodeStandard;
using SkiaSharp;
using System.IO;
public byte[] GetBarcodeBytes(string data)
{
var b = new Barcode();
SKImage img = b.Encode(Type.Code128, data, 300, 100);
using var ms = new MemoryStream();
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return ms.ToArray();
}
using BarcodeStandard;
using SkiaSharp;
using System.IO;
public byte[] GetBarcodeBytes(string data)
{
var b = new Barcode();
SKImage img = b.Encode(Type.Code128, data, 300, 100);
using var ms = new MemoryStream();
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return ms.ToArray();
}
Imports BarcodeStandard
Imports SkiaSharp
Imports System.IO
Public Function GetBarcodeBytes(data As String) As Byte()
Dim b As New Barcode()
Dim img As SKImage = b.Encode(Type.Code128, data, 300, 100)
Using ms As New MemoryStream()
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms)
Return ms.ToArray()
End Using
End Function
IronBarcode Approach:
using IronBarCode;
public byte[] GetBarcodeBytes(string data)
{
return BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
.ResizeTo(300, 100)
.ToPngBinaryData();
}
using IronBarCode;
public byte[] GetBarcodeBytes(string data)
{
return BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
.ResizeTo(300, 100)
.ToPngBinaryData();
}
Imports IronBarCode
Public Function GetBarcodeBytes(data As String) As Byte()
Return BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128) _
.ResizeTo(300, 100) _
.ToPngBinaryData()
End Function
The MemoryStream intermediate step is gone. .ToPngBinaryData() returns the byte[] directly, which is what HTTP response bodies, database BLOB columns, and file writers actually want.
Web API Controller Action
BarcodeLib Approach:
using BarcodeStandard;
using SkiaSharp;
using Microsoft.AspNetCore.Mvc;
using System.IO;
[ApiController]
[Route("api/labels")]
public class LabelsController : ControllerBase
{
[HttpGet("{sku}")]
public IActionResult GetLabel(string sku)
{
var b = new Barcode();
SKImage img = b.Encode(Type.Code128, sku, 400, 120);
using var ms = new MemoryStream();
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return File(ms.ToArray(), "image/png");
}
}
using BarcodeStandard;
using SkiaSharp;
using Microsoft.AspNetCore.Mvc;
using System.IO;
[ApiController]
[Route("api/labels")]
public class LabelsController : ControllerBase
{
[HttpGet("{sku}")]
public IActionResult GetLabel(string sku)
{
var b = new Barcode();
SKImage img = b.Encode(Type.Code128, sku, 400, 120);
using var ms = new MemoryStream();
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return File(ms.ToArray(), "image/png");
}
}
Imports BarcodeStandard
Imports SkiaSharp
Imports Microsoft.AspNetCore.Mvc
Imports System.IO
<ApiController>
<Route("api/labels")>
Public Class LabelsController
Inherits ControllerBase
<HttpGet("{sku}")>
Public Function GetLabel(sku As String) As IActionResult
Dim b As New Barcode()
Dim img As SKImage = b.Encode(Type.Code128, sku, 400, 120)
Using ms As New MemoryStream()
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms)
Return File(ms.ToArray(), "image/png")
End Using
End Function
End Class
IronBarcode Approach:
using IronBarCode;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/labels")]
public class LabelsController : ControllerBase
{
[HttpGet("{sku}")]
public IActionResult GetLabel(string sku)
{
byte[] pngBytes = BarcodeWriter.CreateBarcode(sku, BarcodeEncoding.Code128)
.ResizeTo(400, 120)
.ToPngBinaryData();
return File(pngBytes, "image/png");
}
}
using IronBarCode;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/labels")]
public class LabelsController : ControllerBase
{
[HttpGet("{sku}")]
public IActionResult GetLabel(string sku)
{
byte[] pngBytes = BarcodeWriter.CreateBarcode(sku, BarcodeEncoding.Code128)
.ResizeTo(400, 120)
.ToPngBinaryData();
return File(pngBytes, "image/png");
}
}
Imports IronBarCode
Imports Microsoft.AspNetCore.Mvc
<ApiController>
<Route("api/labels")>
Public Class LabelsController
Inherits ControllerBase
<HttpGet("{sku}")>
Public Function GetLabel(sku As String) As IActionResult
Dim pngBytes As Byte() = BarcodeWriter.CreateBarcode(sku, BarcodeEncoding.Code128) _
.ResizeTo(400, 120) _
.ToPngBinaryData()
Return File(pngBytes, "image/png")
End Function
End Class
The controller action shrinks by removing the MemoryStream block and the SkiaSharp encode step. The byte array flows directly from .ToPngBinaryData() into File().
QR Code Generation
BarcodeLib 3.x does not generate QR codes — the BarcodeStandard.Type enum contains no 2D entries. Projects that needed QR alongside BarcodeLib typically added a second library such as QRCoder. IronBarcode uses a dedicated QRCodeWriter class with additional options for logo embedding and styling.
BarcodeLib Approach:
// BarcodeLib has no QR Code (or any 2D) support.
// Generating a QR code from a BarcodeLib project required adding a
// second library such as QRCoder:
//
// using QRCoder;
// var qrGen = new QRCodeGenerator();
// var data = qrGen.CreateQrCode("https://example.com/product/42", QRCodeGenerator.ECCLevel.Q);
// // ... separate API, separate dependency to maintain.
// BarcodeLib has no QR Code (or any 2D) support.
// Generating a QR code from a BarcodeLib project required adding a
// second library such as QRCoder:
//
// using QRCoder;
// var qrGen = new QRCodeGenerator();
// var data = qrGen.CreateQrCode("https://example.com/product/42", QRCodeGenerator.ECCLevel.Q);
// // ... separate API, separate dependency to maintain.
' BarcodeLib has no QR Code (or any 2D) support.
' Generating a QR code from a BarcodeLib project required adding a
' second library such as QRCoder:
'
' Imports QRCoder
' Dim qrGen As New QRCodeGenerator()
' Dim data = qrGen.CreateQrCode("https://example.com/product/42", QRCodeGenerator.ECCLevel.Q)
' ' ... separate API, separate dependency to maintain.
IronBarcode Approach:
using IronBarCode;
// Basic QR code
QRCodeWriter.CreateQrCode("https://example.com/product/42", 300)
.SaveAsPng("qr.png");
// QR code with embedded brand logo (not possible with BarcodeLib)
QRCodeWriter.CreateQrCode("https://example.com/product/42", 300)
.AddBrandLogo("logo.png")
.SaveAsPng("qr-branded.png");
using IronBarCode;
// Basic QR code
QRCodeWriter.CreateQrCode("https://example.com/product/42", 300)
.SaveAsPng("qr.png");
// QR code with embedded brand logo (not possible with BarcodeLib)
QRCodeWriter.CreateQrCode("https://example.com/product/42", 300)
.AddBrandLogo("logo.png")
.SaveAsPng("qr-branded.png");
Imports IronBarCode
' Basic QR code
QRCodeWriter.CreateQrCode("https://example.com/product/42", 300) _
.SaveAsPng("qr.png")
' QR code with embedded brand logo (not possible with BarcodeLib)
QRCodeWriter.CreateQrCode("https://example.com/product/42", 300) _
.AddBrandLogo("logo.png") _
.SaveAsPng("qr-branded.png")
QRCodeWriter.CreateQrCode() takes the data string and pixel size as parameters. Logo embedding, color customization, and error correction level are all available through chained methods. For QR code styling options, see the IronBarcode QR code documentation.
EAN-13 and UPC-A
These are common in retail inventory systems. The enum names change but the values are direct equivalents.
BarcodeLib Approach:
using BarcodeStandard;
using SkiaSharp;
// EAN-13 product barcode
var b = new Barcode();
SKImage ean = b.Encode(Type.Ean13, "5901234123457", 250, 100);
using (var s = File.OpenWrite("product-ean.png"))
ean.Encode(SKEncodedImageFormat.Png, 100).SaveTo(s);
// UPC-A for US retail
SKImage upc = b.Encode(Type.UpcA, "012345678905", 250, 100);
using (var s = File.OpenWrite("product-upc.png"))
upc.Encode(SKEncodedImageFormat.Png, 100).SaveTo(s);
using BarcodeStandard;
using SkiaSharp;
// EAN-13 product barcode
var b = new Barcode();
SKImage ean = b.Encode(Type.Ean13, "5901234123457", 250, 100);
using (var s = File.OpenWrite("product-ean.png"))
ean.Encode(SKEncodedImageFormat.Png, 100).SaveTo(s);
// UPC-A for US retail
SKImage upc = b.Encode(Type.UpcA, "012345678905", 250, 100);
using (var s = File.OpenWrite("product-upc.png"))
upc.Encode(SKEncodedImageFormat.Png, 100).SaveTo(s);
Imports BarcodeStandard
Imports SkiaSharp
Imports System.IO
' EAN-13 product barcode
Dim b As New Barcode()
Dim ean As SKImage = b.Encode(Type.Ean13, "5901234123457", 250, 100)
Using s = File.OpenWrite("product-ean.png")
ean.Encode(SKEncodedImageFormat.Png, 100).SaveTo(s)
End Using
' UPC-A for US retail
Dim upc As SKImage = b.Encode(Type.UpcA, "012345678905", 250, 100)
Using s = File.OpenWrite("product-upc.png")
upc.Encode(SKEncodedImageFormat.Png, 100).SaveTo(s)
End Using
IronBarcode Approach:
using IronBarCode;
// EAN-13 product barcode
BarcodeWriter.CreateBarcode("5901234123457", BarcodeEncoding.EAN13)
.ResizeTo(250, 100)
.SaveAsPng("product-ean.png");
// UPC-A for US retail
BarcodeWriter.CreateBarcode("012345678905", BarcodeEncoding.UPCA)
.ResizeTo(250, 100)
.SaveAsPng("product-upc.png");
using IronBarCode;
// EAN-13 product barcode
BarcodeWriter.CreateBarcode("5901234123457", BarcodeEncoding.EAN13)
.ResizeTo(250, 100)
.SaveAsPng("product-ean.png");
// UPC-A for US retail
BarcodeWriter.CreateBarcode("012345678905", BarcodeEncoding.UPCA)
.ResizeTo(250, 100)
.SaveAsPng("product-upc.png");
Imports IronBarCode
' EAN-13 product barcode
BarcodeWriter.CreateBarcode("5901234123457", BarcodeEncoding.EAN13) _
.ResizeTo(250, 100) _
.SaveAsPng("product-ean.png")
' UPC-A for US retail
BarcodeWriter.CreateBarcode("012345678905", BarcodeEncoding.UPCA) _
.ResizeTo(250, 100) _
.SaveAsPng("product-upc.png")
Adding Barcode Reading (Net-New Capability)
BarcodeLib has no reading API. If your migration is driven by a new requirement to scan barcodes — from uploaded images, warehouse scanners, or scanned PDF documents — add this without a second library:
BarcodeLib Approach:
// BarcodeLib — no reading API exists
// Adding reading requires a separate library such as ZXing.Net:
// dotnet add package ZXing.Net
// using ZXing;
// var reader = new BarcodeReader();
// // ... separate API, separate dependency graph to manage
// BarcodeLib — no reading API exists
// Adding reading requires a separate library such as ZXing.Net:
// dotnet add package ZXing.Net
// using ZXing;
// var reader = new BarcodeReader();
// // ... separate API, separate dependency graph to manage
' BarcodeLib — no reading API exists
' Adding reading requires a separate library such as ZXing.Net:
' dotnet add package ZXing.Net
' Imports ZXing
' Dim reader As New BarcodeReader()
' ' ... separate API, separate dependency graph to manage
IronBarcode Approach:
using IronBarCode;
// Read a barcode from an image file
var results = BarcodeReader.Read("incoming-label.png");
foreach (var result in results)
{
Console.WriteLine($"Value: {result.Value}");
Console.WriteLine($"Format: {result.Format}");
}
// Read all barcodes from a multi-page PDF — no PDF library required
var pdfResults = BarcodeReader.Read("supplier-invoice.pdf");
foreach (var result in pdfResults)
{
Console.WriteLine($"Page {result.PageNumber}: {result.Value}");
}
// Configure for high-volume scanning with multiple barcodes per image
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = true
};
var warehouseResults = BarcodeReader.Read("dock-scan.png", options);
using IronBarCode;
// Read a barcode from an image file
var results = BarcodeReader.Read("incoming-label.png");
foreach (var result in results)
{
Console.WriteLine($"Value: {result.Value}");
Console.WriteLine($"Format: {result.Format}");
}
// Read all barcodes from a multi-page PDF — no PDF library required
var pdfResults = BarcodeReader.Read("supplier-invoice.pdf");
foreach (var result in pdfResults)
{
Console.WriteLine($"Page {result.PageNumber}: {result.Value}");
}
// Configure for high-volume scanning with multiple barcodes per image
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = true
};
var warehouseResults = BarcodeReader.Read("dock-scan.png", options);
Imports IronBarCode
' Read a barcode from an image file
Dim results = BarcodeReader.Read("incoming-label.png")
For Each result In results
Console.WriteLine($"Value: {result.Value}")
Console.WriteLine($"Format: {result.Format}")
Next
' Read all barcodes from a multi-page PDF — no PDF library required
Dim pdfResults = BarcodeReader.Read("supplier-invoice.pdf")
For Each result In pdfResults
Console.WriteLine($"Page {result.PageNumber}: {result.Value}")
Next
' Configure for high-volume scanning with multiple barcodes per image
Dim options As New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Balanced,
.ExpectMultipleBarcodes = True
}
Dim warehouseResults = BarcodeReader.Read("dock-scan.png", options)
BarcodeReader.Read() accepts image files, PDF files, streams, and System.Drawing.Bitmap objects. The ReadingSpeed enum lets you trade thoroughness for performance when scanning at volume. For reading configuration options, see the IronBarcode reading documentation.
Resolving the SkiaSharp Conflict
If your migration is driven by NU1608 warnings, verify the conflict is resolved after switching packages. After running dotnet remove package BarcodeLib and dotnet add package IronBarcode, rebuild and check the output:
dotnet build 2>&1 | grep -i "NU1608\|SkiaSharp"
dotnet build 2>&1 | grep -i "NU1608\|SkiaSharp"
If no output appears, the conflict is resolved. If SkiaSharp warnings remain, they are coming from a different package in your dependency graph — IronBarcode is not the source.
BarcodeLib Approach:
<ItemGroup>
<PackageReference Include="BarcodeLib" Version="3.1.5" />
<PackageReference Include="SkiaSharp" Version="3.116.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BarcodeLib" Version="3.1.5" />
<PackageReference Include="SkiaSharp" Version="3.116.1" />
</ItemGroup>
IronBarcode Approach:
<ItemGroup>
<PackageReference Include="IronBarcode" Version="*" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="3.116.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IronBarcode" Version="*" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="3.116.1" />
</ItemGroup>
BarcodeLib API to IronBarcode Mapping Reference
| BarcodeLib | IronBarcode |
|---|---|
new Barcode() |
Static API — no instance required |
b.Encode(Type.Code128, "data", w, h) |
BarcodeWriter.CreateBarcode("data", BarcodeEncoding.Code128) |
b.IncludeLabel = true |
.AddAnnotationTextBelowBarcode("text") |
Width/height passed to Encode() |
.ResizeTo(width, height) |
Returns SKImage |
.SaveAsPng(path) / .ToPngBinaryData() |
Type.Code128 |
BarcodeEncoding.Code128 |
Type.Code39 |
BarcodeEncoding.Code39 |
Type.Ean13 |
BarcodeEncoding.EAN13 |
Type.UpcA |
BarcodeEncoding.UPCA |
| No QR support (1D only) | BarcodeEncoding.QRCode (also QRCodeWriter) |
Type.Itf14 |
BarcodeEncoding.ITF14 |
Type.Codabar |
BarcodeEncoding.Codabar |
| No reading API | BarcodeReader.Read(path) |
| SkiaSharp version conflict in MAUI | No conflicting dependencies |
img.Encode(...).SaveTo(stream) |
.SaveAsPng(path) |
MemoryStream + SkiaSharp encode |
.ToPngBinaryData() |
Common Migration Issues and Solutions
Issue 1: Type Enum Namespace Change
BarcodeLib 3.x: Uses BarcodeStandard.Type.Code128 (PascalCase, in the BarcodeStandard namespace). Older 2.x code may use BarcodeLib.TYPE.CODE128 (uppercase constants, BarcodeLib namespace) — both forms appear in real codebases mid-migration.
Solution: Replace with BarcodeEncoding.Code128. A grep across .cs files identifies all occurrences:
grep -rn "Type\.\|TYPE\." --include="*.cs" .
grep -rn "Type\.\|TYPE\." --include="*.cs" .
Common replacements: Type.Code128 / TYPE.CODE128 → BarcodeEncoding.Code128, Type.Ean13 / TYPE.EAN13 → BarcodeEncoding.EAN13, Type.UpcA / TYPE.UPCA → BarcodeEncoding.UPCA, Type.Itf14 / TYPE.ITF14 → BarcodeEncoding.ITF14, Type.Codabar / TYPE.CODABAR → BarcodeEncoding.Codabar. BarcodeLib has no QR entry; any TYPE.QR_Code is dead code from a 2.x version or a fork — replace with BarcodeEncoding.QRCode (or use QRCodeWriter for styled output).
Issue 2: SKImage / Image Return Type
BarcodeLib: b.Encode() returns SKImage in 3.x and System.Drawing.Image in 2.x. Either type will not compile against IronBarcode.
Solution: Remove the intermediate image variable and replace the save logic with the appropriate terminal method on the fluent chain:
// Before (BarcodeLib 3.x)
SKImage img = b.Encode(Type.Code128, data, 300, 100);
using var ms = new MemoryStream();
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return ms.ToArray();
// After
return BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
.ResizeTo(300, 100)
.ToPngBinaryData();
// Before (BarcodeLib 3.x)
SKImage img = b.Encode(Type.Code128, data, 300, 100);
using var ms = new MemoryStream();
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return ms.ToArray();
// After
return BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
.ResizeTo(300, 100)
.ToPngBinaryData();
Imports System.IO
' Before (BarcodeLib 3.x)
Dim img As SKImage = b.Encode(Type.Code128, data, 300, 100)
Using ms As New MemoryStream()
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms)
Return ms.ToArray()
End Using
' After
Return BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128) _
.ResizeTo(300, 100) _
.ToPngBinaryData()
Search for SKImage img = b.Encode and Image img = b.Encode patterns to find all affected locations.
Issue 3: Width and Height Parameters
BarcodeLib: Width and height are positional arguments on Encode(Type, string, int, int) in 3.x, and separate b.Width / b.Height property assignments in older 2.x code. Either form needs porting.
Solution: The width/height become a single .ResizeTo(width, height) call chained after CreateBarcode(). Find the call sites:
# Find Encode() calls and any Width/Height property assignments
grep -n "\.Encode(\|\.Width = \|\.Height = " --include="*.cs" -r .
# Find Encode() calls and any Width/Height property assignments
grep -n "\.Encode(\|\.Width = \|\.Height = " --include="*.cs" -r .
Then replace the size arguments or property pair with a single .ResizeTo(width, height) chain call.
Issue 4: IncludeLabel Boolean Toggle
BarcodeLib: b.IncludeLabel = true is a boolean that automatically renders the encoded data string as the visible text below the bars.
Solution: Use .AddAnnotationTextBelowBarcode("text"), which takes the label string explicitly. In most cases, pass the same data string that was encoded into the barcode. If the original code used IncludeLabel = true and relied on BarcodeLib to auto-render the data as the label, pass that same data string explicitly:
BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
.AddAnnotationTextBelowBarcode(data) // pass the same string
.SaveAsPng(outputPath);
BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
.AddAnnotationTextBelowBarcode(data) // pass the same string
.SaveAsPng(outputPath);
Dim barcodeWriter = BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
barcodeWriter.AddAnnotationTextBelowBarcode(data) ' pass the same string
barcodeWriter.SaveAsPng(outputPath)
Issue 5: SkiaSharp References Left After BarcodeLib Removal
BarcodeLib: Projects frequently accumulated explicit <PackageReference Include="SkiaSharp"> entries specifically to override BarcodeLib's version constraint. These become orphaned after BarcodeLib is removed.
Solution: After switching to IronBarcode, verify whether SkiaSharp is still needed by any other package before removing the explicit reference:
# Check if SkiaSharp is still referenced by anything other than the explicit override
dotnet list package --include-transitive 2>&1 | grep -i skia
# Check if SkiaSharp is still referenced by anything other than the explicit override
dotnet list package --include-transitive 2>&1 | grep -i skia
If SkiaSharp only appears due to the now-removed explicit <PackageReference>, remove that entry. If it is still pulled in by MAUI or another dependency, leave it — IronBarcode will not conflict with it.
BarcodeLib Migration Checklist
Pre-Migration Tasks
Run these searches before starting to understand the scope of changes needed:
# Find all BarcodeLib using directives (both 3.x BarcodeStandard and older BarcodeLib)
grep -rn "using BarcodeStandard\|using BarcodeLib" --include="*.cs" .
# Find Barcode object instantiation
grep -rn "new Barcode()" --include="*.cs" .
# Find Encode calls
grep -rn "\.Encode(" --include="*.cs" .
# Find Type enum usage (3.x PascalCase and 2.x uppercase)
grep -rn "Type\.Code128\|Type\.Ean13\|Type\.UpcA\|TYPE\.CODE128\|TYPE\.EAN13\|TYPE\.UPCA" --include="*.cs" .
# Find IncludeLabel usage
grep -rn "IncludeLabel" --include="*.cs" .
# Find the package references in project files
grep -rn "BarcodeLib" --include="*.csproj" .
# Find NU1608 evidence in lock files
grep -rn "NU1608" .
# Find all BarcodeLib using directives (both 3.x BarcodeStandard and older BarcodeLib)
grep -rn "using BarcodeStandard\|using BarcodeLib" --include="*.cs" .
# Find Barcode object instantiation
grep -rn "new Barcode()" --include="*.cs" .
# Find Encode calls
grep -rn "\.Encode(" --include="*.cs" .
# Find Type enum usage (3.x PascalCase and 2.x uppercase)
grep -rn "Type\.Code128\|Type\.Ean13\|Type\.UpcA\|TYPE\.CODE128\|TYPE\.EAN13\|TYPE\.UPCA" --include="*.cs" .
# Find IncludeLabel usage
grep -rn "IncludeLabel" --include="*.cs" .
# Find the package references in project files
grep -rn "BarcodeLib" --include="*.csproj" .
# Find NU1608 evidence in lock files
grep -rn "NU1608" .
Document all files affected by each search. Note which projects reference BarcodeLib directly and which inherit it transitively. Identify any explicit SkiaSharp version overrides added only to resolve BarcodeLib conflicts.
Code Update Tasks
- Run
dotnet remove package BarcodeLibfor each project - Remove any explicit SkiaSharp version override references added only to fix BarcodeLib conflicts
- Run
dotnet add package IronBarcodefor each project - Add
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";to application startup in each project - Replace
using BarcodeStandard;(orusing BarcodeLib;in older code) andusing SkiaSharp;withusing IronBarCode;across all.csfiles - Remove
using System.Drawing.Imaging;imports left over from 2.xImageFormat.Pngusage - Replace
new Barcode()+Encode()calls withBarcodeWriter.CreateBarcode()fluent chains - Replace
Type.Code128/TYPE.CODE128→BarcodeEncoding.Code128and all other enum values - Replace width/height arguments (or 2.x
b.Width = N; b.Height = M;) with.ResizeTo(N, M)chain calls - Replace
b.IncludeLabel = true;with.AddAnnotationTextBelowBarcode(data) - Replace
img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(...)with.SaveAsPng(path)or.ToPngBinaryData() - Remove intermediate
SKImage/Imagevariables andMemoryStreamblocks where.ToPngBinaryData()replaces them - Add barcode reading code where needed (
BarcodeReader.Read())
Post-Migration Testing
- Build the project and confirm zero NU1608 warnings remain in the restore output
- Run
dotnet build 2>&1 | grep -i "NU1608\|SkiaSharp"to verify the SkiaSharp conflict is fully resolved - Compare visual output of generated barcodes against known-good samples from BarcodeLib
- Verify that QR codes decode correctly using a mobile scanner or the
BarcodeReader.Read()method - Test EAN-13 and UPC-A barcodes against retail scanner hardware if applicable
- Verify images display correctly in all output targets: file system, HTTP response, database storage
- Test any PDF barcode reading scenarios using
BarcodeReader.Read("file.pdf")on real documents - Confirm cross-platform builds succeed if the project targets Linux or macOS
- Verify that MAUI builds complete without SkiaSharp binding errors on Android and iOS targets
Key Benefits of Migrating to IronBarcode
Barcode Reading Without a Second Library: The most immediate gain for teams that needed reading capability is eliminating the second-library dependency. BarcodeReader.Read() is in the same package, uses the same using IronBarCode; statement, and requires no additional NuGet installs. ZXing.Net and its own dependency graph are no longer part of the project.
No SkiaSharp Version Conflict: IronBarcode does not share the SkiaSharp dependency graph with application code. MAUI projects, Blazor projects, and any project where multiple packages converge on SkiaSharp can install IronBarcode without NU1608 warnings or runtime binding failures. The version negotiation that BarcodeLib introduced is gone.
Direct Byte Array Output: .ToPngBinaryData() returns byte[] at the end of the fluent chain. The MemoryStream intermediary that BarcodeLib required for byte array output is eliminated from every controller action, service method, and API handler that generates barcodes.
PDF Barcode Processing: BarcodeReader.Read() accepts PDF files natively. Applications that generate PDF documents with embedded barcodes can read those barcodes back without a separate PDF rendering library. The full chain — generation, PDF embedding, and reading — is handled within IronBarcode.
Commercial Support and SLA: IronBarcode is backed by Iron Software's commercial support model with a defined update cadence. When new .NET releases land or breaking changes appear in the .NET ecosystem, IronBarcode publishes compatibility updates on a timeline tied to the commercial SLA rather than community availability.
QR Code Generation Without a Second Library: QRCodeWriter supports logo embedding, color customization, and error correction level configuration through chained methods. BarcodeLib 3.x generates 1D symbologies only — projects that needed QR alongside BarcodeLib previously added a second library such as QRCoder. Teams whose QR code requirements have expanded gain these features inside the same package, without changing their generation workflow.
Frequently Asked Questions
Why should I migrate from BarcodeLib to IronBarcode?
Common reasons include simplifying licensing (removing SDK + runtime key complexity), eliminating throughput limits, gaining native PDF support, improving Docker/CI/CD deployment, and reducing API boilerplate in production code.
How do I replace BarcodeLib API calls with IronBarcode?
Replace instance creation and licensing boilerplate with IronBarCode.License.LicenseKey = "key". Replace reader calls with BarcodeReader.Read(path) and writer calls with BarcodeWriter.CreateBarcode(data, encoding). Static methods require no instance management.
How much code changes when migrating from BarcodeLib to IronBarcode?
Most migrations result in fewer lines of code. Licensing boilerplate, instance constructors, and explicit format configuration are removed. Core read/write operations map to shorter IronBarcode equivalents with cleaner result objects.
Do I need to keep both BarcodeLib and IronBarcode installed during migration?
No. Most migrations are direct replacements rather than parallel operation. Migrate one service class at a time, replace the NuGet reference, and update the instantiation and API call patterns before moving to the next class.
What is the NuGet package name for IronBarcode?
The package is 'IronBarCode' (with capital B and C). Install it with 'Install-Package IronBarCode' or 'dotnet add package IronBarCode'. The using directive in code is 'using IronBarCode;'.
How does IronBarcode simplify Docker deployment compared to BarcodeLib?
IronBarcode is a NuGet package with no external SDK files or mounted license configuration. In Docker, set the IRONBARCODE_LICENSE_KEY environment variable and the package handles license validation at startup.
Does IronBarcode detect all barcode formats automatically after migrating from BarcodeLib?
Yes. IronBarcode auto-detects symbology across all supported formats. Explicit BarcodeTypes enumeration is not required. If format is already known and performance matters, BarcodeReaderOptions allows restricting the search space as an optimization.
Can IronBarcode read barcodes from PDFs without a separate library?
Yes. BarcodeReader.Read("document.pdf") processes PDF files natively. Results include PageNumber, Format, Value, and Confidence for each barcode found. No external PDF rendering step is required.
How does IronBarcode handle parallel barcode processing?
IronBarcode's static methods are stateless and thread-safe. Use Parallel.ForEach directly over file lists without per-thread instance management. BarcodeReaderOptions.MaxParallelThreads controls the internal thread budget.
What result properties change when migrating from BarcodeLib to IronBarcode?
Common renames: BarcodeValue becomes Value, BarcodeType becomes Format. IronBarcode results also add Confidence and PageNumber. A solution-wide search-and-replace handles the renames in existing result-processing code.
How do I set up IronBarcode licensing in a CI/CD pipeline?
Store IRONBARCODE_LICENSE_KEY as a pipeline secret and assign IronBarCode.License.LicenseKey in application startup code. One secret covers all environments including development, test, staging, and production.
Does IronBarcode support QR code generation with custom styling?
Yes. QRCodeWriter.CreateQrCode() supports custom colors via ChangeBarCodeColor(), logo embedding via AddBrandLogo(), configurable error correction levels, and multiple output formats including PNG, JPG, PDF, and stream.

