qr_encode/qr_encoder/
util.rs

1use std::env::{args_os};
2use std::ffi::{OsStr};
3
4use qr_encoder::cell::{Cell, Color};
5use qr_encoder::config::{QRConfig, ECLevel, EncodingMode};
6
7
8// L M Q H
9#[derive(Copy, Clone, Debug)]
10pub struct ECCodeWordCount(usize, usize, usize, usize);
11
12// L M Q H
13#[derive(Copy, Clone, Debug)]
14pub struct CodeWordBlock(usize, usize, usize, usize);
15
16#[derive(Debug)]
17pub struct CodeWord {
18    pub ecc_codeword_count: usize,
19    pub block_count: usize,
20    pub capacity: usize
21}
22
23const CODEWORD_COUNT: [usize; 41] = [
24    0, 26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
25    404, 466, 532, 581, 655, 733, 815, 901, 991, 1085,
26    1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185,
27    2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706
28];
29
30const CODEWORD_BLOCKS: [CodeWordBlock; 40] = [
31    // directly copied from https://github.com/soldair/node-qrcode/blob/master/lib/core/error-correction-code.js
32    CodeWordBlock(1, 1, 1, 1),
33    CodeWordBlock(1, 1, 1, 1),
34    CodeWordBlock(1, 1, 2, 2),
35    CodeWordBlock(1, 2, 2, 4),
36    CodeWordBlock(1, 2, 4, 4),
37    CodeWordBlock(2, 4, 4, 4),
38    CodeWordBlock(2, 4, 6, 5),
39    CodeWordBlock(2, 4, 6, 6),
40    CodeWordBlock(2, 5, 8, 8),
41    CodeWordBlock(4, 5, 8, 8),
42    CodeWordBlock(4, 5, 8, 11),
43    CodeWordBlock(4, 8, 10, 11),
44    CodeWordBlock(4, 9, 12, 16),
45    CodeWordBlock(4, 9, 16, 16),
46    CodeWordBlock(6, 10, 12, 18),
47    CodeWordBlock(6, 10, 17, 16),
48    CodeWordBlock(6, 11, 16, 19),
49    CodeWordBlock(6, 13, 18, 21),
50    CodeWordBlock(7, 14, 21, 25),
51    CodeWordBlock(8, 16, 20, 25),
52    CodeWordBlock(8, 17, 23, 25),
53    CodeWordBlock(9, 17, 23, 34),
54    CodeWordBlock(9, 18, 25, 30),
55    CodeWordBlock(10, 20, 27, 32),
56    CodeWordBlock(12, 21, 29, 35),
57    CodeWordBlock(12, 23, 34, 37),
58    CodeWordBlock(12, 25, 34, 40),
59    CodeWordBlock(13, 26, 35, 42),
60    CodeWordBlock(14, 28, 38, 45),
61    CodeWordBlock(15, 29, 40, 48),
62    CodeWordBlock(16, 31, 43, 51),
63    CodeWordBlock(17, 33, 45, 54),
64    CodeWordBlock(18, 35, 48, 57),
65    CodeWordBlock(19, 37, 51, 60),
66    CodeWordBlock(19, 38, 53, 63),
67    CodeWordBlock(20, 40, 56, 66),
68    CodeWordBlock(21, 43, 59, 70),
69    CodeWordBlock(22, 45, 62, 74),
70    CodeWordBlock(24, 47, 65, 77),
71    CodeWordBlock(25, 49, 68, 81)
72];
73
74const EC_CODEWORD_TABLE: [ECCodeWordCount; 40] = [
75    ECCodeWordCount(7, 10, 13, 17),
76    ECCodeWordCount(10, 16, 22, 28),
77    ECCodeWordCount(15, 26, 36, 44),
78    ECCodeWordCount(20, 36, 52, 64),
79    ECCodeWordCount(26, 48, 72, 88),
80    ECCodeWordCount(36, 64, 96, 112),
81    ECCodeWordCount(40, 72, 108, 130),
82    ECCodeWordCount(48, 88, 132, 156),
83    ECCodeWordCount(60, 110, 160, 192),
84    ECCodeWordCount(72, 130, 192, 224),
85    ECCodeWordCount(80, 150, 224, 264),
86    ECCodeWordCount(96, 176, 260, 308),
87    ECCodeWordCount(104, 198, 288, 352),
88    ECCodeWordCount(120, 216, 320, 384),
89    ECCodeWordCount(132, 240, 360, 432),
90    ECCodeWordCount(144, 280, 408, 480),
91    ECCodeWordCount(168, 308, 448, 532),
92    ECCodeWordCount(180, 338, 504, 588),
93    ECCodeWordCount(196, 364, 546, 650),
94    ECCodeWordCount(224, 416, 600, 700),
95    ECCodeWordCount(224, 442, 644, 750),
96    ECCodeWordCount(252, 476, 690, 816),
97    ECCodeWordCount(270, 504, 750, 900),
98    ECCodeWordCount(300, 560, 810, 960),
99    ECCodeWordCount(312, 588, 870, 1050),
100    ECCodeWordCount(336, 644, 952, 1110),
101    ECCodeWordCount(360, 700, 1020, 1200),
102    ECCodeWordCount(390, 728, 1050, 1260),
103    ECCodeWordCount(420, 784, 1140, 1350),
104    ECCodeWordCount(450, 812, 1200, 1440),
105    ECCodeWordCount(480, 868, 1290, 1530),
106    ECCodeWordCount(510, 924, 1350, 1620),
107    ECCodeWordCount(540, 980, 1440, 1710),
108    ECCodeWordCount(570, 1036, 1530, 1800),
109    ECCodeWordCount(570, 1064, 1590, 1890),
110    ECCodeWordCount(600, 1120, 1680, 1980),
111    ECCodeWordCount(630, 1204, 1770, 2100),
112    ECCodeWordCount(660, 1260, 1860, 2220),
113    ECCodeWordCount(720, 1316, 1950, 2310),
114    ECCodeWordCount(750, 1372, 2040, 2430)
115];
116
117#[derive(Debug, Clone)]
118pub struct BlockContent {
119    pub blocks: usize,
120    pub codewords_per_block: usize
121}
122
123impl CodeWord {
124    pub fn get_data_codeword_length(&self) -> usize {
125        self.capacity - self.ecc_codeword_count
126    }
127
128    pub fn get_block_count_for_groups(&self) -> (usize, usize) {
129        let group_two = self.capacity % self.block_count;
130        let group_one = self.block_count - group_two;
131
132        (group_one, group_two)
133    }
134
135    pub fn get_data_cw_total_for_groups(&self) -> (BlockContent, BlockContent) {
136        // the purpose of this function is to....
137        // 1. convey the number of blocks in group one and two
138        // 2. the number of codewords that each block would contain
139
140        let (group_one_blocks, group_two_blocks) = self.get_block_count_for_groups();
141
142        let data_capacity = self.capacity - self.ecc_codeword_count;
143        let group_one_capacity = data_capacity / self.block_count;
144
145        let group_two_capacity = if group_two_blocks > 0 {
146            (data_capacity - (group_one_capacity * group_one_blocks)) / group_two_blocks
147        } else {
148            0
149        };
150
151        (
152            BlockContent { blocks: group_one_blocks, codewords_per_block: group_one_capacity },
153            BlockContent { blocks: group_two_blocks, codewords_per_block: group_two_capacity }
154        )
155    }
156}
157
158pub fn codeword_info(version: usize, err_correction_level: &ECLevel) -> CodeWord {
159    let ecc_settings: ECCodeWordCount = EC_CODEWORD_TABLE[version - 1];
160    let block_count = CODEWORD_BLOCKS[version - 1];
161    let capacity = CODEWORD_COUNT[version];
162
163    let (ec_cw_count, blocks): (usize, usize) = match err_correction_level {
164        &ECLevel::Low => (ecc_settings.0, block_count.0),
165        &ECLevel::Medium => (ecc_settings.1, block_count.1),
166        &ECLevel::Q => (ecc_settings.2, block_count.2),
167        &ECLevel::High => (ecc_settings.3, block_count.3)
168    };
169
170    CodeWord {
171        ecc_codeword_count: ec_cw_count,
172        capacity: capacity,
173        block_count: blocks
174    }
175}
176
177
178pub fn get_pixel_points(cell: &Cell) -> Vec<(u32, u32, Color)> {
179    let i = ((cell.point.0 * 20) as u32) + 80;
180    let j = ((cell.point.1 * 20) as u32) + 80;
181    let mut pixels: Vec<(u32, u32, Color)> = vec![];
182    for row in i..(i + 20) {
183        for col in j..(j + 20) {
184            pixels.push((col, row, Color { g: cell.color.g, b: cell.color.b, r: cell.color.r }));
185        }
186    }
187
188    pixels
189}
190
191pub fn get_index_value(index: isize, modifiers: (isize, isize), canvas_size: isize) -> Option<usize> {
192    let x = index / canvas_size;
193    let y = index % canvas_size;
194    let cx = x + modifiers.0;
195    let cy = y + modifiers.1;
196
197    if (cx > -1 && cx < canvas_size) && (cy > -1 && cy < canvas_size) {
198        Some((cx * canvas_size + cy) as usize)
199    } else {
200        None
201    }
202}
203
204pub fn square_count(version: usize) -> usize {
205    (((version - 1) * 4) + 21)
206}
207
208pub fn set_color(index: usize) -> Color {
209    // temporarily color the cells as a kind of debugging
210    match index {
211        0 => Color { r: 255, g: 120, b: 16 },
212        1 => Color { r: 205, g: 120, b: 16 },
213        2 => Color { r: 155, g: 120, b: 16 },
214        3 => Color { r: 105, g: 120, b: 16 },
215        4 => Color { r: 55, g: 120, b: 16 },
216        5 => Color { r: 5, g: 120, b: 16 },
217        6 => Color { r: 255, g: 175, b: 16 },
218        7 => Color { r: 0, g: 0, b: 0 },
219        _ => Color { r: 255, g: 255, b: 0 }
220    }
221}
222//
223// fn get_content_length(mode: u8, version: usize) -> usize {
224//     let modifier = match version {
225//         1...10 => 0,
226//         11...27 => 2,
227//         _ => 4
228//     };
229//
230//     match mode {
231//         1 => 10 + modifier,
232//         2 => 9 + modifier,
233//         8 => 12 + modifier,
234//         _ => {
235//             if version < 10 {
236//                 8
237//             } else {
238//                 16
239//             }
240//         }
241//     }
242// }
243
244fn get_ec_level(level: &str) -> ECLevel {
245    match level {
246        "l" => ECLevel::Low,
247        "q" => ECLevel::Q,
248        "h" => ECLevel::High,
249        _ => ECLevel::Medium
250    }
251}
252
253pub fn args() -> QRConfig {
254    /*
255        default options are....
256            if no version, the default version is 21
257
258
259        to do:
260            flag for encoding type - default will be utf-8 (i think?)
261            ???
262
263    */
264    let mut qr_args = args_os();
265    let mut version = 14usize;
266    let mut data: Option<Vec<u8>> = None;
267    let mut ec_level: ECLevel = ECLevel::Medium;
268    // let encoding = 4u8;
269    let mut arg = qr_args.next();
270    let mut debug_mode = false;
271
272    while arg.is_some() {
273        let value = arg.unwrap();
274        if value == OsStr::new("-v") {
275            version = match qr_args.next() {
276                Some(n) => {
277                    let x = n.to_str().unwrap().parse::<usize>();
278                    match x {
279                        Ok(nx) if nx < 81 => nx, // if it fails to parse, or parses a number greater than 81, set it to version 21.
280                        Ok(_) => 21usize,
281                        Err(_) => 21usize
282                    }
283                },
284                None => 21usize
285            }
286        } else if value == OsStr::new("-m") {
287            data = match qr_args.next() {
288                Some(msg) => {
289                    let string = String::from(msg.to_str().unwrap());
290                    Some(string.into_bytes())
291                },
292                None => panic!("sdasd")
293            }
294        } else if value == OsStr::new("-ec") {
295            ec_level = match qr_args.next() {
296                Some(ec) => {
297                    let ec = ec.to_str().unwrap();
298                    get_ec_level(&ec)
299                },
300                None => ECLevel::Medium
301            }
302        } else if value == OsStr::new("-DEBUG") {
303            debug_mode = true;
304        }
305
306
307        arg = qr_args.next();
308    }
309
310    let mut data = data.unwrap();
311    let codeword_properties = codeword_info(version, &ec_level);
312    data.truncate(codeword_properties.capacity - codeword_properties.ecc_codeword_count);
313
314    QRConfig {
315        version: version,
316        data: data,
317        codewords: vec![],
318        codeword_properties: codeword_properties,
319        mask: 1,
320        encoding: 4u8,
321        encoding_mode: EncodingMode::Byte,
322        debug_mode: debug_mode,
323        requires_alignment: version > 1,
324        err_correction_level: ec_level,
325        size: (((version - 1) * 4) + 21),
326        finder_points: [
327            (0, 0),
328            ((square_count(version) - 7), 0),
329            (0, (square_count(version) - 7))
330        ]
331    }
332}
333
334// Gets the index values for the version information.
335// Might be useful for other parts of the QR canvas in a future refactor. 
336// Upper right version follows the pattern of left-to-right travelling on rows.
337// Lower left version goes top-to-bottom travelling on columns (l-r)
338// the thing I need to determine is that both areas traverse 3 places before making a row or column change,
339// so is there some kind of "threshold" that would signal that it's time to "reset"
340// One thing that is definitely constant is "every three steps, reset, but advance by X. So what is X?"
341//  Lower Left:  reset value = index - (canvas_size * 3) + 1
342//  Upper RIght: reset value = index + canvas_size - 2
343pub fn get_indices_for_dimensions(start: isize, step: isize, step_modifier: isize) -> Vec<usize> {
344    let mut index = start;
345    let mut indices: Vec<usize> = vec![];
346
347    for _ in 0..18 {
348        index += step;
349        indices.push(index as usize);
350
351        if indices.len() % 3 == 0 {
352            index += step_modifier;
353        }
354    }
355
356    indices
357}