authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-02-27 16:01:40 -08:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-02-27 16:01:40 -08:00
logfea3b04ce480363a63c6c0286284b6650b48b915
treec9e60394acd197f0d74fbe1130378bb0da77c433
parent9dc86081ba464532757859a9904c3a095a7aed0d

version 2 works


2 files changed, 293 insertions(+), 12 deletions(-)

qrcode.zig+288-12
...@@ -35,6 +35,14 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -35,6 +35,14 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
35 std.debug.assert(input.len <= max_length);35 std.debug.assert(input.len <= max_length);
36 for (max_lengths, 0..) |l, i| if (l > input.len) break std.log.warn("reccom version: {d},{d}", .{ i, l });36 for (max_lengths, 0..) |l, i| if (l > input.len) break std.log.warn("reccom version: {d},{d}", .{ i, l });
3737
38 const dataCodewordsCount, const ecCodewordsPerBlock, const groupOneBlockCount, const groupOneDataCodewordsCountPerBlock, const groupTwoBlockCount, const groupTwoDataCodewordsCountPerBlock = comptime errorCorrection(level, version);
39 std.log.warn("dataCodewordsCount: {d}", .{dataCodewordsCount});
40 std.log.warn("ecCodewordsPerBlock: {d}", .{ecCodewordsPerBlock});
41 std.log.warn("groupOneBlockCount: {d}", .{groupOneBlockCount});
42 std.log.warn("groupOneDataCodewordsCountPerBlock: {d}", .{groupOneDataCodewordsCountPerBlock});
43 std.log.warn("groupTwoBlockCount: {?d}", .{groupTwoBlockCount});
44 std.log.warn("groupTwoDataCodewordsCountPerBlock: {?d}", .{groupTwoDataCodewordsCountPerBlock});
45
38 const mode_indicator: u4 = switch (mode) {46 const mode_indicator: u4 = switch (mode) {
39 .numeric => 0b0001,47 .numeric => 0b0001,
40 .alphanumeric => 0b0010,48 .alphanumeric => 0b0010,
...@@ -72,7 +80,7 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -72,7 +80,7 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
72 const len_indicator: LenIndicator = @intCast(input.len);80 const len_indicator: LenIndicator = @intCast(input.len);
73 std.log.warn("len_indicator: {d}", .{len_indicator});81 std.log.warn("len_indicator: {d}", .{len_indicator});
7482
75 const total_bits = (max_length + 2) * 8;83 const total_bits = dataCodewordsCount * 8;
76 std.log.warn("total_bits: {d}", .{total_bits});84 std.log.warn("total_bits: {d}", .{total_bits});
7785
78 var scratch: std.bit_set.ArrayBitSet(u8, total_bits) = .initEmpty();86 var scratch: std.bit_set.ArrayBitSet(u8, total_bits) = .initEmpty();
...@@ -98,18 +106,17 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -98,18 +106,17 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
98 scratchw.writeInt(@as(u8, 0x11));106 scratchw.writeInt(@as(u8, 0x11));
99 }107 }
100108
101 // std.log.warn("{b:0>8}", .{&bitReverse(scratch.masks)});109 std.log.warn("{b:0>8}", .{&bitReverse(scratch.masks)});
102 // std.log.warn("{d}", .{&bitReverse(scratch.masks)});110 std.log.warn("{d}", .{&bitReverse(scratch.masks)});
103 // std.log.warn("{x}", .{&bitReverse(scratch.masks)});111 std.log.warn("{x}", .{&bitReverse(scratch.masks)});
104112
105 const groups = 1; // ?113 const groups = if (groupTwoBlockCount) |_| 2 else 1;
106 _ = &groups;114 _ = &groups;
107 const blocks = 1; // ?115 const blocks = groupOneBlockCount;
108 _ = &blocks;116 _ = &blocks;
109 const dc_per_block = 19; //?117 const dc_per_block = groupOneDataCodewordsCountPerBlock;
110 _ = &dc_per_block;118 _ = &dc_per_block;
111 const ecc_per_block = 7; //?119 const ecc_per_block = ecCodewordsPerBlock;
112 _ = &ecc_per_block;
113120
114 var message_polynomial = scratch.masks;121 var message_polynomial = scratch.masks;
115 std.log.warn("message_polynomial: {d}", .{&bitReverse(message_polynomial)});122 std.log.warn("message_polynomial: {d}", .{&bitReverse(message_polynomial)});
...@@ -148,6 +155,7 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -148,6 +155,7 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
148 std.log.warn("interleaved_message: {b:0>8}", .{&bitReverse(interleaved_message)});155 std.log.warn("interleaved_message: {b:0>8}", .{&bitReverse(interleaved_message)});
149156
150 // remainder bits157 // remainder bits
158 const remainder_bits_count = comptime remainderBitsCount(version);
151159
152 //160 //
153161
...@@ -173,8 +181,6 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -173,8 +181,6 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
173 for (8..size) |i| if (i % 2 == 0) grid.set(i, 6);181 for (8..size) |i| if (i % 2 == 0) grid.set(i, 6);
174 for (8..size) |i| if (i % 2 == 0) grid.set(6, i);182 for (8..size) |i| if (i % 2 == 0) grid.set(6, i);
175183
176 // alignment patterns
177
178 // dark module184 // dark module
179 grid.set(8, 4 * (version - 1) + 13);185 grid.set(8, 4 * (version - 1) + 13);
180186
...@@ -188,6 +194,28 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -188,6 +194,28 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
188 for (0..size) |i| data_mask.set(i, 6);194 for (0..size) |i| data_mask.set(i, 6);
189 for (0..size) |i| data_mask.set(6, i);195 for (0..size) |i| data_mask.set(6, i);
190196
197 // alignment patterns
198 const alignment_pattern_centers = comptime alignmentPatternCenters(version);
199 for (alignment_pattern_centers) |y| {
200 for (alignment_pattern_centers) |x| blk: {
201 for (y - 2..y + 2 + 1) |y2| {
202 for (x - 2..x + 2 + 1) |x2| {
203 if (grid.isSet(x2, y2)) break :blk;
204 }
205 }
206 for (y - 2..y + 2 + 1) |y2| for (x - 2..x + 2 + 1) |x2| {
207 grid.setT(x2, y2);
208 data_mask.set(x2, y2);
209 };
210 for (y - 1..y + 1 + 1) |y2| for (x - 1..x + 1 + 1) |x2| {
211 grid.setF(x2, y2);
212 data_mask.set(x2, y2);
213 };
214 grid.setT(x, y);
215 data_mask.set(x, y);
216 }
217 }
218
191 // write data219 // write data
192 var data_iter: BufBiterator = .init(&bitReverse(interleaved_message));220 var data_iter: BufBiterator = .init(&bitReverse(interleaved_message));
193221
...@@ -199,6 +227,12 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,...@@ -199,6 +227,12 @@ pub fn encode(comptime mode: Mode, comptime level: Level, comptime version: u16,
199 grid.debug.set((y * size) + x);227 grid.debug.set((y * size) + x);
200 if (@bitCast(data_iter.next() orelse break)) grid.set(x, y);228 if (@bitCast(data_iter.next() orelse break)) grid.set(x, y);
201 }229 }
230 for (0..remainder_bits_count) |_| {
231 const idx = griditer.next().?;
232 const x = idx % size;
233 const y = (idx - x) / size;
234 grid.debug.set((y * size) + x);
235 }
202236
203 for (0..8) |y| for (0..8) |x| grid.debug.set((y * size) + x);237 for (0..8) |y| for (0..8) |x| grid.debug.set((y * size) + x);
204 for (0..8) |y| for (0..8) |x| grid.debug.set((y * size) + size - 8 + x);238 for (0..8) |y| for (0..8) |x| grid.debug.set((y * size) + size - 8 + x);
...@@ -548,7 +582,7 @@ fn generatorPolynomial(comptime n: usize) [n + 1]u8 {...@@ -548,7 +582,7 @@ fn generatorPolynomial(comptime n: usize) [n + 1]u8 {
548 var multiply_alpha: [n * 2][2]u8 = @splat(@splat(0));582 var multiply_alpha: [n * 2][2]u8 = @splat(@splat(0));
549 for (&prev_alpha, 0..) |a, i| {583 for (&prev_alpha, 0..) |a, i| {
550 for (&term_alpha, 0..) |b, j| {584 for (&term_alpha, 0..) |b, j| {
551 multiply_alpha[(term_alpha.len * i) + j] = .{ a + b, @intCast(i + j) };585 multiply_alpha[(term_alpha.len * i) + j] = .{ @intCast((@as(u16, a) + b) % 255), @intCast(i + j) };
552 }586 }
553 }587 }
554 var combine_alpha: [n + 1]u8 = @splat(0);588 var combine_alpha: [n + 1]u8 = @splat(0);
...@@ -611,6 +645,248 @@ fn formatPattern(level: Level, mask: u3) u15 {...@@ -611,6 +645,248 @@ fn formatPattern(level: Level, mask: u3) u15 {
611 };645 };
612}646}
613647
648fn errorCorrection(level: Level, version: u16) ErrorCorrectionEntry {
649 return switch (level) {
650 .L => &.{
651 std.mem.zeroes(ErrorCorrectionEntry),
652 .{ 19, 7, 1, 19, null, null },
653 .{ 34, 10, 1, 34, null, null },
654 .{ 55, 15, 1, 55, null, null },
655 .{ 80, 20, 1, 80, null, null },
656 .{ 108, 26, 1, 108, null, null },
657 .{ 136, 18, 2, 68, null, null },
658 .{ 156, 20, 2, 78, null, null },
659 .{ 194, 24, 2, 97, null, null },
660 .{ 232, 30, 2, 116, null, null },
661 .{ 274, 18, 2, 68, 2, 69 },
662 .{ 324, 20, 4, 81, null, null },
663 .{ 370, 24, 2, 92, 2, 93 },
664 .{ 428, 26, 4, 107, null, null },
665 .{ 461, 30, 3, 115, 1, 116 },
666 .{ 523, 22, 5, 87, 1, 88 },
667 .{ 589, 24, 5, 98, 1, 99 },
668 .{ 647, 28, 1, 107, 5, 108 },
669 .{ 721, 30, 5, 120, 1, 121 },
670 .{ 795, 28, 3, 113, 4, 114 },
671 .{ 861, 28, 3, 107, 5, 108 },
672 .{ 932, 28, 4, 116, 4, 117 },
673 .{ 1006, 28, 2, 111, 7, 112 },
674 .{ 1094, 30, 4, 121, 5, 122 },
675 .{ 1174, 30, 6, 117, 4, 118 },
676 .{ 1276, 26, 8, 106, 4, 107 },
677 .{ 1370, 28, 10, 114, 2, 115 },
678 .{ 1468, 30, 8, 122, 4, 123 },
679 .{ 1531, 30, 3, 117, 10, 118 },
680 .{ 1631, 30, 7, 116, 7, 117 },
681 .{ 1735, 30, 5, 115, 10, 116 },
682 .{ 1843, 30, 13, 115, 3, 116 },
683 .{ 1955, 30, 17, 115, null, null },
684 .{ 2071, 30, 17, 115, 1, 116 },
685 .{ 2191, 30, 13, 115, 6, 116 },
686 .{ 2306, 30, 12, 121, 7, 122 },
687 .{ 2434, 30, 6, 121, 14, 122 },
688 .{ 2566, 30, 17, 122, 4, 123 },
689 .{ 2702, 30, 4, 122, 18, 123 },
690 .{ 2812, 30, 20, 117, 4, 118 },
691 .{ 2956, 30, 19, 118, 6, 119 },
692 },
693 .M => &.{
694 std.mem.zeroes(ErrorCorrectionEntry),
695 .{ 16, 10, 1, 16, null, null },
696 .{ 28, 16, 1, 28, null, null },
697 .{ 44, 26, 1, 44, null, null },
698 .{ 64, 18, 2, 32, null, null },
699 .{ 86, 24, 2, 43, null, null },
700 .{ 108, 16, 4, 27, null, null },
701 .{ 124, 18, 4, 31, null, null },
702 .{ 154, 22, 2, 38, 2, 39 },
703 .{ 182, 22, 3, 36, 2, 37 },
704 .{ 216, 26, 4, 43, 1, 44 },
705 .{ 254, 30, 1, 50, 4, 51 },
706 .{ 290, 22, 6, 36, 2, 37 },
707 .{ 334, 22, 8, 37, 1, 38 },
708 .{ 365, 24, 4, 40, 5, 41 },
709 .{ 415, 24, 5, 41, 5, 42 },
710 .{ 453, 28, 7, 45, 3, 46 },
711 .{ 507, 28, 10, 46, 1, 47 },
712 .{ 563, 26, 9, 43, 4, 44 },
713 .{ 627, 26, 3, 44, 11, 45 },
714 .{ 669, 26, 3, 41, 13, 42 },
715 .{ 714, 26, 17, 42, null, null },
716 .{ 782, 28, 17, 46, null, null },
717 .{ 860, 28, 4, 47, 14, 48 },
718 .{ 914, 28, 6, 45, 14, 46 },
719 .{ 1000, 28, 8, 47, 13, 48 },
720 .{ 1062, 28, 19, 46, 4, 47 },
721 .{ 1128, 28, 22, 45, 3, 46 },
722 .{ 1193, 28, 3, 45, 23, 46 },
723 .{ 1267, 28, 21, 45, 7, 46 },
724 .{ 1373, 28, 19, 47, 10, 48 },
725 .{ 1455, 28, 2, 46, 29, 47 },
726 .{ 1541, 28, 10, 46, 23, 47 },
727 .{ 1631, 28, 14, 46, 21, 47 },
728 .{ 1725, 28, 14, 46, 23, 47 },
729 .{ 1812, 28, 12, 47, 26, 48 },
730 .{ 1914, 28, 6, 47, 34, 48 },
731 .{ 1992, 28, 29, 46, 14, 47 },
732 .{ 2102, 28, 13, 46, 32, 47 },
733 .{ 2216, 28, 40, 47, 7, 48 },
734 .{ 2334, 28, 18, 47, 31, 48 },
735 },
736 .Q => &.{
737 std.mem.zeroes(ErrorCorrectionEntry),
738 .{ 13, 13, 1, 13, null, null },
739 .{ 22, 22, 1, 22, null, null },
740 .{ 34, 18, 2, 17, null, null },
741 .{ 48, 26, 2, 24, null, null },
742 .{ 62, 18, 2, 15, 2, 16 },
743 .{ 76, 24, 4, 19, null, null },
744 .{ 88, 18, 2, 14, 4, 15 },
745 .{ 110, 22, 4, 18, 2, 19 },
746 .{ 132, 20, 4, 16, 4, 17 },
747 .{ 154, 24, 6, 19, 2, 20 },
748 .{ 180, 28, 4, 22, 4, 23 },
749 .{ 206, 26, 4, 20, 6, 21 },
750 .{ 244, 24, 8, 20, 4, 21 },
751 .{ 261, 20, 11, 16, 5, 17 },
752 .{ 295, 30, 5, 24, 7, 25 },
753 .{ 325, 24, 15, 19, 2, 20 },
754 .{ 367, 28, 1, 22, 15, 23 },
755 .{ 397, 28, 17, 22, 1, 23 },
756 .{ 445, 26, 17, 21, 4, 22 },
757 .{ 485, 30, 15, 24, 5, 25 },
758 .{ 512, 28, 17, 22, 6, 23 },
759 .{ 568, 30, 7, 24, 16, 25 },
760 .{ 614, 30, 11, 24, 14, 25 },
761 .{ 664, 30, 11, 24, 16, 25 },
762 .{ 718, 30, 7, 24, 22, 25 },
763 .{ 754, 28, 28, 22, 6, 23 },
764 .{ 808, 30, 8, 23, 26, 24 },
765 .{ 871, 30, 4, 24, 31, 25 },
766 .{ 911, 30, 1, 23, 37, 24 },
767 .{ 985, 30, 15, 24, 25, 25 },
768 .{ 1033, 30, 42, 24, 1, 25 },
769 .{ 1115, 30, 10, 24, 35, 25 },
770 .{ 1171, 30, 29, 24, 19, 25 },
771 .{ 1231, 30, 44, 24, 7, 25 },
772 .{ 1286, 30, 39, 24, 14, 25 },
773 .{ 1354, 30, 46, 24, 10, 25 },
774 .{ 1426, 30, 49, 24, 10, 25 },
775 .{ 1502, 30, 48, 24, 14, 25 },
776 .{ 1582, 30, 43, 24, 22, 25 },
777 .{ 1666, 30, 34, 24, 34, 25 },
778 },
779 .H => &.{
780 std.mem.zeroes(ErrorCorrectionEntry),
781 .{ 9, 17, 1, 9, null, null },
782 .{ 16, 28, 1, 16, null, null },
783 .{ 26, 22, 2, 13, null, null },
784 .{ 36, 16, 4, 9, null, null },
785 .{ 46, 22, 2, 11, 2, 12 },
786 .{ 60, 28, 4, 15, null, null },
787 .{ 66, 26, 4, 13, 1, 14 },
788 .{ 86, 26, 4, 14, 2, 15 },
789 .{ 100, 24, 4, 12, 4, 13 },
790 .{ 122, 28, 6, 15, 2, 16 },
791 .{ 140, 24, 3, 12, 8, 13 },
792 .{ 158, 28, 7, 14, 4, 15 },
793 .{ 180, 22, 12, 11, 4, 12 },
794 .{ 197, 24, 11, 12, 5, 13 },
795 .{ 223, 24, 11, 12, 7, 13 },
796 .{ 253, 30, 3, 15, 13, 16 },
797 .{ 283, 28, 2, 14, 17, 15 },
798 .{ 313, 28, 2, 14, 19, 15 },
799 .{ 341, 26, 9, 13, 16, 14 },
800 .{ 385, 28, 15, 15, 10, 16 },
801 .{ 406, 30, 19, 16, 6, 17 },
802 .{ 442, 24, 34, 13, null, null },
803 .{ 464, 30, 16, 15, 14, 16 },
804 .{ 514, 30, 30, 16, 2, 17 },
805 .{ 538, 30, 22, 15, 13, 16 },
806 .{ 596, 30, 33, 16, 4, 17 },
807 .{ 628, 30, 12, 15, 28, 16 },
808 .{ 661, 30, 11, 15, 31, 16 },
809 .{ 701, 30, 19, 15, 26, 16 },
810 .{ 745, 30, 23, 15, 25, 16 },
811 .{ 793, 30, 23, 15, 28, 16 },
812 .{ 845, 30, 19, 115, 35, 16 },
813 .{ 901, 30, 11, 15, 46, 16 },
814 .{ 961, 30, 59, 16, 1, 17 },
815 .{ 986, 30, 22, 15, 41, 16 },
816 .{ 1054, 30, 2, 15, 64, 16 },
817 .{ 1096, 30, 24, 15, 46, 16 },
818 .{ 1142, 30, 42, 15, 32, 16 },
819 .{ 1222, 30, 10, 15, 67, 16 },
820 .{ 1276, 30, 20, 15, 61, 16 },
821 },
822 }[version];
823}
824
825const ErrorCorrectionEntry = struct {
826 /// dataCodewordsCount
827 u32,
828 /// ecCodewordsPerBlock
829 u32,
830 /// groupOneBlockCount
831 u32,
832 /// groupOneDataCodewordsCountPerBlock
833 u32,
834 /// groupTwoBlockCount
835 ?u32,
836 /// groupTwoDataCodewordsCountPerBlock
837 ?u32,
838};
839
840fn remainderBitsCount(version: u16) u8 {
841 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];
842}
843
844fn alignmentPatternCenters(version: u16) []const u8 {
845 return .{
846 &.{},
847 &.{},
848 &.{ 6, 18 },
849 &.{ 6, 22 },
850 &.{ 6, 26 },
851 &.{ 6, 30 },
852 &.{ 6, 34 },
853 &.{ 6, 22, 38 },
854 &.{ 6, 24, 42 },
855 &.{ 6, 26, 46 },
856 &.{ 6, 28, 50 },
857 &.{ 6, 30, 54 },
858 &.{ 6, 32, 58 },
859 &.{ 6, 34, 62 },
860 &.{ 6, 26, 46, 66 },
861 &.{ 6, 26, 48, 70 },
862 &.{ 6, 26, 50, 74 },
863 &.{ 6, 30, 54, 78 },
864 &.{ 6, 30, 56, 82 },
865 &.{ 6, 30, 58, 86 },
866 &.{ 6, 34, 62, 90 },
867 &.{ 6, 28, 50, 72, 94 },
868 &.{ 6, 26, 50, 74, 98 },
869 &.{ 6, 30, 54, 78, 102 },
870 &.{ 6, 28, 54, 80, 106 },
871 &.{ 6, 32, 58, 84, 110 },
872 &.{ 6, 30, 58, 86, 114 },
873 &.{ 6, 34, 62, 90, 118 },
874 &.{ 6, 26, 50, 74, 98, 122 },
875 &.{ 6, 30, 54, 78, 102, 126 },
876 &.{ 6, 26, 52, 78, 104, 130 },
877 &.{ 6, 30, 56, 82, 108, 134 },
878 &.{ 6, 34, 60, 86, 112, 138 },
879 &.{ 6, 30, 58, 86, 114, 142 },
880 &.{ 6, 32, 62, 90, 118, 146 },
881 &.{ 6, 30, 54, 78, 102, 126, 150 },
882 &.{ 6, 24, 50, 76, 102, 128, 154 },
883 &.{ 6, 28, 54, 80, 106, 132, 158 },
884 &.{ 6, 32, 58, 84, 110, 136, 162 },
885 &.{ 6, 26, 54, 82, 110, 138, 166 },
886 &.{ 6, 30, 58, 86, 114, 142, 170 },
887 }[version];
888}
889
614//890//
615//891//
616//892//
test.zig+5
...@@ -5,6 +5,11 @@ test {...@@ -5,6 +5,11 @@ test {
5 const grid = qrcode.encode(.latin1, .L, 1, "Ver1");5 const grid = qrcode.encode(.latin1, .L, 1, "Ver1");
6 // 40 45 66 57 23 10 ec 11 ec6 // 40 45 66 57 23 10 ec 11 ec
7 _ = &grid;7 _ = &grid;
8}
9test {
10 const grid = qrcode.encode(.latin1, .L, 2, "Version 2");
11 // 40 95 66 57 27 36 96 f6 e2 03 20 ec 11 ec 11 ec
12 _ = &grid;
813
9 const bg_black = "\x1b[40m";14 const bg_black = "\x1b[40m";
10 const bg_white = "\x1b[47m";15 const bg_white = "\x1b[47m";