# qrcode-rs
[](https://github.com/houseme/qrcode-rs/actions?query=workflow%3ABuild)
[](https://crates.io/crates/qrcode-rs)
[](https://docs.rs/qrcode-rs/)
[](./LICENSE-APACHE)
[](https://crates.io/crates/qrcode-rs)
[](https://github.com/houseme/qrcode-rs/actions/workflows/audit.yml)
`qrcode-rs` is a Rust crate for generating QR Code and Micro QR Code symbols, rendering them in multiple output formats, and optionally decoding them back through [`rqrr`](https://crates.io/crates/rqrr).
It is designed to cover the common cases well out of the box while still exposing lower-level building blocks for advanced encoding workflows such as fixed versions, mode forcing, GS1/FNC1 payloads, structured payload helpers, and custom rendering.
- Documentation: [docs.rs/qrcode-rs](https://docs.rs/qrcode-rs/)
- Crate page: [crates.io/crates/qrcode-rs](https://crates.io/crates/qrcode-rs)
- Repository: [github.com/houseme/qrcode-rs](https://github.com/houseme/qrcode-rs)
## Highlights
- Encode standard QR Code and Micro QR Code symbols.
- Use simple constructors, an ergonomic builder API, or batch generation helpers.
- Render to terminal text, Unicode, ANSI, SVG, PNG, EPS, PIC, HTML, and PDF.
- Generate structured payloads for URLs, plain text, WiFi credentials, vCards, and GS1 data.
- Parse WiFi, vCard, and GS1 QR payloads back into typed data structures.
- Add accessible alt text and ARIA labels for SVG and HTML output.
- Opt into `serde`, CLI support, async rendering, streaming, lightweight logging, and `rqrr`-based decoding via feature flags.
- Use the 2.0 split crates directly when a library needs only core, render, parse, decode, or one backend layer.
- Run without default features for lean `no_std + alloc` usage.
## Installation
Use the default feature set if you want the most common renderers enabled:
```toml
[dependencies]
qrcode-rs = "2.0"
```
If you only need the core encoder and want to avoid the default rendering stack:
```toml
[dependencies]
qrcode-rs = { version = "2.0", default-features = false }
```
Enable only the pieces you need:
```toml
[dependencies]
qrcode-rs = { version = "2.0", default-features = false, features = ["std", "svg", "serde"] }
```
### Feature Flags
| `default` | Enables `std`, `image`, `svg`, `pic`, `eps`, `html`, and `pdf`. |
| `std` | Links the standard library. Disable for `no_std + alloc`. |
| `image` | Raster image rendering, including PNG workflows. |
| `svg`, `pic`, `eps`, `html`, `pdf` | Individual renderer backends. |
| `serde` | `Serialize` / `Deserialize` support for core QR data types. |
| `log` | Emits encoder diagnostics through the `log` crate. |
| `async` | Enables Tokio-backed async rendering helpers. |
| `cli` | Builds the `qrencodes` command-line tool. |
| `decode-rqrr` | Enables decoding through `rqrr`. |
| `compat-1x` | Keeps the 1.x facade API available during the 2.0 migration. |
## Workspace Crates
`qrcode-rs` remains the recommended facade for applications. The 2.0 release
also publishes smaller crates for libraries that need a narrower dependency
surface:
| `qrcode-core` | Core encoding types, module views, traits, and plugin contracts. |
| `qrcode-render` | Shared render traits, text/Unicode/ANSI helpers, and color utilities. |
| `qrcode-image` | Image-backed pixels, PNG/JPEG encoding, logo overlays, and gradients. |
| `qrcode-parse` | WiFi, vCard, and GS1 payload parsing without the facade. |
| `qrcode-decode` | Decoder traits, grayscale views, Structured Append parsing, and the optional `rqrr` adapter. |
| `qrcode-svg`, `qrcode-eps`, `qrcode-pic`, `qrcode-html`, `qrcode-pdf` | Individual renderer backends. |
| `qrcode-cli` | Independently installable `qrencodes` command-line binary. |
For example:
```toml
[dependencies]
qrcode-core = "2.0"
qrcode-svg = "2.0"
```
`qrcode-compat` is a workspace-local migration harness and is not published.
## Quick Start
### Render a PNG
```rust
use image::Luma;
use qrcode_rs::QrCode;
fn main() {
let code = QrCode::new(b"https://example.com").unwrap();
let image = code
.render::<Luma<u8>>()
.min_dimensions(256, 256)
.build();
image.save("/tmp/qrcode.png").unwrap();
}
```
Generates:

### Builder API with a fixed error-correction level
```rust
use qrcode_rs::{EcLevel, QrCode};
use qrcode_rs::render::unicode;
fn main() {
let code = QrCode::builder("https://example.com")
.ec_level(EcLevel::H)
.build()
.unwrap();
let terminal = code
.render::<unicode::Dense1x2>()
.quiet_zone(false)
.build();
println!("{terminal}");
}
```
### Generate a Micro QR SVG
```rust
use qrcode_rs::{EcLevel, QrCode, Version};
use qrcode_rs::render::svg;
fn main() {
let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
let image = code
.render::<svg::Color>()
.min_dimensions(200, 200)
.dark_color(svg::Color("#800000"))
.light_color(svg::Color("#ffff80"))
.build();
println!("{image}");
}
```
Preview:
[](docs/images/test_annex_i_micro_qr_as_svg.svg)
## Common Encoding Helpers
`qrcode-rs` includes convenience constructors for common payload types:
- `QrCode::for_url(...)`
- `QrCode::for_text(...)`
- `QrCode::for_wifi(ssid, password, auth)`
- `QrCode::for_vcard(name, phone, email)`
- `QrCode::for_gs1(...)`
- `QrCode::new_micro(...)`
- `QrCode::batch(inputs, ec_level)`
Example:
```rust
use qrcode_rs::QrCode;
fn main() {
let wifi = QrCode::for_wifi("GuestNetwork", "p\\;ss", "WPA").unwrap();
let contact = QrCode::for_vcard("Ada Lovelace", "+15551234", "ada@example.org").unwrap();
println!("wifi width = {}", wifi.width());
println!("contact width = {}", contact.width());
}
```
## Structured Payload Parsing
The `parse` module can turn QR payload text back into typed domain objects:
```rust
use qrcode_rs::parse::wifi::WifiConfig;
fn main() {
let payload = r#"WIFI:T:WPA;S:GuestNetwork;P:p\;ss;H:false;;"#;
let cfg = WifiConfig::parse(payload).unwrap();
assert_eq!(cfg.ssid(), "GuestNetwork");
assert_eq!(cfg.security().as_str(), "WPA");
assert!(!cfg.hidden());
}
```
There are also parsers and examples for:
- `parse::vcard::VCard`
- `parse::gs1::Gs1Result`
## Accessible Output
For web and document workflows, the crate includes helpers to describe QR codes accessibly:
```rust
use qrcode_rs::QrCode;
use qrcode_rs::render::svg;
fn main() {
let payload = "https://example.com";
let code = QrCode::new(payload).unwrap();
let raw_svg = code.render::<svg::Color>().build();
let labeled_svg = svg::aria_label(&raw_svg, &QrCode::alt_text(payload));
println!("{labeled_svg}");
}
```
## Decoding with `rqrr`
Enable `decode-rqrr` to bridge generated or external grayscale QR images back into data:
```toml
[dependencies]
qrcode-rs = { version = "2.0", features = ["decode-rqrr"] }
```
```rust
use image::Luma;
use qrcode_rs::decode::rqrr::RqrrDecoder;
use qrcode_rs::decode::{GrayPixels, QrDecoder};
use qrcode_rs::QrCode;
fn main() {
let payload = b"https://example.com/decode-bridge";
let code = QrCode::new(payload).unwrap();
let image: image::GrayImage = code.render::<Luma<u8>>().min_dimensions(200, 200).build();
let decoded = RqrrDecoder::new().decode(GrayPixels::from(&image)).unwrap();
assert_eq!(decoded[0].data(), payload);
}
```
## Command-Line Tool
Enable the `cli` feature to build the bundled `qrencodes` binary:
```bash
cargo install qrcode-rs --features cli
```
Basic usage:
```bash
qrencodes "https://example.com"
qrencodes -f svg -o out.svg "https://example.com"
qrencodes -f png -o out.png --size 12 --dark '#1a1a2e' --light '#f5f5dc' "Hello"
```
Supported output formats:
- `string`
- `unicode`
- `ansi`
- `svg`
- `png`
- `eps`
- `pic`
- `html`
- `pdf`
See the full help with:
```bash
cargo run --features cli -- --help
```
## More Examples
The [`examples/`](examples) directory covers the main workflows in this crate:
- Rendering: `encode_image`, `encode_svg`, `encode_html`, `encode_eps`, `encode_pic`, `encode_string`
- Advanced encoding: `encode_eci`, `encode_kanji`, `encode_fnc1`, `const_version`, `typed_encoding_mode`, `structured_append`
- Structured payloads: `parse_wifi`, `parse_vcard`, `parse_gs1`, `stream_codes`
- Plugins and async: `plugin_plain_text`, `plugin_invert_modules`, `async_render`
- Accessibility and styling: `accessible_svg`, `custom_colors`, `color_spaces`, `cmyk_print`, `batch_template`, `alt_text`
- Decoding and errors: `decode_roundtrip`, `error_handling`
- CLI patterns: `cli_tool`
## Migration
For the 1.x to 2.0 upgrade path, see [MIGRATION-1.x-to-2.0.md](MIGRATION-1.x-to-2.0.md). The `compat-1x` feature keeps the legacy facade available while call sites move to the builder, module-view, streaming, and split-crate APIs. Plugin authors can follow [PLUGIN_GUIDE.md](PLUGIN_GUIDE.md).
## Supply-chain verification
The repository checks its locked dependency graph with `cargo deny` and
`cargo vet` in CI. The `minimal` feature is an explicit dependency-free
profile; SVG can be added without enabling raster/image dependencies:
```sh
cargo check --locked --no-default-features --features minimal
cargo check --locked --no-default-features --features minimal,svg
cargo tree --locked --no-default-features --features minimal --edges normal
```
Tagged releases include CycloneDX SBOM archives and Sigstore keyless
signatures. Install [cosign](https://docs.sigstore.dev/cosign/system_config/installation/)
and verify an asset with the certificate emitted alongside it:
```sh
cosign verify-blob release-artifact \
--signature release-artifact.sig \
--certificate release-artifact.pem \
--certificate-identity-regexp '^https://github.com/houseme/qrcode-rs/.github/workflows/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
```
GitHub provenance attestations for crate assets can be verified with:
```sh
gh attestation verify qrcode-rs-2.1.0.crate --repo houseme/qrcode-rs
```
## Security
See [SECURITY.md](SECURITY.md) for supported versions and the private
vulnerability-reporting process. The repository runs a scheduled RustSec
dependency advisory check; the badge above reflects that workflow, not a
security certification. The encoder does not provide encryption or
authentication, so applications must validate untrusted payloads and protect
generated files and logs. The current verification boundary and deferred
security gates are summarized in [docs/security-audit.md](docs/security-audit.md).
## License
Licensed under either of:
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for development and contribution guidelines, including the local property-test, differential-test, and fuzzing commands used by CI.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
## Acknowledgements
Thanks to [Kennytm](https://github.com/kennytm). This crate is based on [`qrcode-rust`](https://github.com/kennytm/qrcode-rust).