---
name: ironbarcode
description: >
  Generate and read 1D/linear and 2D barcode formats in C#/.NET using IronBarcode (the
  `BarCode` NuGet package, namespace `IronBarCode`). Use when the task involves Code
  39/93/128, GS1-128, Codabar, ITF, MSI, Plessey, UPC-A/E, EAN-8/13, Intelligent Mail,
  DataBar/DataBar Expanded, Aztec, DataMatrix, MaxiCode, PDF417, QR, Micro QR or rMQR
  codes — creating barcode images/PDF/HTML/streams, reading barcodes from images, PDFs,
  streams or multi-frame TIFF/GIF, batch/multithreaded scanning, cropping to a region,
  checksum and confidence validation, GS1 element-string parsing, or image
  pre-processing (deskew/threshold/contrast filters) to recover a bad scan — or whenever
  a project already references `IronBarCode`, `BarcodeReader`, `BarcodeWriter`, or
  `GeneratedBarcode`. **Not this skill** for QR-code-specific styling (rounded modules,
  branded logos) or ML-tuned QR detection — that is the sibling **ironqr** skill
  (`IronQR` package); this one covers QR only as one of many symbologies alongside every
  other barcode format.
---

# IronBarcode (C# / .NET)

IronBarcode reads and writes the common 1D and 2D barcode symbologies from a single API:
`BarcodeWriter`/`QRCodeWriter` create barcodes as images, PDF, HTML or streams;
`BarcodeReader` decodes them back out of images, PDFs, streams or byte arrays, with
optional multithreading, cropping and image-correction filters for imperfect scans.
For QR-code-specific work — logo embedding, module/eye styling, or ML-based detection
tuned for blur/rotation/damage — use the **ironqr** skill (`IronQR` package) instead;
that is a separate NuGet package and a separate API, not a mode of this one.

## Scope of this skill

| | |
|---|---|
| Package | `BarCode` (plus a platform variant, see Install) |
| Versions | 2025.x – 2026.x |
| Namespaces | `IronBarCode`, `IronBarCode.Exceptions`, `IronSoftware.Drawing` (shared image type `AnyBitmap`) |
| Runtimes | .NET Framework 4.6.2+, .NET Standard 2.0+, .NET Core 2.0+, .NET 5–10 |

## Install — pick the package for the target platform

`BarCode` and its platform siblings all pull in `BarCode.Slim` (the managed API) and
`BarCode.Detection` (the ML barcode-locator model, via `Microsoft.ML.OnnxRuntime`) plus a
platform-specific native reader package. Keep every Iron package in the solution on the
same version.

| Target | Package |
|---|---|
| Windows | `BarCode` |
| Linux x64 (incl. Docker) | `BarCode.Linux` |
| macOS Intel | `BarCode.MacOs` |
| macOS Apple Silicon | `BarCode.MacOs.ARM` |
| iOS | `BarCode.iOS` |
| Android | `BarCode.Android` |
| Minimal, no ML detection | `BarCode.Slim` (skip if `BarcodeScanMode.MachineLearningScan`/`OnlyDetectionModel` are needed) |

```bash
dotnet add package BarCode          # swap for the row above that matches the runtime
```

Image decoding/encoding is handled by `SixLabors.ImageSharp` (pulled in transitively) —
there is no SkiaSharp dependency. On Linux, native image interop still needs
**libgdiplus**: `apt install -y libgdiplus` (see Deployment).

## Licensing — do this first, every time

```csharp
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE_KEY");
if (!IronBarCode.License.IsLicensed)
    Console.Error.WriteLine("IronBarcode is unlicensed — production calls will throw.");
```

Rules:

- Read the key from the environment or user secrets. **Never** inline a key in source,
  commit one, or echo one to the terminal.
- **Treat a missing key as a blocker, not a warning.** Verified directly against the
  package: an unlicensed call does not silently degrade or watermark — it throws
  `IronSoftware.Exceptions.LicensingException: Production License Required`, with the
  message body reading *"IronBarCode is running in production without a license. *
  *Development use: Free for 7 days * Production use: Requires a license."* The 7-day
  grace is for local development only; treat any deployed/CI environment as production
  and require a real key before it runs there. If `IsLicensed` is false, say so and ask
  for a key rather than letting the user hit this at runtime. Trial keys (30 days, full
  functionality): <https://ironsoftware.com/csharp/barcode/licensing/#trial-license>.
- `IronBarCode.License.IsValidLicense(key)` checks a key without applying it.
- Unlike IronPDF/IronOCR, **`Installation.LicenseKey` is not a synonym here** —
  `IronBarCode.Installation` exposes only `DeploymentPath` (a writable directory for
  native/runtime deployment, see Deployment). The key is set exclusively through
  `License.LicenseKey`, `Web.config`/`App.config` (`<add key="IronBarCode.LicenseKey"
  value="..."/>`), or `appsettings.json` (`"IronBarCode.LicenseKey": "..."`).

## Running a one-off task from the terminal

Requires only the .NET SDK. On **.NET 10+**, a single file is the whole program:

```bash
cat > /tmp/task.cs <<'EOF'
#:package BarCode@2026.8.6
using IronBarCode;
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE_KEY");
var barcode = BarcodeWriter.CreateBarcode("HELLO-WORLD", BarcodeEncoding.Code128);
barcode.SaveAsPng("barcode.png");
EOF
dotnet run /tmp/task.cs
```

Verified directly: unlike IronPDF/IronOCR, this does **not** need
`#:property PublishAot=false` — an unlicensed run reaches the license check and throws
the `LicensingException` above rather than a `PlatformNotSupportedException`, so the
managed `ImageSharp`/ONNX pipeline is not hitting a dynamic-codegen wall under `dotnet
run`. If you additionally `dotnet publish` with Native AOT enabled, treat that specific
combination as unverified and test it before relying on it.

On older SDKs, use a scratch project — and reuse the same directory for later tasks:

```bash
dotnet new console -o /tmp/ironbarcode-scratch && cd /tmp/ironbarcode-scratch
dotnet add package BarCode
# write Program.cs, then:
dotnet run
```

## Recipes

Every call below is verified against the shipped assembly (`BarCode` 2026.8.6): compiled
in a scratch project against the real package, cross-checked against the XML doc
comments IntelliSense reads.

### Read a barcode from an image

```csharp
BarcodeResults results = BarcodeReader.Read("QuickStart.jpg");
foreach (BarcodeResult result in results)
{
    Console.WriteLine(result.Text);        // decoded text
    Console.WriteLine(result.Value);       // same as Text for most formats
    Console.WriteLine(result.BarcodeType); // BarcodeEncoding
    Console.WriteLine(result.PageNumber);
}
int count = results.Count;                 // BarcodeResults : List<BarcodeResult>
BarcodeResult first = results[0];          // indexer works — it's a real List<T>
```

`BarcodeResult` also exposes `BarcodeImage` (cropped `AnyBitmap` of the symbol),
`BinaryValue` (raw bytes), `Width`/`Height`, `Rotation`, `PageOrientation`, `Points`
(the four corner `PointF`s), and `Url` (populated when the decoded value looks like one).

### Tune the read with `BarcodeReaderOptions`

```csharp
var options = new BarcodeReaderOptions
{
    ExpectMultipleBarcodes = true,
    ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128,   // flags enum
    CropArea = new IronSoftware.Drawing.Rectangle(x: 100, y: 200, width: 300, height: 400),
    Speed = ReadingSpeed.Balanced,        // Faster | Balanced | Detailed | ExtremeDetail
    Multithreaded = true,
    MaxParallelThreads = 4,
    RemoveFalsePositive = true,
    ConfidenceThreshold = 0.85,            // 0–1; reject low-confidence reads
    MinScanLines = 3,
    UseCode39ExtendedMode = true,
    AutoRotate = true,
    ScanMode = BarcodeScanMode.Auto,       // Auto | MachineLearningScan | OnlyDetectionModel | OnlyBasicScan
};
BarcodeResults r = BarcodeReader.Read("barcode-image.png", options);
```

