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** **Incompatible changes**
@@ -75,6 +75,8 @@ Bugs
minimum height minimum height
- CLI: stop looping over data args when have error - CLI: stop looping over data args when have error
- composite: preserve `gs1_verify()` warning (if any) - 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) Version 2.16.0 (2025-12-19)
+210 -395
View File
@@ -40,11 +40,7 @@
#include "gridmtx.h" #include "gridmtx.h"
#include "eci.h" #include "eci.h"
static const char EUROPIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "; /* `gm_define_modes()` stuff */
static const char EUROPIUM_UPR[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
static const char EUROPIUM_LWR[] = "abcdefghijklmnopqrstuvwxyz ";
/* gm_define_modes() stuff */
/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */ /* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
#define GM_MULT 6 #define GM_MULT 6
@@ -62,8 +58,8 @@ static int gm_in_numeral(const unsigned int ddata[], const int length, const int
return 1; return 1;
} }
/* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times GM_MULT) */ /* Attempt to calculate the average 'cost' of using numeral mode in number of bits (times GM_MULT) */
/* Also ensures that numeric mode is not selected when it cannot be used: for example in /* 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 a string which has "2.2.0" (cannot have more than one non-numeric character for each
block of three numeric characters) */ 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; 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++; digit_cnt++;
} else if (z_posn(gm_numeral_nondigits, (const char) ddata[i]) != -1) { } else if (z_posn(gm_numeral_nondigits, (const char) ddata[i]) != -1) {
if (nondigit) { if (nondigit) {
break; *p_numeral_end = 0;
return 0;
} }
nondigit = 1; nondigit = 1;
nondigit_posn = i; 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) { if (nondigit) {
break; *p_numeral_end = 0;
return 0;
} }
i++; i++;
nondigit = 2; nondigit = 2;
@@ -107,13 +105,13 @@ static int gm_in_numeral(const unsigned int ddata[], const int length, const int
} }
/* Encoding modes */ /* Encoding modes */
#define GM_CHINESE 'H' #define GM_CHINESE 1
#define GM_NUMBER 'N' #define GM_NUMERAL 2
#define GM_LOWER 'L' #define GM_LOWER 3
#define GM_UPPER 'U' #define GM_UPPER 4
#define GM_MIXED 'M' #define GM_MIXED 5
#define GM_BYTE 'B' #define GM_BYTE 6
/* Note Control is a submode of Lower, Upper and Mixed modes */ #define GM_EOD 7 /* Pseudo-mode, used to put end of data */
/* Indexes into mode_types array */ /* Indexes into mode_types array */
#define GM_H 0 /* Chinese (Hanzi) */ #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 #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 */ /* Calculate optimized encoding modes. Adapted from Project Nayuki */
/* Copyright (c) Project Nayuki. (MIT License) See qr.c for detailed notice */ /* Copyright (c) Project Nayuki. (MIT License) See qr.c for detailed notice */
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
static void gm_define_modes(char *modes, const unsigned int ddata[], const int length, const int debug_print) { 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 */ /* 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 */ /* Initial mode costs */
static const unsigned int head_costs[GM_NUM_MODES] = { 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 */ 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; int i, j, k;
unsigned int min_cost; 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 */ 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); 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] */ * 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)); 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++) { for (i = 0; i < length; i++) {
memset(cur_costs, 0, GM_NUM_MODES * sizeof(unsigned int)); 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 = ddata[i] > 0xFF) && !(space = ddata[i] == ' ')) {
if (!double_byte) { if (!(digit = z_isdigit(ddata[i]))) {
space = ddata[i] == ' '; if (!(lower = z_islower(ddata[i])) && !(upper = z_isupper(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) {
control = ddata[i] < 0x7F; /* Exclude DEL */ control = ddata[i] < 0x7F; /* Exclude DEL */
if (control && i + 1 < length) { eol = i + 1 < length && ddata[i] == 13 && ddata[i + 1] == 10;
eol = ddata[i] == 13 && ddata[i + 1] == 10;
}
}
} }
} else if (i + 1 < length) { } else if (i + 1 < length) {
double_digit = z_isdigit(ddata[i + 1]); double_digit = z_isdigit(ddata[i + 1]);
} }
} }
}
/* Hanzi mode can encode anything */ /* Hanzi mode can encode anything */
cur_costs[GM_H] = prev_costs[GM_H] + (double_digit || eol ? 39 : 78); /* (6.5 : 13) * GM_MULT */ 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)) { if (gm_in_numeral(ddata, length, i, &numeral_end, &numeral_cost)) {
cur_costs[GM_N] = prev_costs[GM_N] + 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) { 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 */ cur_costs[GM_U] = prev_costs[GM_U] + 30; /* 5 * GM_MULT */
char_modes[i][GM_U] = GM_UPPER; 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 */ cur_costs[GM_M] = prev_costs[GM_M] + 36; /* 6 * GM_MULT */
char_modes[i][GM_M] = GM_MIXED; 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++) { for (j = 0; j < GM_NUM_MODES; j++) {
if (char_modes[i][j]) { if (char_modes[i][j]) {
cur_costs[j] += eod_costs[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) { 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 */ /* 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) { static int gm_add_shift_char(char binary[], int bp, const int shifty, const int debug_print) {
int i; int glyph;
int glyph = 0;
if (shifty < 32) { /* See Table 7 - Encoding of control characters */
if (shifty < ' ') {
glyph = 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 { } else {
for (i = 32; i < 64; i++) { glyph = shifty - 63;
if (gm_shift_set[i] == shifty) {
glyph = i;
break;
}
}
} }
if (debug_print) { 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, static int gm_encode(const unsigned int ddata[], const int length, char binary[], const int eci, int *p_bp,
const int debug_print) { const int debug_print) {
/* Create a binary stream representation of the input data. /* Create a binary stream representation of the input data.
7 sets are defined - Chinese characters, Numerals, Lower case letters, Upper case letters, 6 sets are defined - Chinese characters, Numerals, Lower case letters, Upper case letters,
Mixed numerals and latters, Control characters and 8-bit binary data */ Mixed numerals, letters & control characters, and 8-bit binary data */
int sp = 0; int sp = 0;
int current_mode = 0; int current_mode = 0;
int last_mode; int last_mode;
unsigned int glyph = 0; unsigned int glyph = 0;
int c1, c2, done; int numeral_cnt = 0;
int p = 0, ppos; int numeral_pad_posn = 0;
int numbuf[3], punt = 0;
int number_pad_posn = 0;
int byte_count_posn = 0; int byte_count_posn = 0;
int byte_count = 0; int byte_count = 0;
int shift;
int bp = *p_bp; int bp = *p_bp;
char *modes = (char *) z_alloca(length); char *modes = (char *) z_alloca(length);
@@ -360,96 +349,25 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
do { do {
const int next_mode = modes[sp]; const int next_mode = modes[sp];
int numbuf[3], punt = 0, nondigit_posn;
int digit;
if (next_mode != current_mode) { if (next_mode != current_mode) {
switch (current_mode) { if (current_mode == GM_BYTE) {
case 0: /* Add byte block length indicator */
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 */
gm_add_byte_count(binary, byte_count_posn, byte_count); gm_add_byte_count(binary, byte_count_posn, byte_count);
byte_count = 0; byte_count = 0;
switch (next_mode) { } else if (current_mode == GM_NUMERAL && numeral_cnt) {
case GM_CHINESE: bp = z_bin_append_posn(1, 4, binary, bp); break; /* Set numeric block padding value */
case GM_NUMBER: bp = z_bin_append_posn(2, 4, binary, bp); break; (void) z_bin_append_posn(3 - numeral_cnt, 2, binary, numeral_pad_posn);
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;
} }
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) { if (debug_print) {
switch (next_mode) { fputs(gm_debug_modes[next_mode - 1], stdout);
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;
} }
if (bp > 9191) {
return ZINT_ERROR_TOO_LONG;
} }
} }
last_mode = current_mode; last_mode = current_mode;
@@ -457,41 +375,27 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
switch (current_mode) { switch (current_mode) {
case GM_CHINESE: case GM_CHINESE:
done = 0;
if (ddata[sp] > 0xFF) { if (ddata[sp] > 0xFF) {
/* GB2312 character */ /* GB2312 character */
c1 = (ddata[sp] & 0xFF00) >> 8; const unsigned char c1 = (ddata[sp] >> 8) & 0xFF;
c2 = ddata[sp] & 0xFF; const unsigned char c2 = ddata[sp] & 0xFF;
/* GB 2312 always within these ranges */
if (c1 >= 0xA1 && c1 <= 0xA9) { if (c1 >= 0xA1 && c1 <= 0xA9) {
glyph = 0x60 * (c1 - 0xA1) + (c2 - 0xA0); glyph = 0x60 * (c1 - 0xA1) + (c2 - 0xA0);
} else if (c1 >= 0xB0 && c1 <= 0xF7) { } else if (c1 >= 0xB0 && c1 <= 0xF7) {
glyph = 0x60 * (c1 - 0xB0 + 9) + (c2 - 0xA0); 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 */ /* Note not using the unallocated glyphs 7776 to 8191 mentioned in AIMD014 section 6.3.1.2 */
} } else if (sp + 1 < length && ddata[sp] == 13 && ddata[sp + 1] == 10) {
if (!done) {
if (sp != length - 1) {
if (ddata[sp] == 13 && ddata[sp + 1] == 10) {
/* End of Line */ /* End of Line */
glyph = 7776; glyph = 7776;
sp++; sp++;
done = 1; } else if (sp + 1 < length && z_isdigit(ddata[sp]) && z_isdigit(ddata[sp + 1])) {
}
}
}
if (!done) {
if (sp != length - 1) {
if (z_isdigit(ddata[sp]) && z_isdigit(ddata[sp + 1])) {
/* Two digits */ /* Two digits */
glyph = 8033 + (10 * (ddata[sp] - '0')) + (ddata[sp + 1] - '0'); glyph = 8033 + (10 * (ddata[sp] - '0')) + (ddata[sp + 1] - '0');
sp++; sp++;
done = 1; } else {
}
}
}
if (!done) {
/* Byte value */ /* Byte value */
glyph = 7777 + ddata[sp]; glyph = 7777 + ddata[sp];
} }
@@ -504,55 +408,49 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
sp++; sp++;
break; break;
case GM_NUMBER: case GM_NUMERAL:
if (last_mode != current_mode) { if (last_mode != current_mode) {
/* Reserve a space for numeric digit padding value (2 bits) */ /* 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); bp = z_bin_append_posn(0, 2, binary, bp);
} }
p = 0; numeral_cnt = 0;
ppos = -1; nondigit_posn = -1;
/* Numeric compression can also include certain combinations of /* Numeral compression can also include certain combinations of non-digits */
non-numeric character */
numbuf[0] = '0'; numbuf[0] = '0';
numbuf[1] = '0'; numbuf[1] = '0';
numbuf[2] = '0'; numbuf[2] = '0';
do { do {
if (z_isdigit(ddata[sp])) { if (z_isdigit(ddata[sp])) {
numbuf[p] = ddata[sp]; numbuf[numeral_cnt++] = ddata[sp];
p++;
} else if (z_posn(gm_numeral_nondigits, (const char) ddata[sp]) != -1) { } else if (z_posn(gm_numeral_nondigits, (const char) ddata[sp]) != -1) {
if (ppos != -1) { if (nondigit_posn != -1) {
break; break;
} }
punt = ddata[sp]; punt = ddata[sp];
ppos = p; nondigit_posn = numeral_cnt;
} else if (sp < length - 1 && ddata[sp] == 13 && ddata[sp + 1] == 10) { } else if (sp + 1 < length && ddata[sp] == 13 && ddata[sp + 1] == 10) {
/* <end of line> */ /* <end of line> */
if (ppos != -1) { if (nondigit_posn != -1) {
break; break;
} }
punt = ddata[sp]; punt = ddata[sp++];
sp++; nondigit_posn = numeral_cnt;
ppos = p;
} else { } else {
break; break;
} }
sp++; sp++;
} while (p < 3 && sp < length && modes[sp] == GM_NUMBER); } while (numeral_cnt < 3 && sp < length && modes[sp] == GM_NUMERAL);
if (ppos != -1) { if (nondigit_posn != -1) {
switch (punt) { if (punt == 13) {
case ' ': glyph = 0; break; glyph = 15;
case '+': glyph = 3; break; } else {
case '-': glyph = 6; break; glyph = z_posn(gm_numeral_nondigits, punt) * 3;
case '.': glyph = 9; break;
case ',': glyph = 12; break;
case 13: glyph = 15; break;
} }
glyph += ppos; glyph += nondigit_posn;
glyph += 1000; glyph += 1000;
if (debug_print) { if (debug_print) {
@@ -603,28 +501,17 @@ static int gm_encode(const unsigned int ddata[], const int length, char binary[]
break; break;
case GM_MIXED: case GM_MIXED:
shift = 1; if (ddata[sp] == ' ' || (digit = z_isdigit(ddata[sp])) || z_isalpha(ddata[sp])) {
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) {
/* Mixed Mode character */ /* 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) { if (debug_print) {
printf("[%d] ", (int) glyph); printf("[%d] ", (int) glyph);
} }
bp = z_bin_append_posn(glyph, 6, binary, bp); bp = z_bin_append_posn(glyph, 6, binary, bp);
} else { } else {
/* Shift Mode character */ /* 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); 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; break;
case GM_UPPER: case GM_UPPER:
shift = 1; if (ddata[sp] == ' ' || z_isupper(ddata[sp])) {
if (z_isupper(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
/* Upper Case character */ /* Upper Case character */
glyph = z_posn(EUROPIUM_UPR, (const char) ddata[sp]); glyph = ddata[sp] == ' ' ? 26 : ddata[sp] - 'A';
if (debug_print) { if (debug_print) {
printf("[%d] ", (int) glyph); printf("[%d] ", (int) glyph);
} }
bp = z_bin_append_posn(glyph, 5, binary, bp); bp = z_bin_append_posn(glyph, 5, binary, bp);
} else { } else {
/* Shift Mode character */ /* 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); 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; break;
case GM_LOWER: case GM_LOWER:
shift = 1; if (ddata[sp] == ' ' || z_islower(ddata[sp])) {
if (z_islower(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
/* Lower Case character */ /* Lower Case character */
glyph = z_posn(EUROPIUM_LWR, (const char) ddata[sp]); glyph = ddata[sp] == ' ' ? 26 : ddata[sp] - 'a';
if (debug_print) { if (debug_print) {
printf("[%d] ", (int) glyph); printf("[%d] ", (int) glyph);
} }
bp = z_bin_append_posn(glyph, 5, binary, bp); bp = z_bin_append_posn(glyph, 5, binary, bp);
} else { } else {
/* Shift Mode character */ /* 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); 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); } 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) { if (current_mode == GM_BYTE) {
/* Add byte block length indicator */ /* Add byte block length indicator */
gm_add_byte_count(binary, byte_count_posn, byte_count); 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 */ /* Add "end of data" character */
switch (current_mode) { assert(current_mode >= GM_CHINESE && current_mode <= GM_BYTE);
case GM_CHINESE: bp = z_bin_append_posn(8160, 13, binary, bp); break; bp = z_bin_append_posn(gm_mode_switch[GM_EOD][current_mode - 1], gm_mode_len[GM_EOD][current_mode - 1],
case GM_NUMBER: bp = z_bin_append_posn(1018, 10, binary, bp); break; binary, bp);
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;
}
if (bp > 9191) { if (bp > 9191) {
return ZINT_ERROR_TOO_LONG; 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; int i;
const unsigned int *dd = ddata; const unsigned int *dd = ddata;
int bp = 0; int bp = 0;
int p; int padding;
if (reader && (!p_structapp || p_structapp->index == 1)) { /* Appears only in 1st symbol if Structured Append */ 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 */ 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 */ /* Add padding bits if required */
p = 7 - (bp % 7); padding = 7 - (bp % 7);
if (p % 7) { if (padding % 7) {
bp = z_bin_append_posn(0, p, binary, bp); bp = z_bin_append_posn(0, padding, binary, bp);
} }
/* Note bit-padding can't tip `bp` over max 9191 (1313 * 7) */ /* 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; return 0;
} }
static void gm_add_ecc(const char binary[], const int data_posn, const int layers, const int ecc_level, static void gm_add_ecc(const char binary[], const int num_data_cws, const int layers, const int ecc_level,
unsigned char word[]) { unsigned char cws[]) {
int data_cws, i, j, wp, p; int tot_data_cws, i, j, wp;
int n1, b1, n2, b2, e1, b3, e2; int n1, b1, n2, b2, e1, b3, e2;
int block_size, ecc_size; int num_blocks;
unsigned char data[1320], block[130]; unsigned char data[1313] = {0};
unsigned char data_block[115], ecc_block[70];
rs_t rs; 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 */ /* Convert from binary stream to 7-bit codewords */
for (i = 0; i < data_posn; i++) { for (i = 0; i < num_data_cws; i++) {
for (p = 0; p < 7; p++) { for (j = 0; j < 7; j++) {
if (binary[i * 7 + p] == '1') { data[i] |= (binary[i * 7 + j] == '1') << (6 - j);
data[i] += (0x40 >> p);
}
} }
} }
tot_data_cws = gm_data_cws[layers - 1][ecc_level - 1];
/* Add padding codewords */ /* Add padding codewords */
data[data_posn] = 0x00; for (i = num_data_cws + 1; i < tot_data_cws; i++) {
for (i = (data_posn + 1); i < data_cws; i++) {
if (i & 1) { if (i & 1) {
data[i] = 0x7E; 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]; b3 = gm_e1b3e2[layers - 1][ecc_level - 1][1];
e2 = gm_e1b3e2[layers - 1][ecc_level - 1][2]; e2 = gm_e1b3e2[layers - 1][ecc_level - 1][2];
num_blocks = b1 + b2;
zint_rs_init_gf(&rs, 0x89); zint_rs_init_gf(&rs, 0x89);
/* Split the data into blocks */ /* Split the data into blocks */
wp = 0; wp = 0;
for (i = 0; i < (b1 + b2); i++) { for (i = 0; i < num_blocks; i++) {
int data_size; unsigned char block[126];
if (i < b1) { const int block_size = i < b1 ? n1 : n2;
block_size = n1; const int ecc_size = i < b3 ? e1 : e2;
} else { const int data_size = block_size - ecc_size;
block_size = n2;
}
if (i < b3) {
ecc_size = e1;
} else {
ecc_size = e2;
}
data_size = block_size - ecc_size;
for (j = 0; j < data_size; j++) { memcpy(block, data + wp, data_size);
data_block[j] = data[wp]; wp += data_size;
wp++;
}
/* 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_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 < block_size; j++) {
for (j = 0; j < data_size; j++) { cws[num_blocks * j + i] = block[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)];
} }
} }
} }
static void gm_place_macromodule(char grid[], const int x, const int y, const int word1, const int word2, static void gm_place_macromodule(char grid[], const int size, const int x, const int y, const unsigned int cw) {
const int size) {
const int i = (x * 6) + 1; 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) { if (cw & 0x2000) {
grid[(j * size) + i + 2] = '1'; grid[j + i + 2] = '1';
} }
if (word2 & 0x20) { if (cw & 0x1000) {
grid[(j * size) + i + 3] = '1'; grid[j + i + 3] = '1';
} }
if (word2 & 0x10) { for (r = 1; r < 4; r++) {
grid[((j + 1) * size) + i] = '1'; 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) { /* Get the macromodule index, `x` column, `y` row - see https://stackoverflow.com/a/63909183 */
int x, y, macromodule; static int gm_macromodule(const int macromodules_per_dim, const int x, const int y) {
const int offset = 13 - ((modules - 1) / 2); /* 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++) { /* Left */
for (x = 0; x < modules; x++) { if (x == r) {
macromodule = gm_macro_matrix[y + offset][x + offset]; idx = b - y + r;
gm_place_macromodule(grid, x, y, word[macromodule * 2], word[(macromodule * 2) + 1], size); /* 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 */ /* 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; int i, j, layer, start, stop;
const int modules = 1 + (layers << 1); const int macromodules_per_dim = 1 + (layers << 1);
int *layerid = (int *) z_alloca(sizeof(int) * (layers + 1)); int *layer_ids = (int *) z_alloca(sizeof(int) * (layers + 1));
int *id = (int *) z_alloca(sizeof(int) * (modules * modules)); 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 */ /* Calculate Layer IDs */
for (i = 0; i <= layers; i++) { for (i = 0; i <= layers; i++) {
if (ecc_level == 1) { if (ecc_level == 1) {
layerid[i] = 3 - (i % 4); layer_ids[i] = 3 - (i & 0x03);
} else { } else {
layerid[i] = (i + 5 - ecc_level) % 4; layer_ids[i] = (i + 5 - ecc_level) & 0x03;
}
}
for (i = 0; i < modules; i++) {
for (j = 0; j < modules; j++) {
id[(i * modules) + j] = 0;
} }
} }
/* Calculate which value goes in each macromodule */ /* Calculate which value goes in each macromodule */
start = modules >> 1; start = macromodules_per_dim >> 1;
stop = modules >> 1; stop = macromodules_per_dim >> 1;
for (layer = 0; layer <= layers; layer++) { for (layer = 0; layer <= layers; layer++) {
for (i = start; i <= stop; i++) { for (i = start; i <= stop; i++) {
id[(start * modules) + i] = layerid[layer]; ids[(start * macromodules_per_dim) + i] = layer_ids[layer];
id[(i * modules) + start] = layerid[layer]; ids[(i * macromodules_per_dim) + start] = layer_ids[layer];
id[((modules - start - 1) * modules) + i] = layerid[layer]; ids[((macromodules_per_dim - start - 1) * macromodules_per_dim) + i] = layer_ids[layer];
id[(i * modules) + (modules - start - 1)] = layerid[layer]; ids[(i * macromodules_per_dim) + (macromodules_per_dim - start - 1)] = layer_ids[layer];
} }
start--; start--;
stop++; stop++;
} }
/* Place the data in the grid */ /* Place the data in the grid */
for (i = 0; i < modules; i++) { for (i = 0; i < macromodules_per_dim; i++) {
for (j = 0; j < modules; j++) { for (j = 0; j < macromodules_per_dim; j++) {
if (id[(i * modules) + j] & 0x02) { const int id = ids[(i * macromodules_per_dim) + j];
grid[(((i * 6) + 1) * size) + (j * 6) + 1] = '1'; if (id & 0x02) {
grid[(i * 6 + 1) * size + j * 6 + 1] = '1';
} }
if (id[(i * modules) + j] & 0x01) { if (id & 0x01) {
grid[(((i * 6) + 1) * size) + (j * 6) + 2] = '1'; 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) { INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
int warn_number = 0; 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 auto_layers, min_layers, layers, rec_ecc_level, min_rec_ecc_level, ecc_level;
int x, y, i; int x, y, i;
int full_multibyte; int full_multibyte;
char binary[9300]; char binary[9240]; /* 1313 * 7 = 9191 + 46 (max overflow (GM_BYTE) in `gm_encode()`) + 3 */
int data_cws; int num_data_cws;
unsigned char word[1460] = {0}; unsigned char cws[1458] = {0};
int reader = 0; int reader = 0;
const struct zint_structapp *p_structapp = NULL; const struct zint_structapp *p_structapp = NULL;
int size_squared; 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 */ /* 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; auto_layers = 13;
for (i = 12; i > 0; i--) { 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; auto_layers = i;
} }
} }
min_layers = 13; min_layers = 13;
for (i = 12; i > 0; i--) { 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; min_layers = i;
} }
} }
@@ -1101,7 +916,7 @@ INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[],
} else { } else {
return ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 534, return ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 534,
"Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)", "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; 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 */ /* Reduce ECC level */
const int min_ecc_level = layers > 1 ? 1 : 2; /* ECL 1 in version 1 symbols is invalid */ const int min_ecc_level = layers > 1 ? 1 : 2; /* ECL 1 in version 1 symbols is invalid */
do { do {
ecc_level--; ecc_level--;
} while (data_cws > gm_data_cws[layers - 1][ecc_level - 1] && ecc_level > min_ecc_level); } while (num_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]); assert(num_data_cws <= gm_data_cws[layers - 1][ecc_level - 1]);
} }
if (debug_print) { 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 */ /* Feedback options */
symbol->option_1 = ecc_level; symbol->option_1 = ecc_level;
symbol->option_2 = layers; 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 #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 #endif
size = 6 + (layers * 12); size = 6 + (layers * 12);
modules = 1 + (layers * 2); macromodules_per_dim = 1 + (layers * 2);
size_squared = size * size; size_squared = size * size;
grid = (char *) z_alloca(size_squared); grid = (char *) z_alloca(size_squared);
memset(grid, '0', 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); gm_place_layer_id(grid, size, layers, ecc_level);
/* Add macromodule frames */ /* Add macromodule frames */
for (x = 0; x < modules; x++) { for (x = 0; x < macromodules_per_dim; x++) {
const int x_offset = x * 6; const int x_offset = x * 6;
int dark = !(x & 1); int dark = !(x & 1);
for (y = 0; y < modules; y++) { for (y = 0; y < macromodules_per_dim; y++) {
if (dark) { if (dark) {
const int y_offset = y * 6 * size; const int y_offset = y * 6 * size;
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
+40 -50
View File
@@ -33,36 +33,31 @@
#ifndef Z_GRIDMTX_H #ifndef Z_GRIDMTX_H
#define Z_GRIDMTX_H #define Z_GRIDMTX_H
/* From Table 7 - Encoding of control characters */ /* Following 2 tables based on Table 11 - Recommended error correction levels */
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 */
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':',
';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'
};
static const short gm_recommend_cws[13] = { static const short gm_recommend_cws[13] = {
9, 30, 59, 114, 170, 237, 315, 405, 506, 618, 741, 875, 1021 9, 30, 59, 114, 170, 237, 315, 405, 506, 618, 741, 875, 1021
}; };
static const short gm_max_cws[13] = { 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] = { static const short gm_data_cws[13][5] = {
{ 0, 15, 13, 11, 9 }, /* 1 */ /* 90% 80% 70% 60% 50% Total available codewords (Table 1) */
{ 45, 40, 35, 30, 25 }, /* 2 */ { 0, 15, 13, 11, 9 }, /*1 18 */
{ 89, 79, 69, 59, 49 }, /* 3 */ { 45, 40, 35, 30, 25 }, /*2 50 */
{ 146, 130, 114, 98, 81 }, /* 4 */ { 89, 79, 69, 59, 49 }, /*3 98 */
{ 218, 194, 170, 146, 121 }, /* 5 */ { 146, 130, 114, 98, 81 }, /*4 162 */
{ 305, 271, 237, 203, 169 }, /* 6 */ { 218, 194, 170, 146, 121 }, /*5 242 */
{ 405, 360, 315, 270, 225 }, /* 7 */ { 305, 271, 237, 203, 169 }, /*6 338 */
{ 521, 463, 405, 347, 289 }, /* 8 */ { 405, 360, 315, 270, 225 }, /*7 450 */
{ 650, 578, 506, 434, 361 }, /* 9 */ { 521, 463, 405, 347, 289 }, /*8 578 */
{ 794, 706, 618, 530, 441 }, /* 10 */ { 650, 578, 506, 434, 361 }, /*9 722 */
{ 953, 847, 741, 635, 529 }, /* 11 */ { 794, 706, 618, 530, 441 }, /*10 882 */
{ 1125, 1000, 875, 750, 625 }, /* 12 */ { 953, 847, 741, 635, 529 }, /*11 1058 */
{ 1313, 1167, 1021, 875, 729 }, /* 13 */ { 1125, 1000, 875, 750, 625 }, /*12 1250 */
{ 1313, 1167, 1021, 875, 729 }, /*13 1458 */
}; };
/* Table A.1 N1 */ /* 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 */ { { 13, 1, 12 }, { 25, 3, 24 }, { 37, 5, 36 }, { 49, 7, 48 }, { 61, 9, 60 } } /* 13 */
}; };
static const short gm_macro_matrix[27][27] = { /* Codewords to switch from `row` mode to `col` mode (Table 9 Type conversion codes) */
{ 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 }, static const short gm_mode_switch[8][6] = {
{ 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 }, /* CHN NUM LWR UPR MXD BYT */
{ 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 }, { 1, 2, 3, 4, 5, 7 }, /* 0 */
{ 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 }, { 0, 8161, 8162, 8163, 8164, 8165 }, /* GM_CHINESE */
{ 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 }, { 1019, 0, 1020, 1021, 1022, 1023 }, /* GM_NUMERAL */
{ 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 }, { 28, 29, 0, 30, 124, 126 }, /* GM_LOWER */
{ 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 }, { 28, 29, 30, 0, 124, 126 }, /* GM_UPPER */
{ 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 }, { 1009, 1010, 1011, 1012, 0, 1015 }, /* GM_MIXED */
{ 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 }, { 1, 2, 3, 4, 5, 0 }, /* GM_BYTE */
{ 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 }, { 8160, 1018, 27, 27, 1008, 0 }, /* GM_EOD (end of data) */
{ 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 }, /* Bit-lengths of above */
{ 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 }, static const char gm_mode_len[8][6] = {
{ 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 }, { 4, 4, 4, 4, 4, 4 }, /* 0 */
{ 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 }, { 0, 13, 13, 13, 13, 13 }, /* GM_CHINESE */
{ 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 }, { 10, 0, 10, 10, 10, 10 }, /* GM_NUMERAL */
{ 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 }, { 5, 5, 0, 5, 7, 7 }, /* GM_LOWER */
{ 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 }, { 5, 5, 5, 0, 7, 7 }, /* GM_UPPER */
{ 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 }, { 10, 10, 10, 10, 0, 10 }, /* GM_MIXED */
{ 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 }, { 4, 4, 4, 4, 4, 0 }, /* GM_BYTE */
{ 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 }, { 13, 10, 5, 5, 10, 4 }, /* GM_EOD (end of data) */
{ 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 }
}; };
/* vim: set ts=4 sw=4 et : */ /* 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, "" }, /* 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, "" }, /* 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, "" }, /* 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, "" }, /* 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, "" }, /* 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, "" }, /* 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_DBAR_EXPSTK_CC, 139, },
{ "", BARCODE_CHANNEL, 140, }, { "", BARCODE_CHANNEL, 140, },
{ "", BARCODE_CODEONE, 141, }, { "", BARCODE_CODEONE, 141, },
{ "", BARCODE_GRIDMATRIX, 142, }, { "GridMatrix", BARCODE_GRIDMATRIX, 142, },
{ "QRCode", BARCODE_UPNQR, 143, }, { "QRCode", BARCODE_UPNQR, 143, },
{ "", BARCODE_ULTRA, 144, }, { "", BARCODE_ULTRA, 144, },
{ "RMQRCode", BARCODE_RMQR, 145, }, { "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" "input"
run_zxingcpp_test "test_dotcode" "encode" run_zxingcpp_test "test_dotcode" "encode"
run_zxingcpp_test "test_dotcode" "encode_segs" run_zxingcpp_test "test_dotcode" "encode_segs"
run_zxingcpp_test "test_gridmtx"
run_zxingcpp_test "test_hanxin" run_zxingcpp_test "test_hanxin"
run_zxingcpp_test "test_mailmark" "2d_encode" run_zxingcpp_test "test_mailmark" "2d_encode"
run_zxingcpp_test "test_maxicode" "large" 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 <h1 class="title">Zint Barcode Generator and Zint Barcode Studio User
Manual</h1> Manual</h1>
<p class="author">Version 2.16.0.9</p> <p class="author">Version 2.16.0.9</p>
<p class="date">June 2026</p> <p class="date">July 2026</p>
</header> </header>
<nav id="TOC" role="doc-toc"> <nav id="TOC" role="doc-toc">
<ul> <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 that Zint was built with the <code>gs1encoders</code> library, otherwise
the default built-in validation will be used.</p></li> the default built-in validation will be used.</p></li>
<li><p><code>--gs1nocheck</code>, for use with legacy systems that have <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 input is still checked for, as is the validity of GS1 data specified
without AIs (e.g. linear data for GS1 DataBar without AIs (e.g. linear data for GS1 DataBar
Omnidirectional/Limited/etc.). Also checked is GS1 DataBar Expanded and 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 % Zint Barcode Generator and Zint Barcode Studio User Manual
% Version 2.16.0.9 % Version 2.16.0.9
% June 2026 % July 2026
[//]: # ( vim: set ts=4 sw=4 et : ) [//]: # ( 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 Apart from `--gs1`, `--gs1parens` and `--gs1raw` discussed above, there are two
other GS1 options. other GS1 options.
- `--gs1strict`, which enables the use the GS1 Syntax Engine to - `--gs1strict`, which enables the use the GS1 Syntax Engine to strictly
strictly validate GS1 data, including GS1 Digital Link URIs (by default Zint validate GS1 data, including GS1 Digital Link URIs (by default Zint does not
does not validate Digital Links at all). It requires that Zint was built with validate Digital Links at all). It requires that Zint was built with the
the `gs1encoders` library, otherwise the default built-in validation will be `gs1encoders` library, otherwise the default built-in validation will be used.
used.
- `--gs1nocheck`, for use with legacy systems that have data that does not - `--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, conform to the current GS1 standard, this disables checking for valid AIs, and
as is the validity of GS1 data specified without AIs (e.g. linear data for GS1 AI data types and lengths. Printable ASCII input is still checked for, as is the
DataBar Omnidirectional/Limited/etc.). Also checked is GS1 DataBar Expanded and validity of GS1 data specified without AIs (e.g. linear data for GS1 DataBar
GS1 Composite input that is not in the GS1 encodable character set 82 (see GS1 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"), 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 otherwise encodation would fail. In "Unbracketed AI" and raw mode, overlong AI
data will also fail. data will also fail.
+6 -5
View File
@@ -1,6 +1,6 @@
Zint Barcode Generator and Zint Barcode Studio User Manual Zint Barcode Generator and Zint Barcode Studio User Manual
Version 2.16.0.9 Version 2.16.0.9
June 2026 July 2026
******************************************************************************* *******************************************************************************
* For reference the following is a text-only version of the Zint manual, * * 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. gs1encoders library, otherwise the default built-in validation will be used.
- --gs1nocheck, for use with legacy systems that have data that does not - --gs1nocheck, for use with legacy systems that have data that does not
conform to the current GS1 standard. Printable ASCII input is still checked conform to the current GS1 standard, this disables checking for valid AIs,
for, as is the validity of GS1 data specified without AIs (e.g. linear data and AI data types and lengths. Printable ASCII input is still checked for,
for GS1 DataBar Omnidirectional/Limited/etc.). Also checked is GS1 DataBar 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 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 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 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) 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 NAME
+1 -1
View File
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 3.10 .\" 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 .SH NAME
\f[CR]zint\f[R] \- encode data as a barcode image \f[CR]zint\f[R] \- encode data as a barcode image
.SH SYNOPSIS .SH SYNOPSIS
+1 -1
View File
@@ -1,6 +1,6 @@
% ZINT(1) Version 2.16.0.9 % ZINT(1) Version 2.16.0.9
% %
% June 2026 % July 2026
[//]: # ( vim: set ts=4 sw=4 et : ) [//]: # ( vim: set ts=4 sw=4 et : )