Initial implementation of rMQR

According to draft dated June 2018
This commit is contained in:
Robin Stuart 2019-11-25 19:08:25 +00:00
parent 385a0a246f
commit ad28de1819
6 changed files with 783 additions and 211 deletions

View File

@ -181,6 +181,7 @@ extern int dmatrix(struct zint_symbol *symbol, const unsigned char source[], con
extern int vin(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* VIN Code (Vehicle Identification Number) */
extern int mailmark(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* Royal Mail 4-state Mailmark */
extern int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* Ultracode */
extern int rmqr(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* rMQR */
extern int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type); /* Plot to PNG/BMP/PCX */
extern int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type); /* Plot to EPS/EMF/SVG */
@ -414,6 +415,7 @@ static int gs1_compliant(const int symbology) {
case BARCODE_CODE49:
case BARCODE_QRCODE:
case BARCODE_DOTCODE:
case BARCODE_RMQR:
result = 1;
break;
}
@ -440,6 +442,7 @@ static int is_matrix(const int symbology) {
case BARCODE_HANXIN:
case BARCODE_DOTCODE:
case BARCODE_UPNQR:
case BARCODE_RMQR:
result = 1;
break;
}
@ -633,6 +636,7 @@ int ZBarcode_ValidID(int symbol_id) {
case BARCODE_VIN:
case BARCODE_MAILMARK:
case BARCODE_ULTRA:
case BARCODE_RMQR:
result = 1;
break;
}
@ -655,6 +659,8 @@ static int extended_charset(struct zint_symbol *symbol, const unsigned char *sou
break;
case BARCODE_UPNQR: error_number = upnqr(symbol, source, length);
break;
case BARCODE_RMQR: error_number = rmqr(symbol, source, length);
break;
}
return error_number;
@ -1125,7 +1131,7 @@ int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int
}
}
/* Everything from 128 up is Zint-specific */
if (symbol->symbology >= 145) {
if (symbol->symbology > 145) {
strcpy(symbol->errtxt, "216: Symbology out of range, using Code 128");
symbol->symbology = BARCODE_CODE128;
error_number = ZINT_WARN_INVALID_OPTION;
@ -1208,6 +1214,7 @@ int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int
case BARCODE_GRIDMATRIX:
case BARCODE_HANXIN:
case BARCODE_UPNQR:
case BARCODE_RMQR:
error_number = extended_charset(symbol, local_source, in_length);
break;
default:

View File

@ -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
@ -147,7 +146,7 @@ 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(int datastream[], const int version, const int target_binlen, const char mode[], const int jisdata[], const size_t length, const int gs1, const int eci, const int est_binlen,const int debug) {
static void qr_binary(int datastream[], const int version, const int target_codewords, const char mode[], const 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;
@ -163,10 +162,14 @@ static void qr_binary(int datastream[], const int version, const int target_binl
strcpy(binary, "");
if (gs1) {
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 */
@ -198,10 +201,18 @@ static void qr_binary(int datastream[], const int version, const int target_binl
case 'K':
/* Kanji mode */
/* Mode indicator */
if (version < RMQR_VERSION) {
strcat(binary, "1000");
} else {
strcat(binary, "100");
}
/* Character count indicator */
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) {
printf("Kanji block (length %d)\n\t", short_data_block_length);
@ -235,10 +246,18 @@ static void qr_binary(int datastream[], const int version, const int target_binl
case 'B':
/* Byte mode */
/* Mode indicator */
if (version < RMQR_VERSION) {
strcat(binary, "0100");
} else {
strcat(binary, "011");
}
/* Character count indicator */
if (version < RMQR_VERSION) {
bin_append(short_data_block_length, tribus(version, 8, 16, 16), binary);
} else {
bin_append(short_data_block_length, rmqr_byte_cci[version - RMQR_VERSION], binary);
}
if (debug) {
printf("Byte block (length %d)\n\t", short_data_block_length);
@ -267,7 +286,11 @@ static void qr_binary(int datastream[], const int version, const int target_binl
case 'A':
/* Alphanumeric mode */
/* Mode indicator */
if (version < RMQR_VERSION) {
strcat(binary, "0010");
} else {
strcat(binary, "010");
}
percent_count = 0;
for (i = 0; i < short_data_block_length; i++) {
@ -277,7 +300,11 @@ static void qr_binary(int datastream[], const int version, const int target_binl
}
/* Character count indicator */
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) {
printf("Alpha block (length %d)\n\t", short_data_block_length + percent_count);
@ -365,10 +392,18 @@ static void qr_binary(int datastream[], const int version, const int target_binl
case 'N':
/* Numeric mode */
/* Mode indicator */
if (version >= RMQR_VERSION) {
strcat(binary, "0001");
} else {
strcat(binary, "001");
}
/* Character count indicator */
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) {
printf("Number block (length %d)\n\t", short_data_block_length);
@ -416,7 +451,11 @@ static void qr_binary(int datastream[], const int version, const int target_binl
} while (position < length);
/* Terminator */
if (version < RMQR_VERSION) {
strcat(binary, "0000");
} else {
strcat(binary, "000");
}
current_binlen = (int)strlen(binary);
padbits = 8 - (current_binlen % 8);
@ -443,7 +482,7 @@ static void qr_binary(int datastream[], const int version, const int target_binl
/* 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;
@ -455,7 +494,7 @@ static void qr_binary(int datastream[], const int version, const int target_binl
if (debug) {
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");
@ -463,14 +502,20 @@ static void qr_binary(int datastream[], const int version, const int target_binl
}
/* Split data into blocks, add error correction and then interleave the blocks and error correction data */
static void add_ecc(int fullstream[],const int datastream[],const int version,const int data_cw,const int blocks) {
int ecc_cw = qr_total_codewords[version - 1] - data_cw;
static void add_ecc(int fullstream[],const int datastream[],const int version,const int data_cw,const int blocks,int debug) {
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;
int ecc_block_length = ecc_cw / blocks;
int i, j, length_this_block, posn, debug = 0;
int i, j, length_this_block, posn;
#ifndef _MSC_VER
unsigned char data_block[short_data_block_length + 2];
@ -670,35 +715,36 @@ static int cwbit(const int* fullstream,const int i) {
return resultant;
}
static void populate_grid(unsigned char* grid,const int size,const int* fullstream,const int cw) {
static void populate_grid(unsigned char* grid,const int h_size,const int v_size,const int* 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);
if (x < 6)
int x = (h_size - 2) - (row * 2);
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++;
}
@ -715,10 +761,10 @@ static void populate_grid(unsigned char* grid,const int size,const int* fullstre
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);
@ -1335,11 +1381,15 @@ static int getBinaryLength(const int version,char inputMode[],const int inputDat
currentMode = ' '; // Null
if (gs1 == 1) {
if (version < RMQR_VERSION) {
count += 4;
} else {
count += 3;
}
}
if (eci != 0) {
count += 12;
count += 12; // RMQR does not support ECI
}
for (i = 0; i < inputLength; i++) {
@ -1347,11 +1397,19 @@ static int getBinaryLength(const int version,char inputMode[],const int inputDat
count += 4;
switch (inputMode[i]) {
case 'K':
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':
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;
@ -1361,7 +1419,11 @@ static int getBinaryLength(const int version,char inputMode[],const int inputDat
}
break;
case 'A':
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++) {
@ -1381,7 +1443,11 @@ static int getBinaryLength(const int version,char inputMode[],const int inputDat
}
break;
case 'N':
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;
@ -1406,7 +1472,7 @@ static int getBinaryLength(const int version,char inputMode[],const int inputDat
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;
@ -1581,30 +1647,30 @@ 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
int datastream[target_binlen + 1];
int datastream[target_codewords + 1];
int fullstream[qr_total_codewords[version - 1] + 1];
#else
datastream = (int *) _alloca((target_binlen + 1) * sizeof (int));
datastream = (int *) _alloca((target_codewords + 1) * sizeof (int));
fullstream = (int *) _alloca((qr_total_codewords[version - 1] + 1) * sizeof (int));
#endif
qr_binary(datastream, version, target_binlen, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug);
add_ecc(fullstream, datastream, version, target_binlen, blocks);
qr_binary(datastream, version, target_codewords, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug);
add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug);
size = qr_sizes[version - 1];
#ifndef _MSC_VER
@ -1620,7 +1686,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);
@ -1647,8 +1713,6 @@ int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t len
return 0;
}
/* NOTE: From this point forward concerns Micro QR Code only */
static int micro_qr_intermediate(char binary[], const int jisdata[], const char mode[], const size_t length, int *kanji_used, int *alphanum_used, int *byte_used,const int debug) {
/* Convert input data to an "intermediate stage" where data is binary encoded but
control information is not */
@ -2901,7 +2965,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
@ -2958,19 +3022,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
int datastream[target_binlen + 1];
int datastream[target_codewords + 1];
int fullstream[qr_total_codewords[version - 1] + 1];
#else
datastream = (int *) _alloca((target_binlen + 1) * sizeof (int));
datastream = (int *) _alloca((target_codewords + 1) * sizeof (int));
fullstream = (int *) _alloca((qr_total_codewords[version - 1] + 1) * sizeof (int));
#endif
qr_binary(datastream, version, target_binlen, mode, jisdata, length, 0, symbol->eci, est_binlen, symbol->debug);
add_ecc(fullstream, datastream, version, target_binlen, blocks);
qr_binary(datastream, version, target_codewords, mode, jisdata, length, 0, symbol->eci, est_binlen, symbol->debug);
add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug);
size = qr_sizes[version - 1];
#ifndef _MSC_VER
@ -2986,7 +3050,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);
@ -3009,4 +3073,367 @@ 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
int utfdata[length + 1];
int jisdata[length + 1];
char mode[length + 1];
#else
int* datastream;
int* fullstream;
unsigned char* grid;
int* utfdata = (int *) _alloca((length + 1) * sizeof (int));
int* jisdata = (int *) _alloca((length + 1) * sizeof (int));
char* mode = (char *) _alloca(length + 1);
#endif
gs1 = (symbol->input_mode == GS1_MODE);
if ((symbol->input_mode == DATA_MODE) || (symbol->eci != 0)) {
for (i = 0; i < length; i++) {
jisdata[i] = (int) source[i];
}
} else {
/* Convert Unicode input to Shift-JIS */
int error_number = utf8toutf16(symbol, source, utfdata, &length);
if (error_number != 0) {
return error_number;
}
for (i = 0; i < length; i++) {
if (utfdata[i] <= 0xff) {
jisdata[i] = utfdata[i];
} else {
int glyph = 0;
j = 0;
do {
if (sjis_lookup[j * 2] == utfdata[i]) {
glyph = sjis_lookup[(j * 2) + 1];
}
j++;
} while ((j < 6843) && (glyph == 0));
if (glyph == 0) {
strcpy(symbol->errtxt, "575: Invalid character in input data");
return ZINT_ERROR_INVALID_DATA;
}
jisdata[i] = glyph;
}
}
}
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 (rmqr_data_codewords_M[version] >= (est_binlen / 8)) {
if (footprint < best_footprint) {
autosize = version;
best_footprint = footprint;
}
}
} else {
if (rmqr_data_codewords_H[version] >= (est_binlen / 8)) {
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 (rmqr_data_codewords_M[i] >= (est_binlen / 8)) {
version = i;
}
} else {
if (rmqr_data_codewords_H[i] >= (est_binlen / 8)) {
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
int datastream[target_codewords + 1];
int fullstream[rmqr_total_codewords[version] + 1];
#else
datastream = (int *) _alloca((target_codewords + 1) * sizeof (int));
fullstream = (int *) _alloca((rmqr_total_codewords[version] + 1) * sizeof (int));
#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;
}

View File

@ -1,6 +1,5 @@
/* qr.h Data for QR Code */
/* qr.h Data for QR Code, Micro QR Code and rMQR
/*
libzint - the open source barcode library
Copyright (C) 2008-2017 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2006 Kentaro Fukuchi <fukuchi@megaui.net>
@ -38,6 +37,8 @@
#define RHODIUM "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
#define RMQR_VERSION 100
/* From ISO/IEC 18004:2006 Table 7 */
static const unsigned short int qr_data_codewords_L[] = {
19, 34, 55, 80, 108, 136, 156, 194, 232, 274, 324, 370, 428, 461, 523, 589, 647,
@ -69,6 +70,92 @@ static const unsigned short int qr_total_codewords[] = {
2185, 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706
};
static const unsigned short int rmqr_height[] = {
7, 7, 7, 7, 7,
9, 9, 9, 9, 9,
11, 11, 11, 11, 11, 11,
13, 13, 13, 13, 13, 13,
15, 15, 15, 15, 15,
17, 17, 17, 17, 17
};
static const unsigned short int rmqr_width[] = {
43, 59, 77, 99, 139,
43, 59, 77, 99, 139,
27, 43, 59, 77, 99, 139,
27, 43, 59, 77, 99, 139,
43, 59, 77, 99, 139,
43, 59, 77, 99, 139
};
static const unsigned short int rmqr_data_codewords_M[] = {
6, 12, 20, 28, 44, // R7x
12, 21, 31, 42, 63, // R9x
7, 19, 31, 43, 57, 84, // R11x
12, 27, 38, 53, 73, 106, // R13x
33, 48, 67, 88, 127, // R15x
39, 56, 78, 100, 152 // R17x
};
static const unsigned short int rmqr_data_codewords_H[] = {
3, 7, 10, 14, 24, // R7x
7, 11, 17, 22, 33, // R9x
5, 11, 15, 23, 29, 42, // R11x
7, 13, 20, 29, 35, 54, // R13x
15, 26, 31, 48, 69, // R15x
21, 28, 38, 56, 76 // R17x
};
static const short int rmqr_fixed_height_upper_bound[] = {
-1, 4, 9, 15, 21, 26, 31
};
static const unsigned short int rmqr_total_codewords[] = {
13, 21, 32, 44, 68, // R7x
21, 33, 49, 66, 99, // R9x
15, 31, 47, 67, 89, 132, // R11x
21, 41, 60, 85, 113, 166, // R13x
51, 74, 103, 136, 199, // R15x
61, 88, 122, 160, 232 // R17x
};
static const unsigned short int rmqr_numeric_cci[] = {
4, 5, 6, 7, 7,
5, 6, 7, 7, 8,
5, 6, 7, 7, 8, 8,
5, 7, 7, 8, 8, 8,
7, 7, 8, 8, 9,
7, 8, 8, 8, 9
};
static const unsigned short int rmqr_alphanum_cci[] = {
4, 5, 5, 6, 6,
5, 5, 6, 6, 7,
4, 5, 6, 6, 7, 7,
5, 6, 6, 7, 7, 8,
6, 7, 7, 7, 8,
6, 7, 7, 8, 8
};
static const unsigned short int rmqr_byte_cci[] = {
3, 4, 5, 5, 6,
4, 5, 5, 6, 6,
3, 5, 5, 6, 6, 7,
4, 5, 6, 6, 7, 7,
6, 6, 7, 7, 7,
6, 6, 7, 7, 8
};
static const unsigned short int rmqr_kanji_cci[] = {
2, 3, 4, 5, 5,
3, 4, 5, 5, 6,
2, 4, 5, 5, 6, 6,
3, 5, 5, 6, 6, 7,
5, 5, 6, 6, 7,
5, 6, 6, 6, 7
};
static const char qr_blocks_L[] = {
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
@ -89,6 +176,24 @@ static const char qr_blocks_H[] = {
32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81
};
static const char rmqr_blocks_M[] = {
1, 1, 1, 1, 1, // R7x
1, 1, 1, 1, 2, // R9x
1, 1, 1, 1, 2, 2, // R11x
1, 1, 1, 2, 2, 3, // R13x
1, 1, 2, 2, 3, // R15x
1, 2, 2, 3, 4 // R17x
};
static const char rmqr_blocks_H[] = {
1, 1, 1, 1, 2, // R7x
1, 1, 2, 2, 3, // R9x
1, 1, 2, 2, 2, 3, // R11x
1, 1, 2, 2, 3, 4, // R13x
2, 2, 3, 4, 5, // R15x
2, 2, 3, 4, 6 // R17x
};
static const unsigned short 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
@ -102,6 +207,7 @@ static const char 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
};
// Table E1 - Row/column coordinates of center module of alignment patterns
static const unsigned short int qr_table_e1[] = {
6, 18, 0, 0, 0, 0, 0,
6, 22, 0, 0, 0, 0, 0,
@ -144,6 +250,15 @@ static const unsigned short int qr_table_e1[] = {
6, 30, 58, 86, 114, 142, 170
};
// Table D1 - Column coordinates of centre module of alignment patterns
static const unsigned short int rmqr_table_d1[] = {
21, 0, 0, 0,
19, 39, 0, 0,
25, 51, 0, 0,
23, 49, 75, 0,
27, 55, 83, 111
};
static const unsigned int qr_annex_c[] = {
/* Format information bit sequences */
0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d,
@ -165,3 +280,25 @@ static const unsigned int qr_annex_c1[] = {
0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51, 0x34e3,
0x31d4, 0x3e8d, 0x3bba
};
static const unsigned int rmqr_format_info_left[] = {
/* rMQR format information for finder pattern side */
0x1FAB2, 0x1E597, 0x1DBDD, 0x1C4F8, 0x1B86C, 0x1A749, 0x19903, 0x18626, 0x17F0E, 0x1602B,
0x15E61, 0x14144, 0x13DD0, 0x122F5, 0x11CBF, 0x1039A, 0x0F1CA, 0x0EEEF, 0x0D0A5, 0x0CF80,
0x0B314, 0x0AC31, 0x0927B, 0x08D5E, 0x07476, 0x06B53, 0x05519, 0x04A3C, 0x036A8, 0x0298D,
0x017C7, 0x008E2, 0x3F367, 0x3EC42, 0x3D208, 0x3CD2D, 0x3B1B9, 0x3AE9C, 0x390D6, 0x38FF3,
0x376DB, 0x369FE, 0x357B4, 0x34891, 0x33405, 0x32B20, 0x3156A, 0x30A4F, 0x2F81F, 0x2E73A,
0x2D970, 0x2C655, 0x2BAC1, 0x2A5E4, 0x29BAE, 0x2848B, 0x27DA3, 0x26286, 0x25CCC, 0x243E9,
0x23F7D, 0x22058, 0x21E12, 0x20137
};
static const unsigned int rmqr_format_info_right[] = {
/* rMQR format information for subfinder pattern side */
0x20A7B, 0x2155E, 0x22B14, 0x23431, 0x248A5, 0x25780, 0x269CA, 0x276EF, 0x28FC7, 0x290E2,
0x2AEA8, 0x2B18D, 0x2CD19, 0x2D23C, 0x2EC76, 0x2F353, 0x30103, 0x31E26, 0x3206C, 0x33F49,
0x343DD, 0x35CF8, 0x362B2, 0x37D97, 0x384BF, 0x39B9A, 0x3A5D0, 0x3BAF5, 0x3C661, 0x3D944,
0x3E70E, 0x3F82B, 0x003AE, 0x01C8B, 0x022C1, 0x03DE4, 0x04170, 0x05E55, 0x0601F, 0x07F3A,
0x08612, 0x09937, 0x0A77D, 0x0B858, 0x0C4CC, 0x0DBE9, 0x0E5A3, 0x0FA86, 0x108D6, 0x117F3,
0x129B9, 0x1369C, 0x14A08, 0x1552D, 0x16B67, 0x17442, 0x18D6A, 0x1924F, 0x1AC05, 0x1B320,
0x1CFB4, 0x1D091, 0x1EEDB, 0x1F1FE
};

View File

@ -104,7 +104,7 @@ int svg_plot(struct zint_symbol *symbol) {
int html_len = strlen((char *)symbol->text) + 1;
for (0; i < strlen((char *)symbol->text); i++) {
for (i = 0; i < strlen((char *)symbol->text); i++) {
switch(symbol->text[i]) {
case '>':
case '<':

View File

@ -1,7 +1,7 @@
/* zint.h - definitions for libzint
libzint - the open source barcode library
Copyright (C) 2009-2018 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
@ -242,6 +242,7 @@ extern "C" {
#define BARCODE_GRIDMATRIX 142
#define BARCODE_UPNQR 143
#define BARCODE_ULTRA 144
#define BARCODE_RMQR 145
// Output options
#define BARCODE_NO_ASCII 1

View File

@ -67,7 +67,7 @@ void types(void) {
"40: Postnet 86: UK Plessey 141: Code One\n"
"47: MSI Plessey 87: Telepen Numeric 142: Grid Matrix\n"
"49: FIM 89: ITF-14 143: UPNQR\n"
"50: Logmars 90: KIX Code\n"
"50: Logmars 90: KIX Code 145: rMQR\n"
);
}