Skip to content

QR Code Generator — Zig source

Turn any text or URL into a downloadable QR code. Full ISO encoder with all error-correction levels, versions 1-40, SVG and PNG export, colors and quiet-zone control — runs entirely in your browser.

This is the Zig implementation — the same logic the interactive tool runs, in a shareable, citable form.

// qr-code-generator — Zig port: QR format information (BCH).
//
// Display snippet: assembling the module matrix is too long to show here;
// this ports formatInfoString(ecLevel, mask) from the TypeScript lib
// (src/lib/qr.ts), split into the EC-bits lookup and the BCH remainder.
// The full encoder (modes, Reed-Solomon EC, masking, matrix) lives in the
// TypeScript/Go sources.
//
// The 15-bit format string protects 5 data bits — 2 error-correction level
// bits (L=01 M=00 Q=11 H=10) followed by the 3-bit mask pattern — with a
// BCH(15,5) code using generator 0x537, then XORs the result with the
// fixed 0x5412 pattern so an all-zero string is never valid.
const std = @import("std");

pub const FormatError = error{ UnknownEcLevel, OutOfMemory };

/// Error-correction level indicator bits (ISO/IEC 18004 table C.1).
fn ecFormatBits(ec_level: u8) ?u16 {
    return switch (ec_level) {
        'L' => 0b01,
        'M' => 0b00,
        'Q' => 0b11,
        'H' => 0b10,
        else => null,
    };
}

/// 15-bit format info string (MSB first) for (ec_level, mask).
pub fn formatInfo(allocator: std.mem.Allocator, ec_level: u8, mask: u16) FormatError![]u8 {
    const bits = ecFormatBits(ec_level) orelse return FormatError.UnknownEcLevel;
    return formatInfoBch(allocator, (bits << 3) | mask);
}

/// 15-bit format info string (MSB first) for a 5-bit data value.
pub fn formatInfoBch(allocator: std.mem.Allocator, data5: u16) FormatError![]u8 {
    var v: u16 = data5 << 10;
    const g: u16 = 0x537; // BCH(15,5) generator polynomial
    var i: u8 = 14;
    while (i >= 10) : (i -= 1) {
        if (v & (@as(u16, 1) << @intCast(i)) != 0) {
            v ^= g << @intCast(i - 10); // polynomial long division
        }
    }
    const full: u16 = ((data5 << 10) | (v & 0x3FF)) ^ 0x5412; // apply the mask pattern
    return std.fmt.allocPrint(allocator, "{b:0>15}", .{full}) catch return FormatError.OutOfMemory;
}

// Example:
//   formatInfo(allocator, 'L', 0) -> "111011111000100" (0x77C4, matching the published tables)

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →