@veaba/qrcode-rust

原生 Rust 实现的 QRCode 生成库,提供所有包中最高的性能,比流行的 kennytm-qrcode8-10 倍

安装

作为依赖

[dependencies]
qrcode-rust = { git = "https://github.com/veaba/qrcodes", package = "qrcode-rust" }

本地路径

[dependencies]
qrcode-rust = { path = "packages/qrcode-rust" }

基础使用

创建 QRCode

use qrcode_rust::{QRCode, QRErrorCorrectLevel};

fn main() {
    // 创建 QRCode 实例
    let mut qr = QRCode::new("https://github.com/veaba/qrcodes");
    qr.options.correct_level = QRErrorCorrectLevel::H;
    
    // 获取 SVG
    let svg = qr.get_svg();
    println!("{}", svg);
}

指定纠错级别

use qrcode_rust::{QRCode, QRErrorCorrectLevel};

fn main() {
    let mut qr = QRCode::new("https://github.com/veaba/qrcodes");
    
    // 设置纠错级别
    qr.options.correct_level = QRErrorCorrectLevel::H;
    
    let svg = qr.get_svg();
    println!("{}", svg);
}

输出格式

SVG 输出

use qrcode_rust::{QRCode, QRErrorCorrectLevel};

fn main() {
    let mut qr = QRCode::new("https://github.com/veaba/qrcodes");
    qr.options.correct_level = QRErrorCorrectLevel::H;
    
    // 获取 SVG 字符串
    let svg = qr.get_svg();
    
    // 保存到文件
    std::fs::write("qrcode.svg", svg).expect("Failed to write file");
}

获取模块数据

use qrcode_rust::QRCode;

fn main() {
    let mut qr = QRCode::new("https://github.com/veaba/qrcodes");
    
    // 获取模块数量
    let count = qr.get_module_count();
    println!("Module count: {}", count);
    
    // 获取模块数据
    if let Some(modules) = qr.get_modules() {
        for row in 0..count {
            for col in 0..count {
                let is_dark = modules[row as usize][col as usize].unwrap_or(false);
                print!("{}", if is_dark { "██" } else { "  " });
            }
            println!();
        }
    }
}

自定义渲染

use qrcode_rust::QRCode;

fn render_to_console(qr: &QRCode) {
    let count = qr.get_module_count();
    
    for row in 0..count {
        for col in 0..count {
            if qr.is_dark(row, col) {
                print!("██");
            } else {
                print!("  ");
            }
        }
        println!();
    }
}

fn main() {
    let mut qr = QRCode::new("Hello, Rust!");
    render_to_console(&qr);
}

批量生成

顺序生成

use qrcode_rust::QRCode;

fn main() {
    let texts: Vec<String> = (0..100)
        .map(|i| format!("https://github.com/veaba/qrcodes/{}", i))
        .collect();
    
    let mut results = Vec::new();
    
    for text in &texts {
        let mut qr = QRCode::new(text);
        results.push(qr.get_svg());
    }
    
    println!("Generated {} QR codes", results.len());
}

并行生成(使用 Rayon)

use qrcode_rust::QRCode;
use rayon::prelude::*;

fn main() {
    let texts: Vec<String> = (0..10000)
        .map(|i| format!("https://github.com/veaba/qrcodes/{}", i))
        .collect();
    
    // 并行生成
    let results: Vec<String> = texts
        .par_iter()
        .map(|text| {
            let mut qr = QRCode::new(text);
            qr.get_svg()
        })
        .collect();
    
    println!("Generated {} QR codes", results.len());
}

Web 服务

Actix-web 示例

use actix_web::{get, web, App, HttpResponse, HttpServer};
use qrcode_rust::{QRCode, QRErrorCorrectLevel};

#[get("/qrcode")]
async fn generate_qrcode(query: web::Query<QRCodeQuery>) -> HttpResponse {
    let text = query.text.clone().unwrap_or_else(|| "https://github.com/veaba/qrcodes".to_string());
    
    let mut qr = QRCode::new(&text);
    qr.options.correct_level = QRErrorCorrectLevel::H;
    
    let svg = qr.get_svg();
    
    HttpResponse::Ok()
        .content_type("image/svg+xml")
        .body(svg)
}

