TUV
Pure-Rust QR and Micro QR code encoder with SVG, PNG, and terminal output.
TUV, for QRs
Install
Usage
High-level builder (primary API)
UTF-8 string (byte mode — not Kanji mode):
use ;
let qr = from.generate?;

Raw bytes (byte mode; any byte slice, including non-UTF-8):
let qr = from_bytes.with_ecc.generate?;

Shift JIS Kanji mode (raw double-byte bytes, not UTF-8):
let qr = from_bytes.with_ecc.generate?;

Normal or Micro QR version:
let qr = from
.with_ecc
.with_version
.generate?;

Note: Micro QR requires a Micro QR-capable scanner. Standard QR apps (and iPhone Camera) often cannot read Micro QR.
Micro QR with auto-selected smallest version:
let qr = from_bytes
.with_micro
.with_ecc
.generate?;

Backward-compatible render helpers:
let qr = from.generate?;
let svg = qr.to_svg;
let png = qr.to_png;

Render builder
Custom colors (SVG or PNG):
let qr = from.generate?;
let svg = qr.render
.dark_color
.light_color
.min_dimensions
.quiet_zone
.build_svg;

Terminal unicode blocks (text output; encoded symbol shown below). Default scale is 2 columns per module (~66 cols for a typical URL); use Renderer::unicode_scale for larger terminal output:
let terminal = qr.render.build_unicode;
let larger = qr.render.unicode_scale.build_unicode;

Luma image buffer:
let luma = qr.render.build_image_luma;

Transparent background (PNG alpha 0 / SVG without background rect):
let png = qr.render
.transparent_background
.min_dimensions
.build_png;
let svg = qr.render
.transparent_background
.build_svg;

Low-level Bits API
use Bits;
use ;
let mut bits = new;
bits.push_eci_designator?;
bits.push_byte_data?;
bits.push_terminator?;
let qr = from_bits.with_ecc.generate?;

Matrix introspection
After generate(), the resulting QRCode exposes the encoded module grid for inspection, tests, or custom renderers (separate from the PNG/SVG/unicode render helpers above).
use ;
let qr = from
.with_version
.with_ecc
.generate?;
// (x, y) = column, row; (0, 0) is the top-left module.
// The grid is the symbol only (21×21 here)—quiet zone is added at render time.
let x = 10;
let y = 10;
let dark: bool = qr == Dark; // Color::Dark or Color::Light at (x, y)
let max_err = qr.max_allowed_errors; // max flipped modules Reed–Solomon can fix
let functional = qr.is_functional; // true for finder/timing/format modules, not data
let bits = qr.to_vec; // flat Vec<bool>, row-major, dark = true
let colors = qr.to_colors; // same layout as to_vec(), as Color values
// Debug dump only (tests, assert snapshots)—not for terminal display:
let dump = qr.to_debug_str;

Defaults
- When
with_eccis omitted, version and ECC are co-optimized for the smallest symbol (try each version from smallest upward, and at each version try ECC L → M → Q → H). - When
with_versionis set but ECC is omitted, the lowest ECC level that fits at that version is chosen. - When
with_eccis set but version is omitted, only version is auto-selected (unchanged). - Call
with_micro()to search Micro QR versions (v1–4) instead of Normal QR (v1–40). QRCode::from/ UTF-8 strings use byte mode. True Kanji mode requires Shift JIS bytes viafrom_bytesorBits::push_kanji_data.- Mask auto-selects the lowest-penalty pattern when
with_mask_idis omitted. - Micro QR uses a 2-module quiet zone; Normal QR uses 4.
Renderer::transparent_background(defaultfalse) makes PNG light modules and quiet zone fully transparent and omits the SVG background<rect>.to_png/to_svgremain opaque unless you use the render builder.
CLI
An optional command-line tool lives in crates/tuv-cli:
SVG output:

PNG output:

Micro QR version 1:

Micro QR auto version:

Terminal unicode (text output; encoded symbol shown below). Default --unicode-scale is 2 (~66 cols for a typical URL); use 3–4 for easier phone scanning on wider terminals:

Custom colors:

Testing
Encoding and matrix behavior are verified by the crate's own test suite against the QR specification (no external encoder dependency).
License
MIT
Other