Narrowing `ExpectBarcodeTypes` and setting `CropArea` are the two biggest speed/accuracy
levers — the reader isn't guessing across every symbology and the whole frame. Combined
formats: `BarcodeEncoding.AllOneDimensional`, `.AllTwoDimensional`, `.All`.

Other overloads of `BarcodeReader.Read`/`.ReadAsync` accept an `AnyBitmap`, a `byte[]`, a
`Stream`, or an `IEnumerable<>` of any of those (for batches) — all take the same
`BarcodeReaderOptions`.

### Read from PDFs

```csharp
BarcodeResults pdfResults = BarcodeReader.ReadPdf("invoice.pdf");

// Several PDFs at once — returns one BarcodeResults collection per document
IEnumerable<BarcodeResults> many = BarcodeReader.ReadPdfs(new List<string> { "a.pdf", "b.pdf" });
foreach (var doc in many)
    foreach (var item in doc)
        Console.WriteLine($"page {item.PageNumber}: {item.Value}");

var pdfOptions = new PdfBarcodeReaderOptions(new List<int> { 1, 2, 3 })  // 1-based page numbers
{
    DPI = 150,
    Password = "barcode",
    Scale = 3.5,
    Speed = ReadingSpeed.Detailed,
    ExpectBarcodeTypes = BarcodeEncoding.Code93,
    ExpectMultipleBarcodes = true,
};
BarcodeResults fromPages = BarcodeReader.ReadPdf("a.pdf", pdfOptions);
```

Async: `await BarcodeReader.ReadAsync(path, options)` and
`await BarcodeReader.ReadPdfsAsync(paths, pdfOptions)` for multiple PDFs. **Note:**
`BarcodeReader.ReadPdfAsync` only accepts an `IEnumerable<string>`/`byte[]`/`Stream` (no
single-path overload) and the compiler flags it obsolete in favour of `ReadPdfsAsync` —
use `ReadPdfsAsync(new[] { path }, options)` for a single async PDF read.

### Read from streams and byte arrays

```csharp
var streams = new List<MemoryStream>
{
    AnyBitmap.FromFile("image1.jpg").ToStream(),
    AnyBitmap.FromFile("image2.jpg").ToStream(),
};
BarcodeResults fromStreams = BarcodeReader.Read(streams);
```

### Crop to a region before reading

```csharp
var crop = new IronSoftware.Drawing.Rectangle(x: 62, y: 29, width: 345 - 62, height: 522 - 29);
var results = BarcodeReader.Read("sample.png", new BarcodeReaderOptions { CropArea = crop });
```

### Create 1D barcodes

```csharp
GeneratedBarcode code128 = BarcodeWriter.CreateBarcode("https://ironsoftware.com/csharp/barcode", BarcodeEncoding.Code128);
code128.AddBarcodeValueTextBelowBarcode();
code128.SaveAsJpeg("code128.jpg");

GeneratedBarcode ean13 = BarcodeWriter.CreateBarcode("4006381333931", BarcodeEncoding.EAN13);
GeneratedBarcode upcA  = BarcodeWriter.CreateBarcode("01234567890", BarcodeEncoding.UPCA);
GeneratedBarcode code39 = BarcodeWriter.CreateBarcode("IRON-1234", BarcodeEncoding.Code39);
GeneratedBarcode code93 = BarcodeWriter.CreateBarcode("ELEC-COMP-99", BarcodeEncoding.Code93);
GeneratedBarcode codabar = BarcodeWriter.CreateBarcode("10500200", BarcodeEncoding.Codabar);
GeneratedBarcode databar = BarcodeWriter.CreateBarcode("0123456789012", BarcodeEncoding.Databar);
GeneratedBarcode msi = BarcodeWriter.CreateBarcode("1234567890", BarcodeEncoding.MSI);
GeneratedBarcode imb = BarcodeWriter.CreateBarcode("00270123456200800001", BarcodeEncoding.IntelligentMail);
GeneratedBarcode gs1 = BarcodeWriter.CreateBarcode("(01)01234567890128(17)251231(10)BATCH001", BarcodeEncoding.Code128GS1);
```

