@ -39,6 +39,8 @@ static void drawWhiteFunctionModules(uint8_t qrcode[], int version);
static void drawFormatBits ( enum qrcodegen_Ecc ecl , enum qrcodegen_Mask mask , uint8_t qrcode [ ] , int size ) ;
static int getAlignmentPatternPositions ( int version , uint8_t result [ 7 ] ) ;
static void appendErrorCorrection ( uint8_t data [ ] , int version , enum qrcodegen_Ecc ecl , uint8_t result [ ] ) ;
static int getNumRawDataModules ( int version ) ;
static void drawCodewords ( const uint8_t data [ ] , int dataLen , uint8_t qrcode [ ] , int version ) ;
static void applyMask ( const uint8_t functionModules [ ] , uint8_t qrcode [ ] , int size , int mask ) ;
@ -48,6 +50,28 @@ static uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
/*---- Private tables of constants ----*/
static const int16_t NUM_ERROR_CORRECTION_CODEWORDS [ 4 ] [ 41 ] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{ - 1 , 7 , 10 , 15 , 20 , 26 , 36 , 40 , 48 , 60 , 72 , 80 , 96 , 104 , 120 , 132 , 144 , 168 , 180 , 196 , 224 , 224 , 252 , 270 , 300 , 312 , 336 , 360 , 390 , 420 , 450 , 480 , 510 , 540 , 570 , 570 , 600 , 630 , 660 , 720 , 750 } , // Low
{ - 1 , 10 , 16 , 26 , 36 , 48 , 64 , 72 , 88 , 110 , 130 , 150 , 176 , 198 , 216 , 240 , 280 , 308 , 338 , 364 , 416 , 442 , 476 , 504 , 560 , 588 , 644 , 700 , 728 , 784 , 812 , 868 , 924 , 980 , 1036 , 1064 , 1120 , 1204 , 1260 , 1316 , 1372 } , // Medium
{ - 1 , 13 , 22 , 36 , 52 , 72 , 96 , 108 , 132 , 160 , 192 , 224 , 260 , 288 , 320 , 360 , 408 , 448 , 504 , 546 , 600 , 644 , 690 , 750 , 810 , 870 , 952 , 1020 , 1050 , 1140 , 1200 , 1290 , 1350 , 1440 , 1530 , 1590 , 1680 , 1770 , 1860 , 1950 , 2040 } , // Quartile
{ - 1 , 17 , 28 , 44 , 64 , 88 , 112 , 130 , 156 , 192 , 224 , 264 , 308 , 352 , 384 , 432 , 480 , 532 , 588 , 650 , 700 , 750 , 816 , 900 , 960 , 1050 , 1110 , 1200 , 1260 , 1350 , 1440 , 1530 , 1620 , 1710 , 1800 , 1890 , 1980 , 2100 , 2220 , 2310 , 2430 } , // High
} ;
const int8_t NUM_ERROR_CORRECTION_BLOCKS [ 4 ] [ 41 ] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{ - 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , 4 , 4 , 6 , 6 , 6 , 6 , 7 , 8 , 8 , 9 , 9 , 10 , 12 , 12 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 19 , 20 , 21 , 22 , 24 , 25 } , // Low
{ - 1 , 1 , 1 , 1 , 2 , 2 , 4 , 4 , 4 , 5 , 5 , 5 , 8 , 9 , 9 , 10 , 10 , 11 , 13 , 14 , 16 , 17 , 17 , 18 , 20 , 21 , 23 , 25 , 26 , 28 , 29 , 31 , 33 , 35 , 37 , 38 , 40 , 43 , 45 , 47 , 49 } , // Medium
{ - 1 , 1 , 1 , 2 , 2 , 4 , 4 , 6 , 6 , 8 , 8 , 8 , 10 , 12 , 16 , 12 , 17 , 16 , 18 , 21 , 20 , 23 , 23 , 25 , 27 , 29 , 34 , 34 , 35 , 38 , 40 , 43 , 45 , 48 , 51 , 53 , 56 , 59 , 62 , 65 , 68 } , // Quartile
{ - 1 , 1 , 1 , 2 , 4 , 4 , 4 , 5 , 6 , 8 , 8 , 11 , 11 , 16 , 16 , 18 , 16 , 19 , 21 , 25 , 25 , 25 , 34 , 30 , 32 , 35 , 37 , 40 , 42 , 45 , 48 , 51 , 54 , 57 , 60 , 63 , 66 , 70 , 74 , 77 , 81 } , // High
} ;
/*---- Function implementations ----*/
// Public function - see documentation comment in header file.
@ -312,6 +336,66 @@ static int getAlignmentPatternPositions(int version, uint8_t result[7]) {
}
// Appends error correction bytes to each block of the given data array, then interleaves bytes
// from the blocks and stores them in the result array. data[0 : rawCodewords - totalEcc] contains
// the input data. data[rawCodewords - totalEcc : rawCodewords] is used as a temporary work area
// and will be clobbered by this function. The final answer is stored in result[0 : rawCodewords].
static void appendErrorCorrection ( uint8_t data [ ] , int version , enum qrcodegen_Ecc ecl , uint8_t result [ ] ) {
// Calculate parameter numbers
assert ( 0 < = ( int ) ecl & & ( int ) ecl < 4 & & 1 < = version & & version < = 40 ) ;
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS [ ( int ) ecl ] [ version ] ;
int totalEcc = NUM_ERROR_CORRECTION_CODEWORDS [ ( int ) ecl ] [ version ] ;
assert ( totalEcc % numBlocks = = 0 ) ;
int blockEccLen = totalEcc / numBlocks ;
int rawCodewords = getNumRawDataModules ( version ) / 8 ;
int dataLen = rawCodewords - totalEcc ;
int numShortBlocks = numBlocks - rawCodewords % numBlocks ;
int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen ;
// Split data into blocks and append ECC after all data
uint8_t generator [ 30 ] ;
calcReedSolomonGenerator ( blockEccLen , generator ) ;
for ( int i = 0 , j = dataLen , k = 0 ; i < numBlocks ; i + + ) {
int blockLen = shortBlockDataLen ;
if ( i > = numShortBlocks )
blockLen + + ;
calcReedSolomonRemainder ( & data [ k ] , blockLen , generator , blockEccLen , & data [ j ] ) ;
j + = blockEccLen ;
k + = blockLen ;
}
// Interleave (not concatenate) the bytes from every block into a single sequence
for ( int i = 0 , k = 0 ; i < numBlocks ; i + + ) {
for ( int j = 0 , l = i ; j < shortBlockDataLen ; j + + , k + + , l + = numBlocks )
result [ l ] = data [ k ] ;
if ( i > = numShortBlocks )
k + + ;
}
for ( int i = numShortBlocks , l = numBlocks * shortBlockDataLen , k = ( numShortBlocks + 1 ) * shortBlockDataLen ;
i < numBlocks ; i + + , k + = shortBlockDataLen + 1 , l + + )
result [ l ] = data [ k ] ;
for ( int i = 0 , k = dataLen ; i < numBlocks ; i + + ) {
for ( int j = 0 , l = dataLen + i ; j < blockEccLen ; j + + , k + + , l + = numBlocks )
result [ l ] = data [ k ] ;
}
}
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it may not be a multiple of 8.
static int getNumRawDataModules ( int version ) {
assert ( 1 < = version & & version < = 40 ) ;
int result = ( 16 * version + 128 ) * version + 64 ;
if ( version > = 2 ) {
int numAlign = version / 7 + 2 ;
result - = ( 25 * numAlign - 10 ) * numAlign - 55 ;
if ( version > = 7 )
result - = 18 * 2 ; // Subtract version information
}
return result ;
}
// Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of
// the QR Code to be black at function modules and white at codeword modules (including unused remainder bits).
static void drawCodewords ( const uint8_t data [ ] , int dataLen , uint8_t qrcode [ ] , int version ) {