Skip to content

Commit 02baa95

Browse files
authored
Merge pull request #528 from Shane32/reorganize_generate_qr_code
Reorganize GenerateQrCode for better clarity
2 parents 1030701 + 308c231 commit 02baa95

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
@@ -226,109 +226,147 @@ private static ECCLevel ValidateECCLevel(ECCLevel eccLevel)
226226
/// <returns>A QRCodeData structure containing the full QR code matrix, which can be used for rendering or analysis.</returns>
227227
private static QRCodeData GenerateQrCode(BitArray bitArray, ECCLevel eccLevel, int version)
228228
{
229-
//Fill up data code word
230229
var eccInfo = capacityECCTable.Single(x => x.Version == version && x.ErrorCorrectionLevel == eccLevel);
231-
var dataLength = eccInfo.TotalDataCodewords * 8;
232-
var lengthDiff = dataLength - bitArray.Length;
233-
if (lengthDiff > 0)
230+
231+
// Fill up data code word
232+
PadData();
233+
234+
// Calculate error correction blocks
235+
var codeWordWithECC = CalculateECCBlocks();
236+
237+
// Calculate interleaved code word lengths
238+
var interleavedLength = CalculateInterleavedLength();
239+
240+
// Interleave code words
241+
var interleavedData = InterleaveData();
242+
243+
// Place interleaved data on module matrix
244+
var qrData = PlaceModules();
245+
246+
return qrData;
247+
248+
249+
// fills the bit array with a repeating pattern to reach the required length
250+
void PadData()
234251
{
235-
// set 'write index' to end of existing bit array
236-
var index = bitArray.Length;
237-
// extend bit array to required length
238-
bitArray.Length = dataLength;
239-
// pad with 4 zeros (or less if lengthDiff < 4)
240-
index += Math.Min(lengthDiff, 4);
241-
// pad to nearest 8 bit boundary
242-
if ((uint)index % 8 != 0)
243-
index += 8 - (int)((uint)index % 8);
244-
// pad with repeating pattern
245-
var repeatingPatternIndex = 0;
246-
while (index < dataLength)
252+
var dataLength = eccInfo.TotalDataCodewords * 8;
253+
var lengthDiff = dataLength - bitArray.Length;
254+
if (lengthDiff > 0)
247255
{
248-
bitArray[index++] = _repeatingPattern[repeatingPatternIndex++];
249-
if (repeatingPatternIndex >= _repeatingPattern.Length)
250-
repeatingPatternIndex = 0;
256+
// set 'write index' to end of existing bit array
257+
var index = bitArray.Length;
258+
// extend bit array to required length
259+
bitArray.Length = dataLength;
260+
// pad with 4 zeros (or less if lengthDiff < 4)
261+
index += Math.Min(lengthDiff, 4);
262+
// pad to nearest 8 bit boundary
263+
if ((uint)index % 8 != 0)
264+
index += 8 - (int)((uint)index % 8);
265+
// pad with repeating pattern
266+
var repeatingPatternIndex = 0;
267+
while (index < dataLength)
268+
{
269+
bitArray[index++] = _repeatingPattern[repeatingPatternIndex++];
270+
if (repeatingPatternIndex >= _repeatingPattern.Length)
271+
repeatingPatternIndex = 0;
272+
}
251273
}
252274
}
253275

254-
// Generate the generator polynomial using the number of ECC words.
255-
List<CodewordBlock> codeWordWithECC;
256-
using (var generatorPolynom = CalculateGeneratorPolynom(eccInfo.ECCPerBlock))
276+
List<CodewordBlock> CalculateECCBlocks()
257277
{
258-
//Calculate error correction words
259-
codeWordWithECC = new List<CodewordBlock>(eccInfo.BlocksInGroup1 + eccInfo.BlocksInGroup2);
260-
AddCodeWordBlocks(1, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, 0, bitArray.Length, generatorPolynom);
261-
int offset = eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8;
262-
AddCodeWordBlocks(2, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, offset, bitArray.Length - offset, generatorPolynom);
263-
}
278+
List<CodewordBlock> codewordBlocks;
279+
// Generate the generator polynomial using the number of ECC words.
280+
using (var generatorPolynom = CalculateGeneratorPolynom(eccInfo.ECCPerBlock))
281+
{
282+
//Calculate error correction words
283+
codewordBlocks = new List<CodewordBlock>(eccInfo.BlocksInGroup1 + eccInfo.BlocksInGroup2);
284+
AddCodeWordBlocks(1, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, 0, bitArray.Length, generatorPolynom);
285+
int offset = eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8;
286+
AddCodeWordBlocks(2, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, offset, bitArray.Length - offset, generatorPolynom);
287+
return codewordBlocks;
288+
}
264289

265-
//Calculate interleaved code word lengths
266-
int interleavedLength = 0;
267-
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
268-
{
269-
foreach (var codeBlock in codeWordWithECC)
270-
if ((uint)codeBlock.CodeWordsLength / 8 > i)
271-
interleavedLength += 8;
272-
}
273-
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
274-
{
275-
foreach (var codeBlock in codeWordWithECC)
276-
if (codeBlock.ECCWords.Length > i)
277-
interleavedLength += 8;
290+
void AddCodeWordBlocks(int blockNum, int blocksInGroup, int codewordsInGroup, int offset2, int count, Polynom generatorPolynom)
291+
{
292+
var groupLength = codewordsInGroup * 8;
293+
for (var i = 0; i < blocksInGroup; i++)
294+
{
295+
var eccWordList = CalculateECCWords(bitArray, offset2, groupLength, eccInfo, generatorPolynom);
296+
codewordBlocks.Add(new CodewordBlock(offset2, groupLength, eccWordList));
297+
offset2 += groupLength;
298+
}
299+
}
278300
}
279-
interleavedLength += remainderBits[version - 1];
280301

281-
//Interleave code words
282-
var interleavedData = new BitArray(interleavedLength);
283-
int pos = 0;
284-
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
302+
// Calculate the length of the interleaved data
303+
int CalculateInterleavedLength()
285304
{
286-
foreach (var codeBlock in codeWordWithECC)
305+
var length = 0;
306+
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
287307
{
288-
if ((uint)codeBlock.CodeWordsLength / 8 > i)
289-
pos = bitArray.CopyTo(interleavedData, (int)((uint)i * 8) + codeBlock.CodeWordsOffset, pos, 8);
308+
foreach (var codeBlock in codeWordWithECC)
309+
if ((uint)codeBlock.CodeWordsLength / 8 > i)
310+
length += 8;
290311
}
291-
}
292-
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
293-
{
294-
foreach (var codeBlock in codeWordWithECC)
295-
if (codeBlock.ECCWords.Length > i)
296-
pos = DecToBin(codeBlock.ECCWords[i], 8, interleavedData, pos);
312+
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
313+
{
314+
foreach (var codeBlock in codeWordWithECC)
315+
if (codeBlock.ECCWords.Length > i)
316+
length += 8;
317+
}
318+
length += remainderBits[version - 1];
319+
return length;
297320
}
298321

299-
//Place interleaved data on module matrix
300-
var qr = new QRCodeData(version);
301-
var blockedModules = new List<Rectangle>(17);
302-
ModulePlacer.PlaceFinderPatterns(qr, blockedModules);
303-
ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, blockedModules);
304-
ModulePlacer.PlaceAlignmentPatterns(qr, alignmentPatternTable[version].PatternPositions, blockedModules);
305-
ModulePlacer.PlaceTimingPatterns(qr, blockedModules);
306-
ModulePlacer.PlaceDarkModule(qr, version, blockedModules);
307-
ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, blockedModules);
308-
ModulePlacer.PlaceDataWords(qr, interleavedData, blockedModules);
309-
var maskVersion = ModulePlacer.MaskCode(qr, version, blockedModules, eccLevel);
310-
var formatStr = GetFormatString(eccLevel, maskVersion);
311-
312-
ModulePlacer.PlaceFormat(qr, formatStr);
313-
if (version >= 7)
322+
// Interleave the data
323+
BitArray InterleaveData()
314324
{
315-
var versionString = GetVersionString(version);
316-
ModulePlacer.PlaceVersion(qr, versionString);
317-
}
318-
325+
var data = new BitArray(interleavedLength);
326+
int pos = 0;
327+
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
328+
{
329+
foreach (var codeBlock in codeWordWithECC)
330+
{
331+
if ((uint)codeBlock.CodeWordsLength / 8 > i)
332+
pos = bitArray.CopyTo(data, (int)((uint)i * 8) + codeBlock.CodeWordsOffset, pos, 8);
333+
}
334+
}
335+
for (var i = 0; i < eccInfo.ECCPerBlock; i++)
336+
{
337+
foreach (var codeBlock in codeWordWithECC)
338+
if (codeBlock.ECCWords.Length > i)
339+
pos = DecToBin(codeBlock.ECCWords[i], 8, data, pos);
340+
}
319341