`CreateBarcode(string, BarcodeEncoding)` also has a `BarcodeWriterEncoding` overload
(same member names, e.g. `.Code93`, `.Codabar`) — both compile against the same method;
prefer `BarcodeEncoding` since it's the one shared with the reader. **Watch the casing:**
`BarcodeEncoding.Databar` (lowercase `b`) vs `BarcodeWriterEncoding.DataBar` (capital
`B`) — they are two distinct enums with a inconsistent casing between them; use whichever
one you declared the variable's options as, don't mix members from one enum literal with
the other enum's type.

### Create 2D barcodes (QR, DataMatrix, PDF417, Aztec, MaxiCode)

```csharp
GeneratedBarcode qr = QRCodeWriter.CreateQrCode("https://ironsoftware.com", 500, QRCodeWriter.QrErrorCorrectionLevel.Medium);
// QrErrorCorrectionLevel: Low | Medium | High | Highest
qr.SaveAsPdf("MyQR.pdf");

GeneratedBarcode microQr = BarcodeWriter.CreateBarcode("IRON-1234", BarcodeEncoding.MicroQRCode);
GeneratedBarcode rmqr    = BarcodeWriter.CreateBarcode("https://ironsoftware.com/csharp/barcode/", BarcodeEncoding.RMQRCode);
GeneratedBarcode dataMatrix = BarcodeWriter.CreateBarcode("payload", BarcodeEncoding.DataMatrix);
GeneratedBarcode pdf417  = BarcodeWriter.CreateBarcode("payload", BarcodeEncoding.PDF417);
GeneratedBarcode aztec   = BarcodeWriter.CreateBarcode("payload", BarcodeEncoding.Aztec);
GeneratedBarcode maxiCode = BarcodeWriter.CreateBarcode("payload", BarcodeEncoding.MaxiCode);

// DataMatrix with explicit shape control
GeneratedBarcode rectDataMatrix = DataMatrixWriter.CreateDataMatrix(
    "payload", DataMatrixWriter.DataMatrixShape.Rectangular, width: 300, height: 150);
// DataMatrixShape: Automatic | Square | Rectangular
```

A basic branded QR is available here too (`QRCodeWriter.CreateQrCodeWithLogo(value, new
QRCodeLogo("logo.png"))`), but for anything beyond a plain centred logo — rounded
modules/eyes, colour themes, ML-verified readability after styling — use the **ironqr**
skill; that's IronQR's job, not this library's.

### Style, resize, and export

```csharp
GeneratedBarcode barcode = BarcodeWriter.CreateBarcode("PRODUCT-2024-001", BarcodeEncoding.Code128);
barcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Purple);      // 2nd bool param: ForcedChangeColor, default false
barcode.ChangeBackgroundColor(IronSoftware.Drawing.Color.White);
barcode.AddAnnotationTextAboveBarcode("Product URL:");
barcode.AddBarcodeValueTextBelowBarcode();                          // zero-arg overload prints the encoded value
barcode.SetMargins(20);                                              // or SetMargins(left, top, right, bottom)
barcode.ResizeTo(400, 200);                                          // pixels
barcode.ResizeToMil(milWidth: 10, inchHeight: 2, DPI: 300);          // print-accurate sizing (1D only)
barcode.KeepAspectRatio(true, BarCodeAspectSide.Horizontal);          // .Horizontal | .Vertical

barcode.SaveAsPng("out.png");     // also SaveAsJpeg, SaveAsGif, SaveAsTiff, SaveAsWindowsBitmap, SaveAsImage (ext-driven)
barcode.SaveAsPdf("out.pdf");
barcode.SaveAsHtmlFile("out.html");
barcode.SaveAs1BppBitmap("out.bmp");   // monochrome, for thermal/label printers

Stream png = barcode.ToPngStream();    // also ToJpegStream, ToPdfStream, ToTiffStream, ToGifStream, ToWindowsBitmapStream
Stream generic = barcode.ToStream(IronSoftware.Drawing.AnyBitmap.ImageFormat.Jpeg);
string dataUrl = barcode.ToDataUrl();  // "data:image/png;base64,..."
string htmlTag = barcode.ToHtmlTag();  // ready-to-embed <img>
AnyBitmap bmp = barcode.ToBitmap();

bool matchesInput = barcode.Verify("PRODUCT-2024-001");   // round-trip: decodes the image and compares
```

