Browse Source

Split alphanumeric encoding from QRCodeGenerator, split encoding tables (#590)

* Split QRCodeGenerator further

* update

* update

* update

* update

* update test

* update

* update

* update

* Separate GaloisField from CapacityTables

* update

* remove using

* Update QRCoder/QRCodeGenerator/GaloisField.cs

Co-authored-by: Günther Foidl <gue@korporal.at>

---------

Co-authored-by: Günther Foidl <gue@korporal.at>
master
Shane Krueger 4 days ago
committed by GitHub
parent
commit
04cb78bb9f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 309
      QRCoder/QRCodeGenerator.cs
  2. 62
      QRCoder/QRCodeGenerator/AlignmentPatterns.cs
  3. 81
      QRCoder/QRCodeGenerator/AlphanumericEncoder.cs
  4. 216
      QRCoder/QRCodeGenerator/CapacityTables.cs
  5. 48
      QRCoder/QRCodeGenerator/GaloisField.cs
  6. 2
      QRCoderDemoUWP/MainPage.xaml.cs
  7. 4
      QRCoderDemoUWP/Properties/AssemblyInfo.cs
  8. 1
      QRCoderTests/PngByteQRCodeRendererTests.cs
  9. 8
      QRCoderTests/QRGeneratorTests.cs

309
QRCoder/QRCodeGenerator.cs

@ -16,19 +16,6 @@ namespace QRCoder;
/// </summary>
public partial class QRCodeGenerator : IDisposable
{
private static readonly char[] _alphanumEncTable = { ' ', '$', '%', '*', '+', '-', '.', '/', ':' };
private static readonly int[] _capacityBaseValues = { 41, 25, 17, 10, 34, 20, 14, 8, 27, 16, 11, 7, 17, 10, 7, 4, 77, 47, 32, 20, 63, 38, 26, 16, 48, 29, 20, 12, 34, 20, 14, 8, 127, 77, 53, 32, 101, 61, 42, 26, 77, 47, 32, 20, 58, 35, 24, 15, 187, 114, 78, 48, 149, 90, 62, 38, 111, 67, 46, 28, 82, 50, 34, 21, 255, 154, 106, 65, 202, 122, 84, 52, 144, 87, 60, 37, 106, 64, 44, 27, 322, 195, 134, 82, 255, 154, 106, 65, 178, 108, 74, 45, 139, 84, 58, 36, 370, 224, 154, 95, 293, 178, 122, 75, 207, 125, 86, 53, 154, 93, 64, 39, 461, 279, 192, 118, 365, 221, 152, 93, 259, 157, 108, 66, 202, 122, 84, 52, 552, 335, 230, 141, 432, 262, 180, 111, 312, 189, 130, 80, 235, 143, 98, 60, 652, 395, 271, 167, 513, 311, 213, 131, 364, 221, 151, 93, 288, 174, 119, 74, 772, 468, 321, 198, 604, 366, 251, 155, 427, 259, 177, 109, 331, 200, 137, 85, 883, 535, 367, 226, 691, 419, 287, 177, 489, 296, 203, 125, 374, 227, 155, 96, 1022, 619, 425, 262, 796, 483, 331, 204, 580, 352, 241, 149, 427, 259, 177, 109, 1101, 667, 458, 282, 871, 528, 362, 223, 621, 376, 258, 159, 468, 283, 194, 120, 1250, 758, 520, 320, 991, 600, 412, 254, 703, 426, 292, 180, 530, 321, 220, 136, 1408, 854, 586, 361, 1082, 656, 450, 277, 775, 470, 322, 198, 602, 365, 250, 154, 1548, 938, 644, 397, 1212, 734, 504, 310, 876, 531, 364, 224, 674, 408, 280, 173, 1725, 1046, 718, 442, 1346, 816, 560, 345, 948, 574, 394, 243, 746, 452, 310, 191, 1903, 1153, 792, 488, 1500, 909, 624, 384, 1063, 644, 442, 272, 813, 493, 338, 208, 2061, 1249, 858, 528, 1600, 970, 666, 410, 1159, 702, 482, 297, 919, 557, 382, 235, 2232, 1352, 929, 572, 1708, 1035, 711, 438, 1224, 742, 509, 314, 969, 587, 403, 248, 2409, 1460, 1003, 618, 1872, 1134, 779, 480, 1358, 823, 565, 348, 1056, 640, 439, 270, 2620, 1588, 1091, 672, 2059, 1248, 857, 528, 1468, 890, 611, 376, 1108, 672, 461, 284, 2812, 1704, 1171, 721, 2188, 1326, 911, 561, 1588, 963, 661, 407, 1228, 744, 511, 315, 3057, 1853, 1273, 784, 2395, 1451, 997, 614, 1718, 1041, 715, 440, 1286, 779, 535, 330, 3283, 1990, 1367, 842, 2544, 1542, 1059, 652, 1804, 1094, 751, 462, 1425, 864, 593, 365, 3517, 2132, 1465, 902, 2701, 1637, 1125, 692, 1933, 1172, 805, 496, 1501, 910, 625, 385, 3669, 2223, 1528, 940, 2857, 1732, 1190, 732, 2085, 1263, 868, 534, 1581, 958, 658, 405, 3909, 2369, 1628, 1002, 3035, 1839, 1264, 778, 2181, 1322, 908, 559, 1677, 1016, 698, 430, 4158, 2520, 1732, 1066, 3289, 1994, 1370, 843, 2358, 1429, 982, 604, 1782, 1080, 742, 457, 4417, 2677, 1840, 1132, 3486, 2113, 1452, 894, 2473, 1499, 1030, 634, 1897, 1150, 790, 486, 4686, 2840, 1952, 1201, 3693, 2238, 1538, 947, 2670, 1618, 1112, 684, 2022, 1226, 842, 518, 4965, 3009, 2068, 1273, 3909, 2369, 1628, 1002, 2805, 1700, 1168, 719, 2157, 1307, 898, 553, 5253, 3183, 2188, 1347, 4134, 2506, 1722, 1060, 2949, 1787, 1228, 756, 2301, 1394, 958, 590, 5529, 3351, 2303, 1417, 4343, 2632, 1809, 1113, 3081, 1867, 1283, 790, 2361, 1431, 983, 605, 5836, 3537, 2431, 1496, 4588, 2780, 1911, 1176, 3244, 1966, 1351, 832, 2524, 1530, 1051, 647, 6153, 3729, 2563, 1577, 4775, 2894, 1989, 1224, 3417, 2071, 1423, 876, 2625, 1591, 1093, 673, 6479, 3927, 2699, 1661, 5039, 3054, 2099, 1292, 3599, 2181, 1499, 923, 2735, 1658, 1139, 701, 6743, 4087, 2809, 1729, 5313, 3220, 2213, 1362, 3791, 2298, 1579, 972, 2927, 1774, 1219, 750, 7089, 4296, 2953, 1817, 5596, 3391, 2331, 1435, 3993, 2420, 1663, 1024, 3057, 1852, 1273, 784 };
private static readonly int[] _capacityECCBaseValues = { 19, 7, 1, 19, 0, 0, 16, 10, 1, 16, 0, 0, 13, 13, 1, 13, 0, 0, 9, 17, 1, 9, 0, 0, 34, 10, 1, 34, 0, 0, 28, 16, 1, 28, 0, 0, 22, 22, 1, 22, 0, 0, 16, 28, 1, 16, 0, 0, 55, 15, 1, 55, 0, 0, 44, 26, 1, 44, 0, 0, 34, 18, 2, 17, 0, 0, 26, 22, 2, 13, 0, 0, 80, 20, 1, 80, 0, 0, 64, 18, 2, 32, 0, 0, 48, 26, 2, 24, 0, 0, 36, 16, 4, 9, 0, 0, 108, 26, 1, 108, 0, 0, 86, 24, 2, 43, 0, 0, 62, 18, 2, 15, 2, 16, 46, 22, 2, 11, 2, 12, 136, 18, 2, 68, 0, 0, 108, 16, 4, 27, 0, 0, 76, 24, 4, 19, 0, 0, 60, 28, 4, 15, 0, 0, 156, 20, 2, 78, 0, 0, 124, 18, 4, 31, 0, 0, 88, 18, 2, 14, 4, 15, 66, 26, 4, 13, 1, 14, 194, 24, 2, 97, 0, 0, 154, 22, 2, 38, 2, 39, 110, 22, 4, 18, 2, 19, 86, 26, 4, 14, 2, 15, 232, 30, 2, 116, 0, 0, 182, 22, 3, 36, 2, 37, 132, 20, 4, 16, 4, 17, 100, 24, 4, 12, 4, 13, 274, 18, 2, 68, 2, 69, 216, 26, 4, 43, 1, 44, 154, 24, 6, 19, 2, 20, 122, 28, 6, 15, 2, 16, 324, 20, 4, 81, 0, 0, 254, 30, 1, 50, 4, 51, 180, 28, 4, 22, 4, 23, 140, 24, 3, 12, 8, 13, 370, 24, 2, 92, 2, 93, 290, 22, 6, 36, 2, 37, 206, 26, 4, 20, 6, 21, 158, 28, 7, 14, 4, 15, 428, 26, 4, 107, 0, 0, 334, 22, 8, 37, 1, 38, 244, 24, 8, 20, 4, 21, 180, 22, 12, 11, 4, 12, 461, 30, 3, 115, 1, 116, 365, 24, 4, 40, 5, 41, 261, 20, 11, 16, 5, 17, 197, 24, 11, 12, 5, 13, 523, 22, 5, 87, 1, 88, 415, 24, 5, 41, 5, 42, 295, 30, 5, 24, 7, 25, 223, 24, 11, 12, 7, 13, 589, 24, 5, 98, 1, 99, 453, 28, 7, 45, 3, 46, 325, 24, 15, 19, 2, 20, 253, 30, 3, 15, 13, 16, 647, 28, 1, 107, 5, 108, 507, 28, 10, 46, 1, 47, 367, 28, 1, 22, 15, 23, 283, 28, 2, 14, 17, 15, 721, 30, 5, 120, 1, 121, 563, 26, 9, 43, 4, 44, 397, 28, 17, 22, 1, 23, 313, 28, 2, 14, 19, 15, 795, 28, 3, 113, 4, 114, 627, 26, 3, 44, 11, 45, 445, 26, 17, 21, 4, 22, 341, 26, 9, 13, 16, 14, 861, 28, 3, 107, 5, 108, 669, 26, 3, 41, 13, 42, 485, 30, 15, 24, 5, 25, 385, 28, 15, 15, 10, 16, 932, 28, 4, 116, 4, 117, 714, 26, 17, 42, 0, 0, 512, 28, 17, 22, 6, 23, 406, 30, 19, 16, 6, 17, 1006, 28, 2, 111, 7, 112, 782, 28, 17, 46, 0, 0, 568, 30, 7, 24, 16, 25, 442, 24, 34, 13, 0, 0, 1094, 30, 4, 121, 5, 122, 860, 28, 4, 47, 14, 48, 614, 30, 11, 24, 14, 25, 464, 30, 16, 15, 14, 16, 1174, 30, 6, 117, 4, 118, 914, 28, 6, 45, 14, 46, 664, 30, 11, 24, 16, 25, 514, 30, 30, 16, 2, 17, 1276, 26, 8, 106, 4, 107, 1000, 28, 8, 47, 13, 48, 718, 30, 7, 24, 22, 25, 538, 30, 22, 15, 13, 16, 1370, 28, 10, 114, 2, 115, 1062, 28, 19, 46, 4, 47, 754, 28, 28, 22, 6, 23, 596, 30, 33, 16, 4, 17, 1468, 30, 8, 122, 4, 123, 1128, 28, 22, 45, 3, 46, 808, 30, 8, 23, 26, 24, 628, 30, 12, 15, 28, 16, 1531, 30, 3, 117, 10, 118, 1193, 28, 3, 45, 23, 46, 871, 30, 4, 24, 31, 25, 661, 30, 11, 15, 31, 16, 1631, 30, 7, 116, 7, 117, 1267, 28, 21, 45, 7, 46, 911, 30, 1, 23, 37, 24, 701, 30, 19, 15, 26, 16, 1735, 30, 5, 115, 10, 116, 1373, 28, 19, 47, 10, 48, 985, 30, 15, 24, 25, 25, 745, 30, 23, 15, 25, 16, 1843, 30, 13, 115, 3, 116, 1455, 28, 2, 46, 29, 47, 1033, 30, 42, 24, 1, 25, 793, 30, 23, 15, 28, 16, 1955, 30, 17, 115, 0, 0, 1541, 28, 10, 46, 23, 47, 1115, 30, 10, 24, 35, 25, 845, 30, 19, 15, 35, 16, 2071, 30, 17, 115, 1, 116, 1631, 28, 14, 46, 21, 47, 1171, 30, 29, 24, 19, 25, 901, 30, 11, 15, 46, 16, 2191, 30, 13, 115, 6, 116, 1725, 28, 14, 46, 23, 47, 1231, 30, 44, 24, 7, 25, 961, 30, 59, 16, 1, 17, 2306, 30, 12, 121, 7, 122, 1812, 28, 12, 47, 26, 48, 1286, 30, 39, 24, 14, 25, 986, 30, 22, 15, 41, 16, 2434, 30, 6, 121, 14, 122, 1914, 28, 6, 47, 34, 48, 1354, 30, 46, 24, 10, 25, 1054, 30, 2, 15, 64, 16, 2566, 30, 17, 122, 4, 123, 1992, 28, 29, 46, 14, 47, 1426, 30, 49, 24, 10, 25, 1096, 30, 24, 15, 46, 16, 2702, 30, 4, 122, 18, 123, 2102, 28, 13, 46, 32, 47, 1502, 30, 48, 24, 14, 25, 1142, 30, 42, 15, 32, 16, 2812, 30, 20, 117, 4, 118, 2216, 28, 40, 47, 7, 48, 1582, 30, 43, 24, 22, 25, 1222, 30, 10, 15, 67, 16, 2956, 30, 19, 118, 6, 119, 2334, 28, 18, 47, 31, 48, 1666, 30, 34, 24, 34, 25, 1276, 30, 20, 15, 61, 16 };
private static readonly int[] _alignmentPatternBaseValues = { 0, 0, 0, 0, 0, 0, 0, 6, 18, 0, 0, 0, 0, 0, 6, 22, 0, 0, 0, 0, 0, 6, 26, 0, 0, 0, 0, 0, 6, 30, 0, 0, 0, 0, 0, 6, 34, 0, 0, 0, 0, 0, 6, 22, 38, 0, 0, 0, 0, 6, 24, 42, 0, 0, 0, 0, 6, 26, 46, 0, 0, 0, 0, 6, 28, 50, 0, 0, 0, 0, 6, 30, 54, 0, 0, 0, 0, 6, 32, 58, 0, 0, 0, 0, 6, 34, 62, 0, 0, 0, 0, 6, 26, 46, 66, 0, 0, 0, 6, 26, 48, 70, 0, 0, 0, 6, 26, 50, 74, 0, 0, 0, 6, 30, 54, 78, 0, 0, 0, 6, 30, 56, 82, 0, 0, 0, 6, 30, 58, 86, 0, 0, 0, 6, 34, 62, 90, 0, 0, 0, 6, 28, 50, 72, 94, 0, 0, 6, 26, 50, 74, 98, 0, 0, 6, 30, 54, 78, 102, 0, 0, 6, 28, 54, 80, 106, 0, 0, 6, 32, 58, 84, 110, 0, 0, 6, 30, 58, 86, 114, 0, 0, 6, 34, 62, 90, 118, 0, 0, 6, 26, 50, 74, 98, 122, 0, 6, 30, 54, 78, 102, 126, 0, 6, 26, 52, 78, 104, 130, 0, 6, 30, 56, 82, 108, 134, 0, 6, 34, 60, 86, 112, 138, 0, 6, 30, 58, 86, 114, 142, 0, 6, 34, 62, 90, 118, 146, 0, 6, 30, 54, 78, 102, 126, 150, 6, 24, 50, 76, 102, 128, 154, 6, 28, 54, 80, 106, 132, 158, 6, 32, 58, 84, 110, 136, 162, 6, 26, 54, 82, 110, 138, 166, 6, 30, 58, 86, 114, 142, 170 };
private static readonly int[] _remainderBits = { 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 };
private static readonly Dictionary<int, AlignmentPattern> _alignmentPatternTable = CreateAlignmentPatternTable();
private static readonly List<ECCInfo> _capacityECCTable = CreateCapacityECCTable();
private static readonly List<VersionInfo> _capacityTable = CreateCapacityTable();
private static readonly int[] _galoisFieldByExponentAlpha = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1 };
private static readonly int[] _galoisFieldByIntegerValue = { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 };
private static readonly Dictionary<char, int> _alphanumEncDict = CreateAlphanumEncDict();
/// <summary>
/// Initializes the QR code generator
/// </summary>
@ -123,7 +110,7 @@ public partial class QRCodeGenerator : IDisposable
var codedText = PlainTextToBinary(plainText, encoding, eciMode, utf8BOM, forceUtf8);
var dataInputLength = GetDataLength(encoding, plainText, codedText, forceUtf8);
int version = requestedVersion;
int minVersion = GetVersion(dataInputLength + (eciMode != EciMode.Default ? 2 : 0), encoding, eccLevel);
int minVersion = CapacityTables.CalculateMinimumVersion(dataInputLength + (eciMode != EciMode.Default ? 2 : 0), encoding, eccLevel);
if (version == -1)
{
version = minVersion;
@ -133,7 +120,7 @@ public partial class QRCodeGenerator : IDisposable
//Version was passed as fixed version via parameter. Thus let's check if chosen version is valid.
if (minVersion > version)
{
var maxSizeByte = _capacityTable[version - 1].Details.First(x => x.ErrorCorrectionLevel == eccLevel).CapacityDict[encoding];
var maxSizeByte = CapacityTables.GetVersionInfo(version).Details.First(x => x.ErrorCorrectionLevel == eccLevel).CapacityDict[encoding];
throw new QRCoder.Exceptions.DataTooLongException(eccLevel.ToString(), encoding.ToString(), version, maxSizeByte);
}
}
@ -173,7 +160,7 @@ public partial class QRCodeGenerator : IDisposable
public static QRCodeData GenerateQrCode(byte[] binaryData, ECCLevel eccLevel)
{
eccLevel = ValidateECCLevel(eccLevel);
int version = GetVersion(binaryData.Length, EncodingMode.Byte, eccLevel);
int version = CapacityTables.CalculateMinimumVersion(binaryData.Length, EncodingMode.Byte, eccLevel);
int countIndicatorLen = GetCountIndicatorLength(version, EncodingMode.Byte);
// Convert byte array to bit array, with prefix padding for mode indicator and count indicator
@ -213,7 +200,7 @@ public partial class QRCodeGenerator : IDisposable
/// <returns>A QRCodeData structure containing the full QR code matrix, which can be used for rendering or analysis.</returns>
private static QRCodeData GenerateQrCode(BitArray bitArray, ECCLevel eccLevel, int version)
{
var eccInfo = _capacityECCTable.Single(x => x.Version == version && x.ErrorCorrectionLevel == eccLevel);
var eccInfo = CapacityTables.GetEccInfo(version, eccLevel);
// Fill up data code word
PadData();
@ -302,7 +289,7 @@ public partial class QRCodeGenerator : IDisposable
if (codeBlock.ECCWords.Length > i)
length += 8;
}
length += _remainderBits[version - 1];
length += CapacityTables.GetRemainderBits(version);
return length;
}
@ -339,7 +326,7 @@ public partial class QRCodeGenerator : IDisposable
{
ModulePlacer.PlaceFinderPatterns(qr, blockedModules);
ModulePlacer.ReserveSeperatorAreas(size, blockedModules);
ModulePlacer.PlaceAlignmentPatterns(qr, _alignmentPatternTable[version].PatternPositions, blockedModules);
ModulePlacer.PlaceAlignmentPatterns(qr, AlignmentPatterns.FromVersion(version).PatternPositions, blockedModules);
ModulePlacer.PlaceTimingPatterns(qr, blockedModules);
ModulePlacer.PlaceDarkModule(qr, version, blockedModules);
ModulePlacer.ReserveVersionAreas(size, version, blockedModules);
@ -528,7 +515,7 @@ public partial class QRCodeGenerator : IDisposable
// Convert the first coefficient to its corresponding alpha exponent unless it's zero.
// Coefficients that are zero remain zero because log(0) is undefined.
var index0Coefficient = leadTermSource[0].Coefficient;
index0Coefficient = index0Coefficient == 0 ? 0 : GetAlphaExpFromIntVal(index0Coefficient);
index0Coefficient = index0Coefficient == 0 ? 0 : GaloisField.GetAlphaExpFromIntVal(index0Coefficient);
var alphaNotation = new PolynomItem(index0Coefficient, leadTermSource[0].Exponent);
var resPoly = MultiplyGeneratorPolynomByLeadterm(generatorPolynom, alphaNotation, i);
ConvertToDecNotationInPlace(resPoly);
@ -564,40 +551,8 @@ public partial class QRCodeGenerator : IDisposable
for (var i = 0; i < poly.Count; i++)
{
// Convert the alpha exponent of the coefficient to its decimal value and create a new polynomial item with the updated coefficient.
poly[i] = new PolynomItem(GetIntValFromAlphaExp(poly[i].Coefficient), poly[i].Exponent);
}
}
/// <summary>
/// Determines the minimum QR code version required to encode a given amount of data with a specific encoding mode and error correction level.
/// If no suitable version is found, it throws an exception indicating that the data length exceeds the maximum capacity for the given settings.
/// </summary>
/// <param name="length">The length of the data to be encoded.</param>
/// <param name="encMode">The encoding mode (e.g., Numeric, Alphanumeric, Byte).</param>
/// <param name="eccLevel">The error correction level (e.g., Low, Medium, Quartile, High).</param>
/// <returns>The minimum version of the QR code that can accommodate the given data and settings.</returns>
private static int GetVersion(int length, EncodingMode encMode, ECCLevel eccLevel)
{
// capacity table is already sorted by version number ascending, so the smallest version that can hold the data is the first one found
foreach (var x in _capacityTable)
{
// find the requested ECC level and encoding mode in the capacity table
foreach (var y in x.Details)
{
if (y.ErrorCorrectionLevel == eccLevel && y.CapacityDict[encMode] >= length)
{
// if the capacity of the current version is enough, return the version number
return x.Version;
}
}
poly[i] = new PolynomItem(GaloisField.GetIntValFromAlphaExp(poly[i].Coefficient), poly[i].Exponent);
}
// if no version was found, throw an exception
var maxSizeByte = _capacityTable.Where(
x => x.Details.Any(
y => (y.ErrorCorrectionLevel == eccLevel))
).Max(x => x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel).CapacityDict[encMode]);
throw new QRCoder.Exceptions.DataTooLongException(eccLevel.ToString(), encMode.ToString(), maxSizeByte);
}
/// <summary>
@ -614,7 +569,7 @@ public partial class QRCodeGenerator : IDisposable
if (IsInRange(c, '0', '9'))
continue; // numeric - char.IsDigit() for Latin1
result = EncodingMode.Alphanumeric; // not numeric, assume alphanumeric
if (IsInRange(c, 'A', 'Z') || _alphanumEncTable.Contains(c))
if (AlphanumericEncoder.CanEncode(c))
continue; // alphanumeric
return EncodingMode.Byte; // not numeric or alphanumeric, assume byte
}
@ -795,7 +750,7 @@ public partial class QRCodeGenerator : IDisposable
{
return encMode switch
{
EncodingMode.Alphanumeric => PlainTextToBinaryAlphanumeric(plainText),
EncodingMode.Alphanumeric => AlphanumericEncoder.GetBitArray(plainText),
EncodingMode.Numeric => PlainTextToBinaryNumeric(plainText),
EncodingMode.Byte => PlainTextToBinaryByte(plainText, eciMode, utf8BOM, forceUtf8),
_ => _emptyBitArray,
@ -853,40 +808,6 @@ public partial class QRCodeGenerator : IDisposable
return bitArray;
}
/// <summary>
/// Converts alphanumeric plain text into a binary format optimized for QR codes.
/// Alphanumeric encoding packs characters into 11-bit groups for each pair of characters,
/// and 6 bits for a single remaining character if the total count is odd.
/// </summary>
/// <param name="plainText">The alphanumeric text to be encoded, which should only contain characters valid in QR alphanumeric mode.</param>
/// <returns>A BitArray representing the binary data of the encoded alphanumeric text.</returns>
private static BitArray PlainTextToBinaryAlphanumeric(string plainText)
{
// Calculate the length of the BitArray needed based on the number of character pairs.
var codeText = new BitArray((plainText.Length / 2) * 11 + (plainText.Length & 1) * 6);
var codeIndex = 0;
var index = 0;
var count = plainText.Length;
// Process each pair of characters.
while (count >= 2)
{
// Convert each pair of characters to a number by looking them up in the alphanumeric dictionary and calculating.
var dec = _alphanumEncDict[plainText[index++]] * 45 + _alphanumEncDict[plainText[index++]];
// Convert the number to binary and store it in the BitArray.
codeIndex = DecToBin(dec, 11, codeText, codeIndex);
count -= 2;
}
// Handle the last character if the length is odd.
if (count > 0)
{
DecToBin(_alphanumEncDict[plainText[index]], 6, codeText, codeIndex);
}
return codeText;
}
private static readonly Encoding _iso8859_1 =
#if NET5_0_OR_GREATER
Encoding.Latin1;
@ -1088,7 +1009,7 @@ public partial class QRCodeGenerator : IDisposable
// Create a new polynomial term with the coefficients added (as exponents) and exponents summed.
var polItemRes = new PolynomItem
(
ShrinkAlphaExp(polItemBase.Coefficient + polItemMulti.Coefficient),
GaloisField.ShrinkAlphaExp(polItemBase.Coefficient + polItemMulti.Coefficient),
(polItemBase.Exponent + polItemMulti.Exponent)
);
resultPolynom.Add(polItemRes);
@ -1105,11 +1026,11 @@ public partial class QRCodeGenerator : IDisposable
foreach (var polynomOld in resultPolynom)
{
if (polynomOld.Exponent == exponent)
coefficient ^= GetIntValFromAlphaExp(polynomOld.Coefficient);
coefficient ^= GaloisField.GetIntValFromAlphaExp(polynomOld.Coefficient);
}
// Fix the polynomial terms by recalculating the coefficients based on XORed results.
var polynomFixed = new PolynomItem(GetAlphaExpFromIntVal(coefficient), exponent);
var polynomFixed = new PolynomItem(GaloisField.GetAlphaExpFromIntVal(coefficient), exponent);
gluedPolynoms[gluedPolynomsIndex++] = polynomFixed;
}
@ -1161,210 +1082,6 @@ public partial class QRCodeGenerator : IDisposable
}
}
/// <summary>
/// Retrieves the integer value from the Galois field that corresponds to a given exponent.
/// This is used in Reed-Solomon and other error correction calculations involving Galois fields.
/// </summary>
private static int GetIntValFromAlphaExp(int exp)
=> _galoisFieldByExponentAlpha[exp];
/// <summary>
/// Retrieves the exponent from the Galois field that corresponds to a given integer value.
/// Throws an exception if the integer value is zero, as zero does not have a logarithmic representation in the field.
/// </summary>
private static int GetAlphaExpFromIntVal(int intVal)
{
if (intVal == 0)
ThrowIntValOutOfRangeException(); // Zero is not valid as it does not have an exponent representation.
return _galoisFieldByIntegerValue[intVal];
void ThrowIntValOutOfRangeException() => throw new ArgumentOutOfRangeException(nameof(intVal), "The provided integer value is out of range, as zero is not representable.");
}
/// <summary>
/// Normalizes a Galois field exponent to ensure it remains within the bounds of the field's size.
/// This is particularly necessary when performing multiplications in the field which can result in exponents exceeding the field's maximum.
/// </summary>
private static int ShrinkAlphaExp(int alphaExp)
=> (int)((alphaExp % 256) + Math.Floor((double)(alphaExp / 256)));
/// <summary>
/// Creates a dictionary mapping alphanumeric characters to their respective positions used in QR code encoding.
/// This includes digits 0-9, uppercase letters A-Z, and some special characters.
/// </summary>
/// <returns>A dictionary mapping each supported alphanumeric character to its corresponding value.</returns>
private static Dictionary<char, int> CreateAlphanumEncDict()
{
var localAlphanumEncDict = new Dictionary<char, int>(45);
for (int i = 0; i < 10; i++)
localAlphanumEncDict.Add($"{i}"[0], i);
// Add uppercase alphabetic characters.
for (char c = 'A'; c <= 'Z'; c++)
localAlphanumEncDict.Add(c, localAlphanumEncDict.Count);
// Add special characters from a predefined table.
for (int i = 0; i < _alphanumEncTable.Length; i++)
localAlphanumEncDict.Add(_alphanumEncTable[i], localAlphanumEncDict.Count);
return localAlphanumEncDict;
}
/// <summary>
/// Creates a lookup table mapping QR code versions to their corresponding alignment patterns.
/// Alignment patterns are used in QR codes to help scanners accurately read the code at high speeds and when partially obscured.
/// This table provides the necessary patterns based on the QR code version which dictates the size and complexity of the QR code.
/// </summary>
/// <returns>A dictionary where keys are QR code version numbers and values are AlignmentPattern structures detailing the positions of alignment patterns for each version.</returns>
private static Dictionary<int, AlignmentPattern> CreateAlignmentPatternTable()
{
var localAlignmentPatternTable = new Dictionary<int, AlignmentPattern>(40);
for (var i = 0; i < (7 * 40); i += 7)
{
var points = new List<Point>(50);
for (var x = 0; x < 7; x++)
{
if (_alignmentPatternBaseValues[i + x] != 0)
{
for (var y = 0; y < 7; y++)
{
if (_alignmentPatternBaseValues[i + y] != 0)
{
var p = new Point(_alignmentPatternBaseValues[i + x] - 2, _alignmentPatternBaseValues[i + y] - 2);
if (!points.Contains(p))
points.Add(p);
}
}
}
}
var version = (i + 7) / 7;
localAlignmentPatternTable.Add(version, new AlignmentPattern()
{
Version = version,
PatternPositions = points
}
);
}
return localAlignmentPatternTable;
}
/// <summary>
/// Generates a table containing the error correction capacities and data codeword information for different QR code versions and error correction levels.
/// This table is essential for determining how much data can be encoded in a QR code of a specific version and ECC level,
/// as well as how robust the QR code will be against distortions or obstructions.
/// </summary>
/// <returns>A list of ECCInfo structures, each representing the ECC data and capacities for different combinations of QR code versions and ECC levels.</returns>
private static List<ECCInfo> CreateCapacityECCTable()
{
var localCapacityECCTable = new List<ECCInfo>(160);
for (var i = 0; i < (4 * 6 * 40); i += (4 * 6))
{
localCapacityECCTable.AddRange(
new[]
{
new ECCInfo(
(i+24) / 24,
ECCLevel.L,
_capacityECCBaseValues[i],
_capacityECCBaseValues[i+1],
_capacityECCBaseValues[i+2],
_capacityECCBaseValues[i+3],
_capacityECCBaseValues[i+4],
_capacityECCBaseValues[i+5]),
new ECCInfo
(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.M,
totalDataCodewords: _capacityECCBaseValues[i+6],
eccPerBlock: _capacityECCBaseValues[i+7],
blocksInGroup1: _capacityECCBaseValues[i+8],
codewordsInGroup1: _capacityECCBaseValues[i+9],
blocksInGroup2: _capacityECCBaseValues[i+10],
codewordsInGroup2: _capacityECCBaseValues[i+11]
),
new ECCInfo
(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.Q,
totalDataCodewords: _capacityECCBaseValues[i+12],
eccPerBlock: _capacityECCBaseValues[i+13],
blocksInGroup1: _capacityECCBaseValues[i+14],
codewordsInGroup1: _capacityECCBaseValues[i+15],
blocksInGroup2: _capacityECCBaseValues[i+16],
codewordsInGroup2: _capacityECCBaseValues[i+17]
),
new ECCInfo
(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.H,
totalDataCodewords: _capacityECCBaseValues[i+18],
eccPerBlock: _capacityECCBaseValues[i+19],
blocksInGroup1: _capacityECCBaseValues[i+20],
codewordsInGroup1: _capacityECCBaseValues[i+21],
blocksInGroup2: _capacityECCBaseValues[i+22],
codewordsInGroup2: _capacityECCBaseValues[i+23]
)
});
}
return localCapacityECCTable;
}
/// <summary>
/// Generates a list containing detailed capacity information for various versions of QR codes.
/// This table includes capacities for different encoding modes (numeric, alphanumeric, byte, etc.) under each error correction level.
/// The capacity table is crucial for QR code generation, as it determines how much data each QR code version can store depending on the encoding mode and error correction level used.
/// </summary>
private static List<VersionInfo> CreateCapacityTable()
{
var localCapacityTable = new List<VersionInfo>(40);
for (var i = 0; i < (16 * 40); i += 16)
{
localCapacityTable.Add(new VersionInfo(
(i + 16) / 16,
new List<VersionInfoDetails>(4)
{
new VersionInfoDetails(
ECCLevel.L,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, _capacityBaseValues[i] },
{ EncodingMode.Alphanumeric, _capacityBaseValues[i+1] },
{ EncodingMode.Byte, _capacityBaseValues[i+2] },
{ EncodingMode.Kanji, _capacityBaseValues[i+3] },
}
),
new VersionInfoDetails(
ECCLevel.M,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, _capacityBaseValues[i+4] },
{ EncodingMode.Alphanumeric, _capacityBaseValues[i+5] },
{ EncodingMode.Byte, _capacityBaseValues[i+6] },
{ EncodingMode.Kanji, _capacityBaseValues[i+7] },
}
),
new VersionInfoDetails(
ECCLevel.Q,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, _capacityBaseValues[i+8] },
{ EncodingMode.Alphanumeric, _capacityBaseValues[i+9] },
{ EncodingMode.Byte, _capacityBaseValues[i+10] },
{ EncodingMode.Kanji, _capacityBaseValues[i+11] },
}
),
new VersionInfoDetails(
ECCLevel.H,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, _capacityBaseValues[i+12] },
{ EncodingMode.Alphanumeric, _capacityBaseValues[i+13] },
{ EncodingMode.Byte, _capacityBaseValues[i+14] },
{ EncodingMode.Kanji, _capacityBaseValues[i+15] },
}
)
}
));
}
return localCapacityTable;
}
/// <inheritdoc cref="IDisposable.Dispose"/>
public void Dispose()
{

62
QRCoder/QRCodeGenerator/AlignmentPatterns.cs

@ -0,0 +1,62 @@
using System.Collections.Generic;
namespace QRCoder;
public partial class QRCodeGenerator
{
/// <summary>
/// This class contains the alignment patterns used in QR codes.
/// </summary>
private static class AlignmentPatterns
{
/// <summary>
/// A lookup table mapping QR code versions to their corresponding alignment patterns.
/// </summary>
private static readonly Dictionary<int, AlignmentPattern> _alignmentPatternTable = CreateAlignmentPatternTable();
/// <summary>
/// Retrieves the alignment pattern for a specific QR code version.
/// </summary>
public static AlignmentPattern FromVersion(int version) => _alignmentPatternTable[version];
/// <summary>
/// Creates a lookup table mapping QR code versions to their corresponding alignment patterns.
/// Alignment patterns are used in QR codes to help scanners accurately read the code at high speeds and when partially obscured.
/// This table provides the necessary patterns based on the QR code version which dictates the size and complexity of the QR code.
/// </summary>
/// <returns>A dictionary where keys are QR code version numbers and values are AlignmentPattern structures detailing the positions of alignment patterns for each version.</returns>
private static Dictionary<int, AlignmentPattern> CreateAlignmentPatternTable()
{
var alignmentPatternBaseValues = new int[] { 0, 0, 0, 0, 0, 0, 0, 6, 18, 0, 0, 0, 0, 0, 6, 22, 0, 0, 0, 0, 0, 6, 26, 0, 0, 0, 0, 0, 6, 30, 0, 0, 0, 0, 0, 6, 34, 0, 0, 0, 0, 0, 6, 22, 38, 0, 0, 0, 0, 6, 24, 42, 0, 0, 0, 0, 6, 26, 46, 0, 0, 0, 0, 6, 28, 50, 0, 0, 0, 0, 6, 30, 54, 0, 0, 0, 0, 6, 32, 58, 0, 0, 0, 0, 6, 34, 62, 0, 0, 0, 0, 6, 26, 46, 66, 0, 0, 0, 6, 26, 48, 70, 0, 0, 0, 6, 26, 50, 74, 0, 0, 0, 6, 30, 54, 78, 0, 0, 0, 6, 30, 56, 82, 0, 0, 0, 6, 30, 58, 86, 0, 0, 0, 6, 34, 62, 90, 0, 0, 0, 6, 28, 50, 72, 94, 0, 0, 6, 26, 50, 74, 98, 0, 0, 6, 30, 54, 78, 102, 0, 0, 6, 28, 54, 80, 106, 0, 0, 6, 32, 58, 84, 110, 0, 0, 6, 30, 58, 86, 114, 0, 0, 6, 34, 62, 90, 118, 0, 0, 6, 26, 50, 74, 98, 122, 0, 6, 30, 54, 78, 102, 126, 0, 6, 26, 52, 78, 104, 130, 0, 6, 30, 56, 82, 108, 134, 0, 6, 34, 60, 86, 112, 138, 0, 6, 30, 58, 86, 114, 142, 0, 6, 34, 62, 90, 118, 146, 0, 6, 30, 54, 78, 102, 126, 150, 6, 24, 50, 76, 102, 128, 154, 6, 28, 54, 80, 106, 132, 158, 6, 32, 58, 84, 110, 136, 162, 6, 26, 54, 82, 110, 138, 166, 6, 30, 58, 86, 114, 142, 170 };
var localAlignmentPatternTable = new Dictionary<int, AlignmentPattern>(40);
for (var i = 0; i < (7 * 40); i += 7)
{
var points = new List<Point>(50);
for (var x = 0; x < 7; x++)
{
if (alignmentPatternBaseValues[i + x] != 0)
{
for (var y = 0; y < 7; y++)
{
if (alignmentPatternBaseValues[i + y] != 0)
{
var p = new Point(alignmentPatternBaseValues[i + x] - 2, alignmentPatternBaseValues[i + y] - 2);
if (!points.Contains(p))
points.Add(p);
}
}
}
}
var version = (i + 7) / 7;
localAlignmentPatternTable.Add(version, new AlignmentPattern()
{
Version = version,
PatternPositions = points
});
}
return localAlignmentPatternTable;
}
}
}

81
QRCoder/QRCodeGenerator/AlphanumericEncoder.cs

@ -0,0 +1,81 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace QRCoder;
public partial class QRCodeGenerator
{
/// <summary>
/// Encodes alphanumeric characters (<c>0–9</c>, <c>A–Z</c> (uppercase), space, <c>$</c>, <c>%</c>, <c>*</c>, <c>+</c>, <c>-</c>, period, <c>/</c>, colon) into a binary format suitable for QR codes.
/// </summary>
private static class AlphanumericEncoder
{
private static readonly char[] _alphanumEncTable = { ' ', '$', '%', '*', '+', '-', '.', '/', ':' };
/// <summary>
/// A dictionary mapping alphanumeric characters to their respective positions used in QR code encoding.
/// This includes digits 0-9, uppercase letters A-Z, and some special characters.
/// </summary>
private static readonly Dictionary<char, int> _alphanumEncDict = CreateAlphanumEncDict(_alphanumEncTable);
/// <summary>
/// Creates a dictionary mapping alphanumeric characters to their respective positions used in QR code encoding.
/// This includes digits 0-9, uppercase letters A-Z, and some special characters.
/// </summary>
/// <returns>A dictionary mapping each supported alphanumeric character to its corresponding value.</returns>
private static Dictionary<char, int> CreateAlphanumEncDict(char[] alphanumEncTable)
{
var localAlphanumEncDict = new Dictionary<char, int>(45);
// Add 0-9
for (char c = '0'; c <= '9'; c++)
localAlphanumEncDict.Add(c, c - '0');
// Add uppercase alphabetic characters.
for (char c = 'A'; c <= 'Z'; c++)
localAlphanumEncDict.Add(c, localAlphanumEncDict.Count);
// Add special characters from a predefined table.
for (int i = 0; i < _alphanumEncTable.Length; i++)
localAlphanumEncDict.Add(alphanumEncTable[i], localAlphanumEncDict.Count);
return localAlphanumEncDict;
}
/// <summary>
/// Checks if a character is present in the alphanumeric encoding table.
/// </summary>
public static bool CanEncode(char c) => IsInRange(c, 'A', 'Z') || Array.IndexOf(_alphanumEncTable, c) >= 0;
/// <summary>
/// Converts alphanumeric plain text into a binary format optimized for QR codes.
/// Alphanumeric encoding packs characters into 11-bit groups for each pair of characters,
/// and 6 bits for a single remaining character if the total count is odd.
/// </summary>
/// <param name="plainText">The alphanumeric text to be encoded, which should only contain characters valid in QR alphanumeric mode.</param>
/// <returns>A BitArray representing the binary data of the encoded alphanumeric text.</returns>
public static BitArray GetBitArray(string plainText)
{
// Calculate the length of the BitArray needed based on the number of character pairs.
var codeText = new BitArray((plainText.Length / 2) * 11 + (plainText.Length & 1) * 6);
var codeIndex = 0;
var index = 0;
var count = plainText.Length;
// Process each pair of characters.
while (count >= 2)
{
// Convert each pair of characters to a number by looking them up in the alphanumeric dictionary and calculating.
var dec = _alphanumEncDict[plainText[index++]] * 45 + _alphanumEncDict[plainText[index++]];
// Convert the number to binary and store it in the BitArray.
codeIndex = DecToBin(dec, 11, codeText, codeIndex);
count -= 2;
}
// Handle the last character if the length is odd.
if (count > 0)
{
DecToBin(_alphanumEncDict[plainText[index]], 6, codeText, codeIndex);
}
return codeText;
}
}
}

216
QRCoder/QRCodeGenerator/CapacityTables.cs

@ -0,0 +1,216 @@
using System.Collections.Generic;
using System.Linq;
namespace QRCoder;
public partial class QRCodeGenerator
{
/// <summary>
/// Provides QR code capacity and error correction data for each version and encoding mode.
/// Used to determine how much data can be stored in a QR code and which version is required.
/// </summary>
private static class CapacityTables
{
private static readonly int[] _capacityBaseValues = { 41, 25, 17, 10, 34, 20, 14, 8, 27, 16, 11, 7, 17, 10, 7, 4, 77, 47, 32, 20, 63, 38, 26, 16, 48, 29, 20, 12, 34, 20, 14, 8, 127, 77, 53, 32, 101, 61, 42, 26, 77, 47, 32, 20, 58, 35, 24, 15, 187, 114, 78, 48, 149, 90, 62, 38, 111, 67, 46, 28, 82, 50, 34, 21, 255, 154, 106, 65, 202, 122, 84, 52, 144, 87, 60, 37, 106, 64, 44, 27, 322, 195, 134, 82, 255, 154, 106, 65, 178, 108, 74, 45, 139, 84, 58, 36, 370, 224, 154, 95, 293, 178, 122, 75, 207, 125, 86, 53, 154, 93, 64, 39, 461, 279, 192, 118, 365, 221, 152, 93, 259, 157, 108, 66, 202, 122, 84, 52, 552, 335, 230, 141, 432, 262, 180, 111, 312, 189, 130, 80, 235, 143, 98, 60, 652, 395, 271, 167, 513, 311, 213, 131, 364, 221, 151, 93, 288, 174, 119, 74, 772, 468, 321, 198, 604, 366, 251, 155, 427, 259, 177, 109, 331, 200, 137, 85, 883, 535, 367, 226, 691, 419, 287, 177, 489, 296, 203, 125, 374, 227, 155, 96, 1022, 619, 425, 262, 796, 483, 331, 204, 580, 352, 241, 149, 427, 259, 177, 109, 1101, 667, 458, 282, 871, 528, 362, 223, 621, 376, 258, 159, 468, 283, 194, 120, 1250, 758, 520, 320, 991, 600, 412, 254, 703, 426, 292, 180, 530, 321, 220, 136, 1408, 854, 586, 361, 1082, 656, 450, 277, 775, 470, 322, 198, 602, 365, 250, 154, 1548, 938, 644, 397, 1212, 734, 504, 310, 876, 531, 364, 224, 674, 408, 280, 173, 1725, 1046, 718, 442, 1346, 816, 560, 345, 948, 574, 394, 243, 746, 452, 310, 191, 1903, 1153, 792, 488, 1500, 909, 624, 384, 1063, 644, 442, 272, 813, 493, 338, 208, 2061, 1249, 858, 528, 1600, 970, 666, 410, 1159, 702, 482, 297, 919, 557, 382, 235, 2232, 1352, 929, 572, 1708, 1035, 711, 438, 1224, 742, 509, 314, 969, 587, 403, 248, 2409, 1460, 1003, 618, 1872, 1134, 779, 480, 1358, 823, 565, 348, 1056, 640, 439, 270, 2620, 1588, 1091, 672, 2059, 1248, 857, 528, 1468, 890, 611, 376, 1108, 672, 461, 284, 2812, 1704, 1171, 721, 2188, 1326, 911, 561, 1588, 963, 661, 407, 1228, 744, 511, 315, 3057, 1853, 1273, 784, 2395, 1451, 997, 614, 1718, 1041, 715, 440, 1286, 779, 535, 330, 3283, 1990, 1367, 842, 2544, 1542, 1059, 652, 1804, 1094, 751, 462, 1425, 864, 593, 365, 3517, 2132, 1465, 902, 2701, 1637, 1125, 692, 1933, 1172, 805, 496, 1501, 910, 625, 385, 3669, 2223, 1528, 940, 2857, 1732, 1190, 732, 2085, 1263, 868, 534, 1581, 958, 658, 405, 3909, 2369, 1628, 1002, 3035, 1839, 1264, 778, 2181, 1322, 908, 559, 1677, 1016, 698, 430, 4158, 2520, 1732, 1066, 3289, 1994, 1370, 843, 2358, 1429, 982, 604, 1782, 1080, 742, 457, 4417, 2677, 1840, 1132, 3486, 2113, 1452, 894, 2473, 1499, 1030, 634, 1897, 1150, 790, 486, 4686, 2840, 1952, 1201, 3693, 2238, 1538, 947, 2670, 1618, 1112, 684, 2022, 1226, 842, 518, 4965, 3009, 2068, 1273, 3909, 2369, 1628, 1002, 2805, 1700, 1168, 719, 2157, 1307, 898, 553, 5253, 3183, 2188, 1347, 4134, 2506, 1722, 1060, 2949, 1787, 1228, 756, 2301, 1394, 958, 590, 5529, 3351, 2303, 1417, 4343, 2632, 1809, 1113, 3081, 1867, 1283, 790, 2361, 1431, 983, 605, 5836, 3537, 2431, 1496, 4588, 2780, 1911, 1176, 3244, 1966, 1351, 832, 2524, 1530, 1051, 647, 6153, 3729, 2563, 1577, 4775, 2894, 1989, 1224, 3417, 2071, 1423, 876, 2625, 1591, 1093, 673, 6479, 3927, 2699, 1661, 5039, 3054, 2099, 1292, 3599, 2181, 1499, 923, 2735, 1658, 1139, 701, 6743, 4087, 2809, 1729, 5313, 3220, 2213, 1362, 3791, 2298, 1579, 972, 2927, 1774, 1219, 750, 7089, 4296, 2953, 1817, 5596, 3391, 2331, 1435, 3993, 2420, 1663, 1024, 3057, 1852, 1273, 784 };
private static readonly int[] _capacityECCBaseValues = { 19, 7, 1, 19, 0, 0, 16, 10, 1, 16, 0, 0, 13, 13, 1, 13, 0, 0, 9, 17, 1, 9, 0, 0, 34, 10, 1, 34, 0, 0, 28, 16, 1, 28, 0, 0, 22, 22, 1, 22, 0, 0, 16, 28, 1, 16, 0, 0, 55, 15, 1, 55, 0, 0, 44, 26, 1, 44, 0, 0, 34, 18, 2, 17, 0, 0, 26, 22, 2, 13, 0, 0, 80, 20, 1, 80, 0, 0, 64, 18, 2, 32, 0, 0, 48, 26, 2, 24, 0, 0, 36, 16, 4, 9, 0, 0, 108, 26, 1, 108, 0, 0, 86, 24, 2, 43, 0, 0, 62, 18, 2, 15, 2, 16, 46, 22, 2, 11, 2, 12, 136, 18, 2, 68, 0, 0, 108, 16, 4, 27, 0, 0, 76, 24, 4, 19, 0, 0, 60, 28, 4, 15, 0, 0, 156, 20, 2, 78, 0, 0, 124, 18, 4, 31, 0, 0, 88, 18, 2, 14, 4, 15, 66, 26, 4, 13, 1, 14, 194, 24, 2, 97, 0, 0, 154, 22, 2, 38, 2, 39, 110, 22, 4, 18, 2, 19, 86, 26, 4, 14, 2, 15, 232, 30, 2, 116, 0, 0, 182, 22, 3, 36, 2, 37, 132, 20, 4, 16, 4, 17, 100, 24, 4, 12, 4, 13, 274, 18, 2, 68, 2, 69, 216, 26, 4, 43, 1, 44, 154, 24, 6, 19, 2, 20, 122, 28, 6, 15, 2, 16, 324, 20, 4, 81, 0, 0, 254, 30, 1, 50, 4, 51, 180, 28, 4, 22, 4, 23, 140, 24, 3, 12, 8, 13, 370, 24, 2, 92, 2, 93, 290, 22, 6, 36, 2, 37, 206, 26, 4, 20, 6, 21, 158, 28, 7, 14, 4, 15, 428, 26, 4, 107, 0, 0, 334, 22, 8, 37, 1, 38, 244, 24, 8, 20, 4, 21, 180, 22, 12, 11, 4, 12, 461, 30, 3, 115, 1, 116, 365, 24, 4, 40, 5, 41, 261, 20, 11, 16, 5, 17, 197, 24, 11, 12, 5, 13, 523, 22, 5, 87, 1, 88, 415, 24, 5, 41, 5, 42, 295, 30, 5, 24, 7, 25, 223, 24, 11, 12, 7, 13, 589, 24, 5, 98, 1, 99, 453, 28, 7, 45, 3, 46, 325, 24, 15, 19, 2, 20, 253, 30, 3, 15, 13, 16, 647, 28, 1, 107, 5, 108, 507, 28, 10, 46, 1, 47, 367, 28, 1, 22, 15, 23, 283, 28, 2, 14, 17, 15, 721, 30, 5, 120, 1, 121, 563, 26, 9, 43, 4, 44, 397, 28, 17, 22, 1, 23, 313, 28, 2, 14, 19, 15, 795, 28, 3, 113, 4, 114, 627, 26, 3, 44, 11, 45, 445, 26, 17, 21, 4, 22, 341, 26, 9, 13, 16, 14, 861, 28, 3, 107, 5, 108, 669, 26, 3, 41, 13, 42, 485, 30, 15, 24, 5, 25, 385, 28, 15, 15, 10, 16, 932, 28, 4, 116, 4, 117, 714, 26, 17, 42, 0, 0, 512, 28, 17, 22, 6, 23, 406, 30, 19, 16, 6, 17, 1006, 28, 2, 111, 7, 112, 782, 28, 17, 46, 0, 0, 568, 30, 7, 24, 16, 25, 442, 24, 34, 13, 0, 0, 1094, 30, 4, 121, 5, 122, 860, 28, 4, 47, 14, 48, 614, 30, 11, 24, 14, 25, 464, 30, 16, 15, 14, 16, 1174, 30, 6, 117, 4, 118, 914, 28, 6, 45, 14, 46, 664, 30, 11, 24, 16, 25, 514, 30, 30, 16, 2, 17, 1276, 26, 8, 106, 4, 107, 1000, 28, 8, 47, 13, 48, 718, 30, 7, 24, 22, 25, 538, 30, 22, 15, 13, 16, 1370, 28, 10, 114, 2, 115, 1062, 28, 19, 46, 4, 47, 754, 28, 28, 22, 6, 23, 596, 30, 33, 16, 4, 17, 1468, 30, 8, 122, 4, 123, 1128, 28, 22, 45, 3, 46, 808, 30, 8, 23, 26, 24, 628, 30, 12, 15, 28, 16, 1531, 30, 3, 117, 10, 118, 1193, 28, 3, 45, 23, 46, 871, 30, 4, 24, 31, 25, 661, 30, 11, 15, 31, 16, 1631, 30, 7, 116, 7, 117, 1267, 28, 21, 45, 7, 46, 911, 30, 1, 23, 37, 24, 701, 30, 19, 15, 26, 16, 1735, 30, 5, 115, 10, 116, 1373, 28, 19, 47, 10, 48, 985, 30, 15, 24, 25, 25, 745, 30, 23, 15, 25, 16, 1843, 30, 13, 115, 3, 116, 1455, 28, 2, 46, 29, 47, 1033, 30, 42, 24, 1, 25, 793, 30, 23, 15, 28, 16, 1955, 30, 17, 115, 0, 0, 1541, 28, 10, 46, 23, 47, 1115, 30, 10, 24, 35, 25, 845, 30, 19, 15, 35, 16, 2071, 30, 17, 115, 1, 116, 1631, 28, 14, 46, 21, 47, 1171, 30, 29, 24, 19, 25, 901, 30, 11, 15, 46, 16, 2191, 30, 13, 115, 6, 116, 1725, 28, 14, 46, 23, 47, 1231, 30, 44, 24, 7, 25, 961, 30, 59, 16, 1, 17, 2306, 30, 12, 121, 7, 122, 1812, 28, 12, 47, 26, 48, 1286, 30, 39, 24, 14, 25, 986, 30, 22, 15, 41, 16, 2434, 30, 6, 121, 14, 122, 1914, 28, 6, 47, 34, 48, 1354, 30, 46, 24, 10, 25, 1054, 30, 2, 15, 64, 16, 2566, 30, 17, 122, 4, 123, 1992, 28, 29, 46, 14, 47, 1426, 30, 49, 24, 10, 25, 1096, 30, 24, 15, 46, 16, 2702, 30, 4, 122, 18, 123, 2102, 28, 13, 46, 32, 47, 1502, 30, 48, 24, 14, 25, 1142, 30, 42, 15, 32, 16, 2812, 30, 20, 117, 4, 118, 2216, 28, 40, 47, 7, 48, 1582, 30, 43, 24, 22, 25, 1222, 30, 10, 15, 67, 16, 2956, 30, 19, 118, 6, 119, 2334, 28, 18, 47, 31, 48, 1666, 30, 34, 24, 34, 25, 1276, 30, 20, 15, 61, 16 };
private static readonly int[] _remainderBits = { 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 };
/// <summary>
/// A list containing detailed capacity information for each version of QR codes.
/// The index in the capacity table corresponds to one less than the version number.
/// </summary>
private static readonly List<VersionInfo> _capacityTable = CreateCapacityTable(_capacityBaseValues);
/// <summary>
/// A table containing the error correction capacities and data codeword information for different combinations of QR code versions and error correction levels.
/// </summary>
private static readonly List<ECCInfo> _capacityECCTable = CreateCapacityECCTable(_capacityECCBaseValues);
/// <summary>
/// Retrieves the error correction information for a specific QR code version and error correction level.
/// </summary>
/// <param name="version">The version of the QR code (1 to 40).</param>
/// <param name="eccLevel">The desired error correction level (L, M, Q, or H). Do not supply <see cref="ECCLevel.Default"/>.</param>
/// <returns>
/// An <see cref="ECCInfo"/> object containing the total number of data codewords, ECC per block,
/// block group details, and other parameters required for encoding error correction data.
/// </returns>
public static ECCInfo GetEccInfo(int version, ECCLevel eccLevel)
=> _capacityECCTable.Single(x => x.Version == version && x.ErrorCorrectionLevel == eccLevel);
/// <summary>
/// Retrieves the capacity information for a specific QR code version.
/// The returned structure contains detailed data capacity values for each error correction level (L, M, Q, H)
/// and encoding mode (Numeric, Alphanumeric, Byte, Kanji), indicating the maximum number of characters
/// that can be stored in a QR code of the specified version under each configuration.
/// </summary>
/// <param name="version">The version of the QR code (1 to 40).</param>
/// <returns>
/// A <see cref="VersionInfo"/> object containing data capacity details for all error correction levels
/// and encoding modes for the specified version.
/// </returns>
public static VersionInfo GetVersionInfo(int version)
=> _capacityTable[version - 1];
/// <summary>
/// Retrieves the number of remainder bits required for a specific QR code version.
/// Remainder bits are added to the final bit stream to ensure proper alignment with byte boundaries,
/// as required by the QR code specification.
/// </summary>
/// <param name="version">The version of the QR code (1 to 40).</param>
/// <returns>
/// The number of remainder bits (0 to 7) that must be appended to the encoded bit stream.
/// </returns>
public static int GetRemainderBits(int version)
=> _remainderBits[version - 1];
/// <summary>
/// Determines the minimum QR code version required to encode a given amount of data with a specific encoding mode and error correction level.
/// If no suitable version is found, it throws an exception indicating that the data length exceeds the maximum capacity for the given settings.
/// </summary>
/// <param name="length">The length of the data to be encoded.</param>
/// <param name="encMode">The encoding mode (e.g., Numeric, Alphanumeric, Byte).</param>
/// <param name="eccLevel">The error correction level (e.g., Low, Medium, Quartile, High).</param>
/// <returns>The minimum version of the QR code that can accommodate the given data and settings.</returns>
/// <exception cref="QRCoder.Exceptions.DataTooLongException">
/// Thrown when the data length exceeds the maximum capacity for the specified encoding mode and error correction level.
/// </exception>
public static int CalculateMinimumVersion(int length, EncodingMode encMode, ECCLevel eccLevel)
{
// capacity table is already sorted by version number ascending, so the smallest version that can hold the data is the first one found
foreach (var x in _capacityTable)
{
// find the requested ECC level and encoding mode in the capacity table
foreach (var y in x.Details)
{
if (y.ErrorCorrectionLevel == eccLevel && y.CapacityDict[encMode] >= length)
{
// if the capacity of the current version is enough, return the version number
return x.Version;
}
}
}
// if no version was found, throw an exception
var maxSizeByte = _capacityTable.Where(
x => x.Details.Any(
y => (y.ErrorCorrectionLevel == eccLevel))
).Max(x => x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel).CapacityDict[encMode]);
throw new QRCoder.Exceptions.DataTooLongException(eccLevel.ToString(), encMode.ToString(), maxSizeByte);
}
/// <summary>
/// Generates a table containing the error correction capacities and data codeword information for different QR code versions and error correction levels.
/// This table is essential for determining how much data can be encoded in a QR code of a specific version and ECC level,
/// as well as how robust the QR code will be against distortions or obstructions.
/// </summary>
/// <returns>A list of ECCInfo structures, each representing the ECC data and capacities for different combinations of QR code versions and ECC levels.</returns>
private static List<ECCInfo> CreateCapacityECCTable(int[] capacityECCBaseValues)
{
var localCapacityECCTable = new List<ECCInfo>(160);
for (var i = 0; i < (4 * 6 * 40); i += (4 * 6))
{
localCapacityECCTable.AddRange(new[]
{
new ECCInfo(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.L,
totalDataCodewords: capacityECCBaseValues[i],
eccPerBlock: capacityECCBaseValues[i + 1],
blocksInGroup1: capacityECCBaseValues[i + 2],
codewordsInGroup1: capacityECCBaseValues[i + 3],
blocksInGroup2: capacityECCBaseValues[i + 4],
codewordsInGroup2: capacityECCBaseValues[i + 5]),
new ECCInfo(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.M,
totalDataCodewords: capacityECCBaseValues[i + 6],
eccPerBlock: capacityECCBaseValues[i + 7],
blocksInGroup1: capacityECCBaseValues[i + 8],
codewordsInGroup1: capacityECCBaseValues[i + 9],
blocksInGroup2: capacityECCBaseValues[i + 10],
codewordsInGroup2: capacityECCBaseValues[i + 11]
),
new ECCInfo(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.Q,
totalDataCodewords: capacityECCBaseValues[i + 12],
eccPerBlock: capacityECCBaseValues[i + 13],
blocksInGroup1: capacityECCBaseValues[i + 14],
codewordsInGroup1: capacityECCBaseValues[i + 15],
blocksInGroup2: capacityECCBaseValues[i + 16],
codewordsInGroup2: capacityECCBaseValues[i + 17]
),
new ECCInfo(
version: (i + 24) / 24,
errorCorrectionLevel: ECCLevel.H,
totalDataCodewords: capacityECCBaseValues[i + 18],
eccPerBlock: capacityECCBaseValues[i + 19],
blocksInGroup1: capacityECCBaseValues[i + 20],
codewordsInGroup1: capacityECCBaseValues[i + 21],
blocksInGroup2: capacityECCBaseValues[i + 22],
codewordsInGroup2: capacityECCBaseValues[i + 23]
)
});
}
return localCapacityECCTable;
}
/// <summary>
/// Generates a list containing detailed capacity information for various versions of QR codes.
/// This table includes capacities for different encoding modes (numeric, alphanumeric, byte, etc.) under each error correction level.
/// The capacity table is crucial for QR code generation, as it determines how much data each QR code version can store depending on the encoding mode and error correction level used.
/// The index in the capacity table corresponds to one less than the version number.
/// </summary>
private static List<VersionInfo> CreateCapacityTable(int[] capacityBaseValues)
{
var localCapacityTable = new List<VersionInfo>(40);
for (var i = 0; i < (16 * 40); i += 16)
{
localCapacityTable.Add(new VersionInfo(
version: (i + 16) / 16,
versionInfoDetails: new List<VersionInfoDetails>(4)
{
new VersionInfoDetails(
ECCLevel.L,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, capacityBaseValues[i] },
{ EncodingMode.Alphanumeric, capacityBaseValues[i + 1] },
{ EncodingMode.Byte, capacityBaseValues[i + 2] },
{ EncodingMode.Kanji, capacityBaseValues[i + 3] },
}
),
new VersionInfoDetails(
ECCLevel.M,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, capacityBaseValues[i + 4] },
{ EncodingMode.Alphanumeric, capacityBaseValues[i + 5] },
{ EncodingMode.Byte, capacityBaseValues[i + 6] },
{ EncodingMode.Kanji, capacityBaseValues[i + 7] },
}
),
new VersionInfoDetails(
ECCLevel.Q,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, capacityBaseValues[i + 8] },
{ EncodingMode.Alphanumeric, capacityBaseValues[i + 9] },
{ EncodingMode.Byte, capacityBaseValues[i + 10] },
{ EncodingMode.Kanji, capacityBaseValues[i + 11] },
}
),
new VersionInfoDetails(
ECCLevel.H,
new Dictionary<EncodingMode,int>(){
{ EncodingMode.Numeric, capacityBaseValues[i + 12] },
{ EncodingMode.Alphanumeric, capacityBaseValues[i + 13] },
{ EncodingMode.Byte, capacityBaseValues[i + 14] },
{ EncodingMode.Kanji, capacityBaseValues[i + 15] },
}
)
}
));
}
return localCapacityTable;
}
}
}

