7f3b8b4cc7
- README: 测试数 81、输出格式表 + vCard 10字段、透视矫正、格式扩展 - CHANGELOG: v0.3.0 条目(格式扩展+解码增强+vCard扩展) - ROADMAP: v0.2.0/v0.3.0 移至已交付,更新下一版本规划 - CLAUDE.md: 测试 81→105、perspective.rs 模块、Web fmt 参数
375 lines
12 KiB
Markdown
375 lines
12 KiB
Markdown
<p align="center">
|
||
<h1>🀫 QRGen</h1>
|
||
<p>从零手搓的 QR 码生成/解码器 — ISO/IEC 18004 完整实现</p>
|
||
</p>
|
||
|
||
<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/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-81%20passed-brightgreen" alt="tests">
|
||
<img src="https://img.shields.io/badge/clippy-clean-brightgreen" alt="clippy">
|
||
<img src="https://img.shields.io/badge/prettier-formatted-ff69b4" alt="prettier">
|
||
<img src="https://img.shields.io/badge/eslint-checked-4b32c3" alt="eslint">
|
||
<img src="https://img.shields.io/badge/vitest-12%20passed-brightgreen" alt="vitest">
|
||
</p>
|
||
|
||
---
|
||
|
||
## 简介
|
||
|
||
QRGen 是 **从零手写** 的 QR 码(二维码)生成/解码器,完整实现 ISO/IEC 18004 国际标准。不依赖任何第三方 QR 编码/解码库,所有算法(Galois 域运算、Reed-Solomon 纠错编解码、BCH 格式编解码、掩码评分、定位检测)均从底层手搓。
|
||
|
||
支持 **四种使用方式**:程序库(`qr-core`)、命令行(`qrgen`)、桌面 GUI(`qrgen-gui`)、Web 服务(`qrgen-web`)。支持**编码**(文本→QR)和**解码**(QR→文本)双向闭环。
|
||
|
||
## 架构
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph Frontend["React 前端 (GUI)"]
|
||
App[App.tsx 三栏布局]
|
||
Modes[7 种模式表单]
|
||
Preview[实时预览区]
|
||
Export[导出面板]
|
||
History[历史记录]
|
||
App --> Modes
|
||
App --> Preview
|
||
App --> Export
|
||
App --> History
|
||
end
|
||
|
||
subgraph Web["Web 服务 (axum)"]
|
||
HTML[内嵌 HTML 页面]
|
||
API[GET /api/qr + POST /api/decode]
|
||
end
|
||
|
||
subgraph CLI["CLI 命令行"]
|
||
Clap[clap 编码 + --decode 解码]
|
||
end
|
||
|
||
subgraph IPC["Tauri IPC 桥接"]
|
||
Commands[6 个 Tauri commands]
|
||
end
|
||
|
||
subgraph Core["Rust core 库 (qr-core)"]
|
||
Encoder[编码层]
|
||
Decoder[解码层]
|
||
ECC[纠错层]
|
||
Matrix[矩阵层]
|
||
Render[渲染层]
|
||
Encoder --> ECC
|
||
Decoder --> ECC
|
||
ECC --> Matrix
|
||
Matrix --> Render
|
||
end
|
||
|
||
Modes --> Commands
|
||
Commands --> Encoder
|
||
Clap --> Encoder
|
||
HTML --> API
|
||
API --> Encoder
|
||
```
|
||
|
||
### 数据流水线
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
actor U as 用户
|
||
participant UI as React UI / CLI / Web
|
||
participant Q as QrCode::encode()
|
||
participant E as 编码器
|
||
participant RS as Reed-Solomon
|
||
participant M as 矩阵布局
|
||
participant R as 渲染器
|
||
|
||
U->>UI: 输入文本
|
||
UI->>Q: encode(text, config)
|
||
Q->>E: 分析字符集, 自动分段
|
||
E->>E: 模式编码
|
||
E->>RS: 数据码字
|
||
RS->>RS: 纠错码字生成 + 交错
|
||
RS->>M: 最终码字序列
|
||
M->>M: 功能图案 + 蛇形排列 + 掩码
|
||
M->>R: QR 矩阵
|
||
R->>UI: PNG / SVG / ASCII
|
||
|
||
Note over U,R: --- 解码流水线 (逆向) ---
|
||
|
||
U->>UI: 上传图片
|
||
UI->>Q: decode_image(bytes)
|
||
Q->>R: 图像二值化 + 定位图案检测
|
||
R->>M: 布尔矩阵
|
||
M->>M: 读取格式/版本信息 + 解掩码 + 蛇形提取
|
||
M->>RS: 数据码字 + 纠错码字
|
||
RS->>RS: 去交错 + 伴随式 + Berlekamp-Massey + Chien + Forney
|
||
RS->>E: 纠错后数据码字
|
||
E->>E: 模式解码(数字/字母/字节/汉字)
|
||
E->>UI: 解码文本
|
||
```
|
||
|
||
## 功能
|
||
|
||
### 核心算法(全部手写)
|
||
|
||
| 模块 | 内容 | 说明 |
|
||
|------|------|------|
|
||
| Galois 域 | GF(2⁸) 四则运算 + 幂运算 | 预计算 exp/log 表,本原多项式 0x11D |
|
||
| Reed-Solomon | RS 纠错码生成 + 数据交错 | 生成多项式动态构造,多项式长除法 |
|
||
| 编码模式 | 数字 / 字母数字 / 字节 / 汉字 | 4 种模式,自动分段选最优 |
|
||
| 矩阵布局 | 定位/对齐/时序图案 + 蛇形排列 | 8 种掩码 + 四规则惩罚评分 |
|
||
| BCH 编码 | 格式信息 BCH(15,5) + 版本信息 BCH(18,6) | 两级纠错保护 |
|
||
| 版本容量 | 40 版本 × 4 纠错级别完整参数表 | 自动版本选择 |
|
||
|
||
### CLI 命令行
|
||
|
||
```bash
|
||
# 终端 ASCII 预览
|
||
qrgen "Hello World"
|
||
|
||
# 生成 PNG
|
||
qrgen "https://example.com" -o qr.png -s 8
|
||
|
||
# 生成 SVG(高纠错)
|
||
qrgen "重要数据" -o qr.svg -l H
|
||
|
||
# 解码 QR 码图片
|
||
qrgen --decode qr.png
|
||
```
|
||
|
||
### GUI 桌面应用
|
||
|
||
- **7 种编码模式**:文本 / URL / WiFi / vCard(10字段) / Email / 电话 / SMS
|
||
- **解码**:选择图片文件,解码 QR 码为文本
|
||
- **实时预览**:200ms 防抖,PNG 即时渲染
|
||
- **多格式导出**:PNG(可调模块大小)/ SVG / 复制到剪贴板
|
||
- **历史记录**:最近 50 条,点击回填,支持删除和清空
|
||
- **暗色模式**:跟随系统,磨砂玻璃效果
|
||
- **纠错级别可调**:L (7%) / M (15%) / Q (25%) / H (30%)
|
||
|
||
### Web 服务
|
||
|
||
- **内嵌 HTML 界面**:复刻 GUI 三栏布局,7 种编码模式
|
||
- **REST API**:`GET /api/qr` → PNG / SVG;`POST /api/decode` → 上传图片返回文本
|
||
- **Docker 部署**:17.7MB Alpine 镜像,开箱即用
|
||
|
||
## 安装
|
||
|
||
### 从源码构建
|
||
|
||
```bash
|
||
git clone git@lhy-git.liuhangyv.top:Serendipity/QRGen.git
|
||
cd QRGen
|
||
|
||
# 安装前端依赖
|
||
cd gui/src-frontend && pnpm install && cd ../..
|
||
|
||
# CLI
|
||
cargo build --release -p qrgen
|
||
|
||
# Web 服务
|
||
cargo build --release -p qrgen-web
|
||
|
||
# GUI + NSIS 安装包
|
||
cd gui/src-frontend && pnpm build && cd ../..
|
||
cd gui && src-frontend/node_modules/.bin/tauri.cmd build
|
||
```
|
||
|
||
> **要求**:Windows 10+(GUI 需 WebView2),Rust 1.95+,Node.js 22+
|
||
|
||
### Docker(Web 服务)
|
||
|
||
```bash
|
||
# 拉取镜像(或本地构建)
|
||
docker build -t qrgen-web -f web/Dockerfile .
|
||
|
||
# 运行
|
||
docker run -d --name qrgen-web --restart unless-stopped -p 3000:3000 qrgen-web
|
||
|
||
# docker-compose
|
||
# 见 G:\qrgen-web\docker-compose.yaml(NAS 部署用)
|
||
```
|
||
|
||
## 开发
|
||
|
||
```bash
|
||
# 开发模式 GUI(热更新)
|
||
cd gui/src-frontend && pnpm dev # 终端1: 前端
|
||
cargo run -p qrgen-gui # 终端2: Rust 后端
|
||
|
||
# CLI 开发
|
||
cargo run -p qrgen -- "Hello World"
|
||
|
||
# Web 开发
|
||
cargo run -p qrgen-web # → http://localhost:3000
|
||
|
||
# Rust 测试
|
||
cargo test --lib # 81 unit
|
||
|
||
# 前端测试
|
||
cd gui/src-frontend && pnpm test # vitest
|
||
|
||
# 前端类型检查
|
||
cd gui/src-frontend && pnpm tsc --noEmit
|
||
|
||
# Rust lint
|
||
cargo clippy -- -D warnings
|
||
|
||
# 前端代码检查
|
||
cd gui/src-frontend && pnpm lint # eslint
|
||
cd gui/src-frontend && pnpm format:check # prettier
|
||
|
||
# Git hooks(提交前自动运行)
|
||
# pre-commit: lint-staged(prettier + eslint)
|
||
# commit-msg: commitlint(Conventional Commits)
|
||
```
|
||
|
||
### 技术栈
|
||
|
||
| 层 | 技术 |
|
||
|---|---|
|
||
| 桌面框架 | Tauri 2.x |
|
||
| GUI 前端 | React 18 + TypeScript (strict) |
|
||
| UI 样式 | TailwindCSS 3 |
|
||
| 状态管理 | React Context + useReducer |
|
||
| Web 服务 | axum 0.8 + tokio |
|
||
| 核心库 | Rust (qr-core) |
|
||
| CLI | clap + anyhow |
|
||
| 前端包管理 | pnpm |
|
||
| 桌面打包 | NSIS |
|
||
| 容器化 | Docker (alpine, 17.7MB) |
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
QRGen/
|
||
├── core/ # Rust 核心库(算法全部在此)
|
||
│ └── src/
|
||
│ ├── qr.rs # 顶层 API — QrCode::encode()
|
||
│ ├── version.rs # 40 版本容量表 + 自动选择
|
||
│ ├── ecc/
|
||
│ │ ├── galois.rs # GF(2⁸) 运算 + exp/log 表
|
||
│ │ └── reed_solomon.rs # RS 纠错码 + 数据交错
|
||
│ ├── decoder/ # QR 解码器(从零手写)
|
||
│ │ ├── mod.rs # 顶层 API:decode_image + decode_matrix
|
||
│ │ ├── bch.rs # BCH(15,5)+BCH(18,6) 查表解码
|
||
│ │ ├── format.rs # 格式信息 + 版本信息读取
|
||
│ │ ├── extract.rs # 逆向蛇形排列提取码字
|
||
│ │ ├── deinterleave.rs # 逆向 RS 数据交错
|
||
│ │ ├── rs_decode.rs # RS 纠错(伴随式→BM→Chien→Forney)
|
||
│ │ ├── mode_decode.rs # 逆向 4 种编码模式
|
||
│ │ ├── detect.rs # 定位图案检测 + 采样网格
|
||
│ │ └── image.rs # 图像加载 + 二值化
|
||
│ ├── encoder/
|
||
│ │ ├── mode.rs # 4 种编码模式
|
||
│ │ ├── segment.rs # 字符串分段
|
||
│ │ └── bitstream.rs # 比特流拼接
|
||
│ ├── matrix/
|
||
│ │ ├── grid.rs # 模块矩阵
|
||
│ │ ├── patterns.rs # 定位/对齐/时序图案 + BCH 码
|
||
│ │ ├── placement.rs # 蛇形数据排列
|
||
│ │ └── mask.rs # 8 掩码 + 四规则评分
|
||
│ └── render/
|
||
│ ├── png.rs # PNG 输出 (image crate)
|
||
│ ├── svg.rs # SVG 输出
|
||
│ └── ascii.rs # 终端 ASCII
|
||
├── cli/ # CLI 命令行工具
|
||
│ └── src/main.rs # clap 参数解析
|
||
├── gui/ # Tauri 桌面应用
|
||
│ ├── capabilities/default.json # ACL 权限
|
||
│ ├── src/
|
||
│ │ ├── main.rs # Windows 子系统入口
|
||
│ │ └── lib.rs # 6 个 Tauri commands
|
||
│ ├── src-frontend/ # React 前端
|
||
│ │ └── src/
|
||
│ │ ├── App.tsx # 主布局(三栏+底部输入)
|
||
│ │ ├── components/ # ModePanel / QrPreview / ExportPanel / HistoryList
|
||
│ │ ├── modes/ # 7 种模式表单
|
||
│ │ ├── hooks/ # useQrEncode(防抖+编码)
|
||
│ │ ├── store/ # Context + useReducer
|
||
│ │ ├── types/ # TypeScript 类型
|
||
│ │ └── utils/ # qrText.ts 文本构造工具
|
||
│ └── tauri.conf.json # 窗口 + NSIS 打包配置
|
||
├── web/ # Web 服务
|
||
│ ├── Dockerfile # rust-alpine 多阶段构建
|
||
│ └── src/
|
||
│ ├── main.rs # axum HTTP 服务
|
||
│ └── templates/
|
||
│ └── index.html # 内嵌 GUI 风格页面
|
||
├── .dockerignore
|
||
└── Cargo.toml # Workspace: core + cli + gui + web
|
||
```
|
||
|
||
## 支持规格
|
||
|
||
| 维度 | 范围 |
|
||
|------|------|
|
||
| QR 版本 | 1 ~ 40(21×21 ~ 177×177 模块) |
|
||
| 纠错级别 | L (7%) / M (15%) / Q (25%) / H (30%) |
|
||
| 编码模式 | 数字 / 字母数字 / 字节 / 汉字 (Shift JIS) |
|
||
| 输出格式 | PNG / BMP / JPEG / WebP / SVG / 终端 ASCII |
|
||
| vCard 字段 | 姓名/电话/邮箱/公司/职位/地址/网址/生日/备注/照片 (10 字段) |
|
||
| 使用方式 | Library / CLI / GUI / Web API |
|
||
| 解码 | 从图片识读 QR 码 → 文本(支持旋转矫正) |
|
||
| 自动版本选择 | 根据数据长度 + 纠错级别 |
|
||
| 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};
|
||
use qr_core::decoder;
|
||
|
||
// 编码:文本 → QR
|
||
let qr = QrCode::encode("Hello QR!", QrConfig::default())?;
|
||
qr.to_png_bytes(8)?; // PNG 字节
|
||
let svg = qr.to_svg(); // SVG 字符串
|
||
|
||
// 解码:QR 图片 → 文本
|
||
let bytes = std::fs::read("qr.png")?;
|
||
let result = decoder::decode_image(&bytes)?;
|
||
println!("解码结果: {}", result.text);
|
||
```
|
||
|
||
## 发布到 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
|
||
|
||
## 作者
|
||
|
||
[刘航宇](https://github.com/LHY0125) — 河南理工大学人工智能协会
|