#[derive(serde::Deserialize)]
struct QRCodeQuery {
    text: Option<String>,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(generate_qrcode)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Axum 示例

use axum::{
    extract::Query,
    response::Html,
    routing::get,
    Router,
};
use qrcode_rust::{QRCode, QRErrorCorrectLevel};
use serde::Deserialize;

#[derive(Deserialize)]
struct QRCodeParams {
    text: Option<String>,
}

async fn generate_qrcode(Query(params): Query<QRCodeParams>) -> Html<String> {
    let text = params.text.unwrap_or_else(|| "https://github.com/veaba/qrcodes".to_string());
    
    let mut qr = QRCode::new(&text);
    qr.options.correct_level = QRErrorCorrectLevel::H;
    
    Html(qr.get_svg())
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/qrcode", get(generate_qrcode));
    
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    
    println!("Server running on http://127.0.0.1:3000");
    axum::serve(listener, app).await.unwrap();
}

自定义选项

颜色配置

use qrcode_rust::{QRCode, QRCodeOptions, QRErrorCorrectLevel};

fn main() {
    let mut qr = QRCode::new("https://github.com/veaba/qrcodes");
    
    // 自定义颜色
    qr.options.color_dark = "#FF0000".to_string();
    qr.options.color_light = "#FFFFFF".to_string();
    qr.options.correct_level = QRErrorCorrectLevel::H;
    
    let svg = qr.get_svg();
    std::fs::write("red-qrcode.svg", svg).unwrap();
}

性能优化

复用实例

use qrcode_rust::QRCode;

fn main() {
    // 复用同一个实例(注意:每次调用 get_svg 会基于当前状态)
    let texts = vec![
        "https://github.com/veaba/qrcodes/1",
        "https://github.com/veaba/qrcodes/2",
        "https://github.com/veaba/qrcodes/3",
    ];
    
    for text in &texts {
        let mut qr = QRCode::new(text);
        let _svg = qr.get_svg();
        // 处理 svg...
    }
}

基准测试

运行内置基准测试:

cd packages/qrcode-rust
cargo bench --bench comparison_bench

预期结果(基于实际测试,2026-02-02):

single_generation time: [50.915 µs 51.030 µs 51.156 µs] (~19,608 ops/s) batch_generation_100 time: [3.9972 ms 4.0068 ms 4.0165 ms] (~24,959 ops/s) svg_generation time: [34.599 µs 34.742 µs 34.894 µs] (~28,780 ops/s) error_level_L time: [28.890 µs 28.974 µs 29.058 µs] (~34,518 ops/s) error_level_M time: [28.605 µs 28.712 µs 28.837 µs] (~34,827 ops/s) error_level_Q time: [40.171 µs 40.480 µs 40.829 µs] (~24,703 ops/s) error_level_H time: [41.606 µs 41.960 µs 42.347 µs] (~23,832 ops/s)

与 kennytm-qrcode 的性能对比

测试项 @veaba/qrcode-rust kennytm-qrcode 速度提升
单条生成 ~51.0 µs ~438.3 µs 8.6x
批量 100 条 ~4.01 ms ~32.13 ms 8.0x
纠错级别 L ~29.0 µs ~306.5 µs 10.6x
纠错级别 H ~42.0 µs ~446.2 µs 10.6x

结论: @veaba/qrcode-rustkennytm-qrcode8-10 倍

SVG 验证

使用 bench/rust-tools 验证生成的 SVG:

cd bench/rust-tools
cargo run --release --features validation --bin veaba-qr -- "Hello World"

输出示例:

🚀 @veaba QRCode 生成器 ═══════════════════════════════════════ 文本: Hello World 📦 @veaba/qrcode-rust ─────────────────────────────────────── ⏱️ 生成耗时: 66.7µs 📐 二维码版本: 1 (21x21 模块) 📄 SVG 大小: 13798 bytes 🔍 验证中... ✅ 验证通过!

性能数据

基于实际基准测试(2026-02-02):

测试项 平均时间 吞吐量
单条生成 ~51.0 µs ~19,608 ops/s
SVG 生成 ~34.7 µs ~28,780 ops/s
批量 100 条 ~4.01 ms ~24,959 ops/s
纠错级别 L ~29.0 µs ~34,518 ops/s
纠错级别 M ~28.7 µs ~34,827 ops/s
纠错级别 Q ~40.5 µs ~24,703 ops/s
纠错级别 H ~42.0 µs ~23,832 ops/s

测试环境:Rust 1.89.0, Windows

API 参考

QRCode 结构

pub struct QRCode {
    pub options: QRCodeOptions,
    pub type_number: i32,
    pub module_count: i32,
    pub modules: Vec<Vec<Option<bool>>>,
    pub data_cache: Option<Vec<i32>>,
    pub data_list: Vec<QR8bitByte>,
}

方法

方法 说明 返回值
QRCode::new(text) 创建实例 QRCode
get_module_count() 获取模块数 i32
get_modules() 获取模块数据 Option<&Vec<Vec<Option<bool>>>>
is_dark(row, col) 判断模块颜色 bool
get_svg() 获取 SVG String

QRErrorCorrectLevel

pub enum QRErrorCorrectLevel {
    L = 1,  // ~7%
    M = 0,  // ~15%
    Q = 3,  // ~25%
    H = 2,  // ~30%
}

何时使用原生 Rust?

  • ✅ 已经是 Rust 项目
  • ✅ 追求极致性能(比 kennytm 快 8-10 倍)
  • ✅ 需要内存安全保证
  • ✅ 批量生成任务(可使用 Rayon 并行)
  • ✅ 嵌入式或资源受限环境

与 WASM 的关系

Rust 源码 (packages/qrcode-rust/src/) │ ├── 编译为原生库 ──► @veaba/qrcode-rust (Rust 项目使用) │ └── 编译为 WASM ───► @veaba/qrcode-wasm (浏览器使用)

同一份 Rust 代码,编译为两种目标:

  • 原生库:最高性能,无 WASM 开销
  • WASM:浏览器运行,跨平台

更新记录

2026-02-02

  • 更新了基准测试数据
  • 添加了与 kennytm-qrcode 的性能对比
  • 添加了 SVG 验证说明
  • 修复了 rust-tools 中的 crate 名称问题