Skip to content

Commit

Permalink
Merge branch 'master' into string_optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
Shane32 authored May 13, 2024
2 parents 8d13dd7 + b26488e commit 51e8c92
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 49 deletions.
28 changes: 28 additions & 0 deletions QRCoder/Extensions/BitArrayExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections;

namespace QRCoder
{
/// <summary>
/// Helper methods for <see cref="BitArray"/>.
/// </summary>
internal static class BitArrayExtensions
{
/// <summary>
/// Copies a specified number of elements from one <see cref="BitArray"/> to another starting at the specified offsets.
/// </summary>
/// <param name="source">The source <see cref="BitArray"/> from which elements will be copied.</param>
/// <param name="sourceOffset">The zero-based index in the source <see cref="BitArray"/> at which copying begins.</param>
/// <param name="destination">The destination <see cref="BitArray"/> to which elements will be copied.</param>
/// <param name="destinationOffset">The zero-based index in the destination <see cref="BitArray"/> at which storing begins.</param>
/// <param name="count">The number of elements to copy.</param>
/// <returns>The index in the destination <see cref="BitArray"/> immediately following the last copied element.</returns>
public static int CopyTo(this BitArray source, BitArray destination, int sourceOffset, int destinationOffset, int count)
{
for (int i = 0; i < count; i++)
{
destination[destinationOffset + i] = source[sourceOffset + i];
}
return destinationOffset + count;
}
}
}
21 changes: 15 additions & 6 deletions QRCoder/QRCodeGenerator.CodewordBlock.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace QRCoder
using System.Collections;

namespace QRCoder
{
public partial class QRCodeGenerator
{
Expand All @@ -11,18 +13,25 @@ private struct CodewordBlock
/// <summary>
/// Initializes a new instance of the CodewordBlock struct with specified arrays of code words and error correction (ECC) words.
/// </summary>
/// <param name="codeWords">The array of data codewords for this block. Data codewords carry the actual information.</param>
/// <param name="codeWordsOffset">The offset of the data codewords within the main BitArray. Data codewords carry the actual information.</param>
/// <param name="codeWordsLength">The length in bits of the data codewords within the main BitArray.</param>
/// <param name="eccWords">The array of error correction codewords for this block. These codewords help recover the data if the QR code is damaged.</param>
public CodewordBlock(byte[] codeWords, byte[] eccWords)
public CodewordBlock(int codeWordsOffset, int codeWordsLength, byte[] eccWords)
{
this.CodeWords = codeWords;
this.CodeWordsOffset = codeWordsOffset;
this.CodeWordsLength = codeWordsLength;
this.ECCWords = eccWords;
}

/// <summary>
/// Gets the data codewords associated with this block.
/// Gets the offset of the data codewords in the BitArray.
/// </summary>
public int CodeWordsOffset { get; }

/// <summary>
/// Gets the length of the data codewords in the BitArray.
/// </summary>
public byte[] CodeWords { get; }
public int CodeWordsLength { get; }

/// <summary>
/// Gets the error correction codewords associated with this block.
Expand Down
53 changes: 10 additions & 43 deletions QRCoder/QRCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,17 @@ private static QRCodeData GenerateQrCode(BitArray bitArray, ECCLevel eccLevel, i
{
//Calculate error correction words
codeWordWithECC = new List<CodewordBlock>(eccInfo.BlocksInGroup1 + eccInfo.BlocksInGroup2);
AddCodeWordBlocks(1, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, bitArray, 0, bitArray.Length, generatorPolynom);
AddCodeWordBlocks(1, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, 0, bitArray.Length, generatorPolynom);
int offset = eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8;
AddCodeWordBlocks(2, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, bitArray, offset, bitArray.Length - offset, generatorPolynom);
AddCodeWordBlocks(2, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, offset, bitArray.Length - offset, generatorPolynom);
}

//Calculate interleaved code word lengths
int interleavedLength = 0;
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
{
foreach (var codeBlock in codeWordWithECC)
if (codeBlock.CodeWords.Length > i)
if ((uint)codeBlock.CodeWordsLength / 8 > i)
interleavedLength += 8;
}
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
Expand All @@ -258,8 +258,10 @@ private static QRCodeData GenerateQrCode(BitArray bitArray, ECCLevel eccLevel, i
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
{
foreach (var codeBlock in codeWordWithECC)
if (codeBlock.CodeWords.Length > i)
pos = DecToBin(codeBlock.CodeWords[i], 8, interleavedData, pos);
{
if ((uint)codeBlock.CodeWordsLength / 8 > i)
pos = bitArray.CopyTo(interleavedData, (int)((uint)i * 8) + codeBlock.CodeWordsOffset, pos, 8);
}
}
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
{
Expand Down Expand Up @@ -292,17 +294,13 @@ private static QRCodeData GenerateQrCode(BitArray bitArray, ECCLevel eccLevel, i
ModulePlacer.AddQuietZone(qr);
return qr;

void AddCodeWordBlocks(int blockNum, int blocksInGroup, int codewordsInGroup, BitArray bitArray2, int offset2, int count, Polynom generatorPolynom)
void AddCodeWordBlocks(int blockNum, int blocksInGroup, int codewordsInGroup, int offset2, int count, Polynom generatorPolynom)
{
var groupLength = codewordsInGroup * 8;
for (var i = 0; i < blocksInGroup; i++)
{
var bitBlockList = BinaryStringToBitBlockByteList(bitArray2, offset2, groupLength);
var eccWordList = CalculateECCWords(bitArray2, offset2, groupLength, eccInfo, generatorPolynom);
codeWordWithECC.Add(new CodewordBlock(
bitBlockList,
eccWordList)
);
var eccWordList = CalculateECCWords(bitArray, offset2, groupLength, eccInfo, generatorPolynom);
codeWordWithECC.Add(new CodewordBlock(offset2, groupLength, eccWordList));
offset2 += groupLength;
}
}
Expand Down Expand Up @@ -621,37 +619,6 @@ private static Polynom CalculateGeneratorPolynom(int numEccWords)
return generatorPolynom; // Return the completed generator polynomial
}

/// <summary>
/// Converts a segment of a BitArray into a list of bytes where each byte represents a consecutive block of 8 bits from the BitArray.
/// </summary>
private static byte[] BinaryStringToBitBlockByteList(BitArray bitString, int offset, int count)
{
const int blockSize = 8;
if (count % blockSize != 0)
ThrowCountMustBeMultipleOf8Exception();
var numberOfBlocks = (int)((uint)count / blockSize);
var blocklist = new byte[numberOfBlocks];

int j = 0;
count += offset;
for (int i = offset; i < count; i += blockSize)
{
blocklist[j++] = (byte)(
(bitString[i] ? 128 : 0) +
(bitString[i + 1] ? 64 : 0) +
(bitString[i + 2] ? 32 : 0) +
(bitString[i + 3] ? 16 : 0) +
(bitString[i + 4] ? 8 : 0) +
(bitString[i + 5] ? 4 : 0) +
(bitString[i + 6] ? 2 : 0) +
(bitString[i + 7] ? 1 : 0));
}

return blocklist;

void ThrowCountMustBeMultipleOf8Exception() => throw new ArgumentOutOfRangeException(nameof(count), "Count must be a multiple of 8.");
}

/// <summary>
/// Converts a segment of a BitArray into its decimal (integer) equivalent.
/// </summary>
Expand Down

0 comments on commit 51e8c92

Please sign in to comment.