use clap::Parser; use qr_core::qr::{QrCode, QrConfig, VersionMode}; use qr_core::version::EcLevel; use std::path::Path; #[derive(Parser)] #[command(name = "qrgen", about = "QR 码生成器 — 从零手搓的 ISO/IEC 18004 实现")] struct Args { /// 要编码的内容 content: String, /// 输出文件 (.png 或 .svg),不指定则输出终端 ASCII #[arg(short = 'o', long)] output: Option, /// 纠错级别 [L/M/Q/H] [default: M] #[arg(short = 'l', long, default_value = "M")] level: String, /// 手动指定版本 (1-40),不指定则自动选择 #[arg(short = 'v', long)] version: Option, /// 模块像素大小(仅 PNG)[default: 4] #[arg(short = 's', long, default_value = "4")] size: u8, /// 白边模块数 [default: 4] #[arg(short = 'm', long, default_value = "4")] margin: u8, /// 反色(黑底白码) #[arg(long)] invert: bool, } fn main() -> anyhow::Result<()> { let args = Args::parse(); let level = match args.level.to_uppercase().as_str() { "L" => EcLevel::L, "M" => EcLevel::M, "Q" => EcLevel::Q, "H" => EcLevel::H, _ => anyhow::bail!("无效纠错级别: {}。支持 L/M/Q/H", args.level), }; let version = match args.version { Some(v) => { if !(1..=40).contains(&v) { anyhow::bail!("无效版本号: {}。支持 1-40", v); } VersionMode::Fixed(v) } None => VersionMode::Auto, }; let config = QrConfig { level, version, margin: args.margin, }; let qr = QrCode::encode(&args.content, config).map_err(|e| anyhow::anyhow!("编码失败: {}", e))?; match args.output { Some(path) => { let ext = Path::new(&path) .extension() .and_then(|e| e.to_str()) .unwrap_or("") .to_lowercase(); match ext.as_str() { "png" => { let bytes = qr.to_png_bytes(args.size)?; std::fs::write(&path, bytes)?; println!( "已生成: {} (版本 {}, {}×{} 模块, {} 级纠错)", path, qr.version.0, qr.size(), qr.size(), match qr.level { EcLevel::L => "L", EcLevel::M => "M", EcLevel::Q => "Q", EcLevel::H => "H", } ); } "svg" => { let svg = qr.to_svg(); std::fs::write(&path, svg)?; println!("已生成: {} (版本 {}, SVG 格式)", path, qr.version.0); } _ => anyhow::bail!("不支持的文件格式: .{}。支持 .png / .svg", ext), } } None => { // 终端 ASCII 输出 println!("{}", qr.to_ascii(args.invert)); } } Ok(()) }