Skip to footer content
MIGRATION GUIDES

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
$vbLabelText   $csharpLabel

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"
$vbLabelText   $csharpLabel

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
SHELL

If you are not sure how it is referenced, check the .csproj file:

grep -n "BarcodeLib" YourProject.csproj
grep -n "BarcodeLib" YourProject.csproj
SHELL

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
SHELL

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
$vbLabelText   $csharpLabel

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"
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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.
$vbLabelText   $csharpLabel

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")
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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")
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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)
$vbLabelText   $csharpLabel

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"
SHELL

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>
XML

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>
XML

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" .
SHELL

Common replacements: Type.Code128 / TYPE.CODE128BarcodeEncoding.Code128, Type.Ean13 / TYPE.EAN13BarcodeEncoding.EAN13, Type.UpcA / TYPE.UPCABarcodeEncoding.UPCA, Type.Itf14 / TYPE.ITF14BarcodeEncoding.ITF14, Type.Codabar / TYPE.CODABARBarcodeEncoding.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()
$vbLabelText   $csharpLabel

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 .
SHELL

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)
$vbLabelText   $csharpLabel

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
SHELL

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" .
SHELL

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

  1. Run dotnet remove package BarcodeLib for each project
  2. Remove any explicit SkiaSharp version override references added only to fix BarcodeLib conflicts
  3. Run dotnet add package IronBarcode for each project
  4. Add IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"; to application startup in each project
  5. Replace using BarcodeStandard; (or using BarcodeLib; in older code) and using SkiaSharp; with using IronBarCode; across all .cs files
  6. Remove using System.Drawing.Imaging; imports left over from 2.x ImageFormat.Png usage
  7. Replace new Barcode() + Encode() calls with BarcodeWriter.CreateBarcode() fluent chains
  8. Replace Type.Code128 / TYPE.CODE128BarcodeEncoding.Code128 and all other enum values
  9. Replace width/height arguments (or 2.x b.Width = N; b.Height = M;) with .ResizeTo(N, M) chain calls
  10. Replace b.IncludeLabel = true; with .AddAnnotationTextBelowBarcode(data)
  11. Replace img.Encode(SKEncodedImageFormat.Png, 100).SaveTo(...) with .SaveAsPng(path) or .ToPngBinaryData()
  12. Remove intermediate SKImage / Image variables and MemoryStream blocks where .ToPngBinaryData() replaces them
  13. 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.

Jordi Bardia
Software Engineer
Jordi is most proficient in Python, C# and C++, when he isn’t leveraging his skills at Iron Software; he’s game programming. Sharing responsibilities for product testing, product development and research, Jordi adds immense value to continual product improvement. The varied experience keeps him challenged and engaged, and he ...
Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me