feat: CLI 工具 (clap + anyhow)
This commit is contained in:
+102
-2
@@ -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<String>,
|
||||
|
||||
/// 纠错级别 [L/M/Q/H] [default: M]
|
||||
#[arg(short = 'l', long, default_value = "M")]
|
||||
level: String,
|
||||
|
||||
/// 手动指定版本 (1-40),不指定则自动选择
|
||||
#[arg(short = 'v', long)]
|
||||
version: Option<u8>,
|
||||
|
||||
/// 模块像素大小(仅 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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user