### Stamp a barcode onto an existing PDF page

```csharp
GeneratedBarcode stamp = BarcodeWriter.CreateBarcode(
    "https://ironsoftware.com/csharp/barcode/", BarcodeEncoding.Code128, maxWidth: 200, maxHeight: 100);
stamp.StampToExistingPdfPage("report.pdf", x: 200, y: 100, pageNumber: 1, password: "");
stamp.StampToExistingPdfPages("report.pdf", x: 200, y: 100, new List<int> { 1, 2, 3 }, password: "");
```

Reading barcodes out of a PDF and stamping them back onto one both operate directly on
the file path/bytes/stream — no `PdfDocument` object from IronPDF is required, though a
`PdfDocument.Stream` can be passed straight to `BarcodeReader.ReadPdf` if the project
already has one open (see the **ironpdf** skill).

### GS1-128 element strings

```csharp
bool valid = Code128GS1Parser.IsValid("(01)01234567890128(17)251231(10)BATCH001");
ParseResult parsed = Code128GS1Parser.Parse("(01)01234567890128(17)251231(10)BATCH001");
foreach (ParsedElement el in parsed.Elements)
    Console.WriteLine($"AI {el.Identifier}: {el.Data} — {el.Description}");
string formatted = Code128GS1Parser.Format("0101234567890128172512311");   // inserts parentheses/FNC1 breaks
```

### Unicode content

```csharp
string mixed = "123 English العربية 日本語";
GeneratedBarcode unicodeCode = BarcodeWriter.CreateBarcode(mixed, BarcodeEncoding.DataMatrix);
unicodeCode.SaveAsImage("unicode.png");
```

DataMatrix is the recommended format for non-ASCII content — it uses ECI (Extended
Channel Interpretation) to round-trip UTF-8 correctly; other symbologies may mangle
non-Latin text.

### Recover a bad scan with image filters

```csharp
var filters = new ImageFilterCollection
{
    new ContrastFilter(1.5f),
    new BinaryThresholdFilter(),
    // also: AdaptiveThresholdFilter, BilateralFilter, BrightnessFilter, DilateFilter,
    // ErodeFilter, GaussianBlurFilter, HistogramEqualizationFilter, InvertFilter,
    // MedianBlurFilter, SharpenFilter
};
var options = new BarcodeReaderOptions { ImageFilters = filters, Speed = ReadingSpeed.Detailed };
BarcodeResults results = BarcodeReader.Read("problem-scan.tiff", options);
```

Apply the minimum that fixes the actual defect — each filter costs time, and stacking
filters that aren't needed can reduce accuracy rather than improve it.

### Async and multithreading

```csharp
BarcodeResults asyncResult = await BarcodeReader.ReadAsync("image.png", options);

var batchOptions = new BarcodeReaderOptions { Multithreaded = true, MaxParallelThreads = 4 };
BarcodeResults batch = BarcodeReader.Read(new[] { "a.png", "b.png", "c.png" }, batchOptions);
```

### Error handling

```csharp
try
{
    BarcodeResults results = BarcodeReader.Read(filePath);
}
catch (IronBarCode.Exceptions.IronBarCodePdfPasswordException) { /* wrong/missing PDF password */ }
catch (IronBarCode.Exceptions.IronBarCodeFileException) { /* can't open the file */ }
catch (IronBarCode.Exceptions.IronBarCodeNativeException) { /* native/runtime deployment problem */ }
catch (IronBarCode.Exceptions.IronBarCodeException ex) { /* base type for all of the above */ }
```

`IronBarCode.Exceptions` also defines `IronBarCodeEncodingException`,
`IronBarCodeContentTooLongEncodingException`,
`IronBarCodeFormatOnlyAcceptsNumericValuesEncodingException`,
`IronBarCodeUnsupportedException`, `IronBarCodeUnsupportedRendererEncodingException`,
and `IronBarCodeConfidenceThresholdException` — thrown from the corresponding write/read
failure. For verbose diagnostics: `IronSoftware.Logger.LoggingMode =
IronSoftware.Logger.LoggingModes.File; IronSoftware.Logger.LogFilePath = "debug.log";`
(shared across Iron products, from `IronSoftware.Common`).

