diff --git a/QRCoder/QRCodeGenerator.ModulePlacer.BlockedModules.cs b/QRCoder/QRCodeGenerator.ModulePlacer.BlockedModules.cs index 04bb824a..fadd5d23 100644 --- a/QRCoder/QRCodeGenerator.ModulePlacer.BlockedModules.cs +++ b/QRCoder/QRCodeGenerator.ModulePlacer.BlockedModules.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; namespace QRCoder { @@ -9,9 +10,12 @@ private static partial class ModulePlacer /// /// Struct that represents blocked modules using rectangles. /// - public struct BlockedModules + public struct BlockedModules : IDisposable { - private readonly BitArray[] _blockedModules; + private readonly bool[,] _blockedModules; + + [ThreadStatic] + private static bool[,] _staticBlockedModules; /// /// Initializes a new instance of the struct with a specified capacity. @@ -19,10 +23,19 @@ public struct BlockedModules /// The initial capacity of the blocked modules list. public BlockedModules(int size) { - _blockedModules = new BitArray[size]; - for (int i = 0; i < size; i++) + if (_staticBlockedModules != null && _staticBlockedModules.GetUpperBound(0) >= (size - 1)) + { + _blockedModules = _staticBlockedModules; + _staticBlockedModules = null; +#if NET6_0_OR_GREATER + Array.Clear(_blockedModules); +#else + Array.Clear(_blockedModules, 0, _blockedModules.Length); +#endif + } + else { - _blockedModules[i] = new BitArray(size); + _blockedModules = new bool[size, size]; } } @@ -33,7 +46,7 @@ public BlockedModules(int size) /// The y-coordinate of the module. public void Add(int x, int y) { - _blockedModules[y][x] = true; + _blockedModules[y, x] = true; } /// @@ -46,7 +59,7 @@ public void Add(Rectangle rect) { for (int x = rect.X; x < rect.X + rect.Width; x++) { - _blockedModules[y][x] = true; + _blockedModules[y, x] = true; } } } @@ -59,7 +72,7 @@ public void Add(Rectangle rect) /// true if the coordinates are blocked; otherwise, false. public bool IsBlocked(int x, int y) { - return _blockedModules[y][x]; + return _blockedModules[y, x]; } /// @@ -73,12 +86,20 @@ public bool IsBlocked(Rectangle r1) { for (int x = r1.X; x < r1.X + r1.Width; x++) { - if (_blockedModules[y][x]) + if (_blockedModules[y, x]) return true; } } return false; } + + public void Dispose() + { + if (_staticBlockedModules == null || _staticBlockedModules.GetUpperBound(0) < _blockedModules.GetUpperBound(0)) + { + _staticBlockedModules = _blockedModules; + } + } } } } diff --git a/QRCoder/QRCodeGenerator.ModulePlacer.cs b/QRCoder/QRCodeGenerator.ModulePlacer.cs index 6c325d81..3b9c5434 100644 --- a/QRCoder/QRCodeGenerator.ModulePlacer.cs +++ b/QRCoder/QRCodeGenerator.ModulePlacer.cs @@ -114,7 +114,13 @@ public static int MaskCode(QRCodeData qrCode, int version, BlockedModules blocke // Temporary QRCodeData object to test different mask patterns without altering the original. var qrTemp = new QRCodeData(version, false); - BitArray versionString = version >= 7 ? GetVersionString(version) : null; + BitArray versionString = null; + if (version >= 7) + { + versionString = new BitArray(18); + GetVersionString(versionString, version); + } + var formatStr = new BitArray(15); foreach (var pattern in MaskPattern.Patterns) { // Reset the temporary QR code to the current state of the actual QR code. @@ -127,7 +133,7 @@ public static int MaskCode(QRCodeData qrCode, int version, BlockedModules blocke } // Place format information using the current mask pattern. - var formatStr = GetFormatString(eccLevel, pattern.Key - 1); + GetFormatString(formatStr, eccLevel, pattern.Key - 1); ModulePlacer.PlaceFormat(qrTemp, formatStr, false); // Place version information if applicable. @@ -181,6 +187,7 @@ public static int MaskCode(QRCodeData qrCode, int version, BlockedModules blocke qrCode.ModuleMatrix[x + 4][x + 4] ^= MaskPattern.Patterns[selectedPattern.Value](x, x); } } + return selectedPattern.Value - 1; } diff --git a/QRCoder/QRCodeGenerator.cs b/QRCoder/QRCodeGenerator.cs index 353b0b7c..d4db5312 100644 --- a/QRCoder/QRCodeGenerator.cs +++ b/QRCoder/QRCodeGenerator.cs @@ -321,22 +321,25 @@ QRCodeData PlaceModules() { var qr = new QRCodeData(version, true); var size = qr.ModuleMatrix.Count - 8; - var blockedModules = new ModulePlacer.BlockedModules(size); - ModulePlacer.PlaceFinderPatterns(qr, blockedModules); - ModulePlacer.ReserveSeperatorAreas(size, blockedModules); - ModulePlacer.PlaceAlignmentPatterns(qr, alignmentPatternTable[version].PatternPositions, blockedModules); - ModulePlacer.PlaceTimingPatterns(qr, blockedModules); - ModulePlacer.PlaceDarkModule(qr, version, blockedModules); - ModulePlacer.ReserveVersionAreas(size, version, blockedModules); - ModulePlacer.PlaceDataWords(qr, interleavedData, blockedModules); - var maskVersion = ModulePlacer.MaskCode(qr, version, blockedModules, eccLevel); - var formatStr = GetFormatString(eccLevel, maskVersion); - - ModulePlacer.PlaceFormat(qr, formatStr, true); + var tempBitArray = new BitArray(18); //version string requires 18 bits + using (var blockedModules = new ModulePlacer.BlockedModules(size)) + { + ModulePlacer.PlaceFinderPatterns(qr, blockedModules); + ModulePlacer.ReserveSeperatorAreas(size, blockedModules); + ModulePlacer.PlaceAlignmentPatterns(qr, alignmentPatternTable[version].PatternPositions, blockedModules); + ModulePlacer.PlaceTimingPatterns(qr, blockedModules); + ModulePlacer.PlaceDarkModule(qr, version, blockedModules); + ModulePlacer.ReserveVersionAreas(size, version, blockedModules); + ModulePlacer.PlaceDataWords(qr, interleavedData, blockedModules); + var maskVersion = ModulePlacer.MaskCode(qr, version, blockedModules, eccLevel); + GetFormatString(tempBitArray, eccLevel, maskVersion); + ModulePlacer.PlaceFormat(qr, tempBitArray, true); + } + if (version >= 7) { - var versionString = GetVersionString(version); - ModulePlacer.PlaceVersion(qr, versionString, true); + GetVersionString(tempBitArray, version); + ModulePlacer.PlaceVersion(qr, tempBitArray, true); } return qr; @@ -349,12 +352,14 @@ QRCodeData PlaceModules() /// Generates a BitArray containing the format string for a QR code based on the error correction level and mask pattern version. /// The format string includes the error correction level, mask pattern version, and error correction coding. /// + /// The to write to, or null to create a new one. /// The error correction level to be encoded in the format string. /// The mask pattern version to be encoded in the format string. /// A BitArray containing the 15-bit format string used in QR code generation. - private static BitArray GetFormatString(ECCLevel level, int maskVersion) + private static void GetFormatString(BitArray fStrEcc, ECCLevel level, int maskVersion) { - var fStrEcc = new BitArray(15); // Total length including space for mask version and padding + fStrEcc.Length = 15; + fStrEcc.SetAll(false); WriteEccLevelAndVersion(); // Apply the format generator polynomial to add error correction to the format string. @@ -378,7 +383,6 @@ private static BitArray GetFormatString(ECCLevel level, int maskVersion) // XOR the format string with a predefined mask to add robustness against errors. fStrEcc.Xor(_getFormatMask); - return fStrEcc; void WriteEccLevelAndVersion() { @@ -445,11 +449,13 @@ private static void ShiftAwayFromBit0(BitArray fStrEcc, int num) /// Encodes the version information of a QR code into a BitArray using error correction coding similar to format information encoding. /// This method is used for QR codes version 7 and above. /// + /// A to write the version string to. /// The version number of the QR code (7-40). /// A BitArray containing the encoded version information, which includes error correction bits. - private static BitArray GetVersionString(int version) + private static void GetVersionString(BitArray vStr, int version) { - var vStr = new BitArray(18); + vStr.Length = 18; + vStr.SetAll(false); DecToBin(version, 6, vStr, 0); // Convert the version number to a 6-bit binary representation. var count = vStr.Length; @@ -471,8 +477,6 @@ private static BitArray GetVersionString(int version) vStr.Length = 12 + 6; ShiftAwayFromBit0(vStr, (12 - count) + 6); DecToBin(version, 6, vStr, 0); - - return vStr; } ///