public static int MaskCode(ref QrCode qrCode, int version, ref List <Rectangle> blockedModules) { var patternName = String.Empty; var patternScore = 0; var size = qrCode.ModuleMatrix.Count; foreach (var pattern in typeof(MaskPattern).GetMethods()) { if (pattern.Name.Length == 8 && pattern.Name.Substring(0, 7) == "Pattern") { var qrTemp = new QrCode(version); for (var y = 0; y < size; y++) { for (var x = 0; x < size; x++) { qrTemp.ModuleMatrix[y][x] = qrCode.ModuleMatrix[y][x]; } } for (var x = 0; x < size; x++) { for (var y = 0; y < size; y++) { if (!IsBlocked(new Rectangle(x, y, 1, 1), blockedModules)) { qrTemp.ModuleMatrix[y][x] ^= (bool)pattern.Invoke(null, new object[] { x, y }); } } } var score = MaskPattern.Score(ref qrTemp); if (String.IsNullOrEmpty(patternName) || patternScore > score) { patternName = pattern.Name; patternScore = score; } } } var patterMethod = typeof(MaskPattern).GetMethods().Where(x => x.Name == patternName).First(); for (var x = 0; x < size; x++) { for (var y = 0; y < size; y++) { if (!IsBlocked(new Rectangle(x, y, 1, 1), blockedModules)) { qrCode.ModuleMatrix[y][x] ^= (bool)patterMethod.Invoke(null, new object[] { x, y }); } } } return(Convert.ToInt32(patterMethod.Name.Substring(patterMethod.Name.Length - 1, 1)) - 1); }
public static void PlaceTimingPatterns(ref QrCode qrCode, ref List <Rectangle> blockedModules) { var size = qrCode.ModuleMatrix.Count; for (var i = 8; i < size - 8; i++) { if (i % 2 == 0) { qrCode.ModuleMatrix[6][i] = true; qrCode.ModuleMatrix[i][6] = true; } } blockedModules.AddRange(new[] { new Rectangle(6, 8, 1, size - 16), new Rectangle(8, 6, size - 16, 1) }); }
public static void PlaceVersion(ref QrCode qrCode, string versionStr) { var size = qrCode.ModuleMatrix.Count; var vStr = new string(versionStr.Reverse().ToArray()); for (var x = 0; x < 6; x++) { for (var y = 0; y < 3; y++) { qrCode.ModuleMatrix[y + size - 11][x] = vStr[x * 3 + y] == '1' ? true : false; qrCode.ModuleMatrix[x][y + size - 11] = vStr[x * 3 + y] == '1' ? true : false; } } }
public static void PlaceFormat(ref QrCode qrCode, string formatStr) { var size = qrCode.ModuleMatrix.Count; var fStr = new string(formatStr.Reverse().ToArray()); var modules = new int[15, 4] { { 8, 0, size - 1, 8 }, { 8, 1, size - 2, 8 }, { 8, 2, size - 3, 8 }, { 8, 3, size - 4, 8 }, { 8, 4, size - 5, 8 }, { 8, 5, size - 6, 8 }, { 8, 7, size - 7, 8 }, { 8, 8, size - 8, 8 }, { 7, 8, 8, size - 7 }, { 5, 8, 8, size - 6 }, { 4, 8, 8, size - 5 }, { 3, 8, 8, size - 4 }, { 2, 8, 8, size - 3 }, { 1, 8, 8, size - 2 }, { 0, 8, 8, size - 1 } }; for (var i = 0; i < 15; i++) { var p1 = new Point(modules[i, 0], modules[i, 1]); var p2 = new Point(modules[i, 2], modules[i, 3]); qrCode.ModuleMatrix[p1.Y][p1.X] = fStr[i] == '1' ? true : false; qrCode.ModuleMatrix[p2.Y][p2.X] = fStr[i] == '1' ? true : false; } }
public static void PlaceDataWords(ref QrCode qrCode, string data, ref List <Rectangle> blockedModules) { var size = qrCode.ModuleMatrix.Count; var up = true; var datawords = new Queue <bool>(); data.ToList().ForEach(x => datawords.Enqueue(x == '0' ? false : true)); for (var x = size - 1; x >= 0; x = x - 2) { if (x == 7 || x == 6) { x = 5; } for (var yMod = 1; yMod <= size; yMod++) { var y = 0; if (up) { y = size - yMod; if (datawords.Count > 0 && !IsBlocked(new Rectangle(x, y, 1, 1), blockedModules)) { qrCode.ModuleMatrix[y][x] = datawords.Dequeue(); } if (datawords.Count > 0 && x > 0 && !IsBlocked(new Rectangle(x - 1, y, 1, 1), blockedModules)) { qrCode.ModuleMatrix[y][x - 1] = datawords.Dequeue(); } } else { y = yMod - 1; if (datawords.Count > 0 && !IsBlocked(new Rectangle(x, y, 1, 1), blockedModules)) { qrCode.ModuleMatrix[y][x] = datawords.Dequeue(); } if (datawords.Count > 0 && x > 0 && !IsBlocked(new Rectangle(x - 1, y, 1, 1), blockedModules)) { qrCode.ModuleMatrix[y][x - 1] = datawords.Dequeue(); } } } up = !up; } }
public static void PlaceFinderPatterns(ref QrCode qrCode, ref List <Rectangle> blockedModules) { var size = qrCode.ModuleMatrix.Count; int[] locations = { 0, 0, size - 7, 0, 0, size - 7 }; for (var i = 0; i < 6; i = i + 2) { for (var x = 0; x < 7; x++) { for (var y = 0; y < 7; y++) { if (!(((x == 1 || x == 5) && y > 0 && y < 6) || (x > 0 && x < 6 && (y == 1 || y == 5)))) { qrCode.ModuleMatrix[y + locations[i + 1]][x + locations[i]] = true; } } } blockedModules.Add(new Rectangle(locations[i], locations[i + 1], 7, 7)); } }
public static void PlaceDarkModule(ref QrCode qrCode, int version, ref List <Rectangle> blockedModules) { qrCode.ModuleMatrix[4 * version + 9][8] = true; blockedModules.Add(new Rectangle(8, 4 * version + 9, 1, 1)); }
public static int Score(ref QrCode qrCode) { var score = 0; var size = qrCode.ModuleMatrix.Count; //Penalty 1 for (int y = 0; y < size; y++) { var modInRow = 0; var modInColumn = 0; var lastValRow = qrCode.ModuleMatrix[y][0]; var lastValColumn = qrCode.ModuleMatrix[0][y]; for (int x = 0; x < size; x++) { if (qrCode.ModuleMatrix[y][x] == lastValRow) { modInRow++; } else { modInRow = 1; } if (modInRow == 5) { score += 3; } else if (modInRow > 5) { score++; } lastValRow = qrCode.ModuleMatrix[y][x]; if (qrCode.ModuleMatrix[x][y] == lastValColumn) { modInColumn++; } else { modInColumn = 1; } if (modInColumn == 5) { score += 3; } else if (modInColumn > 5) { score++; } lastValColumn = qrCode.ModuleMatrix[x][y]; } } //Penalty 2 for (int y = 0; y < size - 1; y++) { for (int x = 0; x < size - 1; x++) { if (qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y][x + 1] && qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x] && qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x + 1]) { score += 3; } } } //Penalty 3 for (int y = 0; y < size; y++) { for (int x = 0; x < size - 10; x++) { if ((qrCode.ModuleMatrix[y][x] && !qrCode.ModuleMatrix[y][x + 1] && qrCode.ModuleMatrix[y][x + 2] && qrCode.ModuleMatrix[y][x + 3] && qrCode.ModuleMatrix[y][x + 4] && !qrCode.ModuleMatrix[y][x + 5] && qrCode.ModuleMatrix[y][x + 6] && !qrCode.ModuleMatrix[y][x + 7] && !qrCode.ModuleMatrix[y][x + 8] && !qrCode.ModuleMatrix[y][x + 9] && !qrCode.ModuleMatrix[y][x + 10]) || (!qrCode.ModuleMatrix[y][x] && !qrCode.ModuleMatrix[y][x + 1] && !qrCode.ModuleMatrix[y][x + 2] && !qrCode.ModuleMatrix[y][x + 3] && qrCode.ModuleMatrix[y][x + 4] && !qrCode.ModuleMatrix[y][x + 5] && qrCode.ModuleMatrix[y][x + 6] && qrCode.ModuleMatrix[y][x + 7] && qrCode.ModuleMatrix[y][x + 8] && !qrCode.ModuleMatrix[y][x + 9] && qrCode.ModuleMatrix[y][x + 10])) { score += 40; } if ((qrCode.ModuleMatrix[x][y] && !qrCode.ModuleMatrix[x + 1][y] && qrCode.ModuleMatrix[x + 2][y] && qrCode.ModuleMatrix[x + 3][y] && qrCode.ModuleMatrix[x + 4][y] && !qrCode.ModuleMatrix[x + 5][y] && qrCode.ModuleMatrix[x + 6][y] && !qrCode.ModuleMatrix[x + 7][y] && !qrCode.ModuleMatrix[x + 8][y] && !qrCode.ModuleMatrix[x + 9][y] && !qrCode.ModuleMatrix[x + 10][y]) || (!qrCode.ModuleMatrix[x][x] && !qrCode.ModuleMatrix[x + 1][y] && !qrCode.ModuleMatrix[x + 2][y] && !qrCode.ModuleMatrix[x + 3][y] && qrCode.ModuleMatrix[x + 4][y] && !qrCode.ModuleMatrix[x + 5][y] && qrCode.ModuleMatrix[x + 6][y] && qrCode.ModuleMatrix[x + 7][y] && qrCode.ModuleMatrix[x + 8][y] && !qrCode.ModuleMatrix[x + 9][y] && qrCode.ModuleMatrix[x + 10][y])) { score += 40; } } } //Penalty 4 var blackModules = 0; foreach (var row in qrCode.ModuleMatrix) { foreach (bool bit in row) { if (bit) { blackModules++; } } } var percent = (blackModules / (qrCode.ModuleMatrix.Count * qrCode.ModuleMatrix.Count)) * 100; if (percent % 5 == 0) { score += Math.Min((Math.Abs(percent - 55) / 5), (Math.Abs(percent - 45) / 5)) * 10; } else { score += Math.Min((Math.Abs((int)Math.Floor((decimal)percent / 5) - 50) / 5), (Math.Abs(((int)Math.Floor((decimal)percent / 5) + 5) - 50) / 5)) * 10; } return(score); }
public QrCode CreateQrCode(string plainText, ECCLevel eccLevel, bool utf8Bom = false) { var encoding = GetEncodingFromPlaintext(plainText); var codedText = PlainTextToBinary(plainText, encoding, utf8Bom); var dataInputLength = GetDataLength(encoding, plainText, codedText); var version = GetVersion(dataInputLength, encoding, eccLevel); var modeIndicator = DecToBin((int)encoding, 4); var countIndicator = DecToBin(dataInputLength, GetCountIndicatorLength(version, encoding)); var bitString = modeIndicator + countIndicator; bitString += codedText; //Fill up data code word var eccInfo = _capacityEccTable.Where(x => x.Version == version && x.ErrorCorrectionLevel.Equals(eccLevel)).Single(); var dataLength = eccInfo.TotalDataCodewords * 8; var lengthDiff = dataLength - bitString.Length; if (lengthDiff > 0) { bitString += new string('0', Math.Min(lengthDiff, 4)); } if ((bitString.Length % 8) != 0) { bitString += new string('0', 8 - (bitString.Length % 8)); } while (bitString.Length < dataLength) { bitString += "1110110000010001"; } if (bitString.Length > dataLength) { bitString = bitString.Substring(0, dataLength); } //Calculate error correction words var codeWordWithEcc = new List <CodewordBlock>(); for (var i = 0; i < eccInfo.BlocksInGroup1; i++) { var bitStr = bitString.Substring(i * eccInfo.CodewordsInGroup1 * 8, eccInfo.CodewordsInGroup1 * 8); codeWordWithEcc.Add(new CodewordBlock { BitString = bitStr, BlockNumber = i + 1, GroupNumber = 1, CodeWords = BinaryStringToBitBlockList(bitStr), ECCWords = CalculateEccWords(bitStr, eccInfo) }); } bitString = bitString.Substring(eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8); for (var i = 0; i < eccInfo.BlocksInGroup2; i++) { var bitStr = bitString.Substring(i * eccInfo.CodewordsInGroup2 * 8, eccInfo.CodewordsInGroup2 * 8); codeWordWithEcc.Add(new CodewordBlock { BitString = bitStr, BlockNumber = i + 1, GroupNumber = 2, CodeWords = BinaryStringToBitBlockList(bitStr), ECCWords = CalculateEccWords(bitStr, eccInfo) }); } //Interleave code words var interleavedWordsSb = new StringBuilder(); for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++) { foreach (var codeBlock in codeWordWithEcc) { if (codeBlock.CodeWords.Count > i) { interleavedWordsSb.Append(codeBlock.CodeWords[i]); } } } for (var i = 0; i < eccInfo.ECCPerBlock; i++) { foreach (var codeBlock in codeWordWithEcc) { if (codeBlock.ECCWords.Count > i) { interleavedWordsSb.Append(codeBlock.ECCWords[i]); } } } interleavedWordsSb.Append(new string('0', _remainderBits[version - 1])); var interleavedData = interleavedWordsSb.ToString(); //Place interleaved data on module matrix var qr = new QrCode(version); var blockedModules = new List <Rectangle>(); ModulePlacer.PlaceFinderPatterns(ref qr, ref blockedModules); ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, ref blockedModules); ModulePlacer.PlaceAlignmentPatterns(ref qr, _alignmentPatternTable.Where(x => x.Version == version).Select(x => x.PatternPositions).First(), ref blockedModules); ModulePlacer.PlaceTimingPatterns(ref qr, ref blockedModules); ModulePlacer.PlaceDarkModule(ref qr, version, ref blockedModules); ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, ref blockedModules); ModulePlacer.PlaceDataWords(ref qr, interleavedData, ref blockedModules); var maskVersion = ModulePlacer.MaskCode(ref qr, version, ref blockedModules); var formatStr = GetFormatString(eccLevel, maskVersion); ModulePlacer.PlaceFormat(ref qr, formatStr); if (version >= 7) { var versionString = GetVersionString(version); ModulePlacer.PlaceVersion(ref qr, versionString); } ModulePlacer.AddQuietZone(ref qr); return(qr); }