1
0
mirror of https://git.code.sf.net/p/zint/code synced 2026-07-30 18:09:50 +00:00

GRIDMATRIX: fix byte latch 6 -> 7, & allowing more than one

non-digit in numeral (both caused misencodation);
  replace `gm_macro_matrix[]` array with calculation (marginally
  slower but saves ~1.4k);
  replace `gm_shift_set[]` use with simple compares (performance);
  change GM_CHINESE/etc defines to numbers so can index into new
  `gm_shift_set[]` array (simplifies mode switching code);
  GM_NUMBER -> GM_NUMERAL, modules -> macromodules_per_dim, various
  other renamings to hopefully more explanatory names;
  various other changes (mostly performance)
test suite: make use of new zxing-cpp diagnostics2 branch Grid
  Matrix decoder
manual: slight clarification of `--gs1nocheck`
BWIPP: latest
This commit is contained in:
gitlost
2026-07-06 01:22:54 +01:00
parent aadd94d288
commit 4e534c3a09
12 changed files with 792 additions and 801 deletions
+3 -1
View File
@@ -1,4 +1,4 @@
Version 2.16.0.9 (dev) not released yet (2026-06-23)
Version 2.16.0.9 (dev) not released yet (2026-07-06)
====================================================
**Incompatible changes**
@@ -75,6 +75,8 @@ Bugs
minimum height
- CLI: stop looping over data args when have error
- composite: preserve `gs1_verify()` warning (if any)
- GRIDMATRIX: fix byte latch 6 -> 7, & allowing more than one non-digit in
numeral (both caused misencodation)
Version 2.16.0 (2025-12-19)
+210 -395
View File
@@ -40,11 +40,7 @@
#include "gridmtx.h"
#include "eci.h"
static const char EUROPIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ";
static const char EUROPIUM_UPR[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
static const char EUROPIUM_LWR[] = "abcdefghijklmnopqrstuvwxyz ";
/* gm_define_modes() stuff */
/* `gm_define_modes()` stuff */
/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
#define GM_MULT 6
@@ -62,8 +58,8 @@ static int gm_in_numeral(const unsigned int ddata[], const int length, const int
return 1;
}
/* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times GM_MULT) */
/* Also ensures that numeric mode is not selected when it cannot be used: for example in
/* Attempt to calculate the average 'cost' of using numeral mode in number of bits (times GM_MULT) */
/* Also ensures that numeral mode is not selected when it cannot be used: for example in
a string which has "2.2.0" (cannot have more than one non-numeric character for each
block of three numeric characters) */
for (i = in_posn, digit_cnt = 0, nondigit = 0, nondigit_posn = 0; i < length && i < in_posn + 4 && digit_cnt < 3;
@@ -72,13 +68,15 @@ static int gm_in_numeral(const unsigned int ddata[], const int length, const int
digit_cnt++;
} else if (z_posn(gm_numeral_nondigits, (const char) ddata[i]) != -1) {
if (nondigit) {
break;
*p_numeral_end = 0;
return 0;
}
nondigit = 1;
nondigit_posn = i;
} else if (i < length - 1 && ddata[i] == 13 && ddata[i + 1] == 10) {
} else if (i + 1 < length && ddata[i] == 13 && ddata[i + 1] == 10) {
if (nondigit) {
break;
*p_numeral_end = 0;
return 0;
}
i++;
nondigit = 2;
@@ -107,13 +105,13 @@ static int gm_in_numeral(const unsigned int ddata[], const int length, const int
}
/* Encoding modes */
#define GM_CHINESE 'H'
#define GM_NUMBER 'N'
#define GM_LOWER 'L'
#define GM_UPPER 'U'
#define GM_MIXED 'M'
#define GM_BYTE 'B'
/* Note Control is a submode of Lower, Upper and Mixed modes */
#define GM_CHINESE 1
#define GM_NUMERAL 2
#define GM_LOWER 3
#define GM_UPPER 4
#define GM_MIXED 5
#define GM_BYTE 6
#define GM_EOD 7 /* Pseudo-mode, used to put end of data */
/* Indexes into mode_types array */
#define GM_H 0 /* Chinese (Hanzi) */
@@ -125,12 +123,14 @@ static int gm_in_numeral(const unsigned int ddata[], const int length, const int
#define GM_NUM_MODES 6
static const char gm_debug_modes[6][5] = { "HAN ", "NUM ", "LWR ", "UPR ", "MXD ", "BYT " };
/* Calculate optimized encoding modes. Adapted from Project Nayuki */
/* Copyright (c) Project Nayuki. (MIT License) See qr.c for detailed notice */
/* SPDX-License-Identifier: MIT */
static void gm_define_modes(char *modes, const unsigned int ddata[], const int length, const int debug_print) {
/* Must be in same order as GM_H etc */
static const char mode_types[] = { GM_CHINESE, GM_NUMBER, GM_LOWER, GM_UPPER, GM_MIXED, GM_BYTE, '\0' };
static const char mode_types[] = { GM_CHINESE, GM_NUMERAL, GM_LOWER, GM_UPPER, GM_MIXED, GM_BYTE, '\0' };
/* Initial mode costs */
static const unsigned int head_costs[GM_NUM_MODES] = {
@@ -156,7 +156,7 @@ static void gm_define_modes(char *modes, const unsigned int ddata[], const int l
};
unsigned int numeral_end = 0, numeral_cost = 0, byte_count = 0; /* State */
int double_byte, space, numeric, lower, upper, control, double_digit, eol;
int double_byte, space, digit, lower, upper, control, double_digit, eol;
int i, j, k;
unsigned int min_cost;
@@ -169,7 +169,7 @@ static void gm_define_modes(char *modes, const unsigned int ddata[], const int l
ends in mode_types[j] and the total number of bits is minimized over all possible choices */
memset(char_modes, 0, length * GM_NUM_MODES);
/* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/XX_MULT)
/* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/GM_MULT)
* bits needed to encode the entire string prefix of length i, and end in mode_types[j] */
memcpy(prev_costs, head_costs, GM_NUM_MODES * sizeof(unsigned int));
@@ -177,29 +177,18 @@ static void gm_define_modes(char *modes, const unsigned int ddata[], const int l
for (i = 0; i < length; i++) {
memset(cur_costs, 0, GM_NUM_MODES * sizeof(unsigned int));
space = numeric = lower = upper = control = double_digit = eol = 0;
space = digit = lower = upper = control = double_digit = eol = 0;
double_byte = ddata[i] > 0xFF;
if (!double_byte) {
space = ddata[i] == ' ';
if (!space) {
numeric = z_isdigit(ddata[i]);
if (!numeric) {
lower = z_islower(ddata[i]);
if (!lower) {
upper = z_isupper(ddata[i]);
if (!upper) {
if (!(double_byte = ddata[i] > 0xFF) && !(space = ddata[i] == ' ')) {
if (!(digit = z_isdigit(ddata[i]))) {
if (!(lower = z_islower(ddata[i])) && !(upper = z_isupper(ddata[i]))) {
control = ddata[i] < 0x7F; /* Exclude DEL */
if (control && i + 1 < length) {
eol = ddata[i] == 13 && ddata[i + 1] == 10;
}
}
eol = i + 1 < length && ddata[i] == 13 && ddata[i + 1] == 10;
}
} else if (i + 1 < length) {
double_digit = z_isdigit(ddata[i + 1]);
}
}
}
/* Hanzi mode can encode anything */
cur_costs[GM_H] = prev_costs[GM_H] + (double_digit || eol ? 39 : 78); /* (6.5 : 13) * GM_MULT */
@@ -220,7 +209,7 @@ static void gm_define_modes(char *modes, const unsigned int ddata[], const int l
if (gm_in_numeral(ddata, length, i, &numeral_end, &numeral_cost)) {
cur_costs[GM_N] = prev_costs[GM_N] + numeral_cost;
char_modes[i][GM_N] = GM_NUMBER;
char_modes[i][GM_N] = GM_NUMERAL;
}
if (control) {
@@ -239,13 +228,13 @@ static void gm_define_modes(char *modes, const unsigned int ddata[], const int l
cur_costs[GM_U] = prev_costs[GM_U] + 30; /* 5 * GM_MULT */
char_modes[i][GM_U] = GM_UPPER;
}
if (numeric || lower || upper || space) {
if (digit || lower || upper || space) {
cur_costs[GM_M] = prev_costs[GM_M] + 36; /* 6 * GM_MULT */
char_modes[i][GM_M] = GM_MIXED;
}
}
if (i == length - 1) { /* Add end of data costs if last character */
if (i + 1 == length) { /* Add end of data costs if last character */
for (j = 0; j < GM_NUM_MODES; j++) {
if (char_modes[i][j]) {
cur_costs[j] += eod_costs[j];
@@ -287,7 +276,9 @@ static void gm_define_modes(char *modes, const unsigned int ddata[], const int l
}
if (debug_print) {
printf(" Modes: %.*s\n", length, modes);
fputs(" Modes: ", stdout);
for (i = 0; i < length; i++) fputc(gm_debug_modes[modes[i] - 1][0], stdout);
fputc('\n', stdout);
}
}
@@ -300,18 +291,19 @@ static void gm_add_byte_count(char binary[], const int byte_count_posn, const in
/* Add a control character to the data stream */
static int gm_add_shift_char(char binary[], int bp, const int shifty, const int debug_print) {
int i;
int glyph = 0;
int glyph;
if (shifty < 32) {
/* See Table 7 - Encoding of control characters */
if (shifty < ' ') {
glyph = shifty;
} else if (shifty < '0') {
glyph = shifty - 1;
} else if (shifty < 'A') {
glyph = shifty - 11;
} else if (shifty < 'a') {
glyph = shifty - 46;
} else {
for (i = 32; i < 64; i++) {
if (gm_shift_set[i] == shifty) {
glyph = i;
break;
}
}
glyph = shifty - 63;
}
if (debug_print) {
@@ -326,19 +318,16 @@ static int gm_add_shift_char(char binary[], int bp, const int shifty, const int
static int gm_encode(const unsigned int ddata[], const int length, char binary[], const int eci, int *p_bp,
const int debug_print) {
/* Create a binary stream representation of the input data.
7 sets are defined - Chinese characters, Numerals, Lower case letters, Upper case letters,
Mixed numerals and latters, Control characters and 8-bit binary data */
6 sets are defined - Chinese characters, Numerals, Lower case letters, Upper case letters,
Mixed numerals, letters & control characters, and 8-bit binary data */
int sp = 0;
int current_mode = 0;
int last_mode;
unsigned int glyph = 0;
int c1, c2, done;
int p = 0, ppos;
int numbuf[3], punt = 0;
int number_pad_posn = 0;
int numeral_cnt = 0;
int numeral_pad_posn = 0;
int byte_count_posn = 0;
int byte_count = 0;
int shift;
int bp = *p_bp;
char *modes = (char *) z_alloca(length);
@@ -360,96 +349,25 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
do {
const int next_mode = modes[sp];
int numbuf[3], punt = 0, nondigit_posn;
int digit;
if (next_mode != current_mode) {
switch (current_mode) {
case 0:
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1, 4, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(2, 4, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(3, 4, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(4, 4, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(5, 4, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(6, 4, binary, bp); break;
}
break;
case GM_CHINESE:
switch (next_mode) {
case GM_NUMBER: bp = z_bin_append_posn(8161, 13, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(8162, 13, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(8163, 13, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(8164, 13, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(8165, 13, binary, bp); break;
}
break;
case GM_NUMBER:
/* add numeric block padding value */
switch (p) {
case 1:
binary[number_pad_posn] = '1';
binary[number_pad_posn + 1] = '0';
break; /* 2 pad digits */
case 2:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '1';
break; /* 1 pad digits */
case 3:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '0';
break; /* 0 pad digits */
}
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1019, 10, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(1020, 10, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(1021, 10, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(1022, 10, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(1023, 10, binary, bp); break;
}
break;
case GM_LOWER:
case GM_UPPER:
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(28, 5, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(29, 5, binary, bp); break;
case GM_LOWER:
case GM_UPPER:
bp = z_bin_append_posn(30, 5, binary, bp);
break;
case GM_MIXED: bp = z_bin_append_posn(124, 7, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(126, 7, binary, bp); break;
}
break;
case GM_MIXED:
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1009, 10, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(1010, 10, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(1011, 10, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(1012, 10, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(1015, 10, binary, bp); break;
}
break;
case GM_BYTE:
/* add byte block length indicator */
if (current_mode == GM_BYTE) {
/* Add byte block length indicator */
gm_add_byte_count(binary, byte_count_posn, byte_count);
byte_count = 0;
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1, 4, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(2, 4, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(3, 4, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(4, 4, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(5, 4, binary, bp); break;
}
break;
} else if (current_mode == GM_NUMERAL && numeral_cnt) {
/* Set numeric block padding value */
(void) z_bin_append_posn(3 - numeral_cnt, 2, binary, numeral_pad_posn);
}
bp = z_bin_append_posn(gm_mode_switch[current_mode][next_mode - 1],
gm_mode_len[current_mode][next_mode - 1], binary, bp);
if (debug_print) {
switch (next_mode) {
case GM_CHINESE: fputs("CHIN ", stdout); break;
case GM_NUMBER: fputs("NUMB ", stdout); break;
case GM_LOWER: fputs("LOWR ", stdout); break;
case GM_UPPER: fputs("UPPR ", stdout); break;
case GM_MIXED: fputs("MIXD ", stdout); break;
case GM_BYTE: fputs("BYTE ", stdout); break;
fputs(gm_debug_modes[next_mode - 1], stdout);
}
if (bp > 9191) {
return ZINT_ERROR_TOO_LONG;
}
}
last_mode = current_mode;
@@ -457,41 +375,27 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
switch (current_mode) {
case GM_CHINESE:
done = 0;
if (ddata[sp] > 0xFF) {
/* GB2312 character */
c1 = (ddata[sp] & 0xFF00) >> 8;
c2 = ddata[sp] & 0xFF;
const unsigned char c1 = (ddata[sp] >> 8) & 0xFF;
const unsigned char c2 = ddata[sp] & 0xFF;
/* GB 2312 always within these ranges */
if (c1 >= 0xA1 && c1 <= 0xA9) {
glyph = 0x60 * (c1 - 0xA1) + (c2 - 0xA0);
} else if (c1 >= 0xB0 && c1 <= 0xF7) {
glyph = 0x60 * (c1 - 0xB0 + 9) + (c2 - 0xA0);
}
done = 1; /* GB 2312 always within above ranges */
/* Note not using the unallocated glyphs 7776 to 8191 mentioned in AIMD014 section 6.3.1.2 */
}
if (!done) {
if (sp != length - 1) {
if (ddata[sp] == 13 && ddata[sp + 1] == 10) {
} else if (sp + 1 < length && ddata[sp] == 13 && ddata[sp + 1] == 10) {
/* End of Line */
glyph = 7776;
sp++;
done = 1;
}
}
}
if (!done) {
if (sp != length - 1) {
if (z_isdigit(ddata[sp]) && z_isdigit(ddata[sp + 1])) {
} else if (sp + 1 < length && z_isdigit(ddata[sp]) && z_isdigit(ddata[sp + 1])) {
/* Two digits */
glyph = 8033 + (10 * (ddata[sp] - '0')) + (ddata[sp + 1] - '0');
sp++;
done = 1;
}
}
}
if (!done) {
} else {
/* Byte value */
glyph = 7777 + ddata[sp];
}
@@ -504,55 +408,49 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
sp++;
break;
case GM_NUMBER:
case GM_NUMERAL:
if (last_mode != current_mode) {
/* Reserve a space for numeric digit padding value (2 bits) */
number_pad_posn = bp;
numeral_pad_posn = bp;
bp = z_bin_append_posn(0, 2, binary, bp);
}
p = 0;
ppos = -1;
numeral_cnt = 0;
nondigit_posn = -1;
/* Numeric compression can also include certain combinations of
non-numeric character */
/* Numeral compression can also include certain combinations of non-digits */
numbuf[0] = '0';
numbuf[1] = '0';
numbuf[2] = '0';
do {
if (z_isdigit(ddata[sp])) {
numbuf[p] = ddata[sp];
p++;
numbuf[numeral_cnt++] = ddata[sp];
} else if (z_posn(gm_numeral_nondigits, (const char) ddata[sp]) != -1) {
if (ppos != -1) {
if (nondigit_posn != -1) {
break;
}
punt = ddata[sp];
ppos = p;
} else if (sp < length - 1 && ddata[sp] == 13 && ddata[sp + 1] == 10) {
nondigit_posn = numeral_cnt;
} else if (sp + 1 < length && ddata[sp] == 13 && ddata[sp + 1] == 10) {
/* <end of line> */
if (ppos != -1) {
if (nondigit_posn != -1) {
break;
}
punt = ddata[sp];
sp++;
ppos = p;
punt = ddata[sp++];
nondigit_posn = numeral_cnt;
} else {
break;
}
sp++;
} while (p < 3 && sp < length && modes[sp] == GM_NUMBER);
} while (numeral_cnt < 3 && sp < length && modes[sp] == GM_NUMERAL);
if (ppos != -1) {
switch (punt) {
case ' ': glyph = 0; break;
case '+': glyph = 3; break;
case '-': glyph = 6; break;
case '.': glyph = 9; break;
case ',': glyph = 12; break;
case 13: glyph = 15; break;
if (nondigit_posn != -1) {
if (punt == 13) {
glyph = 15;
} else {
glyph = z_posn(gm_numeral_nondigits, punt) * 3;
}
glyph += ppos;
glyph += nondigit_posn;
glyph += 1000;
if (debug_print) {
@@ -603,28 +501,17 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
break;
case GM_MIXED:
shift = 1;
if (z_isdigit(ddata[sp])) {
shift = 0;
} else if (z_isupper(ddata[sp])) {
shift = 0;
} else if (z_islower(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
if (ddata[sp] == ' ' || (digit = z_isdigit(ddata[sp])) || z_isalpha(ddata[sp])) {
/* Mixed Mode character */
glyph = z_posn(EUROPIUM, (const char) ddata[sp]);
glyph = ddata[sp] == ' ' ? 62
: ddata[sp] - (digit ? '0' : z_isupper(ddata[sp]) ? 'A' - 10 : 'a' - 36);
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 6, binary, bp);
} else {
/* Shift Mode character */
bp = z_bin_append_posn(1014, 10, binary, bp); /* shift indicator */
bp = z_bin_append_posn(1014, 10, binary, bp); /* Shift indicator */
bp = gm_add_shift_char(binary, bp, ddata[sp], debug_print);
}
@@ -632,24 +519,16 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
break;
case GM_UPPER:
shift = 1;
if (z_isupper(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
if (ddata[sp] == ' ' || z_isupper(ddata[sp])) {
/* Upper Case character */
glyph = z_posn(EUROPIUM_UPR, (const char) ddata[sp]);
glyph = ddata[sp] == ' ' ? 26 : ddata[sp] - 'A';
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 5, binary, bp);
} else {
/* Shift Mode character */
bp = z_bin_append_posn(125, 7, binary, bp); /* shift indicator */
bp = z_bin_append_posn(125, 7, binary, bp); /* Shift indicator */
bp = gm_add_shift_char(binary, bp, ddata[sp], debug_print);
}
@@ -657,24 +536,16 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
break;
case GM_LOWER:
shift = 1;
if (z_islower(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
if (ddata[sp] == ' ' || z_islower(ddata[sp])) {
/* Lower Case character */
glyph = z_posn(EUROPIUM_LWR, (const char) ddata[sp]);
glyph = ddata[sp] == ' ' ? 26 : ddata[sp] - 'a';
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 5, binary, bp);
} else {
/* Shift Mode character */
bp = z_bin_append_posn(125, 7, binary, bp); /* shift indicator */
bp = z_bin_append_posn(125, 7, binary, bp); /* Shift indicator */
bp = gm_add_shift_char(binary, bp, ddata[sp], debug_print);
}
@@ -687,40 +558,18 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
} while (sp < length);
if (current_mode == GM_NUMBER) {
/* add numeric block padding value */
switch (p) {
case 1:
binary[number_pad_posn] = '1';
binary[number_pad_posn + 1] = '0';
break; /* 2 pad digits */
case 2:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '1';
break; /* 1 pad digit */
case 3:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '0';
break; /* 0 pad digits */
}
}
if (current_mode == GM_BYTE) {
/* Add byte block length indicator */
gm_add_byte_count(binary, byte_count_posn, byte_count);
} else if (current_mode == GM_NUMERAL && numeral_cnt) {
/* HAN numeric block padding value */
(void) z_bin_append_posn(3 - numeral_cnt, 2, binary, numeral_pad_posn);
}
/* Add "end of data" character */
switch (current_mode) {
case GM_CHINESE: bp = z_bin_append_posn(8160, 13, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(1018, 10, binary, bp); break;
case GM_LOWER:
case GM_UPPER:
bp = z_bin_append_posn(27, 5, binary, bp);
break;
case GM_MIXED: bp = z_bin_append_posn(1008, 10, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(0, 4, binary, bp); break;
}
assert(current_mode >= GM_CHINESE && current_mode <= GM_BYTE);
bp = z_bin_append_posn(gm_mode_switch[GM_EOD][current_mode - 1], gm_mode_len[GM_EOD][current_mode - 1],
binary, bp);
if (bp > 9191) {
return ZINT_ERROR_TOO_LONG;
@@ -741,7 +590,7 @@ static int gm_encode_segs(const unsigned int ddata[], const struct zint_seg segs
int i;
const unsigned int *dd = ddata;
int bp = 0;
int p;
int padding;
if (reader && (!p_structapp || p_structapp->index == 1)) { /* Appears only in 1st symbol if Structured Append */
bp = z_bin_append_posn(10, 4, binary, bp); /* FNC3 - Reader Initialisation */
@@ -764,9 +613,9 @@ static int gm_encode_segs(const unsigned int ddata[], const struct zint_seg segs
}
/* Add padding bits if required */
p = 7 - (bp % 7);
if (p % 7) {
bp = z_bin_append_posn(0, p, binary, bp);
padding = 7 - (bp % 7);
if (padding % 7) {
bp = z_bin_append_posn(0, padding, binary, bp);
}
/* Note bit-padding can't tip `bp` over max 9191 (1313 * 7) */
@@ -779,37 +628,27 @@ static int gm_encode_segs(const unsigned int ddata[], const struct zint_seg segs
return 0;
}
static void gm_add_ecc(const char binary[], const int data_posn, const int layers, const int ecc_level,
unsigned char word[]) {
int data_cws, i, j, wp, p;
static void gm_add_ecc(const char binary[], const int num_data_cws, const int layers, const int ecc_level,
unsigned char cws[]) {
int tot_data_cws, i, j, wp;
int n1, b1, n2, b2, e1, b3, e2;
int block_size, ecc_size;
unsigned char data[1320], block[130];
unsigned char data_block[115], ecc_block[70];
int num_blocks;
unsigned char data[1313] = {0};
rs_t rs;
data_cws = gm_data_cws[layers - 1][ecc_level - 1];
for (i = 0; i < 1320; i++) {
data[i] = 0;
}
/* Convert from binary stream to 7-bit codewords */
for (i = 0; i < data_posn; i++) {
for (p = 0; p < 7; p++) {
if (binary[i * 7 + p] == '1') {
data[i] += (0x40 >> p);
}
for (i = 0; i < num_data_cws; i++) {
for (j = 0; j < 7; j++) {
data[i] |= (binary[i * 7 + j] == '1') << (6 - j);
}
}
tot_data_cws = gm_data_cws[layers - 1][ecc_level - 1];
/* Add padding codewords */
data[data_posn] = 0x00;
for (i = (data_posn + 1); i < data_cws; i++) {
for (i = num_data_cws + 1; i < tot_data_cws; i++) {
if (i & 1) {
data[i] = 0x7E;
} else {
data[i] = 0x00;
}
}
@@ -822,155 +661,130 @@ static void gm_add_ecc(const char binary[], const int data_posn, const int layer
b3 = gm_e1b3e2[layers - 1][ecc_level - 1][1];
e2 = gm_e1b3e2[layers - 1][ecc_level - 1][2];
num_blocks = b1 + b2;
zint_rs_init_gf(&rs, 0x89);
/* Split the data into blocks */
wp = 0;
for (i = 0; i < (b1 + b2); i++) {
int data_size;
if (i < b1) {
block_size = n1;
} else {
block_size = n2;
}
if (i < b3) {
ecc_size = e1;
} else {
ecc_size = e2;
}
data_size = block_size - ecc_size;
for (i = 0; i < num_blocks; i++) {
unsigned char block[126];
const int block_size = i < b1 ? n1 : n2;
const int ecc_size = i < b3 ? e1 : e2;
const int data_size = block_size - ecc_size;
for (j = 0; j < data_size; j++) {
data_block[j] = data[wp];
wp++;
}
memcpy(block, data + wp, data_size);
wp += data_size;
/* Calculate ECC data for this block */
/* Calculate and add the ECC data for this block */
zint_rs_init_code(&rs, ecc_size, 1);
zint_rs_encode(&rs, data_size, data_block, ecc_block);
zint_rs_encode(&rs, data_size, block, block + data_size);
/* Add error correction data */
for (j = 0; j < data_size; j++) {
block[j] = data_block[j];
}
for (j = 0; j < ecc_size; j++) {
block[j + data_size] = ecc_block[j];
}
for (j = 0; j < n2; j++) {
word[((b1 + b2) * j) + i] = block[j];
}
if (block_size == n1) {
word[((b1 + b2) * (n1 - 1)) + i] = block[(n1 - 1)];
for (j = 0; j < block_size; j++) {
cws[num_blocks * j + i] = block[j];
}
}
}
static void gm_place_macromodule(char grid[], const int x, const int y, const int word1, const int word2,
const int size) {
static void gm_place_macromodule(char grid[], const int size, const int x, const int y, const unsigned int cw) {
const int i = (x * 6) + 1;
const int j = (y * 6) + 1;
const int j = ((y * 6) + 1) * size;
int r, c;
if (word2 & 0x40) {
grid[(j * size) + i + 2] = '1';
if (cw & 0x2000) {
grid[j + i + 2] = '1';
}
if (word2 & 0x20) {
grid[(j * size) + i + 3] = '1';
if (cw & 0x1000) {
grid[j + i + 3] = '1';
}
if (word2 & 0x10) {
grid[((j + 1) * size) + i] = '1';
for (r = 1; r < 4; r++) {
for (c = 0; c < 4; c++) {
if ((cw >> (15 - r * 4 - c)) & 1) {
grid[j + r * size + i + c] = '1';
}
if (word2 & 0x08) {
grid[((j + 1) * size) + i + 1] = '1';
}
if (word2 & 0x04) {
grid[((j + 1) * size) + i + 2] = '1';
}
if (word2 & 0x02) {
grid[((j + 1) * size) + i + 3] = '1';
}
if (word2 & 0x01) {
grid[((j + 2) * size) + i] = '1';
}
if (word1 & 0x40) {
grid[((j + 2) * size) + i + 1] = '1';
}
if (word1 & 0x20) {
grid[((j + 2) * size) + i + 2] = '1';
}
if (word1 & 0x10) {
grid[((j + 2) * size) + i + 3] = '1';
}
if (word1 & 0x08) {
grid[((j + 3) * size) + i] = '1';
}
if (word1 & 0x04) {
grid[((j + 3) * size) + i + 1] = '1';
}
if (word1 & 0x02) {
grid[((j + 3) * size) + i + 2] = '1';
}
if (word1 & 0x01) {
grid[((j + 3) * size) + i + 3] = '1';
}
}
static void gm_place_data_in_grid(const unsigned char word[], char grid[], const int modules, const int size) {
int x, y, macromodule;
const int offset = 13 - ((modules - 1) / 2);
/* Get the macromodule index, `x` column, `y` row - see https://stackoverflow.com/a/63909183 */
static int gm_macromodule(const int macromodules_per_dim, const int x, const int y) {
/* Ring 0-26 from outermost to inner */
const int r = x < y ? x < macromodules_per_dim - y - 1 ? x : macromodules_per_dim - y - 1
: y < macromodules_per_dim - x - 1 ? y : macromodules_per_dim - x - 1;
const int m = (((macromodules_per_dim - 1) >> 1) - r) * 2 + 1; /* Macromodules per dim for ring */
const int b = m * m - 1; /* Highest index in ring */
int idx;
for (y = 0; y < modules; y++) {
for (x = 0; x < modules; x++) {
macromodule = gm_macro_matrix[y + offset][x + offset];
gm_place_macromodule(grid, x, y, word[macromodule * 2], word[(macromodule * 2) + 1], size);
/* Left */
if (x == r) {
idx = b - y + r;
/* Top */
} else if (y == r) {
idx = b - (m - 1) * 4 + (x - r);
/* Right */
} else if (x == macromodules_per_dim - r - 1) {
idx = b - (m - 1) * 3 + (y - r);
/* Bottom */
} else {
assert(y == macromodules_per_dim - r - 1);
idx = b - (m - 1) - (x - r);
}
return idx << 1; /* 2 codewords per macromodule */
}
static void gm_place_data_in_grid(const unsigned char cws[], char grid[], const int size, const int layers) {
int x, y;
const int macromodules_per_dim = 1 + (layers << 1);
for (y = 0; y < macromodules_per_dim; y++) {
for (x = 0; x < macromodules_per_dim; x++) {
const int macromodule = gm_macromodule(macromodules_per_dim, x, y);
gm_place_macromodule(grid, size, x, y, ((unsigned int) cws[macromodule + 1]) << 7 | cws[macromodule]);
}
}
}
/* Place the layer ID into each macromodule */
static void gm_place_layer_id(char *grid, const int size, const int layers, const int ecc_level) {
static void gm_place_layer_id(char grid[], const int size, const int layers, const int ecc_level) {
int i, j, layer, start, stop;
const int modules = 1 + (layers << 1);
int *layerid = (int *) z_alloca(sizeof(int) * (layers + 1));
int *id = (int *) z_alloca(sizeof(int) * (modules * modules));
const int macromodules_per_dim = 1 + (layers << 1);
int *layer_ids = (int *) z_alloca(sizeof(int) * (layers + 1));
int *ids = (int *) z_alloca(sizeof(int) * (macromodules_per_dim * macromodules_per_dim));
assert(layers > 0); /* Suppress clang-tidy-23 warning clang-analyzer-core.UndefinedBinaryOperatorResult */
/* Calculate Layer IDs */
for (i = 0; i <= layers; i++) {
if (ecc_level == 1) {
layerid[i] = 3 - (i % 4);
layer_ids[i] = 3 - (i & 0x03);
} else {
layerid[i] = (i + 5 - ecc_level) % 4;
}
}
for (i = 0; i < modules; i++) {
for (j = 0; j < modules; j++) {
id[(i * modules) + j] = 0;
layer_ids[i] = (i + 5 - ecc_level) & 0x03;
}
}
/* Calculate which value goes in each macromodule */
start = modules >> 1;
stop = modules >> 1;
start = macromodules_per_dim >> 1;
stop = macromodules_per_dim >> 1;
for (layer = 0; layer <= layers; layer++) {
for (i = start; i <= stop; i++) {
id[(start * modules) + i] = layerid[layer];
id[(i * modules) + start] = layerid[layer];
id[((modules - start - 1) * modules) + i] = layerid[layer];
id[(i * modules) + (modules - start - 1)] = layerid[layer];
ids[(start * macromodules_per_dim) + i] = layer_ids[layer];
ids[(i * macromodules_per_dim) + start] = layer_ids[layer];
ids[((macromodules_per_dim - start - 1) * macromodules_per_dim) + i] = layer_ids[layer];
ids[(i * macromodules_per_dim) + (macromodules_per_dim - start - 1)] = layer_ids[layer];
}
start--;
stop++;
}
/* Place the data in the grid */
for (i = 0; i < modules; i++) {
for (j = 0; j < modules; j++) {
if (id[(i * modules) + j] & 0x02) {
grid[(((i * 6) + 1) * size) + (j * 6) + 1] = '1';
for (i = 0; i < macromodules_per_dim; i++) {
for (j = 0; j < macromodules_per_dim; j++) {
const int id = ids[(i * macromodules_per_dim) + j];
if (id & 0x02) {
grid[(i * 6 + 1) * size + j * 6 + 1] = '1';
}
if (id[(i * modules) + j] & 0x01) {
grid[(((i * 6) + 1) * size) + (j * 6) + 2] = '1';
if (id & 0x01) {
grid[(i * 6 + 1) * size + j * 6 + 1 + 1] = '1';
}
}
}
@@ -978,13 +792,13 @@ static void gm_place_layer_id(char *grid, const int size, const int layers, cons
INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
int warn_number = 0;
int size, modules, error_number;
int size, macromodules_per_dim, error_number;
int auto_layers, min_layers, layers, rec_ecc_level, min_rec_ecc_level, ecc_level;
int x, y, i;
int full_multibyte;
char binary[9300];
int data_cws;
unsigned char word[1460] = {0};
char binary[9240]; /* 1313 * 7 = 9191 + 46 (max overflow (GM_BYTE) in `gm_encode()`) + 3 */
int num_data_cws;
unsigned char cws[1458] = {0};
int reader = 0;
const struct zint_structapp *p_structapp = NULL;
int size_squared;
@@ -1079,17 +893,18 @@ INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[],
}
/* Determine the size of the symbol */
data_cws = bin_len / 7; /* Binary length always a multiple of 7 */
assert(bin_len % 7 == 0); /* Binary length always a multiple of 7 */
num_data_cws = bin_len / 7;
auto_layers = 13;
for (i = 12; i > 0; i--) {
if (gm_recommend_cws[i - 1] >= data_cws) {
if (gm_recommend_cws[i - 1] >= num_data_cws) {
auto_layers = i;
}
}
min_layers = 13;
for (i = 12; i > 0; i--) {
if (gm_max_cws[i - 1] >= data_cws) {
if (gm_max_cws[i - 1] >= num_data_cws) {
min_layers = i;
}
}
@@ -1101,7 +916,7 @@ INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[],
} else {
return ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 534,
"Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)",
symbol->option_2, data_cws, gm_max_cws[symbol->option_2 - 1]);
symbol->option_2, num_data_cws, gm_max_cws[symbol->option_2 - 1]);
}
}
@@ -1130,42 +945,42 @@ INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[],
ecc_level = min_rec_ecc_level;
}
}
if (data_cws > gm_data_cws[layers - 1][ecc_level - 1]) {
if (num_data_cws > gm_data_cws[layers - 1][ecc_level - 1]) {
/* Reduce ECC level */
const int min_ecc_level = layers > 1 ? 1 : 2; /* ECL 1 in version 1 symbols is invalid */
do {
ecc_level--;
} while (data_cws > gm_data_cws[layers - 1][ecc_level - 1] && ecc_level > min_ecc_level);
assert(data_cws <= gm_data_cws[layers - 1][ecc_level - 1]);
} while (num_data_cws > gm_data_cws[layers - 1][ecc_level - 1] && ecc_level > min_ecc_level);
assert(num_data_cws <= gm_data_cws[layers - 1][ecc_level - 1]);
}
if (debug_print) {
printf("Layers: %d, ECC level: %d, Data Codewords: %d\n", layers, ecc_level, data_cws);
printf("Layers: %d, ECC level: %d, Data Codewords: %d\n", layers, ecc_level, num_data_cws);
}
/* Feedback options */
symbol->option_1 = ecc_level;
symbol->option_2 = layers;
gm_add_ecc(binary, data_cws, layers, ecc_level, word);
gm_add_ecc(binary, num_data_cws, layers, ecc_level, cws);
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) z_debug_test_codeword_dump(symbol, word, data_cws);
if (symbol->debug & ZINT_DEBUG_TEST) z_debug_test_codeword_dump(symbol, cws, num_data_cws);
#endif
size = 6 + (layers * 12);
modules = 1 + (layers * 2);
macromodules_per_dim = 1 + (layers * 2);
size_squared = size * size;
grid = (char *) z_alloca(size_squared);
memset(grid, '0', size_squared);
gm_place_data_in_grid(word, grid, modules, size);
gm_place_data_in_grid(cws, grid, size, layers);
gm_place_layer_id(grid, size, layers, ecc_level);
/* Add macromodule frames */
for (x = 0; x < modules; x++) {
for (x = 0; x < macromodules_per_dim; x++) {
const int x_offset = x * 6;
int dark = !(x & 1);
for (y = 0; y < modules; y++) {
for (y = 0; y < macromodules_per_dim; y++) {
if (dark) {
const int y_offset = y * 6 * size;
for (i = 0; i < 5; i++) {
+40 -50
View File
@@ -33,36 +33,31 @@
#ifndef Z_GRIDMTX_H
#define Z_GRIDMTX_H
/* From Table 7 - Encoding of control characters */
static const char gm_shift_set[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* NULL -> SI */
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* DLE -> US */
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':',
';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'
};
/* Following 2 tables based on Table 11 - Recommended error correction levels */
static const short gm_recommend_cws[13] = {
9, 30, 59, 114, 170, 237, 315, 405, 506, 618, 741, 875, 1021
};
static const short gm_max_cws[13] = {
11, 40, 79, 146, 218, 305, 405, 521, 650, 794, 953, 1125, 1313
11, 40, 89, 146, 218, 305, 405, 521, 650, 794, 953, 1125, 1313
};
/* Maximum data codewords per ECL - ECL 1 not permitted for Version 1 */
static const short gm_data_cws[13][5] = {
{ 0, 15, 13, 11, 9 }, /* 1 */
{ 45, 40, 35, 30, 25 }, /* 2 */
{ 89, 79, 69, 59, 49 }, /* 3 */
{ 146, 130, 114, 98, 81 }, /* 4 */
{ 218, 194, 170, 146, 121 }, /* 5 */
{ 305, 271, 237, 203, 169 }, /* 6 */
{ 405, 360, 315, 270, 225 }, /* 7 */
{ 521, 463, 405, 347, 289 }, /* 8 */
{ 650, 578, 506, 434, 361 }, /* 9 */
{ 794, 706, 618, 530, 441 }, /* 10 */
{ 953, 847, 741, 635, 529 }, /* 11 */
{ 1125, 1000, 875, 750, 625 }, /* 12 */
{ 1313, 1167, 1021, 875, 729 }, /* 13 */
/* 90% 80% 70% 60% 50% Total available codewords (Table 1) */
{ 0, 15, 13, 11, 9 }, /*1 18 */
{ 45, 40, 35, 30, 25 }, /*2 50 */
{ 89, 79, 69, 59, 49 }, /*3 98 */
{ 146, 130, 114, 98, 81 }, /*4 162 */
{ 218, 194, 170, 146, 121 }, /*5 242 */
{ 305, 271, 237, 203, 169 }, /*6 338 */
{ 405, 360, 315, 270, 225 }, /*7 450 */
{ 521, 463, 405, 347, 289 }, /*8 578 */
{ 650, 578, 506, 434, 361 }, /*9 722 */
{ 794, 706, 618, 530, 441 }, /*10 882 */
{ 953, 847, 741, 635, 529 }, /*11 1058 */
{ 1125, 1000, 875, 750, 625 }, /*12 1250 */
{ 1313, 1167, 1021, 875, 729 }, /*13 1458 */
};
/* Table A.1 N1 */
@@ -98,34 +93,29 @@ static const char gm_e1b3e2[13][5][3] = {
{ { 13, 1, 12 }, { 25, 3, 24 }, { 37, 5, 36 }, { 49, 7, 48 }, { 61, 9, 60 } } /* 13 */
};
static const short gm_macro_matrix[27][27] = {
{ 728, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650 },
{ 727, 624, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 651 },
{ 726, 623, 528, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 553, 652 },
{ 725, 622, 527, 440, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 463, 554, 653 },
{ 724, 621, 526, 439, 360, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 381, 464, 555, 654 },
{ 723, 620, 525, 438, 359, 288, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 307, 382, 465, 556, 655 },
{ 722, 619, 524, 437, 358, 287, 224, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 241, 308, 383, 466, 557, 656 },
{ 721, 618, 523, 436, 357, 286, 223, 168, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 183, 242, 309, 384, 467, 558, 657 },
{ 720, 617, 522, 435, 356, 285, 222, 167, 120, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 133, 184, 243, 310, 385, 468, 559, 658 },
{ 719, 616, 521, 434, 355, 284, 221, 166, 119, 80, 49, 50, 51, 52, 53, 54, 55, 56, 91, 134, 185, 244, 311, 386, 469, 560, 659 },
{ 718, 615, 520, 433, 354, 283, 220, 165, 118, 79, 48, 25, 26, 27, 28, 29, 30, 57, 92, 135, 186, 245, 312, 387, 470, 561, 660 },
{ 717, 614, 519, 432, 353, 282, 219, 164, 117, 78, 47, 24, 9, 10, 11, 12, 31, 58, 93, 136, 187, 246, 313, 388, 471, 562, 661 },
{ 716, 613, 518, 431, 352, 281, 218, 163, 116, 77, 46, 23, 8, 1, 2, 13, 32, 59, 94, 137, 188, 247, 314, 389, 472, 563, 662 },
{ 715, 612, 517, 430, 351, 280, 217, 162, 115, 76, 45, 22, 7, 0, 3, 14, 33, 60, 95, 138, 189, 248, 315, 390, 473, 564, 663 },
{ 714, 611, 516, 429, 350, 279, 216, 161, 114, 75, 44, 21, 6, 5, 4, 15, 34, 61, 96, 139, 190, 249, 316, 391, 474, 565, 664 },
{ 713, 610, 515, 428, 349, 278, 215, 160, 113, 74, 43, 20, 19, 18, 17, 16, 35, 62, 97, 140, 191, 250, 317, 392, 475, 566, 665 },
{ 712, 609, 514, 427, 348, 277, 214, 159, 112, 73, 42, 41, 40, 39, 38, 37, 36, 63, 98, 141, 192, 251, 318, 393, 476, 567, 666 },
{ 711, 608, 513, 426, 347, 276, 213, 158, 111, 72, 71, 70, 69, 68, 67, 66, 65, 64, 99, 142, 193, 252, 319, 394, 477, 568, 667 },
{ 710, 607, 512, 425, 346, 275, 212, 157, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 143, 194, 253, 320, 395, 478, 569, 668 },
{ 709, 606, 511, 424, 345, 274, 211, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 195, 254, 321, 396, 479, 570, 669 },
{ 708, 605, 510, 423, 344, 273, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 255, 322, 397, 480, 571, 670 },
{ 707, 604, 509, 422, 343, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 323, 398, 481, 572, 671 },
{ 706, 603, 508, 421, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 399, 482, 573, 672 },
{ 705, 602, 507, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 483, 574, 673 },
{ 704, 601, 506, 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 575, 674 },
{ 703, 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 675 },
{ 702, 701, 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, 687, 686, 685, 684, 683, 682, 681, 680, 679, 678, 677, 676 }
/* Codewords to switch from `row` mode to `col` mode (Table 9 Type conversion codes) */
static const short gm_mode_switch[8][6] = {
/* CHN NUM LWR UPR MXD BYT */
{ 1, 2, 3, 4, 5, 7 }, /* 0 */
{ 0, 8161, 8162, 8163, 8164, 8165 }, /* GM_CHINESE */
{ 1019, 0, 1020, 1021, 1022, 1023 }, /* GM_NUMERAL */
{ 28, 29, 0, 30, 124, 126 }, /* GM_LOWER */
{ 28, 29, 30, 0, 124, 126 }, /* GM_UPPER */
{ 1009, 1010, 1011, 1012, 0, 1015 }, /* GM_MIXED */
{ 1, 2, 3, 4, 5, 0 }, /* GM_BYTE */
{ 8160, 1018, 27, 27, 1008, 0 }, /* GM_EOD (end of data) */
};
/* Bit-lengths of above */
static const char gm_mode_len[8][6] = {
{ 4, 4, 4, 4, 4, 4 }, /* 0 */
{ 0, 13, 13, 13, 13, 13 }, /* GM_CHINESE */
{ 10, 0, 10, 10, 10, 10 }, /* GM_NUMERAL */
{ 5, 5, 0, 5, 7, 7 }, /* GM_LOWER */
{ 5, 5, 5, 0, 7, 7 }, /* GM_UPPER */
{ 10, 10, 10, 10, 0, 10 }, /* GM_MIXED */
{ 4, 4, 4, 4, 4, 0 }, /* GM_BYTE */
{ 13, 10, 5, 5, 10, 4 }, /* GM_EOD (end of data) */
};
/* vim: set ts=4 sw=4 et : */
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -738,7 +738,7 @@ static void test_escape_char_process(const testCtx *const p_ctx) {
/* 1*/ { BARCODE_CODABLOCKF, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 101, "(54) 67 62 44 40 44 47 48 2B 6A 67 62 0B 49 4A 4B 4C 18 6A 67 62 0C 4D 50 5B 5C 20 6A 67", 0, "" },
/* 2*/ { BARCODE_CODE16K, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 70, "(25) 21 64 68 71 72 73 74 75 76 77 80 91 92 93 94 95 101 65 60 103 103 103 103 38 59", 0, "" },
/* 3*/ { BARCODE_DOTCODE, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 29, "65 40 44 47 48 49 4A 4B 4C 4D 50 5B 5C 5D 5E 5F 6E 41 3C", 0, "" },
/* 4*/ { BARCODE_GRIDMATRIX, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 30, "30 20 00 02 01 61 00 48 28 16 0C 06 44 03 31 60 74 3C 1F 40 57 00", 0, "" },
/* 4*/ { BARCODE_GRIDMATRIX, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 30, "38 20 00 02 01 61 00 48 28 16 0C 06 44 03 31 60 74 3C 1F 40 57 00", 0, "" },
/* 5*/ { BARCODE_HANXIN, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 23, "2F 80 10 72 09 28 B3 0D 41 BF CC 00 C3 83 A3 C3 F0 2B 80 00 00", 0, "" },
/* 6*/ { BARCODE_MAXICODE, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 30, "(144) 04 3E 3E 00 04 07 08 09 0A 0B 03 3D 2C 24 19 1E 23 1B 18 0E 0C 0D 10 1E 20 21 22 23", 0, "" },
/* 7*/ { BARCODE_PDF417, DATA_MODE, -1, "\\0\\E\\a\\b\\t\\n\\v\\f\\r\\L\\e\\F\\G\\R\\N\\x81\\\\", "", 0, 120, "(27) 19 901 0 23 655 318 98 18 461 639 91 512 29 30 31 129 92 900 900 114 476 670 717 35", 0, "" },
+1 -1
View File
@@ -4119,7 +4119,7 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym
{ "", BARCODE_DBAR_EXPSTK_CC, 139, },
{ "", BARCODE_CHANNEL, 140, },
{ "", BARCODE_CODEONE, 141, },
{ "", BARCODE_GRIDMATRIX, 142, },
{ "GridMatrix", BARCODE_GRIDMATRIX, 142, },
{ "QRCode", BARCODE_UPNQR, 143, },
{ "", BARCODE_ULTRA, 144, },
{ "RMQRCode", BARCODE_RMQR, 145, },
@@ -41,6 +41,7 @@ run_zxingcpp_test "test_dotcode" "large"
run_zxingcpp_test "test_dotcode" "input"
run_zxingcpp_test "test_dotcode" "encode"
run_zxingcpp_test "test_dotcode" "encode_segs"
run_zxingcpp_test "test_gridmtx"
run_zxingcpp_test "test_hanxin"
run_zxingcpp_test "test_mailmark" "2d_encode"
run_zxingcpp_test "test_maxicode" "large"
+3 -2
View File
@@ -334,7 +334,7 @@
<h1 class="title">Zint Barcode Generator and Zint Barcode Studio User
Manual</h1>
<p class="author">Version 2.16.0.9</p>
<p class="date">June 2026</p>
<p class="date">July 2026</p>
</header>
<nav id="TOC" role="doc-toc">
<ul>
@@ -3133,7 +3133,8 @@ Engine to strictly validate GS1 data, including GS1 Digital Link URIs
that Zint was built with the <code>gs1encoders</code> library, otherwise
the default built-in validation will be used.</p></li>
<li><p><code>--gs1nocheck</code>, for use with legacy systems that have
data that does not conform to the current GS1 standard. Printable ASCII
data that does not conform to the current GS1 standard, this disables
checking for valid AIs, and AI data types and lengths. Printable ASCII
input is still checked for, as is the validity of GS1 data specified
without AIs (e.g. linear data for GS1 DataBar
Omnidirectional/Limited/etc.). Also checked is GS1 DataBar Expanded and
+10 -10
View File
@@ -1,6 +1,6 @@
% Zint Barcode Generator and Zint Barcode Studio User Manual
% Version 2.16.0.9
% June 2026
% July 2026
[//]: # ( vim: set ts=4 sw=4 et : )
@@ -1631,17 +1631,17 @@ zint -b AZTEC -d "010952012345678810BCH4\G2107" --esc --gs1raw
Apart from `--gs1`, `--gs1parens` and `--gs1raw` discussed above, there are two
other GS1 options.
- `--gs1strict`, which enables the use the GS1 Syntax Engine to
strictly validate GS1 data, including GS1 Digital Link URIs (by default Zint
does not validate Digital Links at all). It requires that Zint was built with
the `gs1encoders` library, otherwise the default built-in validation will be
used.
- `--gs1strict`, which enables the use the GS1 Syntax Engine to strictly
validate GS1 data, including GS1 Digital Link URIs (by default Zint does not
validate Digital Links at all). It requires that Zint was built with the
`gs1encoders` library, otherwise the default built-in validation will be used.
- `--gs1nocheck`, for use with legacy systems that have data that does not
conform to the current GS1 standard. Printable ASCII input is still checked for,
as is the validity of GS1 data specified without AIs (e.g. linear data for GS1
DataBar Omnidirectional/Limited/etc.). Also checked is GS1 DataBar Expanded and
GS1 Composite input that is not in the GS1 encodable character set 82 (see GS1
conform to the current GS1 standard, this disables checking for valid AIs, and
AI data types and lengths. Printable ASCII input is still checked for, as is the
validity of GS1 data specified without AIs (e.g. linear data for GS1 DataBar
Omnidirectional/Limited/etc.). Also checked is GS1 DataBar Expanded and GS1
Composite input that is not in the GS1 encodable character set 82 (see GS1
General Specifications 26.0 Table 7-2 "GS1 AI encodable character set 82"),
otherwise encodation would fail. In "Unbracketed AI" and raw mode, overlong AI
data will also fail.
+6 -5
View File
@@ -1,6 +1,6 @@
Zint Barcode Generator and Zint Barcode Studio User Manual
Version 2.16.0.9
June 2026
July 2026
*******************************************************************************
* For reference the following is a text-only version of the Zint manual, *
@@ -1668,9 +1668,10 @@ GS1 options.
gs1encoders library, otherwise the default built-in validation will be used.
- --gs1nocheck, for use with legacy systems that have data that does not
conform to the current GS1 standard. Printable ASCII input is still checked
for, as is the validity of GS1 data specified without AIs (e.g. linear data
for GS1 DataBar Omnidirectional/Limited/etc.). Also checked is GS1 DataBar
conform to the current GS1 standard, this disables checking for valid AIs,
and AI data types and lengths. Printable ASCII input is still checked for,
as is the validity of GS1 data specified without AIs (e.g. linear data for
GS1 DataBar Omnidirectional/Limited/etc.). Also checked is GS1 DataBar
Expanded and GS1 Composite input that is not in the GS1 encodable character
set 82 (see GS1 General Specifications 26.0 Table 7-2 “GS1 AI encodable
character set 82”), otherwise encodation would fail. In “Unbracketed AI” and
@@ -5333,7 +5334,7 @@ configured barcode is updated when the "Generate" button is pressed.
Annex D. Man Page ZINT(1)
% ZINT(1) Version 2.16.0.9 % % June 2026
% ZINT(1) Version 2.16.0.9 % % July 2026
NAME
+1 -1
View File
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 3.10
.\"
.TH "ZINT" "1" "June 2026" "Version 2.16.0.9"
.TH "ZINT" "1" "July 2026" "Version 2.16.0.9"
.SH NAME
\f[CR]zint\f[R] \- encode data as a barcode image
.SH SYNOPSIS
+1 -1
View File
@@ -1,6 +1,6 @@
% ZINT(1) Version 2.16.0.9
%
% June 2026
% July 2026
[//]: # ( vim: set ts=4 sw=4 et : )