feat: 顶层 API + PNG/SVG/ASCII 渲染器
This commit is contained in:
@@ -1 +1,27 @@
|
||||
// FIXME: ASCII 渲染器 — Task 10
|
||||
use crate::qr::QrCode;
|
||||
|
||||
/// 终端 ASCII 渲染:██ 表示暗模块," " 表示亮模块
|
||||
pub fn render_ascii(qr: &QrCode, invert: bool) -> String {
|
||||
let size = qr.size() as usize;
|
||||
let margin = qr.margin as usize;
|
||||
let total = size + 2 * margin;
|
||||
|
||||
let dark_char = if invert { " " } else { "██" };
|
||||
let light_char = if invert { "██" } else { " " };
|
||||
|
||||
let mut result = String::new();
|
||||
for y in 0..total {
|
||||
for x in 0..total {
|
||||
let mx = x.saturating_sub(margin);
|
||||
let my = y.saturating_sub(margin);
|
||||
let is_dark = if mx < size && my < size {
|
||||
qr.modules()[my][mx]
|
||||
} else {
|
||||
false
|
||||
};
|
||||
result.push_str(if is_dark { dark_char } else { light_char });
|
||||
}
|
||||
result.push('\n');
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
+43
-1
@@ -1 +1,43 @@
|
||||
// FIXME: PNG 渲染器 — Task 10
|
||||
use crate::qr::QrCode;
|
||||
use image::{ImageBuffer, Luma};
|
||||
|
||||
pub fn render_png(qr: &QrCode, module_size: u8) -> Vec<u8> {
|
||||
let matrix_size = qr.size() as u32;
|
||||
let margin = qr.margin as u32;
|
||||
let total_size = matrix_size + 2 * margin;
|
||||
let img_size = total_size * module_size as u32;
|
||||
|
||||
let mut img = ImageBuffer::new(img_size, img_size);
|
||||
|
||||
for y in 0..total_size {
|
||||
for x in 0..total_size {
|
||||
let module_x = x.saturating_sub(margin);
|
||||
let module_y = y.saturating_sub(margin);
|
||||
|
||||
let is_dark = if module_x < matrix_size && module_y < matrix_size {
|
||||
qr.modules()[module_y as usize][module_x as usize]
|
||||
} else {
|
||||
false // 白边
|
||||
};
|
||||
|
||||
let px_val = if is_dark { 0u8 } else { 255u8 };
|
||||
for dy in 0..module_size as u32 {
|
||||
for dx in 0..module_size as u32 {
|
||||
img.put_pixel(
|
||||
x * module_size as u32 + dx,
|
||||
y * module_size as u32 + dy,
|
||||
Luma([px_val]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut buf = Vec::new();
|
||||
img.write_to(
|
||||
&mut std::io::Cursor::new(&mut buf),
|
||||
image::ImageFormat::Png,
|
||||
)
|
||||
.expect("PNG 编码失败");
|
||||
buf
|
||||
}
|
||||
|
||||
+32
-1
@@ -1 +1,32 @@
|
||||
// FIXME: SVG 渲染器 — Task 10
|
||||
use crate::qr::QrCode;
|
||||
|
||||
pub fn render_svg(qr: &QrCode) -> String {
|
||||
let matrix_size = qr.size() as u32;
|
||||
let margin = qr.margin as u32;
|
||||
let total = matrix_size + 2 * margin;
|
||||
|
||||
let mut svg = String::new();
|
||||
svg.push_str(&format!(
|
||||
r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}" viewBox="0 0 {} {}">"#,
|
||||
total, total, total, total
|
||||
));
|
||||
svg.push_str(&format!(
|
||||
r#"<rect width="{}" height="{}" fill="white"/>"#,
|
||||
total, total
|
||||
));
|
||||
|
||||
for y in 0..matrix_size {
|
||||
for x in 0..matrix_size {
|
||||
if qr.modules()[y as usize][x as usize] {
|
||||
svg.push_str(&format!(
|
||||
r#"<rect x="{}" y="{}" width="1" height="1" fill="black"/>"#,
|
||||
x + margin,
|
||||
y + margin
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg.push_str("</svg>");
|
||||
svg
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user