diff --git a/cli/src/main.rs b/cli/src/main.rs index 6f32072..74d8411 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,3 +1,103 @@ -fn main() { - println!("QRGen - 开发中"); +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(()) }