mirror of
https://git.code.sf.net/p/zint/code
synced 2025-05-29 14:25:23 -04:00
Add multiple segments support for AZTEC, CODEONE, DATAMATRIX, DOTCODE,
GRIDMATRIX, HANXIN, MAXICODE, MICROPDF417, PDF417, QRCODE, RMQR, ULTRA RMQR: fix ECI encoding (wrong bit length for indicator) MICROQR: check versions M1 and M2 for allowed characters so as to give better error messages DOTCODE: some small optimizations common.c: add is_chr(), segs_length(), segs_cpy() CODEONE/CODE128/DOTCODE/GRIDMATRIX/HANXIN/MAXICODE/QRCODE/ULTRA: add namespace prefixes to static funcs/data includes: use Z_ prefix, unuse double underscore prefixes (guard defines) manual.txt: compress some tables using double/treble column sets
This commit is contained in:
parent
3b9d989894
commit
f58c80e290
81 changed files with 12026 additions and 4701 deletions
102
frontend/main.c
102
frontend/main.c
|
@ -127,14 +127,14 @@ static void usage(void) {
|
|||
" --cmyk Use CMYK colour space in EPS/TIF symbols\n"
|
||||
" --cols=NUMBER Set the number of data columns in symbol\n"
|
||||
" --compliantheight Warn if height not compliant, and use standard default\n"
|
||||
" -d, --data=DATA Set the symbol content\n"
|
||||
" -d, --data=DATA Set the symbol data content (segment 0)\n"
|
||||
" --direct Send output to stdout\n"
|
||||
" --dmre Allow Data Matrix Rectangular Extended\n"
|
||||
" --dotsize=NUMBER Set radius of dots in dotty mode\n"
|
||||
" --dotty Use dots instead of squares for matrix symbols\n"
|
||||
" --dump Dump hexadecimal representation to stdout\n"
|
||||
" -e, --ecinos Display table of ECI character encodings\n"
|
||||
" --eci=NUMBER Set the ECI (Extended Channel Interpretation) code\n"
|
||||
" -e, --ecinos Display ECI (Extended Channel Interpretation) table\n"
|
||||
" --eci=NUMBER Set the ECI code for the data (segment 0)\n"
|
||||
" --esc Process escape characters in input data\n"
|
||||
" --fast Use faster encodation (Data Matrix)\n"
|
||||
" --fg=COLOUR Specify a foreground colour (in hex RGB/RGBA)\n"
|
||||
|
@ -165,6 +165,7 @@ static void usage(void) {
|
|||
" --scale=NUMBER Adjust size of X-dimension\n"
|
||||
" --scmvv=NUMBER Prefix SCM with \"[)>\\R01\\Gvv\" (vv is NUMBER) (MaxiCode)\n"
|
||||
" --secure=NUMBER Set error correction level (ECC)\n"
|
||||
" --segN=ECI,DATA Set the ECI & data content for segment N where N is 1 to 9\n"
|
||||
" --separator=NUMBER Set height of row separator bars (stacked symbologies)\n"
|
||||
" --small Use small text\n"
|
||||
" --square Force Data Matrix symbols to be square\n"
|
||||
|
@ -561,6 +562,28 @@ int validate_structapp(const char *optarg, struct zint_structapp *structapp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Parse and validate the segment argument "ECI,DATA" to "--segN" */
|
||||
static int validate_seg(const char *optarg, const int N, struct zint_seg segs[10]) {
|
||||
char eci[10] = {0};
|
||||
const char *comma = strchr(optarg, ',');
|
||||
if (!comma || comma == optarg || comma - optarg > 9 || *(comma + 1) == '\0') {
|
||||
fprintf(stderr, "Error 166: Invalid segment argument, expect \"ECI,DATA\"\n");
|
||||
return 0;
|
||||
}
|
||||
strncpy(eci, optarg, comma - optarg);
|
||||
if (!validate_int(eci, &segs[N].eci)) {
|
||||
fprintf(stderr, "Error 167: Invalid segment ECI (digits only)\n");
|
||||
return 0;
|
||||
}
|
||||
if (segs[N].eci > 999999) {
|
||||
fprintf(stderr, "Error 168: Segment ECI code out of range (0 to 999999)\n");
|
||||
return 0;
|
||||
}
|
||||
segs[N].length = (int) strlen(comma + 1);
|
||||
segs[N].source = (unsigned char *) (comma + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Batch mode - output symbol for each line of text in `filename` */
|
||||
static int batch_process(struct zint_symbol *symbol, const char *filename, const int mirror_mode,
|
||||
const char *filetype, const int rotate_angle) {
|
||||
|
@ -819,6 +842,7 @@ typedef struct { char *arg; int opt; } arg_opt;
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
struct zint_symbol *my_symbol;
|
||||
struct zint_seg segs[10] = {0};
|
||||
int error_number = 0;
|
||||
int rotate_angle = 0;
|
||||
int help = 0;
|
||||
|
@ -839,6 +863,7 @@ int main(int argc, char **argv) {
|
|||
int ret;
|
||||
char *outfile_extension;
|
||||
int data_arg_num = 0;
|
||||
int seg_count = 0;
|
||||
float float_opt;
|
||||
#ifndef _MSC_VER
|
||||
arg_opt arg_opts[argc];
|
||||
|
@ -872,8 +897,9 @@ int main(int argc, char **argv) {
|
|||
OPT_GS1, OPT_GS1NOCHECK, OPT_GS1PARENS, OPT_GSSEP, OPT_GUARDDESCENT,
|
||||
OPT_HEIGHT, OPT_HEIGHTPERROW, OPT_INIT, OPT_MIRROR, OPT_MASK, OPT_MODE,
|
||||
OPT_NOBACKGROUND, OPT_NOQUIETZONES, OPT_NOTEXT, OPT_PRIMARY, OPT_QUIETZONES,
|
||||
OPT_ROTATE, OPT_ROWS, OPT_SCALE, OPT_SCMVV,
|
||||
OPT_SECURE, OPT_SEPARATOR, OPT_SMALL, OPT_SQUARE, OPT_STRUCTAPP,
|
||||
OPT_ROTATE, OPT_ROWS, OPT_SCALE, OPT_SCMVV, OPT_SECURE,
|
||||
OPT_SEG1, OPT_SEG2, OPT_SEG3, OPT_SEG4, OPT_SEG5, OPT_SEG6, OPT_SEG7, OPT_SEG8, OPT_SEG9,
|
||||
OPT_SEPARATOR, OPT_SMALL, OPT_SQUARE, OPT_STRUCTAPP,
|
||||
OPT_VERBOSE, OPT_VERS, OPT_VWHITESP, OPT_WERROR,
|
||||
};
|
||||
int option_index = 0;
|
||||
|
@ -929,6 +955,15 @@ int main(int argc, char **argv) {
|
|||
{"scale", 1, NULL, OPT_SCALE},
|
||||
{"scmvv", 1, NULL, OPT_SCMVV},
|
||||
{"secure", 1, NULL, OPT_SECURE},
|
||||
{"seg1", 1, NULL, OPT_SEG1},
|
||||
{"seg2", 1, NULL, OPT_SEG2},
|
||||
{"seg3", 1, NULL, OPT_SEG3},
|
||||
{"seg4", 1, NULL, OPT_SEG4},
|
||||
{"seg5", 1, NULL, OPT_SEG5},
|
||||
{"seg6", 1, NULL, OPT_SEG6},
|
||||
{"seg7", 1, NULL, OPT_SEG7},
|
||||
{"seg8", 1, NULL, OPT_SEG8},
|
||||
{"seg9", 1, NULL, OPT_SEG9},
|
||||
{"separator", 1, NULL, OPT_SEPARATOR},
|
||||
{"small", 0, NULL, OPT_SMALL},
|
||||
{"square", 0, NULL, OPT_SQUARE},
|
||||
|
@ -1241,6 +1276,32 @@ int main(int argc, char **argv) {
|
|||
fflush(stderr);
|
||||
}
|
||||
break;
|
||||
case OPT_SEG1:
|
||||
case OPT_SEG2:
|
||||
case OPT_SEG3:
|
||||
case OPT_SEG4:
|
||||
case OPT_SEG5:
|
||||
case OPT_SEG6:
|
||||
case OPT_SEG7:
|
||||
case OPT_SEG8:
|
||||
case OPT_SEG9:
|
||||
if (batch_mode == 0) {
|
||||
val = c - OPT_SEG1 + 1; /* Segment number */
|
||||
if (segs[val].source) {
|
||||
fprintf(stderr, "Error 164: Duplicate segment %d\n", val);
|
||||
return do_exit(1);
|
||||
}
|
||||
if (!validate_seg(optarg, c - OPT_SEG1 + 1, segs)) {
|
||||
return do_exit(1);
|
||||
}
|
||||
if (val >= seg_count) {
|
||||
seg_count = val + 1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Warning 165: Can't define segments in batch mode, ignoring '%s'\n", optarg);
|
||||
fflush(stderr);
|
||||
}
|
||||
break;
|
||||
case OPT_SEPARATOR:
|
||||
if (!validate_int(optarg, &val)) {
|
||||
fprintf(stderr, "Error 128: Invalid separator value (digits only)\n");
|
||||
|
@ -1419,6 +1480,10 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Warning 144: Processing first input file '%s' only\n", arg_opts[0].arg);
|
||||
fflush(stderr);
|
||||
}
|
||||
if (seg_count) {
|
||||
fprintf(stderr, "Warning 169: Ignoring segment arguments\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
if (filetype[0] == '\0') {
|
||||
outfile_extension = get_extension(my_symbol->outfile);
|
||||
if (outfile_extension && supported_filetype(outfile_extension, no_png, NULL)) {
|
||||
|
@ -1440,6 +1505,25 @@ int main(int argc, char **argv) {
|
|||
fflush(stderr);
|
||||
}
|
||||
} else {
|
||||
if (seg_count) {
|
||||
if (data_arg_num > 1) {
|
||||
fprintf(stderr, "Error 170: Cannot specify segments and multiple data arguments together\n");
|
||||
return do_exit(1);
|
||||
}
|
||||
if (arg_opts[0].opt != 'd') { /* For simplicity disallow input args for now */
|
||||
fprintf(stderr, "Error 171: Cannot use input argument with segment arguments\n");
|
||||
return do_exit(1);
|
||||
}
|
||||
segs[0].eci = my_symbol->eci;
|
||||
segs[0].source = (unsigned char *) arg_opts[0].arg;
|
||||
segs[0].length = (int) strlen(arg_opts[0].arg);
|
||||
for (i = 0; i < seg_count; i++) {
|
||||
if (segs[i].source == NULL) {
|
||||
fprintf(stderr, "Error 172: Segments must be consecutive - segment %d missing\n", i);
|
||||
return do_exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filetype[0] != '\0') {
|
||||
set_extension(my_symbol->outfile, filetype);
|
||||
}
|
||||
|
@ -1452,8 +1536,12 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
for (i = 0; i < data_arg_num; i++) {
|
||||
if (arg_opts[i].opt == 'd') {
|
||||
ret = ZBarcode_Encode(my_symbol, (unsigned char *) arg_opts[i].arg,
|
||||
(int) strlen(arg_opts[i].arg));
|
||||
if (seg_count) {
|
||||
ret = ZBarcode_Encode_Segs(my_symbol, segs, seg_count);
|
||||
} else {
|
||||
ret = ZBarcode_Encode(my_symbol, (unsigned char *) arg_opts[i].arg,
|
||||
(int) strlen(arg_opts[i].arg));
|
||||
}
|
||||
} else {
|
||||
ret = ZBarcode_Encode_File(my_symbol, arg_opts[i].arg);
|
||||
}
|
||||
|
|
|
@ -150,6 +150,14 @@ static void arg_data(char *cmd, const char *opt, const char *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void arg_seg(char *cmd, const char *opt, const char *data, const int eci) {
|
||||
if (data != NULL) {
|
||||
sprintf(cmd + (int) strlen(cmd), "%s%s%d,\"%s\"", strlen(cmd) ? " " : "", opt, eci, data);
|
||||
} else {
|
||||
sprintf(cmd + (int) strlen(cmd), "%s%s%d", strlen(cmd) ? " " : "", opt, eci);
|
||||
}
|
||||
}
|
||||
|
||||
static int arg_input(char *cmd, const char *filename, const char *input) {
|
||||
FILE *fp;
|
||||
int cnt;
|
||||
|
@ -369,6 +377,77 @@ static void test_dump_args(int index, int debug) {
|
|||
testFinish();
|
||||
}
|
||||
|
||||
// Tests segs
|
||||
static void test_dump_segs(int index, int debug) {
|
||||
|
||||
struct item {
|
||||
int b;
|
||||
char *data;
|
||||
char *data_seg1;
|
||||
char *data_seg2;
|
||||
int eci;
|
||||
int eci_seg1;
|
||||
int eci_seg2;
|
||||
|
||||
char *expected;
|
||||
};
|
||||
// s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<"))
|
||||
struct item data[] = {
|
||||
/* 0*/ { -1, "123", NULL, NULL, -1, -1, -1, "D2 13 9B 39 65 C8 C9 8E B" },
|
||||
/* 1*/ { -1, "123", NULL, NULL, -1, 3, -1, "Error 166: Invalid segment argument, expect \"ECI,DATA\"" },
|
||||
/* 2*/ { -1, "123", "456", NULL, -1, -1, -1, "Error 167: Invalid segment ECI (digits only)" },
|
||||
/* 3*/ { -1, "123", "456", NULL, -1, 1000000, -1, "Error 168: Segment ECI code out of range (0 to 999999)" },
|
||||
/* 4*/ { -1, "123", "456", NULL, -1, 3, -1, "Error 775: Symbology does not support multiple segments" },
|
||||
/* 5*/ { BARCODE_AZTEC, "123", "456", NULL, -1, 3, -1, "2B 7A\nC7 02\nF0 6E\n3F FE\n70 1C\nB7 D6\nB4 58\n15 54\n94 56\nB7 DC\n30 1A\n1F FC\n4C 66\n22 DA\n1E C6" },
|
||||
/* 6*/ { BARCODE_AZTEC, "123", NULL, "789", -1, -1, 3, "Error 172: Segments must be consecutive - segment 1 missing" },
|
||||
};
|
||||
int data_size = ARRAY_SIZE(data);
|
||||
int i;
|
||||
|
||||
char cmd[4096];
|
||||
char buf[4096];
|
||||
|
||||
testStart("test_dump_segs");
|
||||
|
||||
for (i = 0; i < data_size; i++) {
|
||||
|
||||
if (index != -1 && i != index) continue;
|
||||
|
||||
strcpy(cmd, "zint --dump");
|
||||
if (debug & ZINT_DEBUG_PRINT) {
|
||||
strcat(cmd, " --verbose");
|
||||
}
|
||||
|
||||
arg_int(cmd, "-b ", data[i].b);
|
||||
|
||||
if (data[i].data && data[i].data[0]) {
|
||||
arg_data(cmd, "-d ", data[i].data);
|
||||
}
|
||||
if (data[i].eci > 0) {
|
||||
arg_int(cmd, "--eci=", data[i].eci);
|
||||
}
|
||||
|
||||
if (data[i].data_seg1 && data[i].data_seg1[0]) {
|
||||
arg_seg(cmd, "--seg1=", data[i].data_seg1, data[i].eci_seg1);
|
||||
} else if (data[i].eci_seg1 >= 0) {
|
||||
arg_seg(cmd, "--seg1=", NULL, data[i].eci_seg1);
|
||||
}
|
||||
|
||||
if (data[i].data_seg2 && data[i].data_seg2[0]) {
|
||||
arg_seg(cmd, "--seg2=", data[i].data_seg2, data[i].eci_seg2);
|
||||
} else if (data[i].eci_seg2 >= 0) {
|
||||
arg_seg(cmd, "--seg2=", NULL, data[i].eci_seg2);
|
||||
}
|
||||
|
||||
strcat(cmd, " 2>&1");
|
||||
|
||||
assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i), "i:%d exec(%s) NULL\n", i, cmd);
|
||||
assert_zero(strcmp(buf, data[i].expected), "i:%d buf (%s) != expected (%s) (%s)\n", i, buf, data[i].expected, cmd);
|
||||
}
|
||||
|
||||
testFinish();
|
||||
}
|
||||
|
||||
static void test_input(int index, int debug) {
|
||||
|
||||
#define TEST_INPUT_LONG "test_67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
|
@ -997,6 +1076,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */
|
||||
{ "test_dump_args", test_dump_args, 1, 0, 1 },
|
||||
{ "test_dump_segs", test_dump_segs, 1, 0, 1 },
|
||||
{ "test_input", test_input, 1, 0, 1 },
|
||||
{ "test_stdin_input", test_stdin_input, 1, 0, 1 },
|
||||
{ "test_batch_input", test_batch_input, 1, 0, 1 },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue