private int GetVersion(int length, EncodingMode encMode, EccLevel eccLevel)
 {
     var version = capacityTable
         .Where(x => x.Details.Any(y => (y.ErrorCorrectionLevel == eccLevel && y.CapacityDict[encMode] >= Convert.ToInt32(length))))
         .Select(x => new
         {
             version = x.Version,
             capacity = x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel).CapacityDict[encMode]
         }).Min(x => x.version);
     return version;
 }
        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.Single(x => x.Version == version && x.ErrorCorrectionLevel.Equals(eccLevel));
            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++)
            {
                var i1 = i;
                foreach (var codeBlock in codeWordWithEcc.Where(codeBlock => codeBlock.CodeWords.Count > i1))
                    interleavedWordsSb.Append(codeBlock.CodeWords[i]);
            }

            for (var i = 0; i < eccInfo.ECCPerBlock; i++)
            {
                var i1 = i;
                foreach (var codeBlock in codeWordWithEcc.Where(codeBlock => codeBlock.ECCWords.Count > i1))
                    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;
        }
        private string GetFormatString(EccLevel level, int maskVersion)
        {
            var generator = "10100110111";
            var fStrMask = "101010000010010";

            var fStr = (level == EccLevel.L) ? "01" : (level == EccLevel.M) ? "00" : (level == EccLevel.Q) ? "11" : "10";
            fStr += DecToBin(maskVersion, 3);
            var fStrEcc = fStr.PadRight(15, '0').TrimStart('0');
            while (fStrEcc.Length > 10)
            {
                var sb = new StringBuilder();
                generator = generator.PadRight(fStrEcc.Length, '0');
                for (var i = 0; i < fStrEcc.Length; i++)
                    sb.Append((Convert.ToInt32(fStrEcc[i]) ^ Convert.ToInt32(generator[i])).ToString());
                fStrEcc = sb.ToString().TrimStart('0');
            }
            fStrEcc = fStrEcc.PadLeft(10, '0');
            fStr += fStrEcc;

            var sbMask = new StringBuilder();
            for (var i = 0; i < fStr.Length; i++)
                sbMask.Append((Convert.ToInt32(fStr[i]) ^ Convert.ToInt32(fStrMask[i])).ToString());
            return sbMask.ToString();
        }