DEV Community

IronSoftware
IronSoftware

Posted on

ZXing.Net in 2026: Builds on Windows, Breaks on Linux

A ZXing.Net barcode reader can compile cleanly on a developer's Windows machine and then throw the first time it runs in a Linux container, with nothing in the build to warn you. The cause is packaging rather than your code, because on modern .NET the base ZXing.Net package cannot read an image at all, so a separate binding does the actual decoding, and the binding most tutorials reach for wraps System.Drawing.Common, which Microsoft restricted to Windows from .NET 6.

IronBarcode reads from one package that behaves the same on Windows, Linux, and macOS, with no binding to choose, which is the difference this piece is about.

Full disclosure. We build IronBarcode at Iron Software, and this read looks at where ZXing.Net's binding and preprocessing gaps cost a team and where IronBarcode covers them from one package.

ZXing.Net and IronBarcode at a Glance

Here is where the two differ before the detail, because the packaging row at the top is the one that decides your platform.

Aspect ZXing.Net IronBarcode
Reads from the base package alone No, a binding package is required Yes, from one package
Same code across Windows, Linux, macOS No, the binding decides the platform Yes
The common System.Drawing binding Windows-only from .NET 6 No binding to pick
Read a barcode from a PDF Not supported Supported, BarcodeReader.ReadPdf
Imperfect-scan handling Minimal, you supply clean images Built in, deskew, denoise, contrast
Read and write Yes Yes, BarcodeReader.Read and BarcodeWriter.CreateBarcode

Table 1. ZXing.Net and IronBarcode across the packaging, platform, and reading questions, from each project's own repository and documentation.

Which Binding Decides Your Platform?

The base package pushes the real work into a ZXing.Net.Bindings.* package, and which one you pick sets which operating systems your code runs on. The sample most projects start from looks harmless.

using ZXing;
using ZXing.Windows.Compatibility;   // the binding most tutorials reach for

var reader = new BarcodeReader();
using var bitmap = (Bitmap)Image.FromFile("scanned-label.png");
var result = reader.Decode(bitmap);

// Builds and runs on Windows. Throws in a Linux container.
Enter fullscreen mode Exit fullscreen mode

That builds and runs locally and then throws in a Linux container, because the binding it imports is Windows-only. The choice underneath it is wider than one import.

  • You pick an imaging stack before you read a code: ImageSharp, SkiaSharp, or Windows.Compatibility, each with its own namespace and API, and every tutorial assumes a different one.
  • The obvious binding is Windows-only: ZXing.Net.Bindings.Windows.Compatibility wraps System.Drawing.Common, restricted to Windows from .NET 6, so it builds locally and fails at runtime in a Linux container.
  • Getting out is a rewrite, not a config change: moving to ImageSharp or SkiaSharp means rewriting the image-handling layer rather than flipping a setting.

What Does the Reader Still Leave You?

Settle the binding and the reader still hands back most of the hard part, because ZXing.Net decodes what you give it and does little to rescue a poor image. Deskewing, denoising, and contrast correction for a warehouse photo or a damaged label is code you write against a separate imaging library and tune by trial and error. Reading a barcode out of a PDF is not supported either, so you rasterise the pages with another library first and feed the images in. The upstream Java project the port tracks is in maintenance mode, so that list of things you assemble is unlikely to shorten, even as the port itself keeps shipping, 0.16.11 as of October 2025. IronBarcode corrects skew, blur, and low contrast inside the library, and reads barcodes straight out of a PDF without a separate rasteriser.

One Package, the Same on Every Platform

IronBarcode reads, corrects, and writes from a single package, so there is no binding decision and no imaging stack to assemble.

using IronBarCode;

// One package, the same behaviour on Windows, Linux, and macOS
var scanned = BarcodeReader.Read("warehouse-scan.jpg");
Console.WriteLine(scanned.First().Value);

// Straight out of a PDF, no rasteriser to write yourself
var fromPdf = BarcodeReader.ReadPdf("shipping-manifest.pdf");

// Generate from the same package
var label = BarcodeWriter.CreateBarcode("ABC-12345", BarcodeEncoding.Code128);
label.SaveAsPng("label.png");
Enter fullscreen mode Exit fullscreen mode

That reads a scan, pulls a code straight out of a PDF, and writes a new barcode, all from one package that behaves the same on Windows, Linux, and macOS. You can pull IronBarcode from NuGet and run this in a couple of minutes.

Where IronBarcode Reads Everywhere

The one case for ZXing.Net is generating and reading clean images on a single, fixed platform, where the binding is chosen once. In modern .NET that is the exception rather than the rule, since most deployments now cross Linux and containers and a real scan is more often a phone photo at an angle than a clean render.

On that far more common side, the choice is between assembling an imaging layer yourself or covering it with IronBarcode from one package, and the barcode reading guide walks the read path end to end.

IronBarcode has a free trial if you want to run your own scans through it before deciding.

Which input are you dealing with, clean generated codes on a fixed platform, or a photo someone took in a warehouse? Tell us in the comments, that second one has better answers than most people expect.

ZXing.Net is an open-source project distributed under Apache-2.0, and is not affiliated with Iron Software. The details above are drawn from the project's own repository, README, and NuGet listings. If something has changed since, correct us in the comments.

Top comments (0)