## Deployment

| Environment | What to do |
|---|---|
| Docker / Linux | Use `BarCode.Linux`. Install **libgdiplus** in the image (`apt update && apt install -y libgdiplus` on Ubuntu/Debian; `yum install -y libgdiplus` plus `mono-complete` on CentOS/RHEL) — the shared image stack needs it even though rendering itself is managed `ImageSharp`. |
| Azure App Service | At least the **B1** tier is recommended for typical workloads; scale up for high-throughput scanning. Set the license key in code at startup. |
| AWS Lambda | Container-image deployment; ≥512 MB memory (raise it if you see `Runtime exited with error: signal: killed`), timeout around 300 s for batch jobs. `/tmp` is the only writable path — set `IronBarCode.Installation.DeploymentPath = "/tmp/"` so native/runtime files can be copied there. |
| iOS / Android | Use `BarCode.iOS` / `BarCode.Android`. `BarCode.iOS` excludes the ML detection feature — use `BarcodeScanMode.OnlyBasicScan` there. |
| Minimal footprint | `BarCode.Slim` skips `BarCode.Detection` (no ONNX runtime, smaller deploy) — fine if you never set `ScanMode` to `MachineLearningScan`/`OnlyDetectionModel`. |

## When something fails

| Symptom | Cause and fix |
|---|---|
| `LicensingException: Production License Required` | No valid licence applied, or the 7-day development grace has expired. Set `IronBarCode.License.LicenseKey` before any call. |
| `CS0117`/compiler can't find an enum member | Casing mismatch between `BarcodeEncoding` and `BarcodeWriterEncoding` (e.g. `Databar` vs `DataBar`) — check which enum the variable is actually typed as. |
| `ReadPdfAsync` won't accept a single path | That overload only takes an `IEnumerable<string>`/`byte[]`/`Stream`, and is marked obsolete besides. Use `ReadPdfsAsync(new[] { path }, options)`. |
| `IronBarCodePdfPasswordException` | Encrypted PDF. Pass `Password` on `PdfBarcodeReaderOptions`. |
| `DllNotFoundException` / native load error on Linux | Missing `libgdiplus`, or wrong platform package. Install libgdiplus and use `BarCode.Linux`. |
| Nothing detected in a real image | Narrow `ExpectBarcodeTypes`, set `CropArea`, raise `Speed` to `Detailed`/`ExtremeDetail`, and try the image filters (`Deskew`-style correction is covered by `AdaptiveThresholdFilter`/`BinaryThresholdFilter`/`GaussianBlurFilter`). |
| False positives / garbage decodes | `RemoveFalsePositive = true` and set `ConfidenceThreshold` (e.g. 0.8–0.9). |
| Lambda killed mid-run | Memory too low for the ML detection model — raise Lambda memory, or use `BarcodeScanMode.OnlyBasicScan`/`BarCode.Slim` to skip it. |
| Non-Latin text unreadable after decoding | Encode with `BarcodeEncoding.DataMatrix` (ECI-aware) instead of a legacy 1D format. |

## Rules

- **Never invent a member.** Confirm against the XML documentation that ships in the
  package before writing code:
  `grep -o 'name="[MPF]:IronBarCode\.[^"]*Read[^"]*"' ~/.nuget/packages/barcode.slim/<version>/lib/netstandard2.0/IronBarCode.xml`
  That file is the authoritative surface for the installed version — the same file
  IntelliSense reads. Two enums (`BarcodeEncoding`, `BarcodeWriterEncoding`) look
  interchangeable but differ in casing on at least one member; check both when in doubt.
- Keep licence keys out of source and out of terminal output.
- Say when a call is likely to hit the 7-day development-only grace period, and never
  present output as production-ready without a confirmed licensed run.
- Narrow `ExpectBarcodeTypes` and `CropArea` before reaching for image filters — they're
  cheaper and usually fix more.
- Official docs and full API reference: <https://ironsoftware.com/csharp/barcode/docs/>.
  Support: support@ironsoftware.com.
