Pure-Rust QR and Micro QR code encoder with SVG, PNG, and terminal output.
TUV, for QRs
cargo add tuvUTF-8 string (byte mode — not Kanji mode):
use tuv::{QRCode, Version, ECCLevel};
let qr = QRCode::from("https://example.com").generate()?;Raw bytes (byte mode; any byte slice, including non-UTF-8):
let qr = QRCode::from_bytes(b"Hello").with_ecc(ECCLevel::L).generate()?;Shift JIS Kanji mode (raw double-byte bytes, not UTF-8):
let qr = QRCode::from_bytes(b"\x82\xa0").with_ecc(ECCLevel::M).generate()?;Normal or Micro QR version:
let qr = QRCode::from("123")
.with_ecc(ECCLevel::L)
.with_version(Version::Micro(1))
.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 = QRCode::from_bytes(b"123")
.with_micro()
.with_ecc(ECCLevel::L)
.generate()?;Backward-compatible render helpers:
let qr = QRCode::from("https://example.com").generate()?;
let svg = qr.to_svg(true);
let png = qr.to_png(300, true);Custom colors (SVG or PNG):
let qr = QRCode::from("https://example.com").generate()?;
let svg = qr.render()
.dark_color("#800000")
.light_color("#ffff80")
.min_dimensions(200, 200)
.quiet_zone(true)
.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(3).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(true)
.min_dimensions(200, 200)
.build_png();
let svg = qr.render()
.transparent_background(true)
.build_svg();use tuv::bits::Bits;
use tuv::{QRCode, Version, ECCLevel};
let mut bits = Bits::new(Version::Normal(1));
bits.push_eci_designator(9)?;
bits.push_byte_data(b"\xa1\xa2\xa3")?;
bits.push_terminator(ECCLevel::L)?;
let qr = QRCode::from_bits(bits).with_ecc(ECCLevel::L).generate()?;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 tuv::{Color, QRCode, Version, ECCLevel};
let qr = QRCode::from("Hi")
.with_version(Version::Normal(1))
.with_ecc(ECCLevel::L)
.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[(x, y)] == Color::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(x, y); // 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('#', '.');- 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.
An optional command-line tool lives in crates/tuv-cli:
SVG output:
cargo run -p tuv-cli -- "Hello" -o hello.svgPNG output:
cargo run -p tuv-cli -- "Hello" --png -o hello.pngMicro QR version 1:
cargo run -p tuv-cli -- "123" --micro 1 --ecc L -o micro.svgMicro QR auto version:
cargo run -p tuv-cli -- "123" --micro --ecc L -o micro-auto.svgTerminal 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:
cargo run -p tuv-cli -- "Hello" --unicode
cargo run -p tuv-cli -- "https://example.com" --unicode --unicode-scale 3Custom colors:
cargo run -p tuv-cli -- "Hello" --dark-color "#800000" --light-color "#ffff80" -o colored.svgEncoding and matrix behavior are verified by the crate's own test suite against the QR specification (no external encoder dependency).
MIT


