48
QRCoder/QRCodeGenerator/GaloisField.cs

@ -0,0 +1,48 @@
using System;
namespace QRCoder;
public partial class QRCodeGenerator
{
/// <summary>
/// Represents a Galois field of 256 elements (GF(256)) used in finite field arithmetic,
/// typically for error correction algorithms such as Reed-Solomon.
/// <para>
/// Provides mappings between exponential and integer representations of field elements
/// using a primitive element (α). The field is constructed with respect to a generator
/// polynomial and used for efficient encoding and decoding operations.
/// </para>
/// </summary>
private static class GaloisField
{
private static readonly int[] _galoisFieldByExponentAlpha = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1 };
private static readonly int[] _galoisFieldByIntegerValue = { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 };
/// <summary>
/// Retrieves the integer value from the Galois field that corresponds to a given exponent.
/// This is used in Reed-Solomon and other error correction calculations involving Galois fields.
/// </summary>
public static int GetIntValFromAlphaExp(int exp)
=> _galoisFieldByExponentAlpha[exp];
/// <summary>
/// Retrieves the exponent from the Galois field that corresponds to a given integer value.
/// Throws an exception if the integer value is zero, as zero does not have a logarithmic representation in the field.
/// </summary>
public static int GetAlphaExpFromIntVal(int intVal)
{
if (intVal == 0)
ThrowIntValOutOfRangeException(); // Zero is not valid as it does not have an exponent representation.
return _galoisFieldByIntegerValue[intVal];
void ThrowIntValOutOfRangeException() => throw new ArgumentOutOfRangeException(nameof(intVal), "The provided integer value is out of range, as zero is not representable.");
}
/// <summary>
/// Normalizes a Galois field exponent to ensure it remains within the bounds of the field's size.
/// This is particularly necessary when performing multiplications in the field which can result in exponents exceeding the field's maximum.
/// </summary>
public static int ShrinkAlphaExp(int alphaExp)
=> (alphaExp % 256) + (alphaExp / 256);
}
}

