Skip to content

Commit 308c231

Browse files
committed
Reorganize GenerateQrCode for better clarity
1 parent 283a458 commit 308c231

File tree

1 file changed

+120
-82
lines changed

1 file changed

+120
-82
lines changed

QRCoder/QRCodeGenerator.cs

Lines changed: 120 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -200,109 +200,147 @@ public static QRCodeData GenerateQrCode(byte[] binaryData, ECCLevel eccLevel)
200200
/// <returns>A QRCodeData structure containing the full QR code matrix, which can be used for rendering or analysis.</returns>
201201
private static QRCodeData GenerateQrCode(BitArray bitArray, ECCLevel eccLevel, int version)
202202
{
203-
//Fill up data code word
204203
var eccInfo = capacityECCTable.Single(x => x.Version == version && x.ErrorCorrectionLevel == eccLevel);
205-
var dataLength = eccInfo.TotalDataCodewords * 8;
206-
var lengthDiff = dataLength - bitArray.Length;
207-
if (lengthDiff > 0)
204+
205+
// Fill up data code word
206+
PadData();
207+
208+
// Calculate error correction blocks
209+
var codeWordWithECC = CalculateECCBlocks();
210+
211+
// Calculate interleaved code word lengths
212+
var interleavedLength = CalculateInterleavedLength();
213+
214+
// Interleave code words
215+
var interleavedData = InterleaveData();
216+
217+
// Place interleaved data on module matrix
218+
var qrData = PlaceModules();
219+
220+
return qrData;
221+
222+
223+
// fills the bit array with a repeating pattern to reach the required length
224+
void PadData()
208225
{
209-
// set 'write index' to end of existing bit array
210-
var index = bitArray.Length;
211-
// extend bit array to required length
212-
bitArray.Length = dataLength;
213-
// pad with 4 zeros (or less if lengthDiff < 4)
214-
index += Math.Min(lengthDiff, 4);
215-
// pad to nearest 8 bit boundary
216-
if ((uint)index % 8 != 0)
217-
index += 8 - (int)((uint)index % 8);
218-
// pad with repeating pattern
219-
var repeatingPatternIndex = 0;
220-
while (index < dataLength)
226+
var dataLength = eccInfo.TotalDataCodewords * 8;
227+
var lengthDiff = dataLength - bitArray.Length;
228+
if (lengthDiff > 0)
221229
{
222-
bitArray[index++] = _repeatingPattern[repeatingPatternIndex++];
223-
if (repeatingPatternIndex >= _repeatingPattern.Length)
224-
repeatingPatternIndex = 0;
230+
// set 'write index' to end of existing bit array
231+
var index = bitArray.Length;
232+
// extend bit array to required length
233+
bitArray.Length = dataLength;
234+
// pad with 4 zeros (or less if lengthDiff < 4)
235+
index += Math.Min(lengthDiff, 4);
236+
// pad to nearest 8 bit boundary
237+
if ((uint)index % 8 != 0)
238+
index += 8 - (int)((uint)index % 8);
239+
// pad with repeating pattern
240+
var repeatingPatternIndex = 0;
241+
while (index < dataLength)
242+
{
243+
bitArray[index++] = _repeatingPattern[repeatingPatternIndex++];
244+
if (repeatingPatternIndex >= _repeatingPattern.Length)
245+
repeatingPatternIndex = 0;
246+
}
225247
}
226248
}
227249

228-
// Generate the generator polynomial using the number of ECC words.
229-
List<CodewordBlock> codeWordWithECC;
230-
using (var generatorPolynom = CalculateGeneratorPolynom(eccInfo.ECCPerBlock))
250+
List<CodewordBlock> CalculateECCBlocks()
231251
{
232-
//Calculate error correction words
233-
codeWordWithECC = new List<CodewordBlock>(eccInfo.BlocksInGroup1 + eccInfo.BlocksInGroup2);
234-
AddCodeWordBlocks(1, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, 0, bitArray.Length, generatorPolynom);
235-
int offset = eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8;
236-
AddCodeWordBlocks(2, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, offset, bitArray.Length - offset, generatorPolynom);
237-
}
252+
List<CodewordBlock> codewordBlocks;
253+
// Generate the generator polynomial using the number of ECC words.
254+
using (var generatorPolynom = CalculateGeneratorPolynom(eccInfo.ECCPerBlock))
255+
{
256+
//Calculate error correction words
257+
codewordBlocks = new List<CodewordBlock>(eccInfo.BlocksInGroup1 + eccInfo.BlocksInGroup2);
258+
AddCodeWordBlocks(1, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, 0, bitArray.Length, generatorPolynom);
259+
int offset = eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8;
260+
AddCodeWordBlocks(2, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, offset, bitArray.Length - offset, generatorPolynom);
261+
return codewordBlocks;
262+
}
238263

239-
//Calculate interleaved code word lengths
240-
int interleavedLength = 0;
241-
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
242-
{
243-
foreach (var codeBlock in codeWordWithECC)
244-
if ((uint)codeBlock.CodeWordsLength / 8 > i)
245-
interleavedLength += 8;
246-
}
247-
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
248-
{
249-
foreach (var codeBlock in codeWordWithECC)
250-
if (codeBlock.ECCWords.Length > i)
251-
interleavedLength += 8;
264+
void AddCodeWordBlocks(int blockNum, int blocksInGroup, int codewordsInGroup, int offset2, int count, Polynom generatorPolynom)
265+
{
266+
var groupLength = codewordsInGroup * 8;
267+
for (var i = 0; i < blocksInGroup; i++)
268+
{
269+
var eccWordList = CalculateECCWords(bitArray, offset2, groupLength, eccInfo, generatorPolynom);
270+
codewordBlocks.Add(new CodewordBlock(offset2, groupLength, eccWordList));
271+
offset2 += groupLength;
272+
}
273+
}
252274
}
253-
interleavedLength += remainderBits[version - 1];
254275

255-
//Interleave code words
256-
var interleavedData = new BitArray(interleavedLength);
257-
int pos = 0;
258-
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
276+
// Calculate the length of the interleaved data
277+
int CalculateInterleavedLength()
259278
{
260-
foreach (var codeBlock in codeWordWithECC)
279+
var length = 0;
280+
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
261281
{
262-
if ((uint)codeBlock.CodeWordsLength / 8 > i)
263-
pos = bitArray.CopyTo(interleavedData, (int)((uint)i * 8) + codeBlock.CodeWordsOffset, pos, 8);
282+
foreach (var codeBlock in codeWordWithECC)
283+
if ((uint)codeBlock.CodeWordsLength / 8 > i)
284+
length += 8;
264285
}
265-
}
266-
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
267-
{
268-
foreach (var codeBlock in codeWordWithECC)
269-
if (codeBlock.ECCWords.Length > i)
270-
pos = DecToBin(codeBlock.ECCWords[i], 8, interleavedData, pos);
286+
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
287+
{
288+
foreach (var codeBlock in codeWordWithECC)
289+
if (codeBlock.ECCWords.Length > i)
290+
length += 8;
291+
}
292+
length += remainderBits[version - 1];
293+
return length;
271294
}
272295

273-
//Place interleaved data on module matrix
274-
var qr = new QRCodeData(version);
275-
var blockedModules = new List<Rectangle>(17);
276-
ModulePlacer.PlaceFinderPatterns(qr, blockedModules);
277-
ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, blockedModules);
278-
ModulePlacer.PlaceAlignmentPatterns(qr, alignmentPatternTable[version].PatternPositions, blockedModules);
279-
ModulePlacer.PlaceTimingPatterns(qr, blockedModules);
280-
ModulePlacer.PlaceDarkModule(qr, version, blockedModules);
281-
ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, blockedModules);
282-
ModulePlacer.PlaceDataWords(qr, interleavedData, blockedModules);
283-
var maskVersion = ModulePlacer.MaskCode(qr, version, blockedModules, eccLevel);
284-
var formatStr = GetFormatString(eccLevel, maskVersion);
285-
286-
ModulePlacer.PlaceFormat(qr, formatStr);
287-
if (version >= 7)
296+
// Interleave the data
297+
BitArray InterleaveData()
288298
{
289-
var versionString = GetVersionString(version);
290-
ModulePlacer.PlaceVersion(qr, versionString);
291-
}
292-
299+
var data = new BitArray(interleavedLength);
300+
int pos = 0;
301+
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
302+
{
303+
foreach (var codeBlock in codeWordWithECC)
304+
{
305+
if ((uint)codeBlock.CodeWordsLength / 8 > i)
306+
pos = bitArray.CopyTo(data, (int)((uint)i * 8) + codeBlock.CodeWordsOffset, pos, 8);
307+
}
308+
}
309+
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
310+
{
311+
foreach (var codeBlock in codeWordWithECC)
312+
if (codeBlock.ECCWords.Length > i)
313+
pos = DecToBin(codeBlock.ECCWords[i], 8, data, pos);
314+
}
293315