320-
ModulePlacer.AddQuietZone(qr);
321-
return qr;
342+
return data;
343+
}
322344

323-
void AddCodeWordBlocks(int blockNum, int blocksInGroup, int codewordsInGroup, int offset2, int count, Polynom generatorPolynom)
345+
// Place the modules on the QR code matrix
346+
QRCodeData PlaceModules()
324347
{
325-
var groupLength = codewordsInGroup * 8;
326-
for (var i = 0; i < blocksInGroup; i++)
348+
var qr = new QRCodeData(version);
349+
var blockedModules = new List<Rectangle>(17);
350+
ModulePlacer.PlaceFinderPatterns(qr, blockedModules);
351+
ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, blockedModules);
352+
ModulePlacer.PlaceAlignmentPatterns(qr, alignmentPatternTable[version].PatternPositions, blockedModules);
353+
ModulePlacer.PlaceTimingPatterns(qr, blockedModules);
354+
ModulePlacer.PlaceDarkModule(qr, version, blockedModules);
355+
ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, blockedModules);
356+
ModulePlacer.PlaceDataWords(qr, interleavedData, blockedModules);
357+
var maskVersion = ModulePlacer.MaskCode(qr, version, blockedModules, eccLevel);
358+
var formatStr = GetFormatString(eccLevel, maskVersion);
359+
360+
ModulePlacer.PlaceFormat(qr, formatStr);
361+
if (version >= 7)
327362
{
328-
var eccWordList = CalculateECCWords(bitArray, offset2, groupLength, eccInfo, generatorPolynom);
329-
codeWordWithECC.Add(new CodewordBlock(offset2, groupLength, eccWordList));
330-
offset2 += groupLength;
363+
var versionString = GetVersionString(version);
364+
ModulePlacer.PlaceVersion(qr, versionString);
331365
}
366+
367+
ModulePlacer.AddQuietZone(qr);
368+
369+
return qr;
332370
}
333371
}
334372

0 commit comments

Comments
 (0)