2
QRCoderDemoUWP/MainPage.xaml.cs

@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QRCoder;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using QRCoder;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

4
QRCoderDemoUWP/Properties/AssemblyInfo.cs

@ -1,4 +1,4 @@
using System.Reflection;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -26,4 +26,4 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]
[assembly: ComVisible(false)]

1
QRCoderTests/PngByteQRCodeRendererTests.cs

@ -113,7 +113,6 @@ public class PngByteQRCodeRendererTests
var result = HelperFunctions.ByteArrayToHash(pngCodeGfx);
result.ShouldBe("07f760b3eb54901840b094d31e299713");
#else
File.WriteAllBytes(@"C:\Temp\pngbyte_35.png", pngCodeGfx);
using var mStream = new MemoryStream(pngCodeGfx);
var bmp = (Bitmap)Image.FromStream(mStream);
bmp.MakeTransparent(Color.Transparent);

8
QRCoderTests/QRGeneratorTests.cs

@ -21,7 +21,8 @@ public class QRGeneratorTests
var gen = new QRCodeGenerator();
var checkString = string.Empty;
var gField = gen.GetType().GetField("_galoisFieldByExponentAlpha", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null).ShouldBeOfType<int[]>();
var tablesType = Type.GetType("QRCoder.QRCodeGenerator+GaloisField, QRCoder");
var gField = tablesType.GetField("_galoisFieldByExponentAlpha", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null).ShouldBeOfType<int[]>();
gField.Length.ShouldBe(256);
for (int i = 0; i < gField.Length; i++)
{
@ -29,7 +30,7 @@ public class QRGeneratorTests
}
checkString.ShouldBe("0,1,:1,2,:2,4,:3,8,:4,16,:5,32,:6,64,:7,128,:8,29,:9,58,:10,116,:11,232,:12,205,:13,135,:14,19,:15,38,:16,76,:17,152,:18,45,:19,90,:20,180,:21,117,:22,234,:23,201,:24,143,:25,3,:26,6,:27,12,:28,24,:29,48,:30,96,:31,192,:32,157,:33,39,:34,78,:35,156,:36,37,:37,74,:38,148,:39,53,:40,106,:41,212,:42,181,:43,119,:44,238,:45,193,:46,159,:47,35,:48,70,:49,140,:50,5,:51,10,:52,20,:53,40,:54,80,:55,160,:56,93,:57,186,:58,105,:59,210,:60,185,:61,111,:62,222,:63,161,:64,95,:65,190,:66,97,:67,194,:68,153,:69,47,:70,94,:71,188,:72,101,:73,202,:74,137,:75,15,:76,30,:77,60,:78,120,:79,240,:80,253,:81,231,:82,211,:83,187,:84,107,:85,214,:86,177,:87,127,:88,254,:89,225,:90,223,:91,163,:92,91,:93,182,:94,113,:95,226,:96,217,:97,175,:98,67,:99,134,:100,17,:101,34,:102,68,:103,136,:104,13,:105,26,:106,52,:107,104,:108,208,:109,189,:110,103,:111,206,:112,129,:113,31,:114,62,:115,124,:116,248,:117,237,:118,199,:119,147,:120,59,:121,118,:122,236,:123,197,:124,151,:125,51,:126,102,:127,204,:128,133,:129,23,:130,46,:131,92,:132,184,:133,109,:134,218,:135,169,:136,79,:137,158,:138,33,:139,66,:140,132,:141,21,:142,42,:143,84,:144,168,:145,77,:146,154,:147,41,:148,82,:149,164,:150,85,:151,170,:152,73,:153,146,:154,57,:155,114,:156,228,:157,213,:158,183,:159,115,:160,230,:161,209,:162,191,:163,99,:164,198,:165,145,:166,63,:167,126,:168,252,:169,229,:170,215,:171,179,:172,123,:173,246,:174,241,:175,255,:176,227,:177,219,:178,171,:179,75,:180,150,:181,49,:182,98,:183,196,:184,149,:185,55,:186,110,:187,220,:188,165,:189,87,:190,174,:191,65,:192,130,:193,25,:194,50,:195,100,:196,200,:197,141,:198,7,:199,14,:200,28,:201,56,:202,112,:203,224,:204,221,:205,167,:206,83,:207,166,:208,81,:209,162,:210,89,:211,178,:212,121,:213,242,:214,249,:215,239,:216,195,:217,155,:218,43,:219,86,:220,172,:221,69,:222,138,:223,9,:224,18,:225,36,:226,72,:227,144,:228,61,:229,122,:230,244,:231,245,:232,247,:233,243,:234,251,:235,235,:236,203,:237,139,:238,11,:239,22,:240,44,:241,88,:242,176,:243,125,:244,250,:245,233,:246,207,:247,131,:248,27,:249,54,:250,108,:251,216,:252,173,:253,71,:254,142,:255,1,:");
var gField2 = gen.GetType().GetField("_galoisFieldByIntegerValue", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null).ShouldBeOfType<int[]>();
var gField2 = tablesType.GetField("_galoisFieldByIntegerValue", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null).ShouldBeOfType<int[]>();
gField2.Length.ShouldBe(256);
var checkString2 = string.Empty;
for (int i = 0; i < gField2.Length; i++)
@ -369,7 +370,8 @@ public class QRGeneratorTests
var gen = new QRCodeGenerator();
var checkString = string.Empty;
var gField = gen.GetType().GetField("_alphanumEncDict", BindingFlags.NonPublic | BindingFlags.Static);
var encoderType = Type.GetType("QRCoder.QRCodeGenerator+AlphanumericEncoder, QRCoder");
var gField = encoderType.GetField("_alphanumEncDict", BindingFlags.NonPublic | BindingFlags.Static);
foreach (var listitem in (Dictionary<char, int>)gField.GetValue(gen))
{
checkString += $"{listitem.Key},{listitem.Value}:";

Loading…
Cancel
Save