Kanject.Core.Qr

View .md

A first-party QR Code (ISO/IEC 18004) encoder with styled SVG and PNG rendering — all 40 versions, multi-block Reed-Solomon, penalty-based masking. BCL-only and AOT-clean: no System.Drawing, no third-party packages, no native binaries in your Lambda bundle.

Install

bash
dotnet add package Kanject.Core.Qr# Optional: compile-time [QrTemplate] / [QrSource] projectionsdotnet add package Kanject.Core.Qr.Annotations

Register

csharp
using Kanject.Core.Qr.Extensions;// Registers IQrEncoder, IQrSvgRenderer, IQrPngRenderer, and// IQrScannabilityVerifier as singletons — via TryAdd, so registering// your own implementation first overrides any of them.builder.Services.AddQrCodes();

Encode and render

Encode auto-selects the densest mode the payload allows (numeric → alphanumeric → byte) and the smallest version that fits it. Styling — colours, gradients, rounded or dot modules, finder-eye styling, a centre logo — goes through QrRenderOptions, shared by both renderers:

csharp
public class TicketService(IQrEncoder encoder, IQrPngRenderer png){    public byte[] RenderTicketQr(Ticket ticket)    {        var matrix = encoder.Encode($"https://acme.io/t/{ticket.Code}",            new QrEncodeOptions { ErrorCorrection = QrErrorCorrection.H });        return png.Render(matrix, new QrRenderOptions        {            Logo = new QrLogo { DataUri = acmeLogoPng },            VerifyBeforeReturn = true,   // refuse to emit a dead ticket        });    }}

The output, live

This is not an illustration. The QR below is the actual SVG that QrSvgRenderer produced for this exact call — checked into the docs verbatim (regenerate it with scripts/gen-core-qr-figure):

csharp
var matrix = new QrEncoder().Encode(    "https://www.kanject.com/docs/core-qr/",    new QrEncodeOptions { ErrorCorrection = QrErrorCorrection.H });var svg = new QrSvgRenderer().Render(matrix, new QrRenderOptions{    ModuleShape = QrModuleShape.Rounded,    DarkColor = "#221635",    GradientColor = "#6d28d9",    EyeStyle = new QrFinderEyeStyle { Color = "#6d28d9", Rounded = true },    VerifyBeforeReturn = true,});
Version 5, 37×37 modules, error correction H — approved by the scannability verifier. Scan it: you'll land right back on this page.

Scannability, verified

Styling is where QR codes quietly die — a logo that eats too many codewords, grey-on-grey brand colours, an overlay across a finder pattern. The built-in verifier checks contrast, per-block logo error budgets, and reserved-pattern occlusion as pure arithmetic on the matrix. Set VerifyBeforeReturn = true (or use QrRenderOptions.VerifiedDefault) and the renderer throws a coded QrUnscannableException instead of returning a symbol that won't scan.

Compile-time payloads

With Kanject.Core.Qr.Annotations, mark a partial POCO with [QrTemplate] — each {PropertyName} placeholder binds to a public property, URL-escaped — or put [QrSource] on a single string property to use its value verbatim. The generator emits the payload and encode/render helpers; misuse is a compile-time KANQR diagnostic, not a runtime surprise:

csharp
[QrTemplate("https://acme.io/t/{Code}", Ecc = QrErrorCorrection.H)]public sealed partial class TicketQr{    public required string Code { get; init; }}// Generated: ToQrPayload(), ToQrMatrix(…), ToQrSvg(…), ToQrPng(…)var svg = new TicketQr { Code = "1042" }.ToQrSvg(encoder, svgRenderer);

What ships with it

  • Full ISO/IEC 18004 encoder — numeric / alphanumeric / byte modes, versions 1–40, error-correction levels L / M / Q / H
  • IQrSvgRenderer (SVG string) and IQrPngRenderer (PNG bytes) with one shared QrRenderOptions
  • Logo overlays with per-Reed-Solomon-block error budgeting, gradients, module shapes, finder-eye styling
  • IQrScannabilityVerifier — contrast, logo budget, and reserved-pattern checks, no camera loop required
  • [QrTemplate] / [QrSource] source generator — reflection-free, AOT-clean payload projections
  • KANQR### diagnostic codes on every refusal: 001–049 compile-time, 050–099 runtime
Was this page helpful?