294-
ModulePlacer.AddQuietZone(qr);
295-
return qr;
316+
return data;
317+
}
296318

297-
void AddCodeWordBlocks(int blockNum, int blocksInGroup, int codewordsInGroup, int offset2, int count, Polynom generatorPolynom)
319+
// Place the modules on the QR code matrix
320+
QRCodeData PlaceModules()
298321
{
299-
var groupLength = codewordsInGroup * 8;
300-
for (var i = 0; i < blocksInGroup; i++)
322+
var qr = new QRCodeData(version);
323+
var blockedModules = new List<Rectangle>(17);
324+
ModulePlacer.PlaceFinderPatterns(qr, blockedModules);
325+
ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, blockedModules);
326+
ModulePlacer.PlaceAlignmentPatterns(qr, alignmentPatternTable[version].PatternPositions, blockedModules);
327+
ModulePlacer.PlaceTimingPatterns(qr, blockedModules);
328+
ModulePlacer.PlaceDarkModule(qr, version, blockedModules);
329+
ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, blockedModules);
330+
ModulePlacer.PlaceDataWords(qr, interleavedData, blockedModules);
331+
var maskVersion = ModulePlacer.MaskCode(qr, version, blockedModules, eccLevel);
332+
var formatStr = GetFormatString(eccLevel, maskVersion);
333+
334+
ModulePlacer.PlaceFormat(qr, formatStr);
335+
if (version >= 7)
301336
{
302-
var eccWordList = CalculateECCWords(bitArray, offset2, groupLength, eccInfo, generatorPolynom);
303-
codeWordWithECC.Add(new CodewordBlock(offset2, groupLength, eccWordList));
304-
offset2 += groupLength;
337+
var versionString = GetVersionString(version);
338+
ModulePlacer.PlaceVersion(qr, versionString);
305339
}
340+
341+
ModulePlacer.AddQuietZone(qr);
342+
343+
return qr;
306344
}
307345
}
308346

0 commit comments

Comments
 (0)