mirror of
https://git.code.sf.net/p/zint/code
synced 2025-05-30 14:55:20 -04:00
Merge rMQR support in to master
This commit is contained in:
commit
8295883987
10 changed files with 2767 additions and 1781 deletions
531
backend/qr.c
531
backend/qr.c
|
@ -1,8 +1,7 @@
|
|||
/* qr.c Handles QR Code */
|
||||
/* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR
|
||||
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2009 -2017 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2009 - 2019 Robin Stuart <rstuart114@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -151,8 +150,8 @@ static int tribus(const int version,const int a,const int b,const int c) {
|
|||
}
|
||||
|
||||
/* Convert input data to a binary stream and add padding */
|
||||
static void qr_binary(unsigned char datastream[], const int version, const int target_binlen, const char mode[], const unsigned int jisdata[], const size_t length,
|
||||
const int gs1, const int eci, const int est_binlen, const int debug) {
|
||||
static void qr_binary(unsigned char datastream[], const int version, const int target_codewords, const char mode[], const unsigned int jisdata[], const size_t length,
|
||||
const int gs1, const int eci, const int est_binlen,const int debug) {
|
||||
int position = 0;
|
||||
int i;
|
||||
char padbits;
|
||||
|
@ -168,10 +167,14 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
strcpy(binary, "");
|
||||
|
||||
if (gs1) {
|
||||
strcat(binary, "0101"); /* FNC1 */
|
||||
if (version < RMQR_VERSION) {
|
||||
strcat(binary, "0101"); /* FNC1 */
|
||||
} else {
|
||||
strcat(binary, "101");
|
||||
}
|
||||
}
|
||||
|
||||
if (eci != 0) {
|
||||
if (eci != 0) { /* Not applicable to RMQR */
|
||||
strcat(binary, "0111"); /* ECI (Table 4) */
|
||||
if (eci <= 127) {
|
||||
bin_append(eci, 8, binary); /* 000000 to 000127 */
|
||||
|
@ -207,10 +210,18 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
case 'K':
|
||||
/* Kanji mode */
|
||||
/* Mode indicator */
|
||||
strcat(binary, "1000");
|
||||
if (version < RMQR_VERSION) {
|
||||
strcat(binary, "1000");
|
||||
} else {
|
||||
strcat(binary, "100");
|
||||
}
|
||||
|
||||
/* Character count indicator */
|
||||
bin_append(short_data_block_length, tribus(version, 8, 10, 12), binary);
|
||||
if (version < RMQR_VERSION) {
|
||||
bin_append(short_data_block_length, tribus(version, 8, 10, 12), binary);
|
||||
} else {
|
||||
bin_append(short_data_block_length, rmqr_kanji_cci[version - RMQR_VERSION], binary);
|
||||
}
|
||||
|
||||
if (debug & ZINT_DEBUG_PRINT) {
|
||||
printf("Kanji block (length %d)\n\t", short_data_block_length);
|
||||
|
@ -244,10 +255,18 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
case 'B':
|
||||
/* Byte mode */
|
||||
/* Mode indicator */
|
||||
strcat(binary, "0100");
|
||||
if (version < RMQR_VERSION) {
|
||||
strcat(binary, "0100");
|
||||
} else {
|
||||
strcat(binary, "011");
|
||||
}
|
||||
|
||||
/* Character count indicator */
|
||||
bin_append(short_data_block_length + double_byte, tribus(version, 8, 16, 16), binary);
|
||||
if (version < RMQR_VERSION) {
|
||||
bin_append(short_data_block_length + double_byte, tribus(version, 8, 16, 16), binary);
|
||||
} else {
|
||||
bin_append(short_data_block_length + double_byte, rmqr_byte_cci[version - RMQR_VERSION], binary);
|
||||
}
|
||||
|
||||
if (debug & ZINT_DEBUG_PRINT) {
|
||||
printf("Byte block (length %d)\n\t", short_data_block_length + double_byte);
|
||||
|
@ -276,7 +295,11 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
case 'A':
|
||||
/* Alphanumeric mode */
|
||||
/* Mode indicator */
|
||||
strcat(binary, "0010");
|
||||
if (version < RMQR_VERSION) {
|
||||
strcat(binary, "0010");
|
||||
} else {
|
||||
strcat(binary, "010");
|
||||
}
|
||||
|
||||
percent_count = 0;
|
||||
for (i = 0; i < short_data_block_length; i++) {
|
||||
|
@ -286,7 +309,11 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
}
|
||||
|
||||
/* Character count indicator */
|
||||
bin_append(short_data_block_length + percent_count, tribus(version, 9, 11, 13), binary);
|
||||
if (version < RMQR_VERSION) {
|
||||
bin_append(short_data_block_length + percent_count, tribus(version, 9, 11, 13), binary);
|
||||
} else {
|
||||
bin_append(short_data_block_length + percent_count, rmqr_alphanum_cci[version - RMQR_VERSION], binary);
|
||||
}
|
||||
|
||||
if (debug & ZINT_DEBUG_PRINT) {
|
||||
printf("Alpha block (length %d)\n\t", short_data_block_length + percent_count);
|
||||
|
@ -374,10 +401,18 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
case 'N':
|
||||
/* Numeric mode */
|
||||
/* Mode indicator */
|
||||
strcat(binary, "0001");
|
||||
if (version >= RMQR_VERSION) {
|
||||
strcat(binary, "0001");
|
||||
} else {
|
||||
strcat(binary, "001");
|
||||
}
|
||||
|
||||
/* Character count indicator */
|
||||
bin_append(short_data_block_length, tribus(version, 10, 12, 14), binary);
|
||||
if (version < RMQR_VERSION) {
|
||||
bin_append(short_data_block_length, tribus(version, 10, 12, 14), binary);
|
||||
} else {
|
||||
bin_append(short_data_block_length, rmqr_numeric_cci[version - RMQR_VERSION], binary);
|
||||
}
|
||||
|
||||
if (debug & ZINT_DEBUG_PRINT) {
|
||||
printf("Number block (length %d)\n\t", short_data_block_length);
|
||||
|
@ -425,7 +460,11 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
} while (position < length);
|
||||
|
||||
/* Terminator */
|
||||
strcat(binary, "0000");
|
||||
if (version < RMQR_VERSION) {
|
||||
strcat(binary, "0000");
|
||||
} else {
|
||||
strcat(binary, "000");
|
||||
}
|
||||
|
||||
current_binlen = (int)strlen(binary);
|
||||
padbits = 8 - (current_binlen % 8);
|
||||
|
@ -452,7 +491,7 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
|
||||
/* Add pad codewords */
|
||||
toggle = 0;
|
||||
for (i = current_bytes; i < target_binlen; i++) {
|
||||
for (i = current_bytes; i < target_codewords; i++) {
|
||||
if (toggle == 0) {
|
||||
datastream[i] = 0xec;
|
||||
toggle = 1;
|
||||
|
@ -464,7 +503,7 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
|
||||
if (debug & ZINT_DEBUG_PRINT) {
|
||||
printf("Resulting codewords:\n\t");
|
||||
for (i = 0; i < target_binlen; i++) {
|
||||
for (i = 0; i < target_codewords; i++) {
|
||||
printf("0x%2X ", datastream[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
@ -473,7 +512,14 @@ static void qr_binary(unsigned char datastream[], const int version, const int t
|
|||
|
||||
/* Split data into blocks, add error correction and then interleave the blocks and error correction data */
|
||||
static void add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int version, const int data_cw, const int blocks, int debug) {
|
||||
int ecc_cw = qr_total_codewords[version - 1] - data_cw;
|
||||
int ecc_cw;
|
||||
|
||||
if (version < RMQR_VERSION) {
|
||||
ecc_cw = qr_total_codewords[version - 1] - data_cw;
|
||||
} else {
|
||||
ecc_cw = rmqr_total_codewords[version - RMQR_VERSION] - data_cw;
|
||||
}
|
||||
|
||||
int short_data_block_length = data_cw / blocks;
|
||||
int qty_long_blocks = data_cw % blocks;
|
||||
int qty_short_blocks = blocks - qty_long_blocks;
|
||||
|
@ -678,36 +724,36 @@ static int cwbit(const unsigned char* fullstream, const int i) {
|
|||
return resultant;
|
||||
}
|
||||
|
||||
static void populate_grid(unsigned char* grid, const int size, const unsigned char* fullstream, const int cw) {
|
||||
static void populate_grid(unsigned char* grid, const int h_size, const int v_size, const unsigned char* fullstream, const int cw) {
|
||||
int direction = 1; /* up */
|
||||
int row = 0; /* right hand side */
|
||||
|
||||
int i, n, y;
|
||||
|
||||
n = cw * 8;
|
||||
y = size - 1;
|
||||
y = v_size - 1;
|
||||
i = 0;
|
||||
do {
|
||||
int x = (size - 2) - (row * 2);
|
||||
int x = (h_size - 2) - (row * 2);
|
||||
|
||||
if (x < 6)
|
||||
if ((x < 6) && (v_size == h_size))
|
||||
x--; /* skip over vertical timing pattern */
|
||||
|
||||
if (!(grid[(y * size) + (x + 1)] & 0xf0)) {
|
||||
if (!(grid[(y * h_size) + (x + 1)] & 0xf0)) {
|
||||
if (cwbit(fullstream, i)) {
|
||||
grid[(y * size) + (x + 1)] = 0x01;
|
||||
grid[(y * h_size) + (x + 1)] = 0x01;
|
||||
} else {
|
||||
grid[(y * size) + (x + 1)] = 0x00;
|
||||
grid[(y * h_size) + (x + 1)] = 0x00;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < n) {
|
||||
if (!(grid[(y * size) + x] & 0xf0)) {
|
||||
if (!(grid[(y * h_size) + x] & 0xf0)) {
|
||||
if (cwbit(fullstream, i)) {
|
||||
grid[(y * size) + x] = 0x01;
|
||||
grid[(y * h_size) + x] = 0x01;
|
||||
} else {
|
||||
grid[(y * size) + x] = 0x00;
|
||||
grid[(y * h_size) + x] = 0x00;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -724,10 +770,10 @@ static void populate_grid(unsigned char* grid, const int size, const unsigned ch
|
|||
y = 0;
|
||||
direction = 0;
|
||||
}
|
||||
if (y == size) {
|
||||
if (y == v_size) {
|
||||
/* reached the bottom */
|
||||
row++;
|
||||
y = size - 1;
|
||||
y = v_size - 1;
|
||||
direction = 1;
|
||||
}
|
||||
} while (i < n);
|
||||
|
@ -1344,10 +1390,14 @@ static int getBinaryLength(const int version, char inputMode[], const unsigned i
|
|||
currentMode = ' '; // Null
|
||||
|
||||
if (gs1 == 1) {
|
||||
count += 4;
|
||||
if (version < RMQR_VERSION) {
|
||||
count += 4;
|
||||
} else {
|
||||
count += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (eci != 0) {
|
||||
if (eci != 0) { // RMQR does not support ECI
|
||||
count += 4;
|
||||
if (eci <= 127) {
|
||||
count += 8;
|
||||
|
@ -1363,11 +1413,19 @@ static int getBinaryLength(const int version, char inputMode[], const unsigned i
|
|||
count += 4;
|
||||
switch (inputMode[i]) {
|
||||
case 'K':
|
||||
count += tribus(version, 8, 10, 12);
|
||||
if (version < RMQR_VERSION) {
|
||||
count += tribus(version, 8, 10, 12);
|
||||
} else {
|
||||
count += 3 + rmqr_kanji_cci[version - RMQR_VERSION];
|
||||
}
|
||||
count += (blockLength(i, inputMode, inputLength) * 13);
|
||||
break;
|
||||
case 'B':
|
||||
count += tribus(version, 8, 16, 16);
|
||||
if (version < RMQR_VERSION) {
|
||||
count += tribus(version, 8, 16, 16);
|
||||
} else {
|
||||
count += 3 + rmqr_byte_cci[version - RMQR_VERSION];
|
||||
}
|
||||
for (j = i; j < (i + blockLength(i, inputMode, inputLength)); j++) {
|
||||
if (inputData[j] > 0xff) {
|
||||
count += 16;
|
||||
|
@ -1377,7 +1435,11 @@ static int getBinaryLength(const int version, char inputMode[], const unsigned i
|
|||
}
|
||||
break;
|
||||
case 'A':
|
||||
count += tribus(version, 9, 11, 13);
|
||||
if (version < RMQR_VERSION) {
|
||||
count += tribus(version, 9, 11, 13);
|
||||
} else {
|
||||
count += 3 + rmqr_alphanum_cci[version - RMQR_VERSION];
|
||||
}
|
||||
alphalength = blockLength(i, inputMode, inputLength);
|
||||
// In alphanumeric mode % becomes %%
|
||||
for (j = i; j < (i + alphalength); j++) {
|
||||
|
@ -1397,7 +1459,11 @@ static int getBinaryLength(const int version, char inputMode[], const unsigned i
|
|||
}
|
||||
break;
|
||||
case 'N':
|
||||
count += tribus(version, 10, 12, 14);
|
||||
if (version < RMQR_VERSION) {
|
||||
count += tribus(version, 10, 12, 14);
|
||||
} else {
|
||||
count += 3 + rmqr_numeric_cci[version - RMQR_VERSION];
|
||||
}
|
||||
switch (blockLength(i, inputMode, inputLength) % 3) {
|
||||
case 0:
|
||||
count += (blockLength(i, inputMode, inputLength) / 3) * 10;
|
||||
|
@ -1430,7 +1496,7 @@ static void qr_test_codeword_dump(struct zint_symbol *symbol, unsigned char* cod
|
|||
|
||||
int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
|
||||
int i, j, est_binlen;
|
||||
int ecc_level, autosize, version, max_cw, target_binlen, blocks, size;
|
||||
int ecc_level, autosize, version, max_cw, target_codewords, blocks, size;
|
||||
int bitmask, gs1;
|
||||
int canShrink;
|
||||
|
||||
|
@ -1594,31 +1660,31 @@ int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t len
|
|||
ecc_level = LEVEL_H;
|
||||
}
|
||||
|
||||
target_binlen = qr_data_codewords_L[version - 1];
|
||||
target_codewords = qr_data_codewords_L[version - 1];
|
||||
blocks = qr_blocks_L[version - 1];
|
||||
switch (ecc_level) {
|
||||
case LEVEL_M: target_binlen = qr_data_codewords_M[version - 1];
|
||||
case LEVEL_M: target_codewords = qr_data_codewords_M[version - 1];
|
||||
blocks = qr_blocks_M[version - 1];
|
||||
break;
|
||||
case LEVEL_Q: target_binlen = qr_data_codewords_Q[version - 1];
|
||||
case LEVEL_Q: target_codewords = qr_data_codewords_Q[version - 1];
|
||||
blocks = qr_blocks_Q[version - 1];
|
||||
break;
|
||||
case LEVEL_H: target_binlen = qr_data_codewords_H[version - 1];
|
||||
case LEVEL_H: target_codewords = qr_data_codewords_H[version - 1];
|
||||
blocks = qr_blocks_H[version - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
unsigned char datastream[target_binlen + 1];
|
||||
unsigned char datastream[target_codewords + 1];
|
||||
unsigned char fullstream[qr_total_codewords[version - 1] + 1];
|
||||
#else
|
||||
datastream = (unsigned char *) _alloca(target_binlen + 1);
|
||||
datastream = (unsigned char *) _alloca(target_codewords + 1);
|
||||
fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1);
|
||||
#endif
|
||||
|
||||
qr_binary(datastream, version, target_binlen, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug);
|
||||
if (symbol->debug & ZINT_DEBUG_TEST) qr_test_codeword_dump(symbol, datastream, target_binlen);
|
||||
add_ecc(fullstream, datastream, version, target_binlen, blocks, symbol->debug);
|
||||
qr_binary(datastream, version, target_codewords, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug);
|
||||
if (symbol->debug & ZINT_DEBUG_TEST) qr_test_codeword_dump(symbol, datastream, target_codewords);
|
||||
add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug);
|
||||
|
||||
size = qr_sizes[version - 1];
|
||||
#ifndef _MSC_VER
|
||||
|
@ -1634,7 +1700,7 @@ int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t len
|
|||
}
|
||||
|
||||
setup_grid(grid, size, version);
|
||||
populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]);
|
||||
populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]);
|
||||
|
||||
if (version >= 7) {
|
||||
add_version_info(grid, size, version);
|
||||
|
@ -2906,7 +2972,7 @@ int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t len
|
|||
/* For UPNQR the symbol size and error correction capacity is fixed */
|
||||
int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
|
||||
int i, j, est_binlen;
|
||||
int ecc_level, version, target_binlen, blocks, size;
|
||||
int ecc_level, version, target_codewords, blocks, size;
|
||||
int bitmask, error_number;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
@ -2964,20 +3030,19 @@ int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t lengt
|
|||
|
||||
version = 15; // 77 x 77
|
||||
|
||||
target_binlen = qr_data_codewords_M[version - 1];
|
||||
target_codewords = qr_data_codewords_M[version - 1];
|
||||
blocks = qr_blocks_M[version - 1];
|
||||
|
||||
#ifndef _MSC_VER
|
||||
unsigned char datastream[target_binlen + 1];
|
||||
unsigned char datastream[target_codewords + 1];
|
||||
unsigned char fullstream[qr_total_codewords[version - 1] + 1];
|
||||
#else
|
||||
datastream = (unsigned char *) _alloca(target_binlen + 1);
|
||||
datastream = (unsigned char *) _alloca(target_codewords + 1);
|
||||
fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1);
|
||||
#endif
|
||||
|
||||
qr_binary(datastream, version, target_binlen, mode, jisdata, length, 0, symbol->eci, est_binlen, symbol->debug);
|
||||
if (symbol->debug & ZINT_DEBUG_TEST) qr_test_codeword_dump(symbol, datastream, target_binlen);
|
||||
add_ecc(fullstream, datastream, version, target_binlen, blocks, symbol->debug);
|
||||
qr_binary(datastream, version, target_codewords, mode, jisdata, length, 0, symbol->eci, est_binlen, symbol->debug);
|
||||
if (symbol->debug & ZINT_DEBUG_TEST) qr_test_codeword_dump(symbol, datastream, target_codewords);
|
||||
add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug);
|
||||
|
||||
size = qr_sizes[version - 1];
|
||||
#ifndef _MSC_VER
|
||||
|
@ -2993,7 +3058,7 @@ int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t lengt
|
|||
}
|
||||
|
||||
setup_grid(grid, size, version);
|
||||
populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]);
|
||||
populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]);
|
||||
|
||||
add_version_info(grid, size, version);
|
||||
|
||||
|
@ -3016,4 +3081,356 @@ int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t lengt
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void setup_rmqr_grid(unsigned char* grid,const int h_size,const int v_size,const int version) {
|
||||
int i, j;
|
||||
char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F};
|
||||
int h_version, finder_position;
|
||||
|
||||
/* Add timing patterns - top and bottom */
|
||||
for (i = 0; i < h_size; i++) {
|
||||
if (i % 2) {
|
||||
grid[i] = 0x20;
|
||||
grid[((v_size - 1) * h_size) + i] = 0x20;
|
||||
} else {
|
||||
grid[i] = 0x21;
|
||||
grid[((v_size - 1) * h_size) + i] = 0x21;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add timing patterns - left and right */
|
||||
for (i = 0; i < v_size; i++) {
|
||||
if (i % 2) {
|
||||
grid[i * h_size] = 0x20;
|
||||
grid[(i * h_size) + (h_size - 1)] = 0x20;
|
||||
} else {
|
||||
grid[i * h_size] = 0x21;
|
||||
grid[(i * h_size) + (h_size - 1)] = 0x21;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add finder pattern */
|
||||
place_finder(grid, h_size, 0, 0); // This works because finder is always top left
|
||||
|
||||
/* Add finder sub-pattern to bottom right */
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 5; j++) {
|
||||
if (alignment[j] & 0x10 >> i) {
|
||||
grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x11;
|
||||
} else {
|
||||
grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add corner finder pattern - bottom left */
|
||||
grid[(v_size - 2) * h_size] = 0x11;
|
||||
grid[((v_size - 2) * h_size) + 1] = 0x10;
|
||||
grid[((v_size - 1) * h_size) + 1] = 0x11;
|
||||
|
||||
/* Add corner finder pattern - top right */
|
||||
grid[h_size - 2] = 0x11;
|
||||
grid[(h_size * 2) - 2] = 0x10;
|
||||
grid[(h_size * 2) - 1] = 0x11;
|
||||
|
||||
/* Add seperator */
|
||||
for (i = 0; i < 7; i++) {
|
||||
grid[(i * h_size) + 7] = 0x20;
|
||||
}
|
||||
if (v_size > 7) {
|
||||
// Note for v_size = 9 this overrides the bottom right corner finder pattern
|
||||
for(i = 0; i < 8; i++) {
|
||||
grid[(7 * h_size) + i] = 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add alignment patterns */
|
||||
if (h_size > 27) {
|
||||
for(i = 0; i < 5; i++) {
|
||||
if (h_size == rmqr_width[i]) {
|
||||
h_version = i;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
finder_position = rmqr_table_d1[(h_version * 4) + i];
|
||||
|
||||
if (finder_position != 0) {
|
||||
for (j = 0; j < v_size; j++) {
|
||||
if (j % 2) {
|
||||
grid[(j * h_size) + finder_position] = 0x10;
|
||||
} else {
|
||||
grid[(j * h_size) + finder_position] = 0x11;
|
||||
}
|
||||
}
|
||||
|
||||
// Top square
|
||||
grid[h_size + finder_position - 1] = 0x11;
|
||||
grid[(h_size * 2) + finder_position - 1] = 0x11;
|
||||
grid[h_size + finder_position + 1] = 0x11;
|
||||
grid[(h_size * 2) + finder_position + 1] = 0x11;
|
||||
|
||||
// Bottom square
|
||||
grid[(h_size * (v_size - 3)) + finder_position - 1] = 0x11;
|
||||
grid[(h_size * (v_size - 2)) + finder_position - 1] = 0x11;
|
||||
grid[(h_size * (v_size - 3)) + finder_position + 1] = 0x11;
|
||||
grid[(h_size * (v_size - 2)) + finder_position + 1] = 0x11;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reserve space for format information */
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
grid[(h_size * (i + 1)) + j + 8] = 0x20;
|
||||
grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] = 0x20;
|
||||
}
|
||||
}
|
||||
grid[(h_size * 1) + 11] = 0x20;
|
||||
grid[(h_size * 2) + 11] = 0x20;
|
||||
grid[(h_size * 3) + 11] = 0x20;
|
||||
grid[(h_size * (v_size - 6)) + (h_size - 5)] = 0x20;
|
||||
grid[(h_size * (v_size - 6)) + (h_size - 4)] = 0x20;
|
||||
grid[(h_size * (v_size - 6)) + (h_size - 3)] = 0x20;
|
||||
}
|
||||
|
||||
/* rMQR according to 2018 draft standard */
|
||||
int rmqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
|
||||
int i, j, est_binlen;
|
||||
int ecc_level, autosize, version, max_cw, target_codewords, blocks, h_size, v_size;
|
||||
int gs1;
|
||||
int footprint, best_footprint, format_data;
|
||||
unsigned int left_format_info, right_format_info;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
unsigned int jisdata[length + 1];
|
||||
char mode[length + 1];
|
||||
#else
|
||||
unsigned char* datastream;
|
||||
unsigned char* fullstream;
|
||||
unsigned char* grid;
|
||||
unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int));
|
||||
char* mode = (char *) _alloca(length + 1);
|
||||
#endif
|
||||
|
||||
gs1 = ((symbol->input_mode & 0x07) == GS1_MODE);
|
||||
|
||||
if ((symbol->input_mode & 0x07) == DATA_MODE) {
|
||||
sjis_cpy(source, &length, jisdata);
|
||||
} else {
|
||||
int done = 0;
|
||||
if (symbol->eci != 20) { /* Unless ECI 20 (Shift JIS) */
|
||||
/* Try single byte (Latin) conversion first */
|
||||
int error_number = sjis_utf8tosb(symbol->eci && symbol->eci <= 899 ? symbol->eci : 3, source, &length, jisdata);
|
||||
if (error_number == 0) {
|
||||
done = 1;
|
||||
} else if (symbol->eci && symbol->eci <= 899) {
|
||||
strcpy(symbol->errtxt, "575: Invalid characters in input data");
|
||||
return error_number;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
/* Try Shift-JIS */
|
||||
int error_number = sjis_utf8tomb(symbol, source, &length, jisdata);
|
||||
if (error_number != 0) {
|
||||
return error_number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_mode(mode, jisdata, length, gs1);
|
||||
est_binlen = getBinaryLength(RMQR_VERSION + 31, mode, jisdata, length, gs1, symbol->eci);
|
||||
|
||||
ecc_level = LEVEL_M;
|
||||
max_cw = 152;
|
||||
if (symbol->option_1 == 1) {
|
||||
strcpy(symbol->errtxt, "576: Error correction level L not available in rMQR");
|
||||
return ZINT_ERROR_INVALID_OPTION;
|
||||
}
|
||||
|
||||
if (symbol->option_1 == 3) {
|
||||
strcpy(symbol->errtxt, "577: Error correction level Q not available in rMQR");
|
||||
return ZINT_ERROR_INVALID_OPTION;
|
||||
}
|
||||
|
||||
if (symbol->option_1 == 4) {
|
||||
ecc_level = LEVEL_H;
|
||||
max_cw = 76;
|
||||
}
|
||||
|
||||
if (est_binlen > (8 * max_cw)) {
|
||||
strcpy(symbol->errtxt, "578: Input too long for selected error correction level");
|
||||
return ZINT_ERROR_TOO_LONG;
|
||||
}
|
||||
|
||||
if ((symbol->option_2 < 0) || (symbol->option_2 > 38)) {
|
||||
strcpy(symbol->errtxt, "579: Invalid rMQR symbol size");
|
||||
return ZINT_ERROR_INVALID_OPTION;
|
||||
}
|
||||
|
||||
version = 31; // Set default to keep compiler happy
|
||||
|
||||
if (symbol->option_2 == 0) {
|
||||
// Automatic symbol size
|
||||
autosize = 31;
|
||||
best_footprint = rmqr_height[31] * rmqr_width[31];
|
||||
for (version = 30; version >= 0; version--) {
|
||||
est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, symbol->eci);
|
||||
footprint = rmqr_height[version] * rmqr_width[version];
|
||||
if (ecc_level == LEVEL_M) {
|
||||
if (8 * rmqr_data_codewords_M[version] >= est_binlen) {
|
||||
if (footprint < best_footprint) {
|
||||
autosize = version;
|
||||
best_footprint = footprint;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (8 * rmqr_data_codewords_H[version] >= est_binlen) {
|
||||
if (footprint < best_footprint) {
|
||||
autosize = version;
|
||||
best_footprint = footprint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
version = autosize;
|
||||
est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, symbol->eci);
|
||||
}
|
||||
|
||||
if ((symbol->option_2 >= 1) && (symbol->option_2 <= 32)) {
|
||||
// User specified symbol size
|
||||
version = symbol->option_2 - 1;
|
||||
}
|
||||
|
||||
if (symbol->option_2 >= 33) {
|
||||
// User has specified symbol height only
|
||||
version = rmqr_fixed_height_upper_bound[symbol->option_2 - 32];
|
||||
for(i = version - 1; i > rmqr_fixed_height_upper_bound[symbol->option_2 - 33]; i--) {
|
||||
est_binlen = getBinaryLength(RMQR_VERSION + i, mode, jisdata, length, gs1, symbol->eci);
|
||||
if (ecc_level == LEVEL_M) {
|
||||
if (8 * rmqr_data_codewords_M[i] >= est_binlen) {
|
||||
version = i;
|
||||
}
|
||||
} else {
|
||||
if (8 * rmqr_data_codewords_H[i] >= est_binlen) {
|
||||
version = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, symbol->eci);
|
||||
}
|
||||
|
||||
if (symbol->option_1 == -1) {
|
||||
// Detect if there is enough free space to increase ECC level
|
||||
if (est_binlen < (rmqr_data_codewords_H[version] * 8)) {
|
||||
ecc_level = LEVEL_H;
|
||||
}
|
||||
}
|
||||
|
||||
if (ecc_level == LEVEL_M) {
|
||||
target_codewords = rmqr_data_codewords_M[version];
|
||||
blocks = rmqr_blocks_M[version];
|
||||
} else {
|
||||
target_codewords = rmqr_data_codewords_H[version];
|
||||
blocks = rmqr_blocks_H[version];
|
||||
}
|
||||
|
||||
if (est_binlen > (target_codewords * 8)) {
|
||||
// User has selected a symbol too small for the data
|
||||
strcpy(symbol->errtxt, "580: Input too long for selected symbol size");
|
||||
return ZINT_ERROR_TOO_LONG;
|
||||
}
|
||||
|
||||
if (symbol->debug) {
|
||||
printf("Minimum codewords = %d\n", est_binlen / 8);
|
||||
printf("Selected version: %d = R%dx%d-", (version + 1), rmqr_height[version], rmqr_width[version]);
|
||||
if (ecc_level == LEVEL_M) {
|
||||
printf("M\n");
|
||||
} else {
|
||||
printf("H\n");
|
||||
}
|
||||
printf("Number of data codewords in symbol = %d\n", target_codewords);
|
||||
printf("Number of ECC blocks = %d\n", blocks);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
unsigned char datastream[target_codewords + 1];
|
||||
unsigned char fullstream[rmqr_total_codewords[version] + 1];
|
||||
#else
|
||||
datastream = (unsigned char *) _alloca((target_codewords + 1) * sizeof (unsigned char));
|
||||
fullstream = (unsigned char *) _alloca((rmqr_total_codewords[version] + 1) * sizeof (unsigned char));
|
||||
#endif
|
||||
|
||||
qr_binary(datastream, RMQR_VERSION + version, target_codewords, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug);
|
||||
add_ecc(fullstream, datastream, RMQR_VERSION + version, target_codewords, blocks, symbol->debug);
|
||||
|
||||
h_size = rmqr_width[version];
|
||||
v_size = rmqr_height[version];
|
||||
|
||||
#ifndef _MSC_VER
|
||||
unsigned char grid[h_size * v_size];
|
||||
#else
|
||||
grid = (unsigned char *) _alloca((h_size * v_size) * sizeof (unsigned char));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < v_size; i++) {
|
||||
for (j = 0; j < h_size; j++) {
|
||||
grid[(i * h_size) + j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
setup_rmqr_grid(grid, h_size, v_size, version);
|
||||
populate_grid(grid, h_size, v_size, fullstream, rmqr_total_codewords[version]);
|
||||
|
||||
/* apply bitmask */
|
||||
for (i = 0; i < v_size; i++) {
|
||||
for (j = 0; j < h_size; j++) {
|
||||
if ((grid[(i * h_size) + j] & 0xf0) == 0) {
|
||||
// This is a data module
|
||||
if (((i / 2) + (j / 3)) % 2 == 0) { // < This is the data mask from section 7.8.2
|
||||
// This module needs to be changed
|
||||
if (grid[(i * h_size) + j] == 0x01) {
|
||||
grid[(i * h_size) + j] = 0x00;
|
||||
} else {
|
||||
grid[(i * h_size) + j] = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add format information */
|
||||
format_data = version;
|
||||
if (ecc_level == LEVEL_H) {
|
||||
format_data += 32;
|
||||
}
|
||||
left_format_info = rmqr_format_info_left[format_data];
|
||||
right_format_info = rmqr_format_info_right[format_data];
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
grid[(h_size * (i + 1)) + j + 8] = (left_format_info >> ((j * 5) + i)) & 0x01;
|
||||
grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] = (right_format_info >> ((j * 5) + i)) & 0x01;
|
||||
}
|
||||
}
|
||||
grid[(h_size * 1) + 11] = (left_format_info >> 15) & 0x01;
|
||||
grid[(h_size * 2) + 11] = (left_format_info >> 16) & 0x01;
|
||||
grid[(h_size * 3) + 11] = (left_format_info >> 17) & 0x01;
|
||||
grid[(h_size * (v_size - 6)) + (h_size - 5)] = (right_format_info >> 15) & 0x01;
|
||||
grid[(h_size * (v_size - 6)) + (h_size - 4)] = (right_format_info >> 16) & 0x01;
|
||||
grid[(h_size * (v_size - 6)) + (h_size - 3)] = (right_format_info >> 17) & 0x01;
|
||||
|
||||
|
||||
symbol->width = h_size;
|
||||
symbol->rows = v_size;
|
||||
|
||||
for (i = 0; i < v_size; i++) {
|
||||
for (j = 0; j < h_size; j++) {
|
||||
if (grid[(i * h_size) + j] & 0x01) {
|
||||
set_module(symbol, i, j);
|
||||
}
|
||||
}
|
||||
symbol->row_height[i] = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue