1mod qr_code;
8
9pub use qrcode_rust_shared::{
11 qr_8bit_byte::QR8bitByte,
12 qr_bit_buffer::BitBuffer,
13 qr_code_model::{get_type_number, QRErrorCorrectLevel, QRMode, PATTERN_POSITION_TABLE},
14 qr_math::QRMath,
15 qr_polynomial::Polynomial,
16 qr_rs_block::{get_rs_blocks, QRRSBlock},
17 qr_util::{get_bch_digit, get_length_in_bits},
18};
19
20pub use qr_code::{QRCode, QRCodeOptions};
22
23pub struct QRCodeNative {
28 qr: QRCode,
29}
30
31impl QRCodeNative {
32 pub fn new(text: &str, correct_level: QRErrorCorrectLevel) -> Self {
33 let mut qr = QRCode::with_options(QRCodeOptions {
34 width: 256,
35 height: 256,
36 color_dark: String::from("#000000"),
37 color_light: String::from("#ffffff"),
38 correct_level,
39 });
40 qr.make_code(text);
41 QRCodeNative { qr }
42 }
43
44 pub fn module_count(&self) -> i32 {
45 self.qr.get_module_count()
46 }
47
48 pub fn get_module_count(&self) -> i32 {
49 self.qr.get_module_count()
50 }
51
52 pub fn is_dark(&self, row: i32, col: i32) -> bool {
53 self.qr.is_dark(row, col)
54 }
55
56 pub fn to_svg(&self, size: i32) -> String {
57 let count = self.qr.get_module_count();
58 if count == 0 {
59 return String::new();
60 }
61
62 let cell_size = size / count;
63 let actual_size = cell_size * count;
64 let offset = (size - actual_size) / 2;
65
66 let mut svg = format!(
67 r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {} {}" width="{}" height="{}">"#,
68 size, size, size, size
69 );
70
71 svg.push_str(&format!(
72 r#"<rect width="{}" height="{}" fill="{}"/>"#,
73 size, size, self.qr.options.color_light
74 ));
75
76 for row in 0..count {
77 for col in 0..count {
78 if self.qr.is_dark(row, col) {
79 svg.push_str(&format!(
80 r#"<rect x="{}" y="{}" width="{}" height="{}" fill="{}"/>"#,
81 col * cell_size + offset,
82 row * cell_size + offset,
83 cell_size,
84 cell_size,
85 self.qr.options.color_dark
86 ));
87 }
88 }
89 }
90
91 svg.push_str("</svg>");
92 svg
93 }
94}
95
96impl Default for QRCodeNative {
97 fn default() -> Self {
98 Self::new("", QRErrorCorrectLevel::H)
99 }
100}
101
102#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_qrcode_basic_creation() {
112 let mut qr = QRCode::new();
113 qr.make_code("Hello World");
114
115 assert!(qr.module_count > 0, "模块数应该大于 0");
116 assert!(qr.type_number > 0, "类型号应该大于 0");
117
118 if let Some(ref data) = qr.data_cache {
120 println!("\n=== test_qrcode_basic_creation ===");
121 println!("data_cache 长度: {} 字节", data.len());
122 println!("期望: 16 字节数据 + 28 字节纠错 = 44 字节 (版本 2-H)");
123 println!("数据部分 (前 16 字节):");
124 for (i, byte) in data.iter().enumerate().take(16) {
125 println!(" [{:2}] = 0x{:02X}", i, byte);
126 }
127 println!("纠错码部分 (后 28 字节):");
128 for (i, byte) in data.iter().enumerate().skip(16) {
129 println!(" [{:2}] = 0x{:02X}", i, byte);
130 }
131 }
132 }
133
134 #[test]
135 fn test_qrcode_with_options() {
136 let mut qr = QRCode::with_options(QRCodeOptions {
137 width: 256,
138 height: 256,
139 color_dark: String::from("#000000"),
140 color_light: String::from("#ffffff"),
141 correct_level: QRErrorCorrectLevel::H,
142 });
143 qr.make_code("Test");
144
145 assert_eq!(qr.options.color_dark, "#000000");
146 assert_eq!(qr.options.color_light, "#ffffff");
147 }
148
149 #[test]
150 fn test_qrcode_is_dark_in_range() {
151 let mut qr = QRCode::new();
152 qr.make_code("Test");
153
154 let count = qr.module_count;
155
156 for row in 0..count {
158 for col in 0..count {
159 let _ = qr.is_dark(row, col);
160 }
161 }
162 }
163
164 #[test]
165 #[should_panic]
166 fn test_qrcode_is_dark_out_of_range() {
167 let mut qr = QRCode::new();
168 qr.make_code("Test");
169
170 let count = qr.module_count;
171 qr.is_dark(count, 0);
173 }
174
175 #[test]
176 fn test_qrcode_svg_generation() {
177 let mut qr = QRCode::new();
178 qr.make_code("Hello");
179
180 let svg = qr.get_svg();
181
182 assert!(!svg.is_empty(), "SVG 不应该为空");
183 assert!(svg.contains("<svg"), "SVG 应该包含 <svg 标签");
184 assert!(svg.contains("</svg>"), "SVG 应该包含 </svg> 标签");
185 }
186
187 #[test]
188 fn test_qrcode_position_detection_patterns() {
189 let mut qr = QRCode::new();
191 qr.make_code("Test");
192
193 let count = qr.module_count;
194
195 assert!(qr.is_dark(0, 0), "左上角 (0,0) 应该是深色");
197 assert!(qr.is_dark(0, 6), "左上角 (0,6) 应该是深色");
198 assert!(qr.is_dark(6, 0), "左上角 (6,0) 应该是深色");
199 assert!(qr.is_dark(6, 6), "左上角 (6,6) 应该是深色");
200
201 assert!(
203 qr.is_dark(0, count - 1),
204 "右上角 (0,{}) 应该是深色",
205 count - 1
206 );
207 assert!(
208 qr.is_dark(0, count - 7),
209 "右上角 (0,{}) 应该是深色",
210 count - 7
211 );
212 assert!(
213 qr.is_dark(6, count - 1),
214 "右上角 (6,{}) 应该是深色",
215 count - 1
216 );
217 assert!(
218 qr.is_dark(6, count - 7),
219 "右上角 (6,{}) 应该是深色",
220 count - 7
221 );
222
223 assert!(
225 qr.is_dark(count - 1, 0),
226 "左下角 ({},0) 应该是深色",
227 count - 1
228 );
229 assert!(
230 qr.is_dark(count - 7, 0),
231 "左下角 ({},0) 应该是深色",
232 count - 7
233 );
234 assert!(
235 qr.is_dark(count - 1, 6),
236 "左下角 ({},6) 应该是深色",
237 count - 1
238 );
239 assert!(
240 qr.is_dark(count - 7, 6),
241 "左下角 ({},6) 应该是深色",
242 count - 7
243 );
244 }
245
246 #[test]
247 fn test_qrcode_timing_patterns() {
248 let mut qr = QRCode::new();
250 qr.make_code("Test");
251
252 let count = qr.module_count;
253
254 for col in 8..count - 8 {
256 let expected = col % 2 == 0;
257 assert_eq!(
258 qr.is_dark(6, col),
259 expected,
260 "水平定时图案在 (6,{}) 不匹配",
261 col
262 );
263 }
264
265 for row in 8..count - 8 {
267 let expected = row % 2 == 0;
268 assert_eq!(
269 qr.is_dark(row, 6),
270 expected,
271 "垂直定时图案在 ({},6) 不匹配",
272 row
273 );
274 }
275 }
276
277 #[test]
278 fn test_different_error_correction_levels() {
279 let test_data = "Hello World";
280
281 for level in [
282 QRErrorCorrectLevel::L,
283 QRErrorCorrectLevel::M,
284 QRErrorCorrectLevel::Q,
285 QRErrorCorrectLevel::H,
286 ] {
287 let mut qr = QRCode::with_options(QRCodeOptions {
288 width: 256,
289 height: 256,
290 color_dark: String::from("#000000"),
291 color_light: String::from("#ffffff"),
292 correct_level: level,
293 });
294 qr.make_code(test_data);
295
296 assert!(
297 qr.module_count > 0,
298 "纠错级别 {:?} 应该生成有效的二维码",
299 level
300 );
301 }
302 }
303
304 #[test]
305 fn test_empty_string() {
306 let mut qr = QRCode::new();
307 qr.make_code("");
308
309 assert!(qr.module_count > 0, "空字符串也应该生成二维码");
310 }
311
312 #[test]
313 fn test_long_text() {
314 let long_text = "a".repeat(100);
315 let mut qr = QRCode::new();
316 qr.make_code(&long_text);
317
318 assert!(qr.module_count > 0, "长文本应该生成二维码");
319 assert!(qr.type_number > 1, "长文本应该使用更高的类型号");
320 }
321
322 #[test]
323 fn test_complex_text_hello_world_123() {
324 let text = "Test QR Code 123";
326 let mut qr = QRCode::new();
327 qr.make_code(text);
328
329 assert!(qr.module_count > 0, "复杂文本应该生成二维码");
330 assert!(qr.type_number >= 2, "此文本应该使用类型号 >= 2");
331
332 println!("\n=== test_complex_text_hello_world_123 (qrcode-rust) ===");
334 println!("文本: {}", text);
335 println!("类型号: {}", qr.type_number);
336 println!("模块数: {}", qr.module_count);
337
338 if let Some(ref data) = qr.data_cache {
340 println!("data_cache 长度: {} 字节", data.len());
341 println!("数据字节 (前 32 字节):");
342 for (i, byte) in data.iter().enumerate().take(32) {
343 print!("{:02X} ", byte);
344 if (i + 1) % 16 == 0 {
345 println!();
346 }
347 }
348 println!();
349 }
350 }
351
352 #[test]
353 fn test_complex_text_various() {
354 let test_cases = vec![
356 "Test QR Code 123",
357 "Hello World! 2024",
358 "https://example.com/path?query=1&foo=bar",
359 "Email: test@example.com | Phone: +1-234-567-8900",
360 "WiFi:T:WPA;S:MyNetwork;P:MyPassword;;",
361 ];
362
363 for text in test_cases {
364 let mut qr = QRCode::new();
365 qr.make_code(text);
366
367 assert!(qr.module_count > 0, "文本 '{}' 应该生成二维码", text);
368 println!(
369 "文本 '{}' -> 类型号 {}, 模块数 {}",
370 text, qr.type_number, qr.module_count
371 );
372 }
373 }
374
375 #[test]
376 fn test_get_rs_blocks() {
377 for level in [
379 QRErrorCorrectLevel::L,
380 QRErrorCorrectLevel::M,
381 QRErrorCorrectLevel::Q,
382 QRErrorCorrectLevel::H,
383 ] {
384 let blocks = get_rs_blocks(1, level);
385 assert!(
386 !blocks.is_empty(),
387 "类型号 1 纠错级别 {:?} 应该有 RS 块",
388 level
389 );
390 }
391
392 for level in [
394 QRErrorCorrectLevel::L,
395 QRErrorCorrectLevel::M,
396 QRErrorCorrectLevel::Q,
397 QRErrorCorrectLevel::H,
398 ] {
399 let blocks = get_rs_blocks(2, level);
400 assert!(
401 !blocks.is_empty(),
402 "类型号 2 纠错级别 {:?} 应该有 RS 块",
403 level
404 );
405 }
406 }
407}