1const std = @import("std");
2const builtin = @import("builtin");
3const extras = @import("extras");
4
5/// GF(256)[0...255]
6const GF = blk: {
7 var gf: [256]u8 = @splat(2);
8 for (0..256) |n| {
9 if (n == 0) {
10 gf[n] = 1;
11 continue;
12 }
13 if (n < 8) {
14 gf[n] <<= @intCast(n - 1);
15 continue;
16 }
17 gf[n] = gf[n - 1] *% 2;
18 if (gf[n - 1] > 127) gf[n] ^= 0b00011101;
19 }
20 const out = gf;
21 break :blk out;
22};
23
24pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16, input: []const u8) BitGrid(4 * version + 17) {
25 if (mode == .numeric) std.debug.assert(extras.matchesAll(u8, input, isNumeric));
26 if (mode == .alphanumeric) std.debug.assert(extras.matchesAll(u8, input, isAlphanumeric));
27 // latin1 is a full 1-byte format, some readers can detect utf-8
28 // shift jis is a full 2-byte format
29
30 const max_lengths = comptime maxLenPerModeLevelVersion(mode, level);
31 const max_length = max_lengths[version];
32 std.debug.assert(input.len <= max_length);
33
34 const dataCodewordsCount, const ecCodewordsPerBlock, const groupOneBlockCount, const groupOneDataCodewordsCountPerBlock, const groupTwoBlockCount, const groupTwoDataCodewordsCountPerBlock = comptime errorCorrection(level, version);
35
36 const mode_indicator: u4 = switch (mode) {
37 .numeric => 0b0001,
38 .alphanumeric => 0b0010,
39 .latin1 => 0b0100,
40 .shiftjis => 0b1000,
41 };
42
43 const LenIndicator = switch (mode) {
44 .numeric => switch (version) {
45 1...9 => u10,
46 10...26 => u12,
47 27...40 => u14,
48 else => unreachable,
49 },
50 .alphanumeric => switch (version) {
51 1...9 => u9,
52 10...26 => u11,
53 27...40 => u13,
54 else => unreachable,
55 },
56 .latin1 => switch (version) {
57 1...9 => u8,
58 10...26 => u16,
59 27...40 => u16,
60 else => unreachable,
61 },
62 .shiftjis => switch (version) {
63 1...9 => u8,
64 10...26 => u10,
65 27...40 => u12,
66 else => unreachable,
67 },
68 };
69 const len_indicator: LenIndicator = @intCast(input.len);
70
71 const total_bits = dataCodewordsCount * 8;
72
73 var scratch: std.bit_set.ArrayBitSet(u8, total_bits) = .initEmpty();
74 var scratchw: BitsetWriter(u8, total_bits) = .{ .set = &scratch };
75
76 scratchw.writeInt(mode_indicator);
77 scratchw.writeInt(len_indicator);
78 for (input) |x| scratchw.writeInt(x);
79
80 const data_bits = input.len * 8 + @bitSizeOf(@TypeOf(mode_indicator)) + @bitSizeOf(@TypeOf(len_indicator));
81 std.debug.assert(scratchw.idx == data_bits);
82
83 // write @max(4, padding_bits) 0s
84 for (0..@min(4, total_bits - scratchw.idx)) |_| scratchw.writeInt(@as(u1, 0));
85
86 // add zero bits to make data_bits%8 == 0
87 for (0..-%scratchw.idx & 7) |_| scratchw.writeInt(@as(u1, 0));
88
89 // add 236(11101100) 17(00010001) until we reach total_bits
90 while (scratchw.idx < total_bits) {
91 scratchw.writeInt(@as(u8, 0xec));
92 scratchw.writeInt(@as(u8, 0x11));
93 }
94
95 const generator_polynomial = reverseArray(generatorPolynomial(ecCodewordsPerBlock));
96 const generator_polynomial_alpha = to_alpha(generator_polynomial);
97
98 // Now that the message and generator polynomials have been created, divide them to get the error codewords.
99 {
100 // 1. Multiply the message polynomial by x^n where n is the number of error correction codewords to be generated
101 // and multiply the generator polynomial by x^m where m is the leading exponent of the message polynomial.
102 // 2. Multiply the generator polynomial by the lead term of the message polynomial.
103 // 3. XOR the result of Step 2 with the message polynomial and discard the lead 0 term.
104 // 4. Repeat Steps 2-3 n-1 more times where n is the number of data codewords.
105 }
106
107 const group2_block_count = groupTwoBlockCount orelse 0;
108 const group2_datacodewords_per_block = groupTwoDataCodewordsCountPerBlock orelse 0;
109
110 var group1_ec: [groupOneBlockCount][ecCodewordsPerBlock]u8 = @splat(@splat(0));
111 var group2_ec: [group2_block_count][ecCodewordsPerBlock]u8 = @splat(@splat(0));
112
113 for (&group1_ec, 0..) |*g, gn| {
114 const message_polynomial = scratch.masks[groupOneDataCodewordsCountPerBlock * gn ..][0..groupOneDataCodewordsCountPerBlock];
115
116 var mp: [groupOneDataCodewordsCountPerBlock + ecCodewordsPerBlock]?u8 = @splat(null);
117 for (message_polynomial, 0..) |x, i| mp[i] = to_alpha(.{@bitReverse(x)})[0];
118
119 for (0..groupOneDataCodewordsCountPerBlock) |i| {
120 const lead = mp[i] orelse 0;
121 for (&generator_polynomial_alpha, 0..) |x, j| {
122 var y = GF[(@as(usize, x) + lead) % 255];
123 if (mp[i + j]) |z| y ^= GF[z];
124 mp[i + j] = if (y == 0) null else to_alpha(.{y})[0];
125 }
126 }
127 for (g, 0..) |_, i| {
128 g[i] = if (mp[message_polynomial.len..][i]) |x| GF[x] else 0;
129 }
130 }
131 for (&group2_ec, 0..) |*g, gn| {
132 const message_polynomial = scratch.masks[groupOneBlockCount * groupOneDataCodewordsCountPerBlock ..][group2_datacodewords_per_block * gn ..][0..group2_datacodewords_per_block];
133
134 var mp: [group2_datacodewords_per_block + ecCodewordsPerBlock]?u8 = @splat(null);
135 for (message_polynomial, 0..) |x, i| mp[i] = to_alpha(.{@bitReverse(x)})[0];
136
137 for (0..group2_datacodewords_per_block) |i| {
138 const lead = mp[i] orelse 0;
139 for (&generator_polynomial_alpha, 0..) |x, j| {
140 var y = GF[(@as(usize, x) + lead) % 255];
141 if (mp[i + j]) |z| y ^= GF[z];
142 mp[i + j] = if (y == 0) null else to_alpha(.{y})[0];
143 }
144 }
145 for (g, 0..) |_, i| {
146 g[i] = if (mp[message_polynomial.len..][i]) |x| GF[x] else 0;
147 }
148 }
149
150 comptime std.debug.assert(groupOneDataCodewordsCountPerBlock != group2_datacodewords_per_block);
151 const group1_allcodewords_count = groupOneBlockCount * groupOneDataCodewordsCountPerBlock + groupOneBlockCount * ecCodewordsPerBlock;
152 const group2_allcodewords_count = group2_block_count * group2_datacodewords_per_block + group2_block_count * ecCodewordsPerBlock;
153 var interleaved_message: [group1_allcodewords_count + group2_allcodewords_count]u8 = @splat(0);
154 var imi: usize = 0;
155 for (0..@min(groupOneDataCodewordsCountPerBlock, group2_datacodewords_per_block)) |j| {
156 for (0..groupOneBlockCount) |i| {
157 interleaved_message[imi] = scratch.masks[(i * groupOneDataCodewordsCountPerBlock) + j];
158 imi += 1;
159 }
160 for (0..group2_block_count) |i| {
161 interleaved_message[imi] = scratch.masks[(groupOneBlockCount * groupOneDataCodewordsCountPerBlock) + (i * group2_datacodewords_per_block) + j];
162 imi += 1;
163 }
164 }
165 for (0..groupOneDataCodewordsCountPerBlock - @min(groupOneDataCodewordsCountPerBlock, group2_datacodewords_per_block)) |j| {
166 for (0..groupOneBlockCount) |i| {
167 interleaved_message[imi] = scratch.masks[(i * groupOneDataCodewordsCountPerBlock) + j];
168 imi += 1;
169 }
170 }
171 for (0..group2_datacodewords_per_block - @min(groupOneDataCodewordsCountPerBlock, group2_datacodewords_per_block)) |j| {
172 for (0..group2_block_count) |i| {
173 interleaved_message[imi] = scratch.masks[(groupOneBlockCount * groupOneDataCodewordsCountPerBlock) + (i * group2_datacodewords_per_block) + j];
174 imi += 1;
175 }
176 }
177 for (0..ecCodewordsPerBlock) |j| {
178 for (0..groupOneBlockCount) |i| {
179 interleaved_message[imi] = @bitReverse(group1_ec[i][j]);
180 imi += 1;
181 }
182 for (0..group2_block_count) |i| {
183 interleaved_message[imi] = @bitReverse(group2_ec[i][j]);
184 imi += 1;
185 }
186 }
187 std.debug.assert(imi == interleaved_message.len);
188
189 // remainder bits
190 const remainder_bits_count = comptime remainderBitsCount(version);
191 _ = remainder_bits_count;
192
193 //
194
195 const size = 4 * version + 17;
196 var grid: BitGrid(size) = .initEmpty();
197
198 // top left finder pattern
199 for (0..7) |i| for (0..7) |j| grid.setT(0 + i, 0 + j);
200 for (0..5) |i| for (0..5) |j| grid.setF(1 + i, 1 + j);
201 for (0..3) |i| for (0..3) |j| grid.setT(2 + i, 2 + j);
202
203 // top right finder pattern
204 for (0..7) |i| for (0..7) |j| grid.setT(size - 7 + 0 + i, 0 + j);
205 for (0..5) |i| for (0..5) |j| grid.setF(size - 7 + 1 + i, 1 + j);
206 for (0..3) |i| for (0..3) |j| grid.setT(size - 7 + 2 + i, 2 + j);
207
208 // bottom left finder pattern
209 for (0..7) |i| for (0..7) |j| grid.setT(0 + i, size - 7 + 0 + j);
210 for (0..5) |i| for (0..5) |j| grid.setF(1 + i, size - 7 + 1 + j);
211 for (0..3) |i| for (0..3) |j| grid.setT(2 + i, size - 7 + 2 + j);
212
213 // timing pattern
214 for (8..size) |i| if (i % 2 == 0) grid.set(i, 6);
215 for (8..size) |i| if (i % 2 == 0) grid.set(6, i);
216
217 // dark module
218 grid.set(8, 4 * (version - 1) + 13);
219
220 // data mask (data cannot be placed where this is set)
221 var data_mask: BitGrid(size) = .initEmpty();
222 for (0..9) |y| for (0..9) |x| data_mask.set(x, y);
223 for (0..9) |y| for (0..8) |x| data_mask.set(size - 8 + x, y);
224 for (0..8) |y| for (0..9) |x| data_mask.set(x, size - 8 + y);
225 for (0..size) |i| data_mask.set(i, 6);
226 for (0..size) |i| data_mask.set(6, i);
227
228 // alignment patterns
229 const alignment_pattern_centers = comptime alignmentPatternCenters(version);
230 for (alignment_pattern_centers, 0..) |y, i| {
231 for (alignment_pattern_centers, 0..) |x, j| blk: {
232 if (i == 0 and j == 0) break :blk;
233 if (i == 0 and j == alignment_pattern_centers.len - 1) break :blk;
234 if (j == 0 and i == alignment_pattern_centers.len - 1) break :blk;
235
236 for (y - 2..y + 2 + 1) |y2| for (x - 2..x + 2 + 1) |x2| {
237 grid.setT(x2, y2);
238 data_mask.set(x2, y2);
239 };
240 for (y - 1..y + 1 + 1) |y2| for (x - 1..x + 1 + 1) |x2| {
241 grid.setF(x2, y2);
242 data_mask.set(x2, y2);
243 };
244 grid.setT(x, y);
245 data_mask.set(x, y);
246 }
247 }
248
249 // version block
250 if (version >= 7) {
251 var bititer: std.bit_set.IntegerBitSet(18) = .{ .mask = versionBits(version) };
252 for (0..3) |x| {
253 for (0..6) |y| {
254 grid.setV(size - 11 + x, y, bititer.isSet((y * 3) + x));
255 data_mask.set(size - 11 + x, y);
256 }
257 }
258 for (0..6) |x| {
259 for (0..3) |y| {
260 grid.setV(x, size - 11 + y, bititer.isSet((x * 3) + y));
261 data_mask.set(x, size - 11 + y);
262 }
263 }
264 }
265
266 // write data
267 var data_iter: BufBiterator = .init(&bitReverse(interleaved_message));
268
269 var griditer: GridZigZag = .init(size, 6);
270 while (griditer.next()) |idx| {
271 const x = idx % size;
272 const y = (idx - x) / size;
273 if (data_mask.isSet(x, y)) continue;
274 if (@bitCast(data_iter.next() orelse break)) grid.set(x, y);
275 }
276
277 // format info
278 var masks = [_]std.bit_set.IntegerBitSet(15){
279 .{ .mask = @bitReverse(formatPattern(level, 0)) },
280 .{ .mask = @bitReverse(formatPattern(level, 1)) },
281 .{ .mask = @bitReverse(formatPattern(level, 2)) },
282 .{ .mask = @bitReverse(formatPattern(level, 3)) },
283 .{ .mask = @bitReverse(formatPattern(level, 4)) },
284 .{ .mask = @bitReverse(formatPattern(level, 5)) },
285 .{ .mask = @bitReverse(formatPattern(level, 6)) },
286 .{ .mask = @bitReverse(formatPattern(level, 7)) },
287 };
288 var grids = [_]BitGrid(size){
289 grid,
290 grid,
291 grid,
292 grid,
293 grid,
294 grid,
295 grid,
296 grid,
297 };
298 for (&grids, &masks) |*g, m| {
299 g.setV(0, 8, m.isSet(0));
300 g.setV(1, 8, m.isSet(1));
301 g.setV(2, 8, m.isSet(2));
302 g.setV(3, 8, m.isSet(3));
303 g.setV(4, 8, m.isSet(4));
304 g.setV(5, 8, m.isSet(5));
305 g.setV(7, 8, m.isSet(6));
306 g.setV(8, 8, m.isSet(7));
307 g.setV(8, 7, m.isSet(8));
308 g.setV(8, 5, m.isSet(9));
309 g.setV(8, 4, m.isSet(10));
310 g.setV(8, 3, m.isSet(11));
311 g.setV(8, 2, m.isSet(12));
312 g.setV(8, 1, m.isSet(13));
313 g.setV(8, 0, m.isSet(14));
314
315 g.setV(8, size - 1 - 0, m.isSet(0));
316 g.setV(8, size - 1 - 1, m.isSet(1));
317 g.setV(8, size - 1 - 2, m.isSet(2));
318 g.setV(8, size - 1 - 3, m.isSet(3));
319 g.setV(8, size - 1 - 4, m.isSet(4));
320 g.setV(8, size - 1 - 5, m.isSet(5));
321 g.setV(8, size - 1 - 6, m.isSet(6));
322 g.setV(size - 8 + 0, 8, m.isSet(7));
323 g.setV(size - 8 + 1, 8, m.isSet(8));
324 g.setV(size - 8 + 2, 8, m.isSet(9));
325 g.setV(size - 8 + 3, 8, m.isSet(10));
326 g.setV(size - 8 + 4, 8, m.isSet(11));
327 g.setV(size - 8 + 5, 8, m.isSet(12));
328 g.setV(size - 8 + 6, 8, m.isSet(13));
329 g.setV(size - 8 + 7, 8, m.isSet(14));
330 }
331
332 // masking patterns
333 // Pattern 0: (row + column) mod 2 == 0
334 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (row + col) % 2 == 0) grids[0].flip(col, row);
335 // Pattern 1: row mod 2 == 0
336 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and row % 2 == 0) grids[1].flip(col, row);
337 // Pattern 2: column mod 3 == 0
338 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and col % 3 == 0) grids[2].flip(col, row);
339 // Pattern 3: (row + column) mod 3 == 0
340 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (row + col) % 3 == 0) grids[3].flip(col, row);
341 // Pattern 4: (floor(row/2) + floor(column / 3)) mod 2 == 0
342 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (row / 2 + col / 3) % 2 == 0) grids[4].flip(col, row);
343 // Pattern 5: ((row * column) mod 2) + ((row * column) mod 3) == 0
344 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (((row * col) % 2) + ((row * col) % 3)) == 0) grids[5].flip(col, row);
345 // Pattern 6: ( ((row * column) mod 2) + ((row * column) mod 3) ) mod 2 == 0
346 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (((row * col) % 2) + ((row * col) % 3)) % 2 == 0) grids[6].flip(col, row);
347 // Pattern 7: ( ((row + column) mod 2) + ((row * column) mod 3) ) mod 2 == 0
348 for (0..size) |row| for (0..size) |col| if (!data_mask.isSet(col, row) and (((row + col) % 2) + ((row * col) % 3)) % 2 == 0) grids[7].flip(col, row);
349
350 // penalty
351 var penaltys: [8][4]u32 = @splat(@splat(0));
352 for (&grids, 0..) |*g, i| {
353 var prev = false;
354 var run: u16 = 0;
355 for (0..size) |y| {
356 for (0..size) |x| {
357 if (x == 0) {
358 run = 0;
359 prev = g.isSet(0, y);
360 }
361 const this = g.isSet(x, y);
362 if (this == prev) {
363 run += 1;
364 penaltys[i][0] += if (run == 5) 3 else if (run > 5) 1 else 0;
365 } else {
366 run = 1;
367 }
368 prev = this;
369 }
370 }
371 for (0..size) |x| {
372 for (0..size) |y| {
373 if (y == 0) {
374 run = 0;
375 prev = g.isSet(x, 0);
376 }
377 const this = g.isSet(x, y);
378 if (this == prev) {
379 run += 1;
380 penaltys[i][0] += if (run == 5) 3 else if (run > 5) 1 else 0;
381 } else {
382 run = 1;
383 }
384 prev = this;
385 }
386 }
387 }
388 for (&grids, 0..) |*g, i| {
389 for (0..size - 1) |y| {
390 for (0..size - 1) |x| {
391 const p0 = g.isSet(x, y);
392 const p1 = g.isSet(x + 1, y);
393 const p2 = g.isSet(x, y + 1);
394 const p3 = g.isSet(x + 1, y + 1);
395 penaltys[i][1] += if (p0 == p1 and p1 == p2 and p2 == p3) 3 else 0;
396 }
397 }
398 }
399 for (&grids, 0..) |*g, i| {
400 for (0..size) |y| {
401 for (0..size - 10) |x| {
402 const sel = g.sliceX(y, x, 11);
403 penaltys[i][2] += if (sel.mask == 0b00001011101) 40 else 0;
404 penaltys[i][2] += if (sel.mask == 0b10111010000) 40 else 0;
405 }
406 }
407 for (0..size) |x| {
408 for (0..size - 10) |y| {
409 const sel = g.sliceY(x, y, 11);
410 penaltys[i][2] += if (sel.mask == 0b00001011101) 40 else 0;
411 penaltys[i][2] += if (sel.mask == 0b10111010000) 40 else 0;
412 }
413 }
414 }
415 for (&grids, 0..) |*g, i| {
416 const total_modules: comptime_float = size * size;
417 var dark_modules: f32 = 0;
418 for (0..size) |y| {
419 for (0..size) |x| {
420 if (g.isSet(x, y)) {
421 dark_modules += 1;
422 }
423 }
424 }
425 const percent: u32 = @intFromFloat(@ceil(dark_modules / total_modules * 100));
426 const round1 = percent + (-%percent & 4);
427 const round2 = round1 -| 5;
428 const sub = [_]u32{ @abs(@as(i32, @intCast(round1)) - 50), @abs(@as(i32, @intCast(round2)) - 50) };
429 const div = [_]u32{ @divFloor(sub[0], 5), @divFloor(sub[1], 5) };
430 penaltys[i][3] += std.mem.min(u32, &div) * 10;
431 }
432
433 var penalty: [8]u32 = @splat(0);
434 for (0..8) |i| penalty[i] = extras.sum(u32, &penaltys[i]);
435
436 const min_penalty = std.mem.min(u32, &penalty);
437 const min_mask = std.mem.indexOfScalar(u32, &penalty, min_penalty).?;
438 return grids[min_mask];
439}
440
441fn BitGrid(comptime size: usize) type {
442 return struct {
443 bset: std.bit_set.ArrayBitSet(usize, size * size),
444 comptime size: usize = size,
445
446 pub fn initEmpty() @This() {
447 return .{
448 .bset = .initEmpty(),
449 };
450 }
451
452 pub fn isSet(self: *const @This(), x: usize, y: usize) bool {
453 return self.bset.isSet((y * size) + x);
454 }
455
456 pub fn set(self: *@This(), x: usize, y: usize) void {
457 self.bset.set((y * size) + x);
458 }
459
460 pub fn setF(self: *@This(), x: usize, y: usize) void {
461 self.bset.setValue((y * size) + x, false);
462 }
463
464 pub fn setT(self: *@This(), x: usize, y: usize) void {
465 self.bset.setValue((y * size) + x, true);
466 }
467
468 pub fn setV(self: *@This(), x: usize, y: usize, value: bool) void {
469 self.bset.setValue((y * size) + x, value);
470 }
471
472 pub fn flip(self: *@This(), x: usize, y: usize) void {
473 self.bset.toggle((y * size) + x);
474 }
475
476 pub fn sliceX(self: *@This(), y: usize, sx: usize, comptime len: usize) std.bit_set.IntegerBitSet(len) {
477 var result: std.bit_set.IntegerBitSet(len) = .initEmpty();
478 for (0..len) |i| result.setValue(i, self.isSet(sx + i, y));
479 return result;
480 }
481
482 pub fn sliceY(self: *@This(), x: usize, sy: usize, comptime len: usize) std.bit_set.IntegerBitSet(len) {
483 var result: std.bit_set.IntegerBitSet(len) = .initEmpty();
484 for (0..len) |i| result.setValue(i, self.isSet(x, sy + i));
485 return result;
486 }
487
488 pub fn asBlockString(grid: *const @This(), allocator: std.mem.Allocator) ![]u8 {
489 var content: std.Io.Writer.Allocating = .init(allocator);
490 errdefer content.deinit();
491 for (0..grid.size / 2 + 1) |y| {
492 for (0..grid.size / 2 + 1) |x| {
493 var idx: std.bit_set.IntegerBitSet(4) = .initEmpty();
494 inline for (0..2) |x2| {
495 inline for (0..2) |y2| blk: {
496 const real_x = x * 2 + x2;
497 const real_y = y * 2 + y2;
498 if (real_x >= grid.size) break :blk;
499 if (real_y >= grid.size) break :blk;
500 const is_set = grid.isSet(real_x, real_y);
501 if (!is_set) break :blk;
502 idx.set(x2 * 2 + y2);
503 }
504 }
505 const characters = [_][]const u8{ " ", "▘", "▖", "▌", "▝", "▀", "▞", "▛", "▗", "▚", "▄", "▙", "▐", "▜", "▟", "█" };
506 try content.writer.writeAll(characters[(idx.mask)]);
507 }
508 if (builtin.is_test) try content.writer.writeAll("|");
509 try content.writer.writeAll("\n");
510 }
511 return content.toOwnedSlice();
512 }
513
514 pub fn asBlockString2(grid: *const @This(), allocator: std.mem.Allocator) ![]u8 {
515 var content: std.Io.Writer.Allocating = .init(allocator);
516 errdefer content.deinit();
517 for (0..grid.size / 2 + 1) |y| {
518 for (0..grid.size) |x| {
519 var idx: std.bit_set.IntegerBitSet(4) = .initEmpty();
520 inline for (0..2) |y2| blk: {
521 const real_x = x;
522 const real_y = y * 2 + y2;
523 if (real_x >= grid.size) break :blk;
524 if (real_y >= grid.size) break :blk;
525 const is_set = grid.isSet(real_x, real_y);
526 if (!is_set) break :blk;
527 idx.set(y2);
528 }
529 const characters = [_][]const u8{ " ", "▀", "▄", "█" };
530 try content.writer.writeAll(characters[(idx.mask)]);
531 }
532 if (builtin.is_test) try content.writer.writeAll("|");
533 try content.writer.writeAll("\n");
534 }
535 return content.toOwnedSlice();
536 }
537
538 pub fn asBrailleString(grid: *const @This(), allocator: std.mem.Allocator) ![]u8 {
539 const B = packed struct(u8) { @"0": bool, @"1": bool, @"2": bool, @"3": bool, @"4": bool, @"5": bool, @"6": bool, @"7": bool };
540 var content: std.Io.Writer.Allocating = .init(allocator);
541 errdefer content.deinit();
542 for (0..grid.size / 4 + 1) |y| {
543 for (0..grid.size / 2 + 1) |x| {
544 var b: B = std.mem.zeroes(B);
545 inline for (0..2) |x2| {
546 inline for (0..4) |y2| blk: {
547 const real_x = x * 2 + x2;
548 const real_y = y * 4 + y2;
549 if (real_x >= grid.size) break :blk;
550 if (real_y >= grid.size) break :blk;
551 const is_set = grid.isSet(real_x, real_y);
552 if (!is_set) break :blk;
553 @field(b, "01263457"[x2 * 4 + y2 ..][0..1]) = true;
554 }
555 }
556 var cp: u21 = 0x2800;
557 cp += @as(u8, @bitCast(b));
558 var buf: [3]u8 = undefined;
559 _ = std.unicode.utf8Encode(cp, &buf) catch unreachable;
560 try content.writer.writeAll(&buf);
561 }
562 if (builtin.is_test) try content.writer.writeAll("|");
563 try content.writer.writeAll("\n");
564 }
565 return content.toOwnedSlice();
566 }
567
568 pub fn asSvg(grid: *const @This(), allocator: std.mem.Allocator) ![]u8 {
569 var content: std.Io.Writer.Allocating = .init(allocator);
570 errdefer content.deinit();
571 try content.writer.print("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{d}0\" height=\"{d}0\" viewBox=\"-1 -1 {d} {d}\" shape-rendering=\"crispEdges\" stroke=\"#000\">\n", .{ size + 2, size + 1, size + 2, size + 1 });
572 try content.writer.print("<rect x=\"-1\" y=\"-1\" width=\"{d}\" height=\"{d}\" fill=\"#fff\" stroke=\"none\" />\n", .{ size + 2, size + 1 });
573 var prev = false;
574 var run: u16 = 0;
575 for (0..size) |y| {
576 try content.writer.writeAll("<path d=\"");
577 for (0..size) |x| {
578 if (x == 0) {
579 run = 0;
580 prev = grid.isSet(0, y);
581 }
582 const this = grid.isSet(x, y);
583 if (this == prev) {
584 run += 1;
585 } else {
586 if (prev) {
587 try content.writer.print("M{d},{d} h{d} ", .{ x - run, y, run });
588 }
589 run = 1;
590 }
591 prev = this;
592 }
593 if (grid.isSet(size - 1, y)) {
594 const x = size;
595 try content.writer.print("M{d},{d} h{d}", .{ x - run, y, run });
596 }
597 try content.writer.writeAll("\" />\n");
598 }
599 try content.writer.writeAll("</svg>\n");
600 return content.toOwnedSlice();
601 }
602 };
603}
604
605fn BitsetWriter(MaskIntType: type, size: usize) type {
606 return struct {
607 set: *std.bit_set.ArrayBitSet(MaskIntType, size),
608 idx: usize = 0,
609
610 pub fn writeInt(self: *@This(), int: anytype) void {
611 return writeInt2(self, @bitReverse(int));
612 }
613 fn writeInt2(self: *@This(), int: anytype) void {
614 const T = @TypeOf(int);
615 const info = @typeInfo(T).int;
616 comptime std.debug.assert(info.signedness == .unsigned);
617 if (self.idx == size) {
618 return;
619 }
620 if (T == u1) {
621 self.set.setValue(self.idx, @bitCast(int));
622 self.idx += 1;
623 return;
624 }
625 self.set.setValue(self.idx, (int & 1) == 1);
626 self.idx += 1;
627 return writeInt2(self, @as(extras.OneSmallerInt(T), @intCast(int >> 1)));
628 }
629 };
630}
631
632fn bitReverse(array: anytype) [array.len]std.meta.Child(@TypeOf(array)) {
633 var result: [array.len]std.meta.Child(@TypeOf(array)) = @splat(0);
634 for (&array, &result) |x, *y| y.* = @bitReverse(x);
635 return result;
636}
637
638fn reverseArray(array: anytype) @TypeOf(array) {
639 var result: @TypeOf(array) = array;
640 for (0..result.len / 2) |i| {
641 std.mem.swap(std.meta.Child(@TypeOf(result)), &result[i], &result[result.len - 1 - i]);
642 }
643 return result;
644}
645
646//
647
648pub const Mode = enum {
649 numeric,
650 alphanumeric,
651 latin1,
652 shiftjis,
653};
654
655pub const Level = enum {
656 L,
657 M,
658 Q,
659 H,
660};
661
662// Sourced from https://gist.github.com/ZavierHenry/a4b3761212109d5598bb2db79c334782
663pub fn maxLenPerModeLevelVersion(mode: Mode, level: Level) *const [41]u16 {
664 return switch (mode) {
665 .numeric => switch (level) {
666 .L => &.{ 0, 41, 77, 127, 187, 255, 322, 370, 461, 552, 652, 772, 883, 1022, 1101, 1250, 1408, 1548, 1725, 1903, 2061, 2232, 2409, 2620, 2812, 3057, 2383, 3517, 3669, 3909, 4158, 4417, 4686, 4965, 5253, 5529, 5836, 6153, 6479, 6743, 7089 },
667 .M => &.{ 0, 34, 63, 101, 149, 202, 255, 293, 365, 432, 513, 694, 691, 796, 871, 991, 1082, 1212, 1346, 1500, 1600, 1708, 1872, 2059, 2188, 2395, 2544, 2701, 2857, 3035, 3289, 3486, 3693, 3909, 4134, 4343, 4588, 4775, 5039, 5313, 5596 },
668 .Q => &.{ 0, 27, 48, 77, 111, 144, 178, 207, 259, 312, 364, 427, 489, 580, 621, 703, 775, 876, 948, 1063, 1159, 1224, 1358, 1468, 1588, 1718, 1804, 1933, 2085, 2181, 2358, 2473, 2670, 2805, 2949, 3081, 3244, 3417, 3599, 3791, 3993 },
669 .H => &.{ 0, 17, 34, 58, 82, 106, 139, 154, 202, 235, 288, 331, 374, 427, 468, 530, 602, 674, 746, 813, 919, 969, 1056, 1108, 1228, 1286, 1425, 1501, 1581, 1677, 1782, 1897, 2022, 2157, 2301, 2361, 2524, 2625, 2735, 2927, 3057 },
670 },
671 .alphanumeric => switch (level) {
672 .L => &.{ 0, 25, 47, 77, 114, 154, 195, 224, 279, 335, 395, 468, 535, 619, 667, 758, 854, 938, 1046, 1153, 1249, 1352, 1460, 1588, 1704, 1853, 1990, 2132, 2223, 2369, 2520, 2677, 2840, 3009, 3183, 3351, 3537, 3729, 3927, 4087, 4296 },
673 .M => &.{ 0, 20, 38, 61, 90, 122, 154, 178, 221, 262, 311, 366, 419, 483, 528, 600, 656, 734, 816, 909, 970, 1035, 1134, 1248, 1326, 1451, 1542, 1637, 1732, 1839, 1994, 2113, 2238, 2369, 2506, 2632, 2780, 2894, 3054, 3220, 3391 },
674 .Q => &.{ 0, 16, 29, 47, 67, 87, 108, 125, 157, 189, 221, 259, 296, 352, 376, 426, 470, 531, 574, 644, 702, 742, 823, 890, 963, 1041, 1094, 1172, 1263, 1322, 1429, 1499, 1618, 1700, 1787, 1867, 1966, 2071, 2181, 2298, 2420 },
675 .H => &.{ 0, 10, 20, 35, 50, 64, 84, 93, 122, 143, 174, 200, 227, 259, 283, 321, 365, 408, 452, 493, 557, 587, 640, 672, 744, 779, 864, 910, 958, 1016, 1080, 1150, 1226, 1307, 1394, 1431, 1530, 1591, 1658, 1774, 1852 },
676 },
677 .latin1 => switch (level) {
678 .L => &.{ 0, 17, 32, 53, 78, 106, 134, 154, 192, 230, 271, 321, 367, 425, 458, 520, 586, 644, 718, 792, 858, 929, 1003, 1091, 1171, 1273, 1367, 1465, 1528, 1628, 1732, 1840, 1952, 2068, 2188, 2303, 2431, 2563, 2699, 2809, 2953 },
679 .M => &.{ 0, 14, 26, 42, 62, 84, 106, 122, 152, 180, 213, 251, 287, 331, 362, 412, 450, 504, 560, 624, 666, 711, 779, 857, 911, 997, 1059, 1125, 1190, 1264, 1370, 1452, 1538, 1628, 1722, 1809, 1911, 1989, 2099, 2213, 2331 },
680 .Q => &.{ 0, 11, 20, 32, 46, 60, 74, 86, 108, 130, 151, 177, 203, 241, 258, 292, 322, 364, 394, 442, 482, 509, 565, 611, 661, 715, 751, 805, 868, 908, 982, 1030, 1112, 1168, 1228, 1283, 1351, 1423, 1499, 1579, 1663 },
681 .H => &.{ 0, 7, 14, 24, 34, 44, 58, 64, 84, 98, 119, 137, 155, 177, 194, 220, 250, 280, 310, 338, 382, 403, 439, 461, 511, 535, 593, 625, 658, 698, 742, 790, 842, 898, 958, 983, 1051, 1093, 1139, 1219, 1273 },
682 },
683 .shiftjis => switch (level) {
684 .L => &.{ 0, 10, 20, 32, 48, 65, 82, 95, 118, 141, 167, 198, 226, 262, 282, 320, 361, 397, 442, 488, 528, 572, 618, 672, 721, 784, 842, 902, 940, 1002, 1066, 1132, 1201, 1273, 1347, 1417, 1496, 1577, 1661, 1729, 1817 },
685 .M => &.{ 0, 8, 16, 26, 38, 52, 65, 75, 93, 111, 131, 155, 177, 204, 223, 254, 277, 310, 345, 384, 410, 438, 480, 528, 561, 614, 652, 692, 732, 778, 843, 894, 947, 1002, 1060, 1113, 1176, 1224, 1292, 1362, 1435 },
686 .Q => &.{ 0, 7, 12, 20, 28, 37, 45, 53, 66, 80, 93, 109, 125, 149, 159, 180, 198, 224, 243, 272, 297, 314, 348, 376, 407, 440, 462, 496, 534, 559, 604, 634, 684, 719, 756, 790, 832, 876, 923, 972, 1024 },
687 .H => &.{ 0, 4, 8, 15, 21, 27, 36, 39, 52, 60, 74, 85, 96, 109, 120, 136, 154, 173, 191, 208, 235, 248, 270, 284, 315, 330, 365, 385, 405, 430, 457, 486, 518, 553, 590, 605, 647, 673, 701, 750, 784 },
688 },
689 };
690}
691
692fn isNumeric(c: u8) bool {
693 return switch (c) {
694 '0'...'9' => true,
695 else => false,
696 };
697}
698
699fn isAlphanumeric(c: u8) bool {
700 return switch (c) {
701 '0'...'9' => true,
702 'A'...'Z' => true,
703 ' ', '$', '%', '*', '+', '-', '.', '/', ':' => true,
704 else => false,
705 };
706}
707
708fn generatorPolynomial(comptime n: usize) [n + 1]u8 {
709 if (n == 1) return .{ 1, 1 };
710
711 const prev = generatorPolynomial(n - 1);
712 const prev_alpha = to_alpha(prev);
713 const term_alpha: [2]u8 = .{ n - 1, 0 };
714
715 var multiply_alpha: [n * 2][2]u8 = @splat(@splat(0));
716 for (&prev_alpha, 0..) |a, i| {
717 for (&term_alpha, 0..) |b, j| {
718 multiply_alpha[(term_alpha.len * i) + j] = .{ @intCast((@as(u16, a) + b) % 255), @intCast(i + j) };
719 }
720 }
721 var combine_alpha: [n + 1]u8 = @splat(0);
722 for (0..n + 1) |i| {
723 for (&multiply_alpha) |el| {
724 if (el[1] == i) combine_alpha[i] ^= GF[el[0]];
725 }
726 }
727 return combine_alpha;
728}
729
730fn to_alpha(array: anytype) [array.len]u8 {
731 var result: [array.len]u8 = array;
732 for (&result) |*x| x.* = @intCast(std.mem.indexOfScalar(u8, &GF, x.*) orelse 0);
733 return result;
734}
735
736fn formatPattern(level: Level, mask: u3) u15 {
737 return switch (level) {
738 .L => switch (mask) {
739 0 => 0b111011111000100,
740 1 => 0b111001011110011,
741 2 => 0b111110110101010,
742 3 => 0b111100010011101,
743 4 => 0b110011000101111,
744 5 => 0b110001100011000,
745 6 => 0b110110001000001,
746 7 => 0b110100101110110,
747 },
748 .M => switch (mask) {
749 0 => 0b101010000010010,
750 1 => 0b101000100100101,
751 2 => 0b101111001111100,
752 3 => 0b101101101001011,
753 4 => 0b100010111111001,
754 5 => 0b100000011001110,
755 6 => 0b100111110010111,
756 7 => 0b100101010100000,
757 },
758 .Q => switch (mask) {
759 0 => 0b011010101011111,
760 1 => 0b011000001101000,
761 2 => 0b011111100110001,
762 3 => 0b011101000000110,
763 4 => 0b010010010110100,
764 5 => 0b010000110000011,
765 6 => 0b010111011011010,
766 7 => 0b010101111101101,
767 },
768 .H => switch (mask) {
769 0 => 0b001011010001001,
770 1 => 0b001001110111110,
771 2 => 0b001110011100111,
772 3 => 0b001100111010000,
773 4 => 0b000011101100010,
774 5 => 0b000001001010101,
775 6 => 0b000110100001100,
776 7 => 0b000100000111011,
777 },
778 };
779}
780
781fn errorCorrection(level: Level, version: u16) ErrorCorrectionEntry {
782 return switch (level) {
783 .L => &.{
784 std.mem.zeroes(ErrorCorrectionEntry),
785 .{ 19, 7, 1, 19, null, null },
786 .{ 34, 10, 1, 34, null, null },
787 .{ 55, 15, 1, 55, null, null },
788 .{ 80, 20, 1, 80, null, null },
789 .{ 108, 26, 1, 108, null, null },
790 .{ 136, 18, 2, 68, null, null },
791 .{ 156, 20, 2, 78, null, null },
792 .{ 194, 24, 2, 97, null, null },
793 .{ 232, 30, 2, 116, null, null },
794 .{ 274, 18, 2, 68, 2, 69 },
795 .{ 324, 20, 4, 81, null, null },
796 .{ 370, 24, 2, 92, 2, 93 },
797 .{ 428, 26, 4, 107, null, null },
798 .{ 461, 30, 3, 115, 1, 116 },
799 .{ 523, 22, 5, 87, 1, 88 },
800 .{ 589, 24, 5, 98, 1, 99 },
801 .{ 647, 28, 1, 107, 5, 108 },
802 .{ 721, 30, 5, 120, 1, 121 },
803 .{ 795, 28, 3, 113, 4, 114 },
804 .{ 861, 28, 3, 107, 5, 108 },
805 .{ 932, 28, 4, 116, 4, 117 },
806 .{ 1006, 28, 2, 111, 7, 112 },
807 .{ 1094, 30, 4, 121, 5, 122 },
808 .{ 1174, 30, 6, 117, 4, 118 },
809 .{ 1276, 26, 8, 106, 4, 107 },
810 .{ 1370, 28, 10, 114, 2, 115 },
811 .{ 1468, 30, 8, 122, 4, 123 },
812 .{ 1531, 30, 3, 117, 10, 118 },
813 .{ 1631, 30, 7, 116, 7, 117 },
814 .{ 1735, 30, 5, 115, 10, 116 },
815 .{ 1843, 30, 13, 115, 3, 116 },
816 .{ 1955, 30, 17, 115, null, null },
817 .{ 2071, 30, 17, 115, 1, 116 },
818 .{ 2191, 30, 13, 115, 6, 116 },
819 .{ 2306, 30, 12, 121, 7, 122 },
820 .{ 2434, 30, 6, 121, 14, 122 },
821 .{ 2566, 30, 17, 122, 4, 123 },
822 .{ 2702, 30, 4, 122, 18, 123 },
823 .{ 2812, 30, 20, 117, 4, 118 },
824 .{ 2956, 30, 19, 118, 6, 119 },
825 },
826 .M => &.{
827 std.mem.zeroes(ErrorCorrectionEntry),
828 .{ 16, 10, 1, 16, null, null },
829 .{ 28, 16, 1, 28, null, null },
830 .{ 44, 26, 1, 44, null, null },
831 .{ 64, 18, 2, 32, null, null },
832 .{ 86, 24, 2, 43, null, null },
833 .{ 108, 16, 4, 27, null, null },
834 .{ 124, 18, 4, 31, null, null },
835 .{ 154, 22, 2, 38, 2, 39 },
836 .{ 182, 22, 3, 36, 2, 37 },
837 .{ 216, 26, 4, 43, 1, 44 },
838 .{ 254, 30, 1, 50, 4, 51 },
839 .{ 290, 22, 6, 36, 2, 37 },
840 .{ 334, 22, 8, 37, 1, 38 },
841 .{ 365, 24, 4, 40, 5, 41 },
842 .{ 415, 24, 5, 41, 5, 42 },
843 .{ 453, 28, 7, 45, 3, 46 },
844 .{ 507, 28, 10, 46, 1, 47 },
845 .{ 563, 26, 9, 43, 4, 44 },
846 .{ 627, 26, 3, 44, 11, 45 },
847 .{ 669, 26, 3, 41, 13, 42 },
848 .{ 714, 26, 17, 42, null, null },
849 .{ 782, 28, 17, 46, null, null },
850 .{ 860, 28, 4, 47, 14, 48 },
851 .{ 914, 28, 6, 45, 14, 46 },
852 .{ 1000, 28, 8, 47, 13, 48 },
853 .{ 1062, 28, 19, 46, 4, 47 },
854 .{ 1128, 28, 22, 45, 3, 46 },
855 .{ 1193, 28, 3, 45, 23, 46 },
856 .{ 1267, 28, 21, 45, 7, 46 },
857 .{ 1373, 28, 19, 47, 10, 48 },
858 .{ 1455, 28, 2, 46, 29, 47 },
859 .{ 1541, 28, 10, 46, 23, 47 },
860 .{ 1631, 28, 14, 46, 21, 47 },
861 .{ 1725, 28, 14, 46, 23, 47 },
862 .{ 1812, 28, 12, 47, 26, 48 },
863 .{ 1914, 28, 6, 47, 34, 48 },
864 .{ 1992, 28, 29, 46, 14, 47 },
865 .{ 2102, 28, 13, 46, 32, 47 },
866 .{ 2216, 28, 40, 47, 7, 48 },
867 .{ 2334, 28, 18, 47, 31, 48 },
868 },
869 .Q => &.{
870 std.mem.zeroes(ErrorCorrectionEntry),
871 .{ 13, 13, 1, 13, null, null },
872 .{ 22, 22, 1, 22, null, null },
873 .{ 34, 18, 2, 17, null, null },
874 .{ 48, 26, 2, 24, null, null },
875 .{ 62, 18, 2, 15, 2, 16 },
876 .{ 76, 24, 4, 19, null, null },
877 .{ 88, 18, 2, 14, 4, 15 },
878 .{ 110, 22, 4, 18, 2, 19 },
879 .{ 132, 20, 4, 16, 4, 17 },
880 .{ 154, 24, 6, 19, 2, 20 },
881 .{ 180, 28, 4, 22, 4, 23 },
882 .{ 206, 26, 4, 20, 6, 21 },
883 .{ 244, 24, 8, 20, 4, 21 },
884 .{ 261, 20, 11, 16, 5, 17 },
885 .{ 295, 30, 5, 24, 7, 25 },
886 .{ 325, 24, 15, 19, 2, 20 },
887 .{ 367, 28, 1, 22, 15, 23 },
888 .{ 397, 28, 17, 22, 1, 23 },
889 .{ 445, 26, 17, 21, 4, 22 },
890 .{ 485, 30, 15, 24, 5, 25 },
891 .{ 512, 28, 17, 22, 6, 23 },
892 .{ 568, 30, 7, 24, 16, 25 },
893 .{ 614, 30, 11, 24, 14, 25 },
894 .{ 664, 30, 11, 24, 16, 25 },
895 .{ 718, 30, 7, 24, 22, 25 },
896 .{ 754, 28, 28, 22, 6, 23 },
897 .{ 808, 30, 8, 23, 26, 24 },
898 .{ 871, 30, 4, 24, 31, 25 },
899 .{ 911, 30, 1, 23, 37, 24 },
900 .{ 985, 30, 15, 24, 25, 25 },
901 .{ 1033, 30, 42, 24, 1, 25 },
902 .{ 1115, 30, 10, 24, 35, 25 },
903 .{ 1171, 30, 29, 24, 19, 25 },
904 .{ 1231, 30, 44, 24, 7, 25 },
905 .{ 1286, 30, 39, 24, 14, 25 },
906 .{ 1354, 30, 46, 24, 10, 25 },
907 .{ 1426, 30, 49, 24, 10, 25 },
908 .{ 1502, 30, 48, 24, 14, 25 },
909 .{ 1582, 30, 43, 24, 22, 25 },
910 .{ 1666, 30, 34, 24, 34, 25 },
911 },
912 .H => &.{
913 std.mem.zeroes(ErrorCorrectionEntry),
914 .{ 9, 17, 1, 9, null, null },
915 .{ 16, 28, 1, 16, null, null },
916 .{ 26, 22, 2, 13, null, null },
917 .{ 36, 16, 4, 9, null, null },
918 .{ 46, 22, 2, 11, 2, 12 },
919 .{ 60, 28, 4, 15, null, null },
920 .{ 66, 26, 4, 13, 1, 14 },
921 .{ 86, 26, 4, 14, 2, 15 },
922 .{ 100, 24, 4, 12, 4, 13 },
923 .{ 122, 28, 6, 15, 2, 16 },
924 .{ 140, 24, 3, 12, 8, 13 },
925 .{ 158, 28, 7, 14, 4, 15 },
926 .{ 180, 22, 12, 11, 4, 12 },
927 .{ 197, 24, 11, 12, 5, 13 },
928 .{ 223, 24, 11, 12, 7, 13 },
929 .{ 253, 30, 3, 15, 13, 16 },
930 .{ 283, 28, 2, 14, 17, 15 },
931 .{ 313, 28, 2, 14, 19, 15 },
932 .{ 341, 26, 9, 13, 16, 14 },
933 .{ 385, 28, 15, 15, 10, 16 },
934 .{ 406, 30, 19, 16, 6, 17 },
935 .{ 442, 24, 34, 13, null, null },
936 .{ 464, 30, 16, 15, 14, 16 },
937 .{ 514, 30, 30, 16, 2, 17 },
938 .{ 538, 30, 22, 15, 13, 16 },
939 .{ 596, 30, 33, 16, 4, 17 },
940 .{ 628, 30, 12, 15, 28, 16 },
941 .{ 661, 30, 11, 15, 31, 16 },
942 .{ 701, 30, 19, 15, 26, 16 },
943 .{ 745, 30, 23, 15, 25, 16 },
944 .{ 793, 30, 23, 15, 28, 16 },
945 .{ 845, 30, 19, 115, 35, 16 },
946 .{ 901, 30, 11, 15, 46, 16 },
947 .{ 961, 30, 59, 16, 1, 17 },
948 .{ 986, 30, 22, 15, 41, 16 },
949 .{ 1054, 30, 2, 15, 64, 16 },
950 .{ 1096, 30, 24, 15, 46, 16 },
951 .{ 1142, 30, 42, 15, 32, 16 },
952 .{ 1222, 30, 10, 15, 67, 16 },
953 .{ 1276, 30, 20, 15, 61, 16 },
954 },
955 }[version];
956}
957
958const ErrorCorrectionEntry = struct {
959 /// dataCodewordsCount
960 u32,
961 /// ecCodewordsPerBlock
962 u32,
963 /// groupOneBlockCount
964 u32,
965 /// groupOneDataCodewordsCountPerBlock
966 u32,
967 /// groupTwoBlockCount
968 ?u32,
969 /// groupTwoDataCodewordsCountPerBlock
970 ?u32,
971};
972
973fn remainderBitsCount(version: u16) u8 {
974 return .{ 0, 0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 }[version];
975}
976
977fn alignmentPatternCenters(version: u16) []const u8 {
978 return .{
979 &.{},
980 &.{},
981 &.{ 6, 18 },
982 &.{ 6, 22 },
983 &.{ 6, 26 },
984 &.{ 6, 30 },
985 &.{ 6, 34 },
986 &.{ 6, 22, 38 },
987 &.{ 6, 24, 42 },
988 &.{ 6, 26, 46 },
989 &.{ 6, 28, 50 },
990 &.{ 6, 30, 54 },
991 &.{ 6, 32, 58 },
992 &.{ 6, 34, 62 },
993 &.{ 6, 26, 46, 66 },
994 &.{ 6, 26, 48, 70 },
995 &.{ 6, 26, 50, 74 },
996 &.{ 6, 30, 54, 78 },
997 &.{ 6, 30, 56, 82 },
998 &.{ 6, 30, 58, 86 },
999 &.{ 6, 34, 62, 90 },
1000 &.{ 6, 28, 50, 72, 94 },
1001 &.{ 6, 26, 50, 74, 98 },
1002 &.{ 6, 30, 54, 78, 102 },
1003 &.{ 6, 28, 54, 80, 106 },
1004 &.{ 6, 32, 58, 84, 110 },
1005 &.{ 6, 30, 58, 86, 114 },
1006 &.{ 6, 34, 62, 90, 118 },
1007 &.{ 6, 26, 50, 74, 98, 122 },
1008 &.{ 6, 30, 54, 78, 102, 126 },
1009 &.{ 6, 26, 52, 78, 104, 130 },
1010 &.{ 6, 30, 56, 82, 108, 134 },
1011 &.{ 6, 34, 60, 86, 112, 138 },
1012 &.{ 6, 30, 58, 86, 114, 142 },
1013 &.{ 6, 32, 62, 90, 118, 146 },
1014 &.{ 6, 30, 54, 78, 102, 126, 150 },
1015 &.{ 6, 24, 50, 76, 102, 128, 154 },
1016 &.{ 6, 28, 54, 80, 106, 132, 158 },
1017 &.{ 6, 32, 58, 84, 110, 136, 162 },
1018 &.{ 6, 26, 54, 82, 110, 138, 166 },
1019 &.{ 6, 30, 58, 86, 114, 142, 170 },
1020 }[version];
1021}
1022
1023fn versionBits(version: u16) u18 {
1024 return ([_]u18{
1025 0,
1026 0,
1027 0,
1028 0,
1029 0,
1030 0,
1031 0,
1032 0b000111110010010100,
1033 0b001000010110111100,
1034 0b001001101010011001,
1035 0b001010010011010011,
1036 0b001011101111110110,
1037 0b001100011101100010,
1038 0b001101100001000111,
1039 0b001110011000001101,
1040 0b001111100100101000,
1041 0b010000101101111000,
1042 0b010001010001011101,
1043 0b010010101000010111,
1044 0b010011010100110010,
1045 0b010100100110100110,
1046 0b010101011010000011,
1047 0b010110100011001001,
1048 0b010111011111101100,
1049 0b011000111011000100,
1050 0b011001000111100001,
1051 0b011010111110101011,
1052 0b011011000010001110,
1053 0b011100110000011010,
1054 0b011101001100111111,
1055 0b011110110101110101,
1056 0b011111001001010000,
1057 0b100000100111010101,
1058 0b100001011011110000,
1059 0b100010100010111010,
1060 0b100011011110011111,
1061 0b100100101100001011,
1062 0b100101010000101110,
1063 0b100110101001100100,
1064 0b100111010101000001,
1065 0b101000110001101001,
1066 })[version];
1067}
1068
1069pub fn getMinVersion(comptime level: Level, comptime mode: Mode, length: usize) ?u16 {
1070 const max_lengths = maxLenPerModeLevelVersion(mode, level);
1071 for (max_lengths, 0..) |l, i| {
1072 if (l > length) return @intCast(i);
1073 }
1074 return null;
1075}
1076
1077//
1078//
1079//
1080//
1081
1082const BufBiterator = struct {
1083 buf: []const u8,
1084 bits: std.bit_set.IntegerBitSet(8),
1085 idx: u32, // buf index
1086 jdx: u8, // bits index
1087
1088 pub fn init(buf: []const u8) BufBiterator {
1089 std.debug.assert(buf.len > 0);
1090 return .{
1091 .buf = buf,
1092 .bits = .{ .mask = buf[0] },
1093 .idx = 0,
1094 .jdx = 0,
1095 };
1096 }
1097
1098 pub fn next(self: *BufBiterator) ?u1 {
1099 if (self.jdx == 8) {
1100 self.jdx = 0;
1101 self.idx += 1;
1102 if (self.idx == self.buf.len) return null;
1103 self.bits.mask = self.buf[self.idx];
1104 return self.next();
1105 }
1106 const result = self.bits.isSet(7 - self.jdx);
1107 self.jdx += 1;
1108 return @intFromBool(result);
1109 }
1110};
1111
1112//
1113//
1114//
1115//
1116//
1117
1118const GridZigZag = struct {
1119 grid_size: usize,
1120 col_skip: usize,
1121 dir: u1,
1122 phase: u1,
1123 y: usize,
1124 x: usize,
1125
1126 pub fn init(grid_size: usize, col_skip: usize) GridZigZag {
1127 return .{
1128 .grid_size = grid_size,
1129 .col_skip = col_skip,
1130 .dir = 0,
1131 .phase = 0,
1132 .y = grid_size,
1133 .x = grid_size - 2,
1134 };
1135 }
1136
1137 pub fn next(self: *@This()) ?usize {
1138 blk: switch (self.dir) {
1139 0 => switch (self.phase) { //up
1140 0 => { //prev left
1141 if (self.y == 0) {
1142 self.x -= 1;
1143 self.dir = 1;
1144 self.phase = 1;
1145 if (self.x == self.col_skip and self.col_skip == 0) return null;
1146 if (self.x == self.col_skip) self.x -= 1;
1147 break :blk;
1148 }
1149 self.y -= 1;
1150 self.x += 1;
1151 self.phase +%= 1;
1152 },
1153 1 => { //prev right
1154 self.x -= 1;
1155 self.phase +%= 1;
1156 },
1157 },
1158 1 => switch (self.phase) { //down
1159 0 => { //prev left
1160 if (self.y == self.grid_size - 1) {
1161 if (self.x == 0) return null;
1162 self.x -= 1;
1163 if (self.x == self.col_skip and self.col_skip == 0) return null;
1164 if (self.x == self.col_skip) self.x -= 1;
1165 self.dir = 0;
1166 self.phase = 1;
1167 break :blk;
1168 }
1169 self.x += 1;
1170 self.y += 1;
1171 self.phase +%= 1;
1172 },
1173 1 => { //prev right
1174 self.x -= 1;
1175 self.phase +%= 1;
1176 },
1177 },
1178 }
1179 return (self.y * self.grid_size) + self.x;
1180 }
1181};