Continued implementing C library by adding functions to append Reed-Solomon ECC and interleave blocks.

pull/11/head
Project Nayuki 8 years ago
parent 3f6916d43e
commit 703fcf587d

@ -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) {

Loading…
Cancel
Save