diff --git a/backend/qr.c b/backend/qr.c index 570ed5ab..5c44891f 100644 --- a/backend/qr.c +++ b/backend/qr.c @@ -20,6 +20,9 @@ */ #include +#ifdef _MSC_VER +#include +#endif #include "common.h" #include #include "sjis.h" @@ -151,7 +154,7 @@ int estimate_binary_length(char mode[], int length) void qr_binary(int datastream[], int version, int target_binlen, char mode[], int jisdata[], int length) { /* Convert input data to a binary stream and add padding */ - int position = 0, debug = 1; + int position = 0, debug = 0; int short_data_block_length, i, scheme; char data_block, padbits; int current_binlen, current_bytes; @@ -160,7 +163,7 @@ void qr_binary(int datastream[], int version, int target_binlen, char mode[], in #ifndef _MSC_VER char binary[target_binlen * 8]; #else - char binary = (char *)_alloca(target_binlen * 8); + char* binary = (char *)_alloca(target_binlen * 8); #endif strcpy(binary, ""); @@ -500,7 +503,7 @@ void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int b int qty_long_blocks = data_cw % blocks; int qty_short_blocks = blocks - qty_long_blocks; int ecc_block_length = ecc_cw / blocks; - int i, j, length_this_block, posn, debug = 1; + int i, j, length_this_block, posn, debug = 0; RS *rs; @@ -510,10 +513,10 @@ void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int b int interleaved_data[data_cw + 2]; int interleaved_ecc[ecc_cw + 2]; #else - unsigned char data_block = (unsigned char *)_alloca(short_data_block_length + 2); - unsigned char ecc_block = (unsigned char *)_alloca(ecc_block_length + 2); - int interleaved_data = (int *)_alloca(data_cw + 2); - int interleaved_ecc = (int *)_alloca(ecc_cw + 2); + unsigned char* data_block = (unsigned char *)_alloca(short_data_block_length + 2); + unsigned char* ecc_block = (unsigned char *)_alloca(ecc_block_length + 2); + int* interleaved_data = (int *)_alloca((data_cw + 2) * sizeof(int)); + int* interleaved_ecc = (int *)_alloca((ecc_cw + 2) * sizeof(int)); #endif posn = 0; @@ -604,40 +607,459 @@ void place_finder(unsigned char grid[], int size, int x, int y) } } -void setup_grid(unsigned char* grid, int size) +void place_align(unsigned char grid[], int size, int x, int y) +{ + int xp, yp; + + int alignment[] = { + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + }; + + x -= 2; + y -= 2; /* Input values represent centre of pattern */ + + for(xp = 0; xp < 5; xp++) { + for(yp = 0; yp < 5; yp++) { + if (alignment[xp + (5 * yp)] == 1) { + grid[((yp + y) * size) + (xp + x)] = 0x11; + } else { + grid[((yp + y) * size) + (xp + x)] = 0x10; + } + } + } +} + +void setup_grid(unsigned char* grid, int size, int version) { int i, toggle = 1; + int loopsize, x, y, xcoord, ycoord; + /* Add timing patterns */ for(i = 0; i < size; i++) { if(toggle == 1) { - grid[(6 * size) + i] = 0x11; - grid[(i * size) + 6] = 0x11; + grid[(6 * size) + i] = 0x21; + grid[(i * size) + 6] = 0x21; toggle = 0; } else { - grid[(6 * size) + i] = 0x10; - grid[(i * size) + 6] = 0x10; + grid[(6 * size) + i] = 0x20; + grid[(i * size) + 6] = 0x20; toggle = 1; } } + /* Add finder patterns */ place_finder(grid, size, 0, 0); place_finder(grid, size, 0, size - 7); place_finder(grid, size, size - 7, 0); + + /* Add separators */ + for(i = 0; i < 7; i++) { + grid[(7 * size) + i] = 0x10; + grid[(i * size) + 7] = 0x10; + grid[(7 * size) + (size - 1 - i)] = 0x10; + grid[(i * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + i] = 0x10; + grid[((size - 1 - i) * size) + 7] = 0x10; + } + grid[(7 * size) + 7] = 0x10; + grid[(7 * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + 7] = 0x10; + + /* Add alignment patterns */ + if(version != 1) { + /* Version 1 does not have alignment patterns */ + + loopsize = qr_align_loopsize[version - 1]; + for(x = 0; x < loopsize; x++) { + for(y = 0; y < loopsize; y++) { + xcoord = qr_table_e1[((version - 2) * 7) + x]; + ycoord = qr_table_e1[((version - 2) * 7) + y]; + + if(!(grid[(ycoord * size) + xcoord] & 0x10)) { + place_align(grid, size, xcoord, ycoord); + } + } + } + } + + /* Reserve space for format information */ + for(i = 0; i < 8; i++) { + grid[(8 * size) + i] += 0x20; + grid[(i * size) + 8] += 0x20; + grid[(8 * size) + (size - 1 - i)] = 0x20; + grid[((size - 1 - i) * size) + 8] = 0x20; + } + grid[(8 * size) + 8] += 20; + grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */ + + /* Reserve space for version information */ + if(version >= 7) { + for(i = 0; i < 6; i++) { + grid[((size - 9) * size) + i] = 0x20; + grid[((size - 10) * size) + i] = 0x20; + grid[((size - 11) * size) + i] = 0x20; + grid[(i * size) + (size - 9)] = 0x20; + grid[(i * size) + (size - 10)] = 0x20; + grid[(i * size) + (size - 11)] = 0x20; + } + } +} + +int cwbit(int* datastream, int i) { + int word = i / 8; + int bit = i % 8; + int resultant = 0; + + switch(bit) { + case 0: if(datastream[word] & 0x80) { resultant = 1; } else { resultant = 0; } break; + case 1: if(datastream[word] & 0x40) { resultant = 1; } else { resultant = 0; } break; + case 2: if(datastream[word] & 0x20) { resultant = 1; } else { resultant = 0; } break; + case 3: if(datastream[word] & 0x10) { resultant = 1; } else { resultant = 0; } break; + case 4: if(datastream[word] & 0x08) { resultant = 1; } else { resultant = 0; } break; + case 5: if(datastream[word] & 0x04) { resultant = 1; } else { resultant = 0; } break; + case 6: if(datastream[word] & 0x02) { resultant = 1; } else { resultant = 0; } break; + case 7: if(datastream[word] & 0x01) { resultant = 1; } else { resultant = 0; } break; + } + + return resultant; +} + +void populate_grid(unsigned char* grid, int size, int* datastream, int cw) +{ + int direction = 1; /* up */ + int row = 0; /* right hand side */ + + int i, n, x, y; + + n = cw * 8; + y = size - 1; + i = 0; + do { + x = (size - 2) - (row * 2); + if(x < 6) + x--; /* skip over vertical timing pattern */ + + if(!(grid[(y * size) + (x + 1)] & 0xf0)) { + if (cwbit(datastream, i)) { + grid[(y * size) + (x + 1)] = 0x01; + } else { + grid[(y * size) + (x + 1)] = 0x00; + } + i++; + } + + if(i < n) { + if(!(grid[(y * size) + x] & 0xf0)) { + if (cwbit(datastream, i)) { + grid[(y * size) + x] = 0x01; + } else { + grid[(y * size) + x] = 0x00; + } + i++; + } + } + + if(direction) { y--; } else { y++; } + if(y == -1) { + /* reached the top */ + row++; + y = 0; + direction = 0; + } + if(y == size) { + /* reached the bottom */ + row++; + y = size - 1; + direction = 1; + } + } while (i < n); +} + +int evaluate(unsigned char *grid, int size, int pattern) +{ + int x, y, block; + int result = 0; + char state; + int p; + int dark_mods; + int percentage, k; + +#ifndef _MSC_VER + char local[size * size]; +#else + char* local = (char *)_alloca((size * size) * sizeof(char)); +#endif + + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + switch(pattern) { + case 0: if (grid[(y * size) + x] & 0x01) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 1: if (grid[(y * size) + x] & 0x02) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 2: if (grid[(y * size) + x] & 0x04) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 3: if (grid[(y * size) + x] & 0x08) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 4: if (grid[(y * size) + x] & 0x10) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 5: if (grid[(y * size) + x] & 0x20) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 6: if (grid[(y * size) + x] & 0x40) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 7: if (grid[(y * size) + x] & 0x80) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + } + } + } + + /* Test 1: Adjacent modules in row/column in same colour */ + /* Vertical */ + for(x = 0; x < size; x++) { + state = local[x]; + block = 0; + for(y = 0; y < size; y++) { + if(local[(y * size) + x] == state) { + block++; + } else { + if(block > 5) { + result += (3 + block); + } + block = 0; + state = local[(y * size) + x]; + } + } + if(block > 5) { + result += (3 + block); + } + } + + /* Horizontal */ + for(y = 0; y < size; y++) { + state = local[y * size]; + block = 0; + for(x = 0; x < size; x++) { + if(local[(y * size) + x] == state) { + block++; + } else { + if(block > 5) { + result += (3 + block); + } + block = 0; + state = local[(y * size) + x]; + } + } + if(block > 5) { + result += (3 + block); + } + } + + /* Test 2 is not implimented */ + + /* Test 3: 1:1:3:1:1 ratio pattern in row/column */ + /* Vertical */ + for(x = 0; x < size; x++) { + for(y = 0; y < (size - 7); y++) { + p = 0; + if(local[(y * size) + x] == '1') { p += 0x40; } + if(local[((y + 1) * size) + x] == '1') { p += 0x20; } + if(local[((y + 2) * size) + x] == '1') { p += 0x10; } + if(local[((y + 3) * size) + x] == '1') { p += 0x08; } + if(local[((y + 4) * size) + x] == '1') { p += 0x04; } + if(local[((y + 5) * size) + x] == '1') { p += 0x02; } + if(local[((y + 6) * size) + x] == '1') { p += 0x01; } + if(p == 0x5d) { + result += 40; + } + } + } + + /* Horizontal */ + for(y = 0; y < size; y++) { + for(x = 0; x < (size - 7); x++) { + p = 0; + if(local[(y * size) + x] == '1') { p += 0x40; } + if(local[(y * size) + x + 1] == '1') { p += 0x20; } + if(local[(y * size) + x + 2] == '1') { p += 0x10; } + if(local[(y * size) + x + 3] == '1') { p += 0x08; } + if(local[(y * size) + x + 4] == '1') { p += 0x04; } + if(local[(y * size) + x + 5] == '1') { p += 0x02; } + if(local[(y * size) + x + 6] == '1') { p += 0x01; } + if(p == 0x5d) { + result += 40; + } + } + } + + /* Test 4: Proportion of dark modules in entire symbol */ + dark_mods = 0; + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + if(local[(y * size) + x] == '1') { + dark_mods++; + } + } + } + percentage = 100 * (dark_mods / (size * size)); + if(percentage <= 50) { + k = ((100 - percentage) - 50) / 5; + } else { + k = (percentage - 50) / 5; + } + + result += 10 * k; + + return result; +} + + +int apply_bitmask(unsigned char *grid, int size) +{ + int x, y; + unsigned char p; + int pattern, penalty[8]; + int best_val, best_pattern; + int bit; + +#ifndef _MSC_VER + unsigned char mask[size * size]; + unsigned char eval[size * size]; +#else + unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); +#endif + + /* Perform data masking */ + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + mask[(y * size) + x] = 0x00; + + if (!(grid[(y * size) + x] & 0xf0)) { + if(((y + x) % 2) == 0) { mask[(y * size) + x] += 0x01; } + if((y % 2) == 0) { mask[(y * size) + x] += 0x02; } + if((x % 3) == 0) { mask[(y * size) + x] += 0x04; } + if(((y + x) % 3) == 0) { mask[(y * size) + x] += 0x08; } + if((((y / 2) + (x / 3)) % 2) == 0) { mask[(y * size) + x] += 0x10; } + if((((y * x) % 2) + ((y * x) % 3)) == 0) { mask[(y * size) + x] += 0x20; } + if(((((y * x) % 2) + ((y * x) % 3)) % 2) == 0) { mask[(y * size) + x] += 0x40; } + if(((((y + x) % 2) + ((y * x) % 3)) % 2) == 0) { mask[(y * size) + x] += 0x80; } + } + } + } + + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; } + + eval[(y * size) + x] = mask[(y * size) + x] ^ p; + } + } + + + /* Evaluate result */ + for(pattern = 0; pattern < 8; pattern++) { + penalty[pattern] = evaluate(eval, size, pattern); + } + + best_pattern = 0; + best_val = penalty[0]; + for(pattern = 1; pattern < 8; pattern++) { + if(penalty[pattern] < best_val) { + best_pattern = pattern; + best_val = penalty[pattern]; + } + } + + /* Apply mask */ + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + bit = 0; + switch(best_pattern) { + case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; + case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; + case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; + case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; + case 4: if(mask[(y * size) + x] & 0x10) { bit = 1; } break; + case 5: if(mask[(y * size) + x] & 0x20) { bit = 1; } break; + case 6: if(mask[(y * size) + x] & 0x40) { bit = 1; } break; + case 7: if(mask[(y * size) + x] & 0x80) { bit = 1; } break; + } + if(bit == 1) { + if(grid[(y * size) + x] & 0x01) { + grid[(y * size) + x] = 0x00; + } else { + grid[(y * size) + x] = 0x01; + } + } + } + } + + return best_pattern; +} + +void add_format_info(unsigned char *grid, int size, int ecc_level, int pattern) +{ + /* Add format information to grid */ + + int format = pattern; + unsigned int seq; + int i; + + switch(ecc_level) { + case LEVEL_L: format += 0x08; break; + case LEVEL_Q: format += 0x18; break; + case LEVEL_H: format += 0x10; break; + } + + seq = qr_annex_c[format]; + + for(i = 0; i < 6; i++) { + grid[(i * size) + 8] += (seq >> i) & 0x01; + } + + for(i = 0; i < 8; i++) { + grid[(8 * size) + (size - i - 1)] += (seq >> i) & 0x01; + } + + for(i = 0; i < 6; i++) { + grid[(8 * size) + (5 - i)] += (seq >> (i + 9)) & 0x01; + } + + for(i = 0; i < 7; i++) { + grid[(((size - 7) + i) * size) + 8] += (seq >> (i + 8)) & 0x01; + } + + grid[(7 * size) + 8] += (seq >> 6) & 0x01; + grid[(8 * size) + 8] += (seq >> 7) & 0x01; + grid[(8 * size) + 7] += (seq >> 8) & 0x01; +} + +void add_version_info(unsigned char *grid, int size, int version) +{ + /* Add version information */ + int i; + + long int version_data = qr_annex_d[version - 7]; + for(i = 0; i < 6; i++) { + grid[((size - 11) * size) + i] += (version_data >> (17 - (i * 3))) & 0x01; + grid[((size - 10) * size) + i] += (version_data >> (16 - (i * 3))) & 0x01; + grid[((size - 9) * size) + i] += (version_data >> (15 - (i * 3))) & 0x01; + grid[(i * size) + (size - 11)] += (version_data >> (17 - (i * 3))) & 0x01; + grid[(i * size) + (size - 10)] += (version_data >> (16 - (i * 3))) & 0x01; + grid[(i * size) + (size - 9)] += (version_data >> (15 - (i * 3))) & 0x01; + } } int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) { int error_number, i, j, glyph, est_binlen; int ecc_level, autosize, version, max_cw, target_binlen, blocks, size; + int bitmask; #ifndef _MSC_VER int utfdata[length + 1]; int jisdata[length + 1]; char mode[length + 1]; #else - int utfdata = (int *)_alloca((length + 1) * sizeof(int)); - int jisdata = (int *)_alloca((length + 1) * sizeof(int)); - char mode = (char *)_alloca((length + 1) * sizeof(int)); + int* utfdata = (int *)_alloca((length + 1) * sizeof(int)); + int* jisdata = (int *)_alloca((length + 1) * sizeof(int)); + char* mode = (char *)_alloca(length + 1); #endif switch(symbol->input_mode) { @@ -739,8 +1161,8 @@ int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) int datastream[target_binlen + 1]; int fullstream[qr_total_codewords[version - 1] + 1]; #else - int datastream = (int *)_alloca((target_binlen + 1) * sizeof(int)); - int fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int)); + int* datastream = (int *)_alloca((target_binlen + 1) * sizeof(int)); + int* fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int)); #endif qr_binary(datastream, version, target_binlen, mode, jisdata, length); @@ -750,7 +1172,7 @@ int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) #ifndef _MSC_VER unsigned char grid[size * size]; #else - unsigned char grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + unsigned char* grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); #endif for(i = 0; i < size; i++) { @@ -759,7 +1181,13 @@ int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) } } - setup_grid(grid, size); + setup_grid(grid, size, version); + populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]); + bitmask = apply_bitmask(grid, size); + add_format_info(grid, size, ecc_level, bitmask); + if(version >= 7) { + add_version_info(grid, size, version); + } symbol->width = size; symbol->rows = size; @@ -773,8 +1201,6 @@ int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) symbol->row_height[i] = 1; } - printf("Version %d: target %d bytes\n", version, target_binlen); - return 0; } diff --git a/backend/qr.h b/backend/qr.h index 7f4efb15..bc90b0cf 100644 --- a/backend/qr.h +++ b/backend/qr.h @@ -82,3 +82,65 @@ static int qr_sizes[] = { 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177 }; + +static int qr_align_loopsize[] = { + 0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7 +}; + +static int qr_table_e1[] = { + 6, 18, 0, 0, 0, 0, 0, + 6, 22, 0, 0, 0, 0, 0, + 6, 26, 0, 0, 0, 0, 0, + 6, 30, 0, 0, 0, 0, 0, + 6, 34, 0, 0, 0, 0, 0, + 6, 22, 38, 0, 0, 0, 0, + 6, 24, 42, 0, 0, 0, 0, + 6, 26, 46, 0, 0, 0, 0, + 6, 28, 50, 0, 0, 0, 0, + 6, 30, 54, 0, 0, 0, 0, + 6, 32, 58, 0, 0, 0, 0, + 6, 34, 62, 0, 0, 0, 0, + 6, 26, 46, 66, 0, 0, 0, + 6, 26, 48, 70, 0, 0, 0, + 6, 26, 50, 74, 0, 0, 0, + 6, 30, 54, 78, 0, 0, 0, + 6, 30, 56, 82, 0, 0, 0, + 6, 30, 58, 86, 0, 0, 0, + 6, 34, 62, 90, 0, 0, 0, + 6, 28, 50, 72, 94, 0, 0, + 6, 26, 50, 74, 98, 0, 0, + 6, 30, 54, 78, 102, 0, 0, + 6, 28, 54, 80, 106, 0, 0, + 6, 32, 58, 84, 110, 0, 0, + 6, 30, 58, 86, 114, 0, 0, + 6, 34, 62, 90, 118, 0, 0, + 6, 26, 50, 74, 98, 122, 0, + 6, 30, 54, 78, 102, 126, 0, + 6, 26, 52, 78, 104, 130, 0, + 6, 30, 56, 82, 108, 134, 0, + 6, 34, 60, 86, 112, 138, 0, + 6, 30, 58, 86, 114, 142, 0, + 6, 34, 62, 90, 118, 146, 0, + 6, 30, 54, 78, 102, 126, 150, + 6, 24, 50, 76, 102, 128, 154, + 6, 28, 54, 80, 106, 132, 158, + 6, 32, 58, 84, 110, 136, 162, + 6, 26, 54, 82, 110, 138, 166, + 6, 30, 58, 86, 114, 142, 170 +}; + +static unsigned int qr_annex_c[] = { + /* Format information bit sequences */ + 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, + 0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, + 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed +}; + +static long int qr_annex_d[] = { + /* Version information bit sequences */ + 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, + 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, + 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, + 0x2542e, 0x26a64, 0x27541, 0x28c69 +}; + diff --git a/backend/qrrs.c b/backend/qrrs.c index d6162615..e85ae20c 100644 --- a/backend/qrrs.c +++ b/backend/qrrs.c @@ -248,6 +248,7 @@ void free_rs_cache(void) free_rs_char(rs); rs = next; } + rslist = NULL; } /* The guts of the Reed-Solomon encoder, meant to be #included