You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1467 lines
67 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #if NET40 || NET461
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Collections;
  6. using System.Linq;
  7. using System.Reflection;
  8. namespace Apewer.Internals.QrCode
  9. {
  10. internal class QRCodeGenerator : IDisposable
  11. {
  12. private static readonly char[] numTable = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
  13. private static readonly char[] alphanumEncTable = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' };
  14. private 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 };
  15. private 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 };
  16. private 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 };
  17. private 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 };
  18. private List<AlignmentPattern> alignmentPatternTable;
  19. private List<ECCInfo> capacityECCTable;
  20. private List<VersionInfo> capacityTable;
  21. private List<Antilog> galoisField;
  22. private Dictionary<char, int> alphanumEncDict;
  23. public enum EciMode
  24. {
  25. Default = 0,
  26. Iso8859_1 = 3,
  27. Iso8859_2 = 4,
  28. Utf8 = 26
  29. }
  30. public QRCodeGenerator()
  31. {
  32. this.CreateAntilogTable();
  33. this.CreateAlphanumEncDict();
  34. this.CreateCapacityTable();
  35. this.CreateCapacityECCTable();
  36. this.CreateAlignmentPatternTable();
  37. }
  38. public QRCodeData CreateQrCode(PayloadGenerator.Payload payload)
  39. {
  40. return CreateQrCode(payload.ToString(), payload.EccLevel, false, false, payload.EciMode, payload.Version);
  41. }
  42. public QRCodeData CreateQrCode(PayloadGenerator.Payload payload, ECCLevel eccLevel)
  43. {
  44. return CreateQrCode(payload.ToString(), eccLevel, false, false, payload.EciMode, payload.Version);
  45. }
  46. public QRCodeData CreateQrCode(string plainText, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1)
  47. {
  48. EncodingMode encoding = GetEncodingFromPlaintext(plainText, forceUtf8);
  49. var codedText = this.PlainTextToBinary(plainText, encoding, eciMode, utf8BOM, forceUtf8);
  50. var dataInputLength = this.GetDataLength(encoding, plainText, codedText, forceUtf8);
  51. int version = requestedVersion;
  52. if (version == -1)
  53. {
  54. version = this.GetVersion(dataInputLength, encoding, eccLevel);
  55. }
  56. string modeIndicator = String.Empty;
  57. if (eciMode != EciMode.Default)
  58. {
  59. modeIndicator = DecToBin((int)EncodingMode.ECI, 4);
  60. modeIndicator += DecToBin((int)eciMode, 8);
  61. }
  62. modeIndicator += DecToBin((int)encoding, 4);
  63. var countIndicator = DecToBin(dataInputLength, this.GetCountIndicatorLength(version, encoding));
  64. var bitString = modeIndicator + countIndicator;
  65. bitString += codedText;
  66. //Fill up data code word
  67. var eccInfo = this.capacityECCTable.Single(x => x.Version == version && x.ErrorCorrectionLevel.Equals(eccLevel));
  68. var dataLength = eccInfo.TotalDataCodewords * 8;
  69. var lengthDiff = dataLength - bitString.Length;
  70. if (lengthDiff > 0)
  71. bitString += new string('0', Math.Min(lengthDiff, 4));
  72. if ((bitString.Length % 8) != 0)
  73. bitString += new string('0', 8 - (bitString.Length % 8));
  74. while (bitString.Length < dataLength)
  75. bitString += "1110110000010001";
  76. if (bitString.Length > dataLength)
  77. bitString = bitString.Substring(0, dataLength);
  78. //Calculate error correction words
  79. var codeWordWithECC = new List<CodewordBlock>();
  80. for (var i = 0; i < eccInfo.BlocksInGroup1; i++)
  81. {
  82. var bitStr = bitString.Substring(i * eccInfo.CodewordsInGroup1 * 8, eccInfo.CodewordsInGroup1 * 8);
  83. var bitBlockList = this.BinaryStringToBitBlockList(bitStr);
  84. var bitBlockListDec = this.BinaryStringListToDecList(bitBlockList);
  85. var eccWordList = this.CalculateECCWords(bitStr, eccInfo);
  86. var eccWordListDec = this.BinaryStringListToDecList(eccWordList);
  87. codeWordWithECC.Add(
  88. new CodewordBlock(1,
  89. i + 1,
  90. bitStr,
  91. bitBlockList,
  92. eccWordList,
  93. bitBlockListDec,
  94. eccWordListDec)
  95. );
  96. }
  97. bitString = bitString.Substring(eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8);
  98. for (var i = 0; i < eccInfo.BlocksInGroup2; i++)
  99. {
  100. var bitStr = bitString.Substring(i * eccInfo.CodewordsInGroup2 * 8, eccInfo.CodewordsInGroup2 * 8);
  101. var bitBlockList = this.BinaryStringToBitBlockList(bitStr);
  102. var bitBlockListDec = this.BinaryStringListToDecList(bitBlockList);
  103. var eccWordList = this.CalculateECCWords(bitStr, eccInfo);
  104. var eccWordListDec = this.BinaryStringListToDecList(eccWordList);
  105. codeWordWithECC.Add(new CodewordBlock(2,
  106. i + 1,
  107. bitStr,
  108. bitBlockList,
  109. eccWordList,
  110. bitBlockListDec,
  111. eccWordListDec)
  112. );
  113. }
  114. //Interleave code words
  115. var interleavedWordsSb = new StringBuilder();
  116. for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
  117. {
  118. foreach (var codeBlock in codeWordWithECC)
  119. if (codeBlock.CodeWords.Count > i)
  120. interleavedWordsSb.Append(codeBlock.CodeWords[i]);
  121. }
  122. for (var i = 0; i < eccInfo.ECCPerBlock; i++)
  123. {
  124. foreach (var codeBlock in codeWordWithECC)
  125. if (codeBlock.ECCWords.Count > i)
  126. interleavedWordsSb.Append(codeBlock.ECCWords[i]);
  127. }
  128. interleavedWordsSb.Append(new string('0', this.remainderBits[version - 1]));
  129. var interleavedData = interleavedWordsSb.ToString();
  130. //Place interleaved data on module matrix
  131. var qr = new QRCodeData(version);
  132. var blockedModules = new List<Rectangle>();
  133. ModulePlacer.PlaceFinderPatterns(ref qr, ref blockedModules);
  134. ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, ref blockedModules);
  135. ModulePlacer.PlaceAlignmentPatterns(ref qr, this.alignmentPatternTable.Where(x => x.Version == version).Select(x => x.PatternPositions).First(), ref blockedModules);
  136. ModulePlacer.PlaceTimingPatterns(ref qr, ref blockedModules);
  137. ModulePlacer.PlaceDarkModule(ref qr, version, ref blockedModules);
  138. ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, ref blockedModules);
  139. ModulePlacer.PlaceDataWords(ref qr, interleavedData, ref blockedModules);
  140. var maskVersion = ModulePlacer.MaskCode(ref qr, version, ref blockedModules, eccLevel);
  141. var formatStr = GetFormatString(eccLevel, maskVersion);
  142. ModulePlacer.PlaceFormat(ref qr, formatStr);
  143. if (version >= 7)
  144. {
  145. var versionString = GetVersionString(version);
  146. ModulePlacer.PlaceVersion(ref qr, versionString);
  147. }
  148. ModulePlacer.AddQuietZone(ref qr);
  149. return qr;
  150. }
  151. private static string GetFormatString(ECCLevel level, int maskVersion)
  152. {
  153. var generator = "10100110111";
  154. var fStrMask = "101010000010010";
  155. var fStr = (level == ECCLevel.L) ? "01" : (level == ECCLevel.M) ? "00" : (level == ECCLevel.Q) ? "11" : "10";
  156. fStr += DecToBin(maskVersion, 3);
  157. var fStrEcc = fStr.PadRight(15, '0').TrimStart('0');
  158. while (fStrEcc.Length > 10)
  159. {
  160. var sb = new StringBuilder();
  161. generator = generator.PadRight(fStrEcc.Length, '0');
  162. for (var i = 0; i < fStrEcc.Length; i++)
  163. sb.Append((Convert.ToInt32(fStrEcc[i]) ^ Convert.ToInt32(generator[i])).ToString());
  164. fStrEcc = sb.ToString().TrimStart('0');
  165. }
  166. fStrEcc = fStrEcc.PadLeft(10, '0');
  167. fStr += fStrEcc;
  168. var sbMask = new StringBuilder();
  169. for (var i = 0; i < fStr.Length; i++)
  170. sbMask.Append((Convert.ToInt32(fStr[i]) ^ Convert.ToInt32(fStrMask[i])).ToString());
  171. return sbMask.ToString();
  172. }
  173. private static string GetVersionString(int version)
  174. {
  175. var generator = "1111100100101";
  176. var vStr = DecToBin(version, 6);
  177. var vStrEcc = vStr.PadRight(18, '0').TrimStart('0');
  178. while (vStrEcc.Length > 12)
  179. {
  180. var sb = new StringBuilder();
  181. generator = generator.PadRight(vStrEcc.Length, '0');
  182. for (var i = 0; i < vStrEcc.Length; i++)
  183. sb.Append((Convert.ToInt32(vStrEcc[i]) ^ Convert.ToInt32(generator[i])).ToString());
  184. vStrEcc = sb.ToString().TrimStart('0');
  185. }
  186. vStrEcc = vStrEcc.PadLeft(12, '0');
  187. vStr += vStrEcc;
  188. return vStr;
  189. }
  190. private static class ModulePlacer
  191. {
  192. public static void AddQuietZone(ref QRCodeData qrCode)
  193. {
  194. var quietLine = new bool[qrCode.ModuleMatrix.Count + 8];
  195. for (var i = 0; i < quietLine.Length; i++)
  196. quietLine[i] = false;
  197. for (var i = 0; i < 4; i++)
  198. qrCode.ModuleMatrix.Insert(0, new BitArray(quietLine));
  199. for (var i = 0; i < 4; i++)
  200. qrCode.ModuleMatrix.Add(new BitArray(quietLine));
  201. for (var i = 4; i < qrCode.ModuleMatrix.Count - 4; i++)
  202. {
  203. bool[] quietPart = { false, false, false, false };
  204. var tmpLine = new List<bool>(quietPart);
  205. tmpLine.AddRange(qrCode.ModuleMatrix[i].Cast<bool>());
  206. tmpLine.AddRange(quietPart);
  207. qrCode.ModuleMatrix[i] = new BitArray(tmpLine.ToArray());
  208. }
  209. }
  210. private static string ReverseString(string inp)
  211. {
  212. string newStr = string.Empty;
  213. if (inp.Length > 0)
  214. {
  215. for (int i = inp.Length - 1; i >= 0; i--)
  216. newStr += inp[i];
  217. }
  218. return newStr;
  219. }
  220. public static void PlaceVersion(ref QRCodeData qrCode, string versionStr)
  221. {
  222. var size = qrCode.ModuleMatrix.Count;
  223. var vStr = ReverseString(versionStr);
  224. for (var x = 0; x < 6; x++)
  225. {
  226. for (var y = 0; y < 3; y++)
  227. {
  228. qrCode.ModuleMatrix[y + size - 11][x] = vStr[x * 3 + y] == '1';
  229. qrCode.ModuleMatrix[x][y + size - 11] = vStr[x * 3 + y] == '1';
  230. }
  231. }
  232. }
  233. public static void PlaceFormat(ref QRCodeData qrCode, string formatStr)
  234. {
  235. var size = qrCode.ModuleMatrix.Count;
  236. var fStr = ReverseString(formatStr);
  237. var modules = new[,] {
  238. { 8, 0, size - 1, 8 },
  239. { 8, 1, size - 2, 8 },
  240. { 8, 2, size - 3, 8 },
  241. { 8, 3, size - 4, 8 },
  242. { 8, 4, size - 5, 8 },
  243. { 8, 5, size - 6, 8 },
  244. { 8, 7, size - 7, 8 },
  245. { 8, 8, size - 8, 8 },
  246. { 7, 8, 8, size - 7 },
  247. { 5, 8, 8, size - 6 },
  248. { 4, 8, 8, size - 5 },
  249. { 3, 8, 8, size - 4 },
  250. { 2, 8, 8, size - 3 },
  251. { 1, 8, 8, size - 2 },
  252. { 0, 8, 8, size - 1 } };
  253. for (var i = 0; i < 15; i++)
  254. {
  255. var p1 = new Point(modules[i, 0], modules[i, 1]);
  256. var p2 = new Point(modules[i, 2], modules[i, 3]);
  257. qrCode.ModuleMatrix[p1.Y][p1.X] = fStr[i] == '1';
  258. qrCode.ModuleMatrix[p2.Y][p2.X] = fStr[i] == '1';
  259. }
  260. }
  261. public static int MaskCode(ref QRCodeData qrCode, int version, ref List<Rectangle> blockedModules, ECCLevel eccLevel)
  262. {
  263. var patternName = string.Empty;
  264. var patternScore = 0;
  265. var size = qrCode.ModuleMatrix.Count;
  266. var methods = typeof(MaskPattern).GetMethods();
  267. foreach (var pattern in methods)
  268. {
  269. if (pattern.Name.Length == 8 && pattern.Name.StartsWith("Pattern"))
  270. {
  271. var qrTemp = new QRCodeData(version);
  272. for (var y = 0; y < size; y++)
  273. {
  274. for (var x = 0; x < size; x++)
  275. {
  276. qrTemp.ModuleMatrix[y][x] = qrCode.ModuleMatrix[y][x];
  277. }
  278. }
  279. var formatStr = GetFormatString(eccLevel, Convert.ToInt32((pattern.Name.Substring(7, 1))) - 1);
  280. ModulePlacer.PlaceFormat(ref qrTemp, formatStr);
  281. if (version >= 7)
  282. {
  283. var versionString = GetVersionString(version);
  284. ModulePlacer.PlaceVersion(ref qrTemp, versionString);
  285. }
  286. for (var x = 0; x < size; x++)
  287. {
  288. for (var y = 0; y < size; y++)
  289. {
  290. if (!IsBlocked(new Rectangle(x, y, 1, 1), blockedModules))
  291. {
  292. qrTemp.ModuleMatrix[y][x] ^= (bool)pattern.Invoke(null, new object[] { x, y });
  293. }
  294. }
  295. }
  296. var score = MaskPattern.Score(ref qrTemp);
  297. if (string.IsNullOrEmpty(patternName) || patternScore > score)
  298. {
  299. patternName = pattern.Name;
  300. patternScore = score;
  301. }
  302. }
  303. }
  304. var patterMethod = null as MethodInfo;
  305. foreach (var i in typeof(MaskPattern).GetMethods())
  306. {
  307. if (i.Name == patternName)
  308. {
  309. patterMethod = i;
  310. break;
  311. }
  312. }
  313. for (var x = 0; x < size; x++)
  314. {
  315. for (var y = 0; y < size; y++)
  316. {
  317. if (!IsBlocked(new Rectangle(x, y, 1, 1), blockedModules))
  318. {
  319. qrCode.ModuleMatrix[y][x] ^= (bool)patterMethod.Invoke(null, new object[] { x, y });
  320. }
  321. }
  322. }
  323. return Convert.ToInt32(patterMethod.Name.Substring(patterMethod.Name.Length - 1, 1)) - 1;
  324. }
  325. public static void PlaceDataWords(ref QRCodeData qrCode, string data, ref List<Rectangle> blockedModules)
  326. {
  327. var size = qrCode.ModuleMatrix.Count;
  328. var up = true;
  329. var datawords = new Queue<bool>();
  330. for (int i = 0; i < data.Length; i++)
  331. {
  332. datawords.Enqueue(data[i] != '0');
  333. }
  334. for (var x = size - 1; x >= 0; x = x - 2)
  335. {
  336. if (x == 6)
  337. x = 5;
  338. for (var yMod = 1; yMod <= size; yMod++)
  339. {
  340. int y;
  341. if (up)
  342. {
  343. y = size - yMod;
  344. if (datawords.Count > 0 && !IsBlocked(new Rectangle(x, y, 1, 1), blockedModules))
  345. qrCode.ModuleMatrix[y][x] = datawords.Dequeue();
  346. if (datawords.Count > 0 && x > 0 && !IsBlocked(new Rectangle(x - 1, y, 1, 1), blockedModules))
  347. qrCode.ModuleMatrix[y][x - 1] = datawords.Dequeue();
  348. }
  349. else
  350. {
  351. y = yMod - 1;
  352. if (datawords.Count > 0 && !IsBlocked(new Rectangle(x, y, 1, 1), blockedModules))
  353. qrCode.ModuleMatrix[y][x] = datawords.Dequeue();
  354. if (datawords.Count > 0 && x > 0 && !IsBlocked(new Rectangle(x - 1, y, 1, 1), blockedModules))
  355. qrCode.ModuleMatrix[y][x - 1] = datawords.Dequeue();
  356. }
  357. }
  358. up = !up;
  359. }
  360. }
  361. public static void ReserveSeperatorAreas(int size, ref List<Rectangle> blockedModules)
  362. {
  363. blockedModules.AddRange(new[]{
  364. new Rectangle(7, 0, 1, 8),
  365. new Rectangle(0, 7, 7, 1),
  366. new Rectangle(0, size-8, 8, 1),
  367. new Rectangle(7, size-7, 1, 7),
  368. new Rectangle(size-8, 0, 1, 8),
  369. new Rectangle(size-7, 7, 7, 1)
  370. });
  371. }
  372. public static void ReserveVersionAreas(int size, int version, ref List<Rectangle> blockedModules)
  373. {
  374. blockedModules.AddRange(new[]{
  375. new Rectangle(8, 0, 1, 6),
  376. new Rectangle(8, 7, 1, 1),
  377. new Rectangle(0, 8, 6, 1),
  378. new Rectangle(7, 8, 2, 1),
  379. new Rectangle(size-8, 8, 8, 1),
  380. new Rectangle(8, size-7, 1, 7)
  381. });
  382. if (version >= 7)
  383. {
  384. blockedModules.AddRange(new[]{
  385. new Rectangle(size-11, 0, 3, 6),
  386. new Rectangle(0, size-11, 6, 3)
  387. });
  388. }
  389. }
  390. public static void PlaceDarkModule(ref QRCodeData qrCode, int version, ref List<Rectangle> blockedModules)
  391. {
  392. qrCode.ModuleMatrix[4 * version + 9][8] = true;
  393. blockedModules.Add(new Rectangle(8, 4 * version + 9, 1, 1));
  394. }
  395. public static void PlaceFinderPatterns(ref QRCodeData qrCode, ref List<Rectangle> blockedModules)
  396. {
  397. var size = qrCode.ModuleMatrix.Count;
  398. int[] locations = { 0, 0, size - 7, 0, 0, size - 7 };
  399. for (var i = 0; i < 6; i = i + 2)
  400. {
  401. for (var x = 0; x < 7; x++)
  402. {
  403. for (var y = 0; y < 7; y++)
  404. {
  405. if (!(((x == 1 || x == 5) && y > 0 && y < 6) || (x > 0 && x < 6 && (y == 1 || y == 5))))
  406. {
  407. qrCode.ModuleMatrix[y + locations[i + 1]][x + locations[i]] = true;
  408. }
  409. }
  410. }
  411. blockedModules.Add(new Rectangle(locations[i], locations[i + 1], 7, 7));
  412. }
  413. }
  414. public static void PlaceAlignmentPatterns(ref QRCodeData qrCode, List<Point> alignmentPatternLocations, ref List<Rectangle> blockedModules)
  415. {
  416. foreach (var loc in alignmentPatternLocations)
  417. {
  418. var alignmentPatternRect = new Rectangle(loc.X, loc.Y, 5, 5);
  419. var blocked = false;
  420. foreach (var blockedRect in blockedModules)
  421. {
  422. if (Intersects(alignmentPatternRect, blockedRect))
  423. {
  424. blocked = true;
  425. break;
  426. }
  427. }
  428. if (blocked)
  429. continue;
  430. for (var x = 0; x < 5; x++)
  431. {
  432. for (var y = 0; y < 5; y++)
  433. {
  434. if (y == 0 || y == 4 || x == 0 || x == 4 || (x == 2 && y == 2))
  435. {
  436. qrCode.ModuleMatrix[loc.Y + y][loc.X + x] = true;
  437. }
  438. }
  439. }
  440. blockedModules.Add(new Rectangle(loc.X, loc.Y, 5, 5));
  441. }
  442. }
  443. public static void PlaceTimingPatterns(ref QRCodeData qrCode, ref List<Rectangle> blockedModules)
  444. {
  445. var size = qrCode.ModuleMatrix.Count;
  446. for (var i = 8; i < size - 8; i++)
  447. {
  448. if (i % 2 == 0)
  449. {
  450. qrCode.ModuleMatrix[6][i] = true;
  451. qrCode.ModuleMatrix[i][6] = true;
  452. }
  453. }
  454. blockedModules.AddRange(new[]{
  455. new Rectangle(6, 8, 1, size-16),
  456. new Rectangle(8, 6, size-16, 1)
  457. });
  458. }
  459. private static bool Intersects(Rectangle r1, Rectangle r2)
  460. {
  461. return r2.X < r1.X + r1.Width && r1.X < r2.X + r2.Width && r2.Y < r1.Y + r1.Height && r1.Y < r2.Y + r2.Height;
  462. }
  463. private static bool IsBlocked(Rectangle r1, List<Rectangle> blockedModules)
  464. {
  465. var isBlocked = false;
  466. foreach (var blockedMod in blockedModules)
  467. {
  468. if (Intersects(blockedMod, r1))
  469. isBlocked = true;
  470. }
  471. return isBlocked;
  472. }
  473. private static class MaskPattern
  474. {
  475. public static bool Pattern1(int x, int y)
  476. {
  477. return (x + y) % 2 == 0;
  478. }
  479. public static bool Pattern2(int x, int y)
  480. {
  481. return y % 2 == 0;
  482. }
  483. public static bool Pattern3(int x, int y)
  484. {
  485. return x % 3 == 0;
  486. }
  487. public static bool Pattern4(int x, int y)
  488. {
  489. return (x + y) % 3 == 0;
  490. }
  491. public static bool Pattern5(int x, int y)
  492. {
  493. return ((int)(Math.Floor(y / 2d) + Math.Floor(x / 3d)) % 2) == 0;
  494. }
  495. public static bool Pattern6(int x, int y)
  496. {
  497. return ((x * y) % 2) + ((x * y) % 3) == 0;
  498. }
  499. public static bool Pattern7(int x, int y)
  500. {
  501. return (((x * y) % 2) + ((x * y) % 3)) % 2 == 0;
  502. }
  503. public static bool Pattern8(int x, int y)
  504. {
  505. return (((x + y) % 2) + ((x * y) % 3)) % 2 == 0;
  506. }
  507. public static int Score(ref QRCodeData qrCode)
  508. {
  509. int score1 = 0,
  510. score2 = 0,
  511. score3 = 0,
  512. score4 = 0;
  513. var size = qrCode.ModuleMatrix.Count;
  514. //Penalty 1
  515. for (var y = 0; y < size; y++)
  516. {
  517. var modInRow = 0;
  518. var modInColumn = 0;
  519. var lastValRow = qrCode.ModuleMatrix[y][0];
  520. var lastValColumn = qrCode.ModuleMatrix[0][y];
  521. for (var x = 0; x < size; x++)
  522. {
  523. if (qrCode.ModuleMatrix[y][x] == lastValRow)
  524. modInRow++;
  525. else
  526. modInRow = 1;
  527. if (modInRow == 5)
  528. score1 += 3;
  529. else if (modInRow > 5)
  530. score1++;
  531. lastValRow = qrCode.ModuleMatrix[y][x];
  532. if (qrCode.ModuleMatrix[x][y] == lastValColumn)
  533. modInColumn++;
  534. else
  535. modInColumn = 1;
  536. if (modInColumn == 5)
  537. score1 += 3;
  538. else if (modInColumn > 5)
  539. score1++;
  540. lastValColumn = qrCode.ModuleMatrix[x][y];
  541. }
  542. }
  543. //Penalty 2
  544. for (var y = 0; y < size - 1; y++)
  545. {
  546. for (var x = 0; x < size - 1; x++)
  547. {
  548. if (qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y][x + 1] &&
  549. qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x] &&
  550. qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x + 1])
  551. score2 += 3;
  552. }
  553. }
  554. //Penalty 3
  555. for (var y = 0; y < size; y++)
  556. {
  557. for (var x = 0; x < size - 10; x++)
  558. {
  559. if ((qrCode.ModuleMatrix[y][x] &&
  560. !qrCode.ModuleMatrix[y][x + 1] &&
  561. qrCode.ModuleMatrix[y][x + 2] &&
  562. qrCode.ModuleMatrix[y][x + 3] &&
  563. qrCode.ModuleMatrix[y][x + 4] &&
  564. !qrCode.ModuleMatrix[y][x + 5] &&
  565. qrCode.ModuleMatrix[y][x + 6] &&
  566. !qrCode.ModuleMatrix[y][x + 7] &&
  567. !qrCode.ModuleMatrix[y][x + 8] &&
  568. !qrCode.ModuleMatrix[y][x + 9] &&
  569. !qrCode.ModuleMatrix[y][x + 10]) ||
  570. (!qrCode.ModuleMatrix[y][x] &&
  571. !qrCode.ModuleMatrix[y][x + 1] &&
  572. !qrCode.ModuleMatrix[y][x + 2] &&
  573. !qrCode.ModuleMatrix[y][x + 3] &&
  574. qrCode.ModuleMatrix[y][x + 4] &&
  575. !qrCode.ModuleMatrix[y][x + 5] &&
  576. qrCode.ModuleMatrix[y][x + 6] &&
  577. qrCode.ModuleMatrix[y][x + 7] &&
  578. qrCode.ModuleMatrix[y][x + 8] &&
  579. !qrCode.ModuleMatrix[y][x + 9] &&
  580. qrCode.ModuleMatrix[y][x + 10]))
  581. {
  582. score3 += 40;
  583. }
  584. if ((qrCode.ModuleMatrix[x][y] &&
  585. !qrCode.ModuleMatrix[x + 1][y] &&
  586. qrCode.ModuleMatrix[x + 2][y] &&
  587. qrCode.ModuleMatrix[x + 3][y] &&
  588. qrCode.ModuleMatrix[x + 4][y] &&
  589. !qrCode.ModuleMatrix[x + 5][y] &&
  590. qrCode.ModuleMatrix[x + 6][y] &&
  591. !qrCode.ModuleMatrix[x + 7][y] &&
  592. !qrCode.ModuleMatrix[x + 8][y] &&
  593. !qrCode.ModuleMatrix[x + 9][y] &&
  594. !qrCode.ModuleMatrix[x + 10][y]) ||
  595. (!qrCode.ModuleMatrix[x][y] &&
  596. !qrCode.ModuleMatrix[x + 1][y] &&
  597. !qrCode.ModuleMatrix[x + 2][y] &&
  598. !qrCode.ModuleMatrix[x + 3][y] &&
  599. qrCode.ModuleMatrix[x + 4][y] &&
  600. !qrCode.ModuleMatrix[x + 5][y] &&
  601. qrCode.ModuleMatrix[x + 6][y] &&
  602. qrCode.ModuleMatrix[x + 7][y] &&
  603. qrCode.ModuleMatrix[x + 8][y] &&
  604. !qrCode.ModuleMatrix[x + 9][y] &&
  605. qrCode.ModuleMatrix[x + 10][y]))
  606. {
  607. score3 += 40;
  608. }
  609. }
  610. }
  611. //Penalty 4
  612. double blackModules = 0;
  613. foreach (var row in qrCode.ModuleMatrix)
  614. foreach (bool bit in row)
  615. if (bit)
  616. blackModules++;
  617. var percent = (blackModules / (qrCode.ModuleMatrix.Count * qrCode.ModuleMatrix.Count)) * 100;
  618. var prevMultipleOf5 = Math.Abs((int)Math.Floor(percent / 5) * 5 - 50) / 5;
  619. var nextMultipleOf5 = Math.Abs((int)Math.Floor(percent / 5) * 5 - 45) / 5;
  620. score4 = Math.Min(prevMultipleOf5, nextMultipleOf5) * 10;
  621. return score1 + score2 + score3 + score4;
  622. }
  623. }
  624. }
  625. private List<string> CalculateECCWords(string bitString, ECCInfo eccInfo)
  626. {
  627. var eccWords = eccInfo.ECCPerBlock;
  628. var messagePolynom = this.CalculateMessagePolynom(bitString);
  629. var generatorPolynom = this.CalculateGeneratorPolynom(eccWords);
  630. for (var i = 0; i < messagePolynom.PolyItems.Count; i++)
  631. messagePolynom.PolyItems[i] = new PolynomItem(messagePolynom.PolyItems[i].Coefficient,
  632. messagePolynom.PolyItems[i].Exponent + eccWords);
  633. for (var i = 0; i < generatorPolynom.PolyItems.Count; i++)
  634. generatorPolynom.PolyItems[i] = new PolynomItem(generatorPolynom.PolyItems[i].Coefficient,
  635. generatorPolynom.PolyItems[i].Exponent + (messagePolynom.PolyItems.Count - 1));
  636. var leadTermSource = messagePolynom;
  637. for (var i = 0; (leadTermSource.PolyItems.Count > 0 && leadTermSource.PolyItems[leadTermSource.PolyItems.Count - 1].Exponent > 0); i++)
  638. {
  639. if (leadTermSource.PolyItems[0].Coefficient == 0)
  640. {
  641. leadTermSource.PolyItems.RemoveAt(0);
  642. leadTermSource.PolyItems.Add(new PolynomItem(0, leadTermSource.PolyItems[leadTermSource.PolyItems.Count - 1].Exponent - 1));
  643. }
  644. else
  645. {
  646. var resPoly = this.MultiplyGeneratorPolynomByLeadterm(generatorPolynom, this.ConvertToAlphaNotation(leadTermSource).PolyItems[0], i);
  647. resPoly = this.ConvertToDecNotation(resPoly);
  648. resPoly = this.XORPolynoms(leadTermSource, resPoly);
  649. leadTermSource = resPoly;
  650. }
  651. }
  652. return leadTermSource.PolyItems.Select(x => DecToBin(x.Coefficient, 8)).List();
  653. }
  654. private Polynom ConvertToAlphaNotation(Polynom poly)
  655. {
  656. var newPoly = new Polynom();
  657. for (var i = 0; i < poly.PolyItems.Count; i++)
  658. newPoly.PolyItems.Add(
  659. new PolynomItem(
  660. (poly.PolyItems[i].Coefficient != 0
  661. ? this.GetAlphaExpFromIntVal(poly.PolyItems[i].Coefficient)
  662. : 0), poly.PolyItems[i].Exponent));
  663. return newPoly;
  664. }
  665. private Polynom ConvertToDecNotation(Polynom poly)
  666. {
  667. var newPoly = new Polynom();
  668. for (var i = 0; i < poly.PolyItems.Count; i++)
  669. newPoly.PolyItems.Add(new PolynomItem(this.GetIntValFromAlphaExp(poly.PolyItems[i].Coefficient), poly.PolyItems[i].Exponent));
  670. return newPoly;
  671. }
  672. private int GetVersion(int length, EncodingMode encMode, ECCLevel eccLevel)
  673. {
  674. var version = this.capacityTable.Where(
  675. x => x.Details.Count(
  676. y => (y.ErrorCorrectionLevel == eccLevel
  677. && y.CapacityDict[encMode] >= Convert.ToInt32(length)
  678. )
  679. ) > 0
  680. ).Select(x => new
  681. {
  682. version = x.Version,
  683. capacity = x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel)
  684. .CapacityDict[encMode]
  685. }).Min(x => x.version);
  686. return version;
  687. }
  688. private EncodingMode GetEncodingFromPlaintext(string plainText, bool forceUtf8)
  689. {
  690. EncodingMode result = EncodingMode.Numeric;
  691. foreach (char c in plainText)
  692. {
  693. if (forceUtf8 || !Methods.Contains(alphanumEncTable, c))
  694. return EncodingMode.Byte;
  695. if (!Methods.Contains(numTable, c))
  696. result = EncodingMode.Alphanumeric;
  697. }
  698. return result;
  699. }
  700. private Polynom CalculateMessagePolynom(string bitString)
  701. {
  702. var messagePol = new Polynom();
  703. for (var i = bitString.Length / 8 - 1; i >= 0; i--)
  704. {
  705. messagePol.PolyItems.Add(new PolynomItem(this.BinToDec(bitString.Substring(0, 8)), i));
  706. bitString = bitString.Remove(0, 8);
  707. }
  708. return messagePol;
  709. }
  710. private Polynom CalculateGeneratorPolynom(int numEccWords)
  711. {
  712. var generatorPolynom = new Polynom();
  713. generatorPolynom.PolyItems.AddRange(new[]{
  714. new PolynomItem(0,1),
  715. new PolynomItem(0,0)
  716. });
  717. for (var i = 1; i <= numEccWords - 1; i++)
  718. {
  719. var multiplierPolynom = new Polynom();
  720. multiplierPolynom.PolyItems.AddRange(new[]{
  721. new PolynomItem(0,1),
  722. new PolynomItem(i,0)
  723. });
  724. generatorPolynom = this.MultiplyAlphaPolynoms(generatorPolynom, multiplierPolynom);
  725. }
  726. return generatorPolynom;
  727. }
  728. private List<string> BinaryStringToBitBlockList(string bitString)
  729. {
  730. return new List<char>(bitString.ToCharArray()).Select((x, i) => new { Index = i, Value = x })
  731. .GroupBy(x => x.Index / 8)
  732. .Select(x => String.Join("", x.Select(v => v.Value.ToString()).ToArray()))
  733. .List();
  734. }
  735. private List<int> BinaryStringListToDecList(List<string> binaryStringList)
  736. {
  737. // return binaryStringList.Select(binaryString => this.BinToDec(binaryString));
  738. var newList = new List<int>(binaryStringList.Count);
  739. for (var i = 0; i < binaryStringList.Count; i++) newList.Add(BinToDec(binaryStringList[i]));
  740. return newList;
  741. }
  742. private int BinToDec(string binStr)
  743. {
  744. return Convert.ToInt32(binStr, 2);
  745. }
  746. private static string DecToBin(int decNum)
  747. {
  748. return Convert.ToString(decNum, 2);
  749. }
  750. private static string DecToBin(int decNum, int padLeftUpTo)
  751. {
  752. var binStr = DecToBin(decNum);
  753. return binStr.PadLeft(padLeftUpTo, '0');
  754. }
  755. private int GetCountIndicatorLength(int version, EncodingMode encMode)
  756. {
  757. if (version < 10)
  758. {
  759. if (encMode.Equals(EncodingMode.Numeric))
  760. return 10;
  761. else if (encMode.Equals(EncodingMode.Alphanumeric))
  762. return 9;
  763. else
  764. return 8;
  765. }
  766. else if (version < 27)
  767. {
  768. if (encMode.Equals(EncodingMode.Numeric))
  769. return 12;
  770. else if (encMode.Equals(EncodingMode.Alphanumeric))
  771. return 11;
  772. else if (encMode.Equals(EncodingMode.Byte))
  773. return 16;
  774. else
  775. return 10;
  776. }
  777. else
  778. {
  779. if (encMode.Equals(EncodingMode.Numeric))
  780. return 14;
  781. else if (encMode.Equals(EncodingMode.Alphanumeric))
  782. return 13;
  783. else if (encMode.Equals(EncodingMode.Byte))
  784. return 16;
  785. else
  786. return 12;
  787. }
  788. }
  789. private int GetDataLength(EncodingMode encoding, string plainText, string codedText, bool forceUtf8)
  790. {
  791. return forceUtf8 || this.IsUtf8(encoding, plainText) ? (codedText.Length / 8) : plainText.Length;
  792. }
  793. private bool IsUtf8(EncodingMode encoding, string plainText)
  794. {
  795. return (encoding == EncodingMode.Byte && !this.IsValidISO(plainText));
  796. }
  797. private bool IsValidISO(string input)
  798. {
  799. var bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(input);
  800. //var result = Encoding.GetEncoding("ISO-8859-1").GetString(bytes);
  801. var result = Encoding.GetEncoding("ISO-8859-1").GetString(bytes, 0, bytes.Length);
  802. return String.Equals(input, result);
  803. }
  804. private string PlainTextToBinary(string plainText, EncodingMode encMode, EciMode eciMode, bool utf8BOM, bool forceUtf8)
  805. {
  806. switch (encMode)
  807. {
  808. case EncodingMode.Alphanumeric:
  809. return PlainTextToBinaryAlphanumeric(plainText);
  810. case EncodingMode.Numeric:
  811. return PlainTextToBinaryNumeric(plainText);
  812. case EncodingMode.Byte:
  813. return PlainTextToBinaryByte(plainText, eciMode, utf8BOM, forceUtf8);
  814. case EncodingMode.Kanji:
  815. return string.Empty;
  816. case EncodingMode.ECI:
  817. default:
  818. return string.Empty;
  819. }
  820. }
  821. private string PlainTextToBinaryNumeric(string plainText)
  822. {
  823. var codeText = string.Empty;
  824. while (plainText.Length >= 3)
  825. {
  826. var dec = Convert.ToInt32(plainText.Substring(0, 3));
  827. codeText += DecToBin(dec, 10);
  828. plainText = plainText.Substring(3);
  829. }
  830. if (plainText.Length == 2)
  831. {
  832. var dec = Convert.ToInt32(plainText);
  833. codeText += DecToBin(dec, 7);
  834. }
  835. else if (plainText.Length == 1)
  836. {
  837. var dec = Convert.ToInt32(plainText);
  838. codeText += DecToBin(dec, 4);
  839. }
  840. return codeText;
  841. }
  842. private string PlainTextToBinaryAlphanumeric(string plainText)
  843. {
  844. var codeText = string.Empty;
  845. while (plainText.Length >= 2)
  846. {
  847. var token = plainText.Substring(0, 2);
  848. var dec = this.alphanumEncDict[token[0]] * 45 + this.alphanumEncDict[token[1]];
  849. codeText += DecToBin(dec, 11);
  850. plainText = plainText.Substring(2);
  851. }
  852. if (plainText.Length > 0)
  853. {
  854. codeText += DecToBin(this.alphanumEncDict[plainText[0]], 6);
  855. }
  856. return codeText;
  857. }
  858. private string PlainTextToBinaryECI(string plainText)
  859. {
  860. var codeText = string.Empty;
  861. byte[] _bytes = Encoding.GetEncoding("ascii").GetBytes(plainText);
  862. foreach (byte _byte in _bytes)
  863. {
  864. codeText += DecToBin(_byte, 8);
  865. }
  866. return codeText;
  867. }
  868. private string ConvertToIso8859(string value, string Iso = "ISO-8859-2")
  869. {
  870. Encoding iso = Encoding.GetEncoding(Iso);
  871. Encoding utf8 = Encoding.UTF8;
  872. byte[] utfBytes = utf8.GetBytes(value);
  873. byte[] isoBytes = Encoding.Convert(utf8, iso, utfBytes);
  874. #if !PCL
  875. return iso.GetString(isoBytes);
  876. #else
  877. return iso.GetString(isoBytes, 0, isoBytes.Length);
  878. #endif
  879. }
  880. private string PlainTextToBinaryByte(string plainText, EciMode eciMode, bool utf8BOM, bool forceUtf8)
  881. {
  882. byte[] codeBytes;
  883. var codeText = string.Empty;
  884. if (this.IsValidISO(plainText) && !forceUtf8)
  885. codeBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(plainText);
  886. else
  887. {
  888. switch (eciMode)
  889. {
  890. case EciMode.Iso8859_1:
  891. codeBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(ConvertToIso8859(plainText, "ISO-8859-1"));
  892. break;
  893. case EciMode.Iso8859_2:
  894. codeBytes = Encoding.GetEncoding("ISO-8859-2").GetBytes(ConvertToIso8859(plainText, "ISO-8859-2"));
  895. break;
  896. case EciMode.Default:
  897. case EciMode.Utf8:
  898. default:
  899. codeBytes = utf8BOM ? Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(plainText)).ToArray() : Encoding.UTF8.GetBytes(plainText);
  900. break;
  901. }
  902. }
  903. foreach (var b in codeBytes)
  904. codeText += DecToBin(b, 8);
  905. return codeText;
  906. }
  907. private Polynom XORPolynoms(Polynom messagePolynom, Polynom resPolynom)
  908. {
  909. var resultPolynom = new Polynom();
  910. Polynom longPoly, shortPoly;
  911. if (messagePolynom.PolyItems.Count >= resPolynom.PolyItems.Count)
  912. {
  913. longPoly = messagePolynom;
  914. shortPoly = resPolynom;
  915. }
  916. else
  917. {
  918. longPoly = resPolynom;
  919. shortPoly = messagePolynom;
  920. }
  921. for (var i = 0; i < longPoly.PolyItems.Count; i++)
  922. {
  923. var polItemRes = new PolynomItem
  924. (
  925. longPoly.PolyItems[i].Coefficient ^
  926. (shortPoly.PolyItems.Count > i ? shortPoly.PolyItems[i].Coefficient : 0),
  927. messagePolynom.PolyItems[0].Exponent - i
  928. );
  929. resultPolynom.PolyItems.Add(polItemRes);
  930. }
  931. resultPolynom.PolyItems.RemoveAt(0);
  932. return resultPolynom;
  933. }
  934. private Polynom MultiplyGeneratorPolynomByLeadterm(Polynom genPolynom, PolynomItem leadTerm, int lowerExponentBy)
  935. {
  936. var resultPolynom = new Polynom();
  937. foreach (var polItemBase in genPolynom.PolyItems)
  938. {
  939. var polItemRes = new PolynomItem(
  940. (polItemBase.Coefficient + leadTerm.Coefficient) % 255,
  941. polItemBase.Exponent - lowerExponentBy
  942. );
  943. resultPolynom.PolyItems.Add(polItemRes);
  944. }
  945. return resultPolynom;
  946. }
  947. private Polynom MultiplyAlphaPolynoms(Polynom polynomBase, Polynom polynomMultiplier)
  948. {
  949. var resultPolynom = new Polynom();
  950. foreach (var polItemBase in polynomMultiplier.PolyItems)
  951. {
  952. foreach (var polItemMulti in polynomBase.PolyItems)
  953. {
  954. var polItemRes = new PolynomItem
  955. (
  956. ShrinkAlphaExp(polItemBase.Coefficient + polItemMulti.Coefficient),
  957. (polItemBase.Exponent + polItemMulti.Exponent)
  958. );
  959. resultPolynom.PolyItems.Add(polItemRes);
  960. }
  961. }
  962. var exponentsToGlue = resultPolynom.PolyItems.GroupBy(x => x.Exponent).Where(x => x.Count() > 1).Select(x => x.First().Exponent);
  963. var gluedPolynoms = new List<PolynomItem>();
  964. var toGlue = exponentsToGlue as IList<int> ?? exponentsToGlue.List();
  965. foreach (var exponent in toGlue)
  966. {
  967. var coefficient = resultPolynom.PolyItems.Where(x => x.Exponent == exponent).Aggregate(0, (current, polynomOld)
  968. => current ^ this.GetIntValFromAlphaExp(polynomOld.Coefficient));
  969. var polynomFixed = new PolynomItem(this.GetAlphaExpFromIntVal(coefficient), exponent);
  970. gluedPolynoms.Add(polynomFixed);
  971. }
  972. resultPolynom.PolyItems.RemoveAll(x => toGlue.Contains(x.Exponent));
  973. resultPolynom.PolyItems.AddRange(gluedPolynoms);
  974. resultPolynom.PolyItems = resultPolynom.PolyItems.OrderByDescending(x => x.Exponent).List();
  975. return resultPolynom;
  976. }
  977. private int GetIntValFromAlphaExp(int exp)
  978. {
  979. return this.galoisField.Where(alog => alog.ExponentAlpha == exp).Select(alog => alog.IntegerValue).First();
  980. }
  981. private int GetAlphaExpFromIntVal(int intVal)
  982. {
  983. return this.galoisField.Where(alog => alog.IntegerValue == intVal).Select(alog => alog.ExponentAlpha).First();
  984. }
  985. private static int ShrinkAlphaExp(int alphaExp)
  986. {
  987. // ReSharper disable once PossibleLossOfFraction
  988. return (int)((alphaExp % 256) + Math.Floor((double)(alphaExp / 256)));
  989. }
  990. private void CreateAlphanumEncDict()
  991. {
  992. this.alphanumEncDict = new Dictionary<char, int>();
  993. for (int i = 0; i < alphanumEncTable.Length; i++)
  994. this.alphanumEncDict.Add(alphanumEncTable[i], i);
  995. }
  996. private void CreateAlignmentPatternTable()
  997. {
  998. this.alignmentPatternTable = new List<AlignmentPattern>();
  999. for (var i = 0; i < (7 * 40); i = i + 7)
  1000. {
  1001. var points = new List<Point>();
  1002. for (var x = 0; x < 7; x++)
  1003. {
  1004. if (this.alignmentPatternBaseValues[i + x] != 0)
  1005. {
  1006. for (var y = 0; y < 7; y++)
  1007. {
  1008. if (this.alignmentPatternBaseValues[i + y] != 0)
  1009. {
  1010. var p = new Point(this.alignmentPatternBaseValues[i + x] - 2, this.alignmentPatternBaseValues[i + y] - 2);
  1011. if (!points.Contains(p))
  1012. points.Add(p);
  1013. }
  1014. }
  1015. }
  1016. }
  1017. this.alignmentPatternTable.Add(new AlignmentPattern()
  1018. {
  1019. Version = (i + 7) / 7,
  1020. PatternPositions = points
  1021. }
  1022. );
  1023. }
  1024. }
  1025. private void CreateCapacityECCTable()
  1026. {
  1027. this.capacityECCTable = new List<ECCInfo>();
  1028. for (var i = 0; i < (4 * 6 * 40); i = i + (4 * 6))
  1029. {
  1030. this.capacityECCTable.AddRange(
  1031. new[]
  1032. {
  1033. new ECCInfo(
  1034. (i+24) / 24,
  1035. ECCLevel.L,
  1036. this.capacityECCBaseValues[i],
  1037. this.capacityECCBaseValues[i+1],
  1038. this.capacityECCBaseValues[i+2],
  1039. this.capacityECCBaseValues[i+3],
  1040. this.capacityECCBaseValues[i+4],
  1041. this.capacityECCBaseValues[i+5]),
  1042. new ECCInfo
  1043. (
  1044. version: (i + 24) / 24,
  1045. errorCorrectionLevel: ECCLevel.M,
  1046. totalDataCodewords: this.capacityECCBaseValues[i+6],
  1047. eccPerBlock: this.capacityECCBaseValues[i+7],
  1048. blocksInGroup1: this.capacityECCBaseValues[i+8],
  1049. codewordsInGroup1: this.capacityECCBaseValues[i+9],
  1050. blocksInGroup2: this.capacityECCBaseValues[i+10],
  1051. codewordsInGroup2: this.capacityECCBaseValues[i+11]
  1052. ),
  1053. new ECCInfo
  1054. (
  1055. version: (i + 24) / 24,
  1056. errorCorrectionLevel: ECCLevel.Q,
  1057. totalDataCodewords: this.capacityECCBaseValues[i+12],
  1058. eccPerBlock: this.capacityECCBaseValues[i+13],
  1059. blocksInGroup1: this.capacityECCBaseValues[i+14],
  1060. codewordsInGroup1: this.capacityECCBaseValues[i+15],
  1061. blocksInGroup2: this.capacityECCBaseValues[i+16],
  1062. codewordsInGroup2: this.capacityECCBaseValues[i+17]
  1063. ),
  1064. new ECCInfo
  1065. (
  1066. version: (i + 24) / 24,
  1067. errorCorrectionLevel: ECCLevel.H,
  1068. totalDataCodewords: this.capacityECCBaseValues[i+18],
  1069. eccPerBlock: this.capacityECCBaseValues[i+19],
  1070. blocksInGroup1: this.capacityECCBaseValues[i+20],
  1071. codewordsInGroup1: this.capacityECCBaseValues[i+21],
  1072. blocksInGroup2: this.capacityECCBaseValues[i+22],
  1073. codewordsInGroup2: this.capacityECCBaseValues[i+23]
  1074. )
  1075. });
  1076. }
  1077. }
  1078. private void CreateCapacityTable()
  1079. {
  1080. this.capacityTable = new List<VersionInfo>();
  1081. for (var i = 0; i < (16 * 40); i = i + 16)
  1082. {
  1083. this.capacityTable.Add(new VersionInfo(
  1084. (i + 16) / 16,
  1085. new List<VersionInfoDetails>
  1086. {
  1087. new VersionInfoDetails(
  1088. ECCLevel.L,
  1089. new Dictionary<EncodingMode,int>(){
  1090. { EncodingMode.Numeric, this.capacityBaseValues[i] },
  1091. { EncodingMode.Alphanumeric, this.capacityBaseValues[i+1] },
  1092. { EncodingMode.Byte, this.capacityBaseValues[i+2] },
  1093. { EncodingMode.Kanji, this.capacityBaseValues[i+3] },
  1094. }
  1095. ),
  1096. new VersionInfoDetails(
  1097. ECCLevel.M,
  1098. new Dictionary<EncodingMode,int>(){
  1099. { EncodingMode.Numeric, this.capacityBaseValues[i+4] },
  1100. { EncodingMode.Alphanumeric, this.capacityBaseValues[i+5] },
  1101. { EncodingMode.Byte, this.capacityBaseValues[i+6] },
  1102. { EncodingMode.Kanji, this.capacityBaseValues[i+7] },
  1103. }
  1104. ),
  1105. new VersionInfoDetails(
  1106. ECCLevel.Q,
  1107. new Dictionary<EncodingMode,int>(){
  1108. { EncodingMode.Numeric, this.capacityBaseValues[i+8] },
  1109. { EncodingMode.Alphanumeric, this.capacityBaseValues[i+9] },
  1110. { EncodingMode.Byte, this.capacityBaseValues[i+10] },
  1111. { EncodingMode.Kanji, this.capacityBaseValues[i+11] },
  1112. }
  1113. ),
  1114. new VersionInfoDetails(
  1115. ECCLevel.H,
  1116. new Dictionary<EncodingMode,int>(){
  1117. { EncodingMode.Numeric, this.capacityBaseValues[i+12] },
  1118. { EncodingMode.Alphanumeric, this.capacityBaseValues[i+13] },
  1119. { EncodingMode.Byte, this.capacityBaseValues[i+14] },
  1120. { EncodingMode.Kanji, this.capacityBaseValues[i+15] },
  1121. }
  1122. )
  1123. }
  1124. ));
  1125. }
  1126. }
  1127. private void CreateAntilogTable()
  1128. {
  1129. this.galoisField = new List<Antilog>();
  1130. int gfItem = 1;
  1131. for (var i = 0; i < 256; i++)
  1132. {
  1133. this.galoisField.Add(new Antilog(i, gfItem));
  1134. gfItem *= 2;
  1135. if (gfItem > 255)
  1136. gfItem ^= 285;
  1137. }
  1138. }
  1139. /// <summary>
  1140. /// Error correction level. These define the tolerance levels for how much of the code can be lost before the code cannot be recovered.
  1141. /// </summary>
  1142. public enum ECCLevel
  1143. {
  1144. /// <summary>
  1145. /// 7% may be lost before recovery is not possible
  1146. /// </summary>
  1147. L,
  1148. /// <summary>
  1149. /// 15% may be lost before recovery is not possible
  1150. /// </summary>
  1151. M,
  1152. /// <summary>
  1153. /// 25% may be lost before recovery is not possible
  1154. /// </summary>
  1155. Q,
  1156. /// <summary>
  1157. /// 30% may be lost before recovery is not possible
  1158. /// </summary>
  1159. H
  1160. }
  1161. private enum EncodingMode
  1162. {
  1163. Numeric = 1,
  1164. Alphanumeric = 2,
  1165. Byte = 4,
  1166. Kanji = 8,
  1167. ECI = 7
  1168. }
  1169. private struct AlignmentPattern
  1170. {
  1171. public int Version;
  1172. public List<Point> PatternPositions;
  1173. }
  1174. private struct CodewordBlock
  1175. {
  1176. public CodewordBlock(int groupNumber, int blockNumber, string bitString, List<string> codeWords,
  1177. List<string> eccWords, List<int> codeWordsInt, List<int> eccWordsInt)
  1178. {
  1179. this.GroupNumber = groupNumber;
  1180. this.BlockNumber = blockNumber;
  1181. this.BitString = bitString;
  1182. this.CodeWords = codeWords;
  1183. this.ECCWords = eccWords;
  1184. this.CodeWordsInt = codeWordsInt;
  1185. this.ECCWordsInt = eccWordsInt;
  1186. }
  1187. public int GroupNumber { get; }
  1188. public int BlockNumber { get; }
  1189. public string BitString { get; }
  1190. public List<string> CodeWords { get; }
  1191. public List<int> CodeWordsInt { get; }
  1192. public List<string> ECCWords { get; }
  1193. public List<int> ECCWordsInt { get; }
  1194. }
  1195. private struct ECCInfo
  1196. {
  1197. public ECCInfo(int version, ECCLevel errorCorrectionLevel, int totalDataCodewords, int eccPerBlock, int blocksInGroup1,
  1198. int codewordsInGroup1, int blocksInGroup2, int codewordsInGroup2)
  1199. {
  1200. this.Version = version;
  1201. this.ErrorCorrectionLevel = errorCorrectionLevel;
  1202. this.TotalDataCodewords = totalDataCodewords;
  1203. this.ECCPerBlock = eccPerBlock;
  1204. this.BlocksInGroup1 = blocksInGroup1;
  1205. this.CodewordsInGroup1 = codewordsInGroup1;
  1206. this.BlocksInGroup2 = blocksInGroup2;
  1207. this.CodewordsInGroup2 = codewordsInGroup2;
  1208. }
  1209. public int Version { get; }
  1210. public ECCLevel ErrorCorrectionLevel { get; }
  1211. public int TotalDataCodewords { get; }
  1212. public int ECCPerBlock { get; }
  1213. public int BlocksInGroup1 { get; }
  1214. public int CodewordsInGroup1 { get; }
  1215. public int BlocksInGroup2 { get; }
  1216. public int CodewordsInGroup2 { get; }
  1217. }
  1218. private struct VersionInfo
  1219. {
  1220. public VersionInfo(int version, List<VersionInfoDetails> versionInfoDetails)
  1221. {
  1222. this.Version = version;
  1223. this.Details = versionInfoDetails;
  1224. }
  1225. public int Version { get; }
  1226. public List<VersionInfoDetails> Details { get; }
  1227. }
  1228. private struct VersionInfoDetails
  1229. {
  1230. public VersionInfoDetails(ECCLevel errorCorrectionLevel, Dictionary<EncodingMode, int> capacityDict)
  1231. {
  1232. this.ErrorCorrectionLevel = errorCorrectionLevel;
  1233. this.CapacityDict = capacityDict;
  1234. }
  1235. public ECCLevel ErrorCorrectionLevel { get; }
  1236. public Dictionary<EncodingMode, int> CapacityDict { get; }
  1237. }
  1238. private struct Antilog
  1239. {
  1240. public Antilog(int exponentAlpha, int integerValue)
  1241. {
  1242. this.ExponentAlpha = exponentAlpha;
  1243. this.IntegerValue = integerValue;
  1244. }
  1245. public int ExponentAlpha { get; }
  1246. public int IntegerValue { get; }
  1247. }
  1248. private struct PolynomItem
  1249. {
  1250. public PolynomItem(int coefficient, int exponent)
  1251. {
  1252. this.Coefficient = coefficient;
  1253. this.Exponent = exponent;
  1254. }
  1255. public int Coefficient { get; }
  1256. public int Exponent { get; }
  1257. }
  1258. private class Polynom
  1259. {
  1260. public Polynom()
  1261. {
  1262. this.PolyItems = new List<PolynomItem>();
  1263. }
  1264. public List<PolynomItem> PolyItems { get; set; }
  1265. public override string ToString()
  1266. {
  1267. var sb = new StringBuilder();
  1268. //this.PolyItems.ForEach(x => sb.Append("a^" + x.Coefficient + "*x^" + x.Exponent + " + "));
  1269. foreach (var polyItem in this.PolyItems)
  1270. {
  1271. sb.Append("a^" + polyItem.Coefficient + "*x^" + polyItem.Exponent + " + ");
  1272. }
  1273. return sb.ToString().TrimEnd(new[] { ' ', '+' });
  1274. }
  1275. }
  1276. private class Point
  1277. {
  1278. public int X { get; }
  1279. public int Y { get; }
  1280. public Point(int x, int y)
  1281. {
  1282. this.X = x;
  1283. this.Y = y;
  1284. }
  1285. }
  1286. private class Rectangle
  1287. {
  1288. public int X { get; }
  1289. public int Y { get; }
  1290. public int Width { get; }
  1291. public int Height { get; }
  1292. public Rectangle(int x, int y, int w, int h)
  1293. {
  1294. this.X = x;
  1295. this.Y = y;
  1296. this.Width = w;
  1297. this.Height = h;
  1298. }
  1299. }
  1300. public void Dispose()
  1301. {
  1302. this.alignmentPatternBaseValues = null;
  1303. this.alignmentPatternTable = null;
  1304. this.alphanumEncDict = null;
  1305. this.capacityBaseValues = null;
  1306. this.capacityECCBaseValues = null;
  1307. this.capacityECCTable = null;
  1308. this.capacityTable = null;
  1309. this.galoisField = null;
  1310. this.remainderBits = null;
  1311. }
  1312. }
  1313. }
  1314. #endif