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;
}
///