@@ -105,6 +105,10 @@ public static QRCodeData GenerateQrCode(PayloadGenerator.Payload payload)
105
105
/// <returns>Returns the raw QR code data which can be used for rendering.</returns>
106
106
public static QRCodeData GenerateQrCode ( PayloadGenerator . Payload payload , ECCLevel eccLevel )
107
107
{
108
+ if ( eccLevel == ECCLevel . Default )
109
+ eccLevel = payload . EccLevel ;
110
+ else if ( payload . EccLevel != ECCLevel . Default && eccLevel != payload . EccLevel )
111
+ throw new ArgumentOutOfRangeException ( nameof ( eccLevel ) , $ "The provided payload requires a ECC level of { eccLevel } .") ;
108
112
return GenerateQrCode ( payload . ToString ( ) , eccLevel , false , false , payload . EciMode , payload . Version ) ;
109
113
}
110
114
@@ -121,6 +125,7 @@ public static QRCodeData GenerateQrCode(PayloadGenerator.Payload payload, ECCLev
121
125
/// <returns>Returns the raw QR code data which can be used for rendering.</returns>
122
126
public static QRCodeData GenerateQrCode ( string plainText , ECCLevel eccLevel , bool forceUtf8 = false , bool utf8BOM = false , EciMode eciMode = EciMode . Default , int requestedVersion = - 1 )
123
127
{
128
+ eccLevel = ValidateECCLevel ( eccLevel ) ;
124
129
EncodingMode encoding = GetEncodingFromPlaintext ( plainText , forceUtf8 ) ;
125
130
var codedText = PlainTextToBinary ( plainText , encoding , eciMode , utf8BOM , forceUtf8 ) ;
126
131
var dataInputLength = GetDataLength ( encoding , plainText , codedText , forceUtf8 ) ;
@@ -165,7 +170,6 @@ public static QRCodeData GenerateQrCode(string plainText, ECCLevel eccLevel, boo
165
170
return GenerateQrCode ( completeBitArray , eccLevel , version ) ;
166
171
}
167
172
168
-
169
173
/// <summary>
170
174
/// Calculates the QR code data which than can be used in one of the rendering classes to generate a graphical representation.
171
175
/// </summary>
@@ -175,6 +179,7 @@ public static QRCodeData GenerateQrCode(string plainText, ECCLevel eccLevel, boo
175
179
/// <returns>Returns the raw QR code data which can be used for rendering.</returns>
176
180
public static QRCodeData GenerateQrCode ( byte [ ] binaryData , ECCLevel eccLevel )
177
181
{
182
+ eccLevel = ValidateECCLevel ( eccLevel ) ;
178
183
int version = GetVersion ( binaryData . Length , EncodingMode . Byte , eccLevel ) ;
179
184
180
185
int countIndicatorLen = GetCountIndicatorLength ( version , EncodingMode . Byte ) ;
@@ -187,6 +192,27 @@ public static QRCodeData GenerateQrCode(byte[] binaryData, ECCLevel eccLevel)
187
192
return GenerateQrCode ( bitArray , eccLevel , version ) ;
188
193
}
189
194
195
+ /// <summary>
196
+ /// Validates the specified error correction level.
197
+ /// Returns the provided level if it is valid, or the level M if the provided level is Default.
198
+ /// Throws an exception if an invalid level is provided.
199
+ /// </summary>
200
+ private static ECCLevel ValidateECCLevel ( ECCLevel eccLevel )
201
+ {
202
+ switch ( eccLevel )
203
+ {
204
+ case ECCLevel . L :
205
+ case ECCLevel . M :
206
+ case ECCLevel . Q :
207
+ case ECCLevel . H :
208
+ return eccLevel ;
209
+ case ECCLevel . Default :
210
+ return ECCLevel . M ;
211
+ default :
212
+ throw new ArgumentOutOfRangeException ( nameof ( eccLevel ) , eccLevel , "Invalid error correction level." ) ;
213
+ }
214
+ }
215
+
190
216
private static readonly BitArray _repeatingPattern = new BitArray (
191
217
new [ ] { true , true , true , false , true , true , false , false , false , false , false , true , false , false , false , true } ) ;
192
218
@@ -200,109 +226,147 @@ public static QRCodeData GenerateQrCode(byte[] binaryData, ECCLevel eccLevel)
200
226
/// <returns>A QRCodeData structure containing the full QR code matrix, which can be used for rendering or analysis.</returns>
201
227
private static QRCodeData GenerateQrCode ( BitArray bitArray , ECCLevel eccLevel , int version )
202
228
{
203
- //Fill up data code word
204
229
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 )
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 ( )
208
251
{
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 )
252
+ var dataLength = eccInfo . TotalDataCodewords * 8 ;
253
+ var lengthDiff = dataLength - bitArray . Length ;
254
+ if ( lengthDiff > 0 )
221
255
{
222
- bitArray [ index ++ ] = _repeatingPattern [ repeatingPatternIndex ++ ] ;
223
- if ( repeatingPatternIndex >= _repeatingPattern . Length )
224
- 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
+ }
225
273
}
226
274
}
227
275
228
- // Generate the generator polynomial using the number of ECC words.
229
- List < CodewordBlock > codeWordWithECC ;
230
- using ( var generatorPolynom = CalculateGeneratorPolynom ( eccInfo . ECCPerBlock ) )
276
+ List < CodewordBlock > CalculateECCBlocks ( )
231
277
{
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
- }
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
+ }
238
289
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 ;
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
+ }
252
300
}
253
- interleavedLength += remainderBits [ version - 1 ] ;
254
301
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 ++ )
302
+ // Calculate the length of the interleaved data
303
+ int CalculateInterleavedLength ( )
259
304
{
260
- foreach ( var codeBlock in codeWordWithECC )
305
+ var length = 0 ;
306
+ for ( var i = 0 ; i < Math . Max ( eccInfo . CodewordsInGroup1 , eccInfo . CodewordsInGroup2 ) ; i ++ )
261
307
{
262
- if ( ( uint ) codeBlock . CodeWordsLength / 8 > i )
263
- 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 ;
264
311
}
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 ) ;
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 ;
271
320
}
272
321
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 )
322
+ // Interleave the data
323
+ BitArray InterleaveData ( )
288
324
{
289
- var versionString = GetVersionString ( version ) ;
290
- ModulePlacer . PlaceVersion ( qr , versionString ) ;
291
- }
292
-
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
+ }
293
341
294
- ModulePlacer . AddQuietZone ( qr ) ;
295
- return qr ;
342
+ return data ;
343
+ }
296
344
297
- 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 ( )
298
347
{
299
- var groupLength = codewordsInGroup * 8 ;
300
- 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 )
301
362
{
302
- var eccWordList = CalculateECCWords ( bitArray , offset2 , groupLength , eccInfo , generatorPolynom ) ;
303
- codeWordWithECC . Add ( new CodewordBlock ( offset2 , groupLength , eccWordList ) ) ;
304
- offset2 += groupLength ;
363
+ var versionString = GetVersionString ( version ) ;
364
+ ModulePlacer . PlaceVersion ( qr , versionString ) ;
305
365
}
366
+
367
+ ModulePlacer . AddQuietZone ( qr ) ;
368
+
369
+ return qr ;
306
370
}
307
371
}
308
372
0 commit comments