docs: 开源规范化 — doc comments + 社区文件 + 示例代码 + crates.io 就绪

- 为 core 公开 API 添加完整 doc comments(rustdoc 可用)
- 新增 .editorconfig / CONTRIBUTING / CODE_OF_CONDUCT / SECURITY
- 新增 Issue 模板(bug + feature)+ PR 模板
- 新增 3 个代码示例(examples/)
- 更新 Cargo.toml 元数据(description/repository/keywords/categories/MSRV)
- 更新 README + CHANGELOG
This commit is contained in:
2026-06-19 18:56:28 +08:00
parent cbcd4e5123
commit ce8063431e
17 changed files with 640 additions and 18 deletions
+29
View File
@@ -0,0 +1,29 @@
# EditorConfig — 跨编辑器统一编码风格
# https://editorconfig.org
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
[*.rs]
indent_style = space
indent_size = 4
[*.{ts,tsx,js,jsx,json,css,html,md,yaml,yml}]
indent_style = space
indent_size = 2
[*.toml]
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab
indent_size = 4
[*.{png,jpg,jpeg,gif,svg,ico,ttf,woff,woff2,eot}]
insert_final_newline = false
+29
View File
@@ -0,0 +1,29 @@
---
name: Bug 报告
about: 报告一个问题,帮助我们改进
title: "[Bug] "
labels: bug
assignees: ''
---
**描述问题**
一句话描述你遇到什么 bug。
**复现步骤**
1. 执行 `...`
2. 输入 `...`
3. 看到错误 `...`
**预期行为**
你期望发生什么?
**截图或日志**
如果适用,粘贴错误日志或截图。
**环境**
- OS: [如 Windows 11, macOS 15]
- Rust 版本: [`rustc --version` 输出]
- QRGen 版本: [v0.1.0 或 commit hash]
**补充信息**
其他相关内容。
+19
View File
@@ -0,0 +1,19 @@
---
name: 功能请求
about: 提出一个新功能或改进建议
title: "[Feature] "
labels: enhancement
assignees: ''
---
**动机**
这个功能解决什么问题?你的使用场景是什么?
**方案描述**
描述你期望的方案。如果有 API 设计,请写出伪代码。
**备选方案**
你考虑过哪些替代方案?
**补充信息**
截图、参考链接等。
+35
View File
@@ -0,0 +1,35 @@
## 概述
<!-- 一句话描述这个 PR 做了什么 -->
## 变更类型
- [ ] Bug 修复
- [ ] 新功能
- [ ] 重构(无功能变更)
- [ ] 文档更新
- [ ] 测试
- [ ] 其他:
## 测试
<!-- 描述你如何验证这个 PR -->
- [ ] `cargo test` 全部通过
- [ ] `cargo clippy -- -D warnings` 无警告
- [ ] `cargo fmt` 已运行
- [ ] 新增测试:
## 截图(如适用)
## 关联 Issue
Closes #
## 检查清单
- [ ] 代码已自审
- [ ] 注释清晰(中文)
- [ ] 文档已更新
- [ ] 无硬编码密钥
- [ ] 无破坏性变更(或已标注)
+4 -2
View File
@@ -1,6 +1,6 @@
# Changelog
## 0.1.0 (2026-06-18)
## 0.1.0 (2026-06-19)
### Added
@@ -59,4 +59,6 @@
- Webaxum 0.8 + tokio,编译期 HTML 嵌入 (include_str!)
- 82 个测试(58 单元 + 24 集成)
- NSIS Windows 安装包 + Docker Alpine 镜像
- GitHub Actions 就绪(测试 + clippy + fmt
- 文档:API doc commentsrustdoc 可用)+ 3 个代码示例
- 社区:CONTRIBUTING / CODE_OF_CONDUCT / SECURITY / Issue & PR 模板
- 工程:.editorconfig / MSRV=1.87 / crates.io 就绪
+29
View File
@@ -0,0 +1,29 @@
# 行为准则
## 承诺
为了营造一个开放和友好的环境,我们承诺让所有人无论年龄、体型、身体条件、种族、性别认同与表达、经验水平、教育程度、社会经济地位、国籍、个人外貌、宗教信仰或性取向,都能无骚扰地参与本项目。
## 标准
**鼓励的行为:**
- 使用友好和包容的语言
- 尊重不同的观点和经验
- 优雅地接受建设性批评
- 关注对社区最有利的事
- 对其他社区成员表达同理心
**不可接受的行为:**
- 使用带有性别色彩、性暗示的语言或图像
- 人身攻击、政治抨击或网络暴力
- 公开或私下骚扰
- 未经明确许可发布他人私人信息
- 在专业场合中不合理的其他行为
## 执行
项目维护者有责任澄清可接受行为的标准,并对任何不可接受的行为采取适当且公平的纠正措施。
如遇违规行为,请联系:**lhy3364451258@163.com**
本行为准则改编自 [Contributor Covenant](https://www.contributor-covenant.org)。
+105
View File
@@ -0,0 +1,105 @@
# 贡献指南
感谢你对 QRGen 的关注!这份指南帮助你了解如何参与项目。
## 项目架构
QRGen 是 Rust workspace,四层架构:
| crate | 用途 | 技术栈 |
|-------|------|--------|
| `qr-core` | 核心算法库 | Rust,纯算法无三方依赖 |
| `qrgen` | CLI 命令行 | clap + anyhow |
| `qrgen-gui` | 桌面应用 | Tauri 2.x + React 18 + TypeScript |
| `qrgen-web` | Web 服务 | axum 0.8 + tokio |
详细架构见 [CLAUDE.md](CLAUDE.md)。
## 开发环境
- **Rust** 1.95+ (`stable-x86_64-pc-windows-gnu``stable-x86_64-unknown-linux-gnu`)
- **Node.js** 22+(仅 GUI 前端需要)
- **pnpm**GUI 前端包管理)
## 本地构建
```bash
# 克隆
git clone git@lhy-git.liuhangyv.top:Serendipity/QRGen.git
cd QRGen
# 安装 GUI 前端依赖
cd gui/src-frontend && pnpm install && cd ../..
# 编译检查
cargo check
# CLI
cargo build -p qrgen
# Web
cargo build -p qrgen-web
# GUI(需要前端依赖)
cd gui/src-frontend && pnpm build && cd ../..
cargo build -p qrgen-gui
```
## 提交规范
使用 Conventional Commits 格式:
```
<type>: <简短描述>
feat: 添加 Logo 图片支持
fix: 修复 PNG margin 全黑问题
refactor: 提取 fill_module 辅助函数
docs: 更新 README 安装说明
test: 添加格式信息 roundtrip 测试
```
类型:`feat` `fix` `refactor` `docs` `test` `chore` `perf` `ci`
## 代码风格
- **Rust**: `cargo fmt` + `cargo clippy -- -D warnings` 必须通过
- **TypeScript**: `pnpm tsc --noEmit` 必须通过(strict 模式)
- 注释用中文,标识符用英文
## 测试
```bash
# 全量测试
cargo test # 所有 crate
# 仅核心库
cargo test -p qr-core
# 特定测试
cargo test -p qr-core -- mask # 掩码相关测试
# 覆盖率
cargo tarpaulin --out Html
```
测试覆盖率目标 ≥ 80%。
## 提交流程
1. Fork 仓库
2. 创建功能分支 (`git checkout -b feat/my-feature`)
3. 编码 + 测试(遵循 TDD
4. `cargo fmt` + `cargo clippy -- -D warnings`
5. `cargo test` 全部通过
6. 提交并 push
7. 创建 Pull Request
## Issue 规范
- Bug 报告:附重现步骤 + 预期/实际行为
- 功能请求:描述使用场景和期望效果
## 感谢
所有贡献者将在 [README.md](README.md) 中致谢。
+9 -1
View File
@@ -6,4 +6,12 @@ members = ["core", "cli", "gui", "web"]
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["刘航宇"]
authors = ["刘航宇 <lhy3364451258@163.com>"]
description = "从零手写的 QR 码生成器 — ISO/IEC 18004 完整实现"
repository = "https://github.com/LHY0125/QRGen"
homepage = "https://github.com/LHY0125/QRGen"
documentation = "https://github.com/LHY0125/QRGen"
readme = "README.md"
keywords = ["qr", "qr-code", "qrcode", "encoding", "barcode"]
categories = ["encoding", "command-line-utilities", "gui", "web-programming"]
rust-version = "1.87"
+45 -2
View File
@@ -5,13 +5,14 @@
<p align="center">
<img src="https://img.shields.io/badge/version-0.1.0-blue" alt="version">
<img src="https://img.shields.io/badge/rust-1.95-000000" alt="rust">
<img src="https://img.shields.io/badge/tauri-2.x-ffa03a" alt="tauri">
<img src="https://img.shields.io/badge/react-18-61dafb" alt="react">
<img src="https://img.shields.io/badge/axum-0.8-ff6b35" alt="axum">
<img src="https://img.shields.io/badge/rust-1.95-000000" alt="rust">
<img src="https://img.shields.io/badge/docker-ready-2496ed" alt="docker">
<img src="https://img.shields.io/badge/license-MIT-green" alt="license">
<img src="https://img.shields.io/badge/tests-82%20passed-brightgreen" alt="tests">
<img src="https://img.shields.io/badge/tests-58%20passed-brightgreen" alt="tests">
<img src="https://img.shields.io/badge/clippy-clean-brightgreen" alt="clippy">
</p>
---
@@ -271,6 +272,48 @@ QRGen/
| 自动版本选择 | 根据数据长度 + 纠错级别 |
| Docker 镜像 | ~18MB (alpine) |
## 代码示例
`examples/` 目录包含三个示例:
```bash
# 基础编码(默认配置)
cargo run --example basic_qr
# 高纠错级别(H 级,30% 容错)
cargo run --example high_ecc
# 自定义配置(固定版本 + 大尺寸 PNG)
cargo run --example custom_config
```
作为程序库使用:
```rust
use qr_core::qr::{QrCode, QrConfig};
let qr = QrCode::encode("Hello QR!", QrConfig::default())?;
println!("{}", qr.to_ascii(false)); // 终端预览
qr.to_png_bytes(8)?; // PNG 字节
let svg = qr.to_svg(); // SVG 字符串
```
## 发布到 crates.io
`qr-core` 可作为 Rust 库被其他项目引用:
```bash
cargo add qr-core
```
## 社区
- [贡献指南](CONTRIBUTING.md) — 如何参与开发
- [行为准则](CODE_OF_CONDUCT.md) — 社区规范
- [安全策略](SECURITY.md) — 漏洞报告流程
- [变更日志](CHANGELOG.md) — 版本历史
- [Issue 模板](.github/ISSUE_TEMPLATE/) — Bug 报告 / 功能请求
## 许可证
MIT License
+36
View File
@@ -0,0 +1,36 @@
# 安全策略
## 报告漏洞
如果你发现 QRGen 的安全漏洞,**请勿公开提交 Issue**。
请发送邮件至:**lhy3364451258@163.com**
在邮件中包含:
- 漏洞描述
- 复现步骤
- 影响范围评估
- 建议修复方案(如有)
我会在 **48 小时内回复**,并在确认后尽快发布修复。
## 安全考量
QRGen 是一个 QR 码生成工具,不处理用户隐私数据。关注的安全领域:
- **输入验证**:恶意构造的超长文本可能导致内存问题
- **文件路径**:CLI 输出路径防止目录遍历(已内置 `..` 拒绝)
- **Web 服务**:如果公网部署,需限制速率(建议通过反向代理实现)
- **依赖安全**:定期 `cargo audit` 检查 Rust 依赖漏洞
## 支持版本
| 版本 | 安全更新 |
|------|----------|
| 最新版 | ✅ |
| 旧版本 | ❌ 请升级到最新版 |
## 披露策略
- 修复发布后,漏洞细节将在 CHANGELOG 中公开
- 严重漏洞会优先发布补丁,延迟细节披露
+20
View File
@@ -4,9 +4,29 @@ version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
description.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
readme.workspace = true
keywords.workspace = true
categories.workspace = true
rust-version.workspace = true
[dependencies]
image = { version = "0.25", default-features = false, features = ["png"] }
serde = { version = "1", features = ["derive"] }
[dev-dependencies]
[[example]]
name = "basic_qr"
path = "../examples/basic_qr.rs"
[[example]]
name = "high_ecc"
path = "../examples/high_ecc.rs"
[[example]]
name = "custom_config"
path = "../examples/custom_config.rs"
+119 -2
View File
@@ -12,21 +12,61 @@ use crate::matrix::placement::place_data;
use crate::version::{get_data_capacity, EcLevel, Version};
/// 版本选择模式
///
/// 控制 QR 码版本(尺寸)的确定方式:
/// - `Auto`:根据数据量和纠错级别自动选择最小可用版本
/// - `Fixed(v)`:强制使用指定版本(1~40),数据超限时返回错误
///
/// ```rust
/// use qr_core::qr::{QrCode, QrConfig, VersionMode};
/// use qr_core::version::EcLevel;
///
/// // 自动选择版本
/// let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap();
/// assert_eq!(qr.version.0, 1);
///
/// // 强制指定版本
/// let config = QrConfig {
/// version: VersionMode::Fixed(5),
/// ..Default::default()
/// };
/// let qr = QrCode::encode("VERSION 5", config).unwrap();
/// assert_eq!(qr.version.0, 5);
/// ```
#[derive(Debug, Clone)]
pub enum VersionMode {
/// 根据数据量自动选择最小可用版本
Auto,
/// 强制固定版本(1~40
Fixed(u8),
}
/// QR 码配置
/// QR 码编码配置
///
/// 控制纠错级别、版本选择策略和静区边距。
///
/// ```rust
/// use qr_core::qr::QrConfig;
/// use qr_core::version::EcLevel;
///
/// let config = QrConfig {
/// level: EcLevel::H, // 30% 纠错能力
/// margin: 8, // 8 模块静区
/// ..Default::default()
/// };
/// ```
#[derive(Debug, Clone)]
pub struct QrConfig {
/// 纠错级别(L/M/Q/H
pub level: EcLevel,
/// 版本选择模式
pub version: VersionMode,
/// 静区边距(模块数),默认 4
pub margin: u8,
}
impl Default for QrConfig {
/// 默认配置:M 级纠错 + 自动版本 + 4 模块边距
fn default() -> Self {
QrConfig {
level: EcLevel::M,
@@ -37,16 +77,61 @@ impl Default for QrConfig {
}
/// 生成的 QR 码
///
/// 包含编码后的矩阵数据和元信息,可通过方法导出为 SVG / PNG / ASCII。
///
/// ```rust
/// use qr_core::qr::{QrCode, QrConfig};
///
/// let qr = QrCode::encode("https://example.com", QrConfig::default()).unwrap();
/// println!("版本: {}, 尺寸: {}×{}", qr.version.0, qr.size(), qr.size());
///
/// // 导出为 SVG
/// let svg = qr.to_svg();
/// assert!(svg.starts_with("<svg"));
///
/// // 导出为 PNG 字节
/// let png = qr.to_png_bytes(4).unwrap();
/// assert!(png.len() > 100);
///
/// // 终端 ASCII 输出
/// let ascii = qr.to_ascii(false);
/// assert!(!ascii.is_empty());
/// ```
pub struct QrCode {
/// QR 码版本(1~40
pub version: Version,
/// 纠错级别
pub level: EcLevel,
/// 选中的掩码编号(0~7
pub mask: u8,
matrix: Matrix,
/// 静区边距(模块数)
pub margin: u8,
}
impl QrCode {
/// 编码字符串生成 QR 码
/// 编码字符串 QR 码
///
/// 执行完整的 9 步流水线:分段 → 版本选择 → 模式编码 → 纠错 → 矩阵布局 →
/// 蛇形排列 → 掩码评分 → 格式信息 → 版本信息。
///
/// # 参数
/// - `text`:要编码的文本,支持汉字(Shift JIS)、数字、字母、字节
/// - `config`[`QrConfig`] 编码配置
///
/// # 错误
/// - 输入为空时返回 `"输入为空"`
/// - 版本无效时返回 `"无效版本号 (1-40)"`
/// - 数据超出版本容量时返回 `"数据过长,超出 QR 码最大容量"`
///
/// ```rust
/// use qr_core::qr::{QrCode, QrConfig};
///
/// let qr = QrCode::encode("Hello QR!", QrConfig::default()).unwrap();
/// assert_eq!(qr.version.0, 1);
/// assert_eq!(qr.size(), 21);
/// ```
pub fn encode(text: &str, config: QrConfig) -> Result<Self, String> {
// 1. 分段
let segments = segment_text(text);
@@ -127,22 +212,54 @@ impl QrCode {
})
}
/// 返回 QR 码的布尔矩阵(`true` = 深色模块)
///
/// 矩阵尺寸为 `size() × size()`,包含功能图案、数据模块和静区。
pub fn modules(&self) -> &[Vec<bool>] {
&self.matrix.modules
}
/// 返回 QR 码的边长(模块数,含静区)
///
/// 取值范围:21(版本 1 + 4×2 边距)到 185(版本 40 + 4×2 边距)
pub fn size(&self) -> u8 {
self.matrix.size
}
/// 导出为 SVG 字符串
///
/// SVG 内含 `viewBox`、深色模块用 `#000` 填充。
///
/// ```rust
/// use qr_core::qr::{QrCode, QrConfig};
///
/// let qr = QrCode::encode("test", QrConfig::default()).unwrap();
/// let svg = qr.to_svg();
/// assert!(svg.starts_with("<svg"));
/// ```
pub fn to_svg(&self) -> String {
crate::render::svg::render_svg(self)
}
/// 导出为终端 ASCII 文本
///
/// 深色模块用 `██`,浅色模块用 ` `(双空格)。
/// `invert=true` 时反转颜色(白底黑码 → 黑底白码)。
pub fn to_ascii(&self, invert: bool) -> String {
crate::render::ascii::render_ascii(self, invert)
}
/// 导出为 PNG 字节数据
///
/// `module_size` 控制每个模块的像素大小(2~20),越大文件越大。
///
/// ```rust
/// use qr_core::qr::{QrCode, QrConfig};
///
/// let qr = QrCode::encode("PNG test", QrConfig::default()).unwrap();
/// let bytes = qr.to_png_bytes(4).unwrap();
/// std::fs::write("test.png", &bytes).unwrap();
/// ```
pub fn to_png_bytes(&self, module_size: u8) -> Result<Vec<u8>, image::ImageError> {
crate::render::png::render_png(self, module_size)
}
+73 -8
View File
@@ -1,17 +1,33 @@
use serde::Serialize;
use std::sync::OnceLock;
/// 纠错级别
/// QR 码纠错级别
///
/// 决定 QR 码被遮挡/损毁后仍可扫描的能力。纠错越强,可存储的数据越少。
///
/// ```rust
/// use qr_core::version::{EcLevel, Version};
///
/// let ver = Version::new(1).unwrap();
/// let h = ver.ec_info(EcLevel::H);
/// let l = ver.ec_info(EcLevel::L);
/// // H 级纠错码字更多,数据码字更少
/// assert!(h.ec_per_block > l.ec_per_block);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum EcLevel {
L, // 约 7%
M, // 约 15%
Q, //25%
H, // 约 30%
/// L 级 — 约 7% 纠错能力
L,
/// M 级 —15% 纠错能力(默认)
M,
/// Q 级 — 约 25% 纠错能力
Q,
/// H 级 — 约 30% 纠错能力
H,
}
impl EcLevel {
/// 格式信息中使用的指示位
/// 格式信息中使用的 2-bit 指示位
pub fn indicator_bits(self) -> u8 {
match self {
EcLevel::L => 0b01,
@@ -22,7 +38,23 @@ impl EcLevel {
}
}
/// 版本号 1~40
/// QR 码版本号1~40
///
/// 版本决定 QR 码的物理尺寸:`side = 17 + version × 4` 模块。
/// 版本 1 是 21×21,版本 40 是 177×177。
///
/// ```rust
/// use qr_core::version::Version;
///
/// let v1 = Version::new(1).unwrap();
/// assert_eq!(v1.size(), 21);
///
/// let v40 = Version::new(40).unwrap();
/// assert_eq!(v40.size(), 177);
///
/// assert!(Version::new(0).is_none());
/// assert!(Version::new(41).is_none());
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub struct Version(pub u8);
@@ -104,16 +136,27 @@ impl Version {
}
}
/// 纠错分组信息
///
/// 一组 QR 数据被分为多个块,每个块独立计算 RS 纠错码。
#[derive(Debug, Clone)]
pub struct EcInfo {
/// 数据码字总数
pub total_codewords: u16,
/// 每个块的纠错码字数
pub ec_per_block: u8,
/// 分组信息(1~2 组,不同数据码字数)
pub blocks: Vec<BlockInfo>,
}
/// 单个分组信息
///
/// 所有块的数据码字总数 + 纠错码字总数 = QR 码总容量。
#[derive(Debug, Clone)]
pub struct BlockInfo {
/// 该组块数
pub count: u16,
/// 每个块的数据码字数
pub data_codewords: u16,
}
@@ -1290,6 +1333,16 @@ fn init_capacity_table() -> [[u16; 4]; 40] {
table
}
/// 查询指定版本+纠错级别的数据码字容量
///
/// 返回数据码字数(非比特数),乘以 8 得比特容量。
///
/// ```rust
/// use qr_core::version::{get_data_capacity, Version, EcLevel};
///
/// let cap = get_data_capacity(Version(1), EcLevel::M);
/// assert_eq!(cap, 16); // 版本 1-M 有 16 个数据码字
/// ```
// SAFETY: version.0 ∈ [1,40] 由 Version::new() 保证; level 是 4 变体枚举
#[allow(clippy::indexing_slicing)]
pub fn get_data_capacity(version: Version, level: EcLevel) -> u16 {
@@ -1298,7 +1351,19 @@ pub fn get_data_capacity(version: Version, level: EcLevel) -> u16 {
cap[version.0 as usize - 1][level as usize]
}
/// 自动选择最小版本:返回能容纳 data_bits 比特的最小版本
/// 自动选择能容纳 `data_bits` 比特的最小版本
///
/// 返回 `None` 表示数据量超出 QR 码最大容量(版本 40)。
///
/// ```rust
/// use qr_core::version::{pick_version, EcLevel};
///
/// let v = pick_version(100, EcLevel::M).unwrap();
/// assert_eq!(v.0, 1); // 版本 1-M 可容纳 16×8=128 bit >= 100
///
/// let too_big = pick_version(50_000, EcLevel::H);
/// assert!(too_big.is_none());
/// ```
pub fn pick_version(data_bits: u16, level: EcLevel) -> Option<Version> {
for v in 1..=40 {
let cap_bits = get_data_capacity(Version(v), level) * 8;
+30
View File
@@ -0,0 +1,30 @@
//! QRGen 基础示例:生成 QR 码并导出为多种格式
//!
//! 运行: `cargo run --example basic_qr`
use qr_core::qr::{QrCode, QrConfig};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let text = "https://github.com/LHY0125/QRGen";
// 使用默认配置(M 级纠错,自动版本,4 模块边距)
let qr = QrCode::encode(text, QrConfig::default())?;
println!("版本: {}", qr.version.0);
println!("尺寸: {}×{} 模块", qr.size(), qr.size());
println!("掩码: {}", qr.mask);
// 终端 ASCII 预览
println!("\n--- ASCII 预览 ---");
println!("{}", qr.to_ascii(false));
// 导出 PNG
qr.to_png_bytes(8)?;
println!("\nPNG 生成成功");
// 导出 SVG
let svg = qr.to_svg();
println!("SVG 长度: {} 字节", svg.len());
Ok(())
}
+27
View File
@@ -0,0 +1,27 @@
//! QRGen 自定义配置:强制指定版本、模块大小
//!
//! 运行: `cargo run --example custom_config`
use qr_core::qr::{QrCode, QrConfig, VersionMode};
use qr_core::version::EcLevel;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 强制使用版本 10(57×57 模块)
let config = QrConfig {
level: EcLevel::Q,
version: VersionMode::Fixed(10),
margin: 4,
};
let qr = QrCode::encode("固定版本 10 的 QR 码", config)?;
assert_eq!(qr.version.0, 10);
// 导出大尺寸 PNG(每个模块 8 像素)
let png = qr.to_png_bytes(8)?;
println!("版本 10 QR 码 PNG: {} 字节", png.len());
// 反转色终端输出(白底黑码 → 黑底白码)
println!("\n{}", qr.to_ascii(true));
Ok(())
}
+22
View File
@@ -0,0 +1,22 @@
//! QRGen 高纠错示例:生成可抵抗 30% 损坏的 QR 码
//!
//! 运行: `cargo run --example high_ecc`
use qr_core::qr::{QrCode, QrConfig, VersionMode};
use qr_core::version::EcLevel;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = QrConfig {
level: EcLevel::H, // 30% 纠错能力
version: VersionMode::Auto,
margin: 6, // 更大的静区
};
let qr = QrCode::encode("重要数据 - High ECC", config)?;
println!("版本: {}, 纠错: {:?}, 尺寸: {}×{}", qr.version.0, qr.level, qr.size(), qr.size());
let svg = qr.to_svg();
println!("SVG 生成成功: {} 字节", svg.len());
Ok(())
}
+9 -3
View File
@@ -24,9 +24,15 @@ struct QrParams {
fmt: String,
}
fn default_level() -> String { "M".into() }
fn default_margin() -> u8 { 4 }
fn default_size() -> u8 { 8 }
fn default_level() -> String {
"M".into()
}
fn default_margin() -> u8 {
4
}
fn default_size() -> u8 {
8
}
fn parse_level(s: &str) -> Result<EcLevel, String> {
match s.to_uppercase().as_str() {