From b572bb513d931bf873f1c323de6e3dde4a15bea1 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 29 Mar 2020 22:23:07 +0100 Subject: [PATCH] Ultra: Disable code compression by default Ensures symbols are valid until better version of specification is available --- backend/ultra.c | 145 ++++++++++++++++++++++++------------------------ backend/zint.h | 3 + frontend/main.c | 63 ++++++++++----------- 3 files changed, 107 insertions(+), 104 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index 938a01bb..cc3a43ef 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -1,7 +1,7 @@ /* ultra.c - Ultracode libzint - the open source barcode library - Copyright (C) 2019 Robin Stuart + Copyright (C) 2020 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -117,6 +117,18 @@ static const int tiles[] = { * Dated 2001-03-09 * Corrected thanks to input from Terry Burton */ +/* + * NOTE: Included here is an attempt to allow code compression within Ultracode. Unfortunately + * the copy of the standard this was written from was an early draft which includes self + * contradictions, so this is a "best guess" implementation. Because it is not guaranteed + * to be correct this compression is not applied by default. To enable compression set + * + * symbol->option_1 = ULTRA_COMPRESSION; + * + * Code compression should be enabled by default when is has been implemented according to + * a more reliable version of the specification. + */ + /* Generate divisor polynomial gQ(x) for GF283() given the required ECC size, 3 to 101 */ void ultra_genPoly(short EccSize, unsigned short gPoly[], unsigned short gfPwr[], unsigned short gfLog[]) { int i, j; @@ -239,15 +251,8 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_locn, ch letters_encoded = i - in_locn; - //printf("8BIT FRAG: "); - //for (i = 0; i < codeword_count; i++) { - // printf("%d ", cw[i]); - //} - //printf("\n"); - *cw_len = codeword_count; - //printf("%d letters in %d codewords\n", letters_encoded, codeword_count); if (codeword_count == 0) { return 0.0; } else { @@ -326,15 +331,8 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_locn, char letters_encoded = i - in_locn; - //printf("ASCII FRAG: "); - //for (i = 0; i < codeword_count; i++) { - // printf("%d ", cw[i]); - //} - //printf("\n"); - *cw_len = codeword_count; - //printf("%d letters in %d codewords\n", letters_encoded, codeword_count); if (codeword_count == 0) { return 0.0; } else { @@ -529,7 +527,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu if (pad == 3) { pad = 0; } - //printf("Pad = %d\n", pad); + for (i = 0; i < pad; i++) { subcw[subcodeword_count] = 42; // Latch to other C43 set used as pad subcodeword_count++; @@ -537,12 +535,6 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu letters_encoded = sublocn - in_locn; - //printf("C43 SUBFRAG: "); - //for (i = 0; i < subcodeword_count; i++) { - // printf("%d ", subcw[i]); - //} - //printf("\n"); - for (i = 0; i < subcodeword_count; i += 3) { base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2]; cw[codeword_count] = base43_value / 282; @@ -551,15 +543,8 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu codeword_count++; } - // printf("C43 FRAG: "); - //for (i = 0; i < codeword_count; i++) { - // printf("%d ", cw[i]); - //} - //printf("\n"); - *cw_len = codeword_count; - //printf("%d letters in %d codewords\n", letters_encoded, codeword_count); if (codeword_count == 0) { return 0.0; } else { @@ -585,13 +570,13 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou int gs1 = 0; #ifndef _MSC_VER - unsigned char crop_source[in_length]; - char mode[in_length]; - int cw_fragment[in_length]; + unsigned char crop_source[in_length + 1]; + char mode[in_length + 1]; + int cw_fragment[in_length + 1]; #else - unsigned char * crop_source = (unsigned char *) _alloca(in_length * sizeof (unsigned char)); - char * mode = (char *) _alloca(in_length * sizeof (char)); - int * cw_fragment = (int *) _alloca(in_length * sizeof (int)); + unsigned char * crop_source = (unsigned char *) _alloca((in_length + 1) * sizeof (unsigned char)); + char * mode = (char *) _alloca(in_length + 1 * sizeof (char)); + int * cw_fragment = (int *) _alloca(in_length + 1 * sizeof (int)); #endif /* _MSC_VER */ /* Section 7.6.2 indicates that ECI \000003 to \811799 are supported */ @@ -608,6 +593,11 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou symbol_mode = EIGHTBIT_MODE; } } + + if (symbol->option_1 != ULTRA_COMPRESSION) { + // Force eight-bit mode by default as other modes are poorly documented + symbol_mode = EIGHTBIT_MODE; + } if (symbol->output_options & READER_INIT) { /* Reader Initialisation mode */ @@ -715,28 +705,35 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou } /* Attempt encoding in all three modes to see which offers best compaction and store results */ - current_mode = symbol_mode; - input_locn = 0; - do { - end_char = input_locn + PREDICT_WINDOW; - eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1); - ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1); - c43_score = look_ahead_c43(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1); + if (symbol->option_1 != ULTRA_COMPRESSION) { + current_mode = symbol_mode; + input_locn = 0; + do { + end_char = input_locn + PREDICT_WINDOW; + eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1); + ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1); + c43_score = look_ahead_c43(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1); - mode[input_locn] = 'a'; - current_mode = ASCII_MODE; + mode[input_locn] = 'a'; + current_mode = ASCII_MODE; - if ((c43_score > ascii_score) && (c43_score > eightbit_score)) { - mode[input_locn] = 'c'; - current_mode = C43_MODE; - } + if ((c43_score > ascii_score) && (c43_score > eightbit_score)) { + mode[input_locn] = 'c'; + current_mode = C43_MODE; + } - if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) { + if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) { + mode[input_locn] = '8'; + current_mode = EIGHTBIT_MODE; + } + input_locn++; + } while (input_locn < crop_length); + } else { + // Force eight-bit mode + for (input_locn = 0; input_locn < crop_length; input_locn++) { mode[input_locn] = '8'; - current_mode = EIGHTBIT_MODE; } - input_locn++; - } while (input_locn < crop_length); + } mode[input_locn] = '\0'; /* Use results from test to perform actual mode switching */ @@ -784,9 +781,6 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou input_locn += block_length; } while (input_locn < crop_length); - //printf("RED: %s\n", crop_source); - //printf("MOD: %s\n", mode); - return codeword_count; } @@ -823,12 +817,9 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords); - printf("Codewords returned = %d\n", data_cw_count); - - //for (int i = 0; i < data_cw_count; i++) { - // printf("%d ", data_codewords[i]); - //} - //printf("\n"); + if (symbol->debug) { + printf("Codewords returned = %d\n", data_cw_count); + } /* Default ECC level is EC2 */ if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) { @@ -850,7 +841,9 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si } acc = qcc - 3; - printf("ECC codewords: %d\n", qcc); + if (symbol->debug) { + printf("ECC codewords: %d\n", qcc); + } /* Maximum capacity is 282 codewords */ total_cws = data_cw_count + qcc + 5; @@ -874,7 +867,9 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si columns = (total_cws / rows) + 1; } - printf("Calculated size is %d rows by %d columns\n", rows, columns); + if (symbol->debug) { + printf("Calculated size is %d rows by %d columns\n", rows, columns); + } /* Insert MCC and ACC into data codewords */ for (i = 282; i > 2; i--) { @@ -904,11 +899,13 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si } codeword[locn++] = qcc; // QCC - printf("Rearranged codewords with ECC:\n"); - for (i = 0; i < locn; i++) { - printf("%d ", codeword[i]); + if (symbol->debug) { + printf("Rearranged codewords with ECC:\n"); + for (i = 0; i < locn; i++) { + printf("%d ", codeword[i]); + } + printf("\n"); } - printf("\n"); total_height = (rows * 6) + 1; total_width = columns + 6 + (columns / 15); @@ -976,7 +973,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si tilex++; } } - //printf("[%d] = %s\n", codeword[i], tilepat); + for (j = 0; j < 5; j++) { pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[j]; } @@ -1003,12 +1000,14 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si pattern[((tiley + j) * total_width) + tilex] = tilepat[j]; } - printf("DCC: %d\n", dcc); + if (symbol->debug) { + printf("DCC: %d\n", dcc); - for (i = 0; i < (total_height * total_width); i++) { - printf("%c", pattern[i]); - if ((i + 1) % total_width == 0) { - printf("\n"); + for (i = 0; i < (total_height * total_width); i++) { + printf("%c", pattern[i]); + if ((i + 1) % total_width == 0) { + printf("\n"); + } } } diff --git a/backend/zint.h b/backend/zint.h index 2146d8c3..cd2a86a1 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -267,6 +267,9 @@ extern "C" { #define DM_SQUARE 100 #define DM_DMRE 101 +// Ultracode specific option +#define ULTRA_COMPRESSION 128 + // Warning and error conditions #define ZINT_WARN_INVALID_OPTION 2 #define ZINT_WARN_USES_ECI 3 diff --git a/frontend/main.c b/frontend/main.c index bbda6326..da24c8f5 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -37,37 +37,38 @@ /* Print list of supported symbologies */ void types(void) { - printf( " 1: Code 11 51: Pharma One-Track 92: Aztec Code\n" - " 2: Standard 2of5 52: PZN 93: DAFT Code\n" - " 3: Interleaved 2of5 53: Pharma Two-Track 97: Micro QR Code\n" - " 4: IATA 2of5 55: PDF417 98: HIBC Code 128\n" - " 6: Data Logic 56: PDF417 Trunc 99: HIBC Code 39\n" - " 7: Industrial 2of5 57: Maxicode 102: HIBC Data Matrix\n" - " 8: Code 39 58: QR Code 104: HIBC QR Code\n" - " 9: Extended Code 39 60: Code 128-B 106: HIBC PDF417\n" - "13: EAN 63: AP Standard Customer 108: HIBC MicroPDF417\n" - "14: EAN + Check 66: AP Reply Paid 110: HIBC Codablock-F\n" - "16: GS1-128 67: AP Routing 112: HIBC Aztec Code\n" - "18: Codabar 68: AP Redirection 115: DotCode\n" - "20: Code 128 69: ISBN 116: Han Xin Code\n" - "21: Leitcode 70: RM4SCC 121: RM Mailmark\n" - "22: Identcode 71: Data Matrix 128: Aztec Runes\n" - "23: Code 16k 72: EAN-14 129: Code 32\n" - "24: Code 49 73: VIN (North America) 130: Comp EAN\n" - "25: Code 93 74: Codablock-F 131: Comp GS1-128\n" - "28: Flattermarken 75: NVE-18 132: Comp DataBar Omni\n" - "29: GS1 DataBar Omni 76: Japanese Post 133: Comp DataBar Ltd\n" - "30: GS1 DataBar Ltd 77: Korea Post 134: Comp DataBar ExpOm\n" - "31: GS1 DataBar ExpOm 79: GS1 DataBar Stack 135: Comp UPC-A\n" - "32: Telepen Alpha 80: GS1 DataBar Stack Omni 136: Comp UPC-E\n" - "34: UPC-A 81: GS1 DataBar ESO 137: Comp DataBar Stack\n" - "35: UPC-A + Check 82: Planet 138: Comp DataBar Stack Omni\n" - "37: UPC-E 84: MicroPDF 139: Comp DataBar ESO\n" - "38: UPC-E + Check 85: USPS OneCode 140: Channel Code\n" - "40: Postnet 86: UK Plessey 141: Code One\n" - "47: MSI Plessey 87: Telepen Numeric 142: Grid Matrix\n" - "49: FIM 89: ITF-14 143: UPNQR\n" - "50: Logmars 90: KIX Code 145: rMQR\n" + printf( " 1: Code 11 52: PZN 97: Micro QR Code\n" + " 2: Standard 2of5 53: Pharma Two-Track 98: HIBC Code 128\n" + " 3: Interleaved 2of5 55: PDF417 99: HIBC Code 39\n" + " 4: IATA 2of5 56: PDF417 Trunc 102: HIBC Data Matrix\n" + " 6: Data Logic 57: Maxicode 104: HIBC QR Code\n" + " 7: Industrial 2of5 58: QR Code 106: HIBC PDF417\n" + " 8: Code 39 60: Code 128-B 108: HIBC MicroPDF417\n" + " 9: Extended Code 39 63: AP Standard Customer 110: HIBC Codablock-F\n" + "13: EAN 66: AP Reply Paid 112: HIBC Aztec Code\n" + "14: EAN + Check 67: AP Routing 115: DotCode\n" + "16: GS1-128 68: AP Redirection 116: Han Xin Code\n" + "18: Codabar 69: ISBN 121: RM Mailmark\n" + "20: Code 128 70: RM4SCC 128: Aztec Runes\n" + "21: Leitcode 71: Data Matrix 129: Code 32\n" + "22: Identcode 72: EAN-14 130: Comp EAN\n" + "23: Code 16k 73: VIN (North America) 131: Comp GS1-128\n" + "24: Code 49 74: Codablock-F 132: Comp DataBar Omni\n" + "25: Code 93 75: NVE-18 133: Comp DataBar Ltd\n" + "28: Flattermarken 76: Japanese Post 134: Comp DataBar ExpOm\n" + "29: GS1 DataBar Omni 77: Korea Post 135: Comp UPC-A\n" + "30: GS1 DataBar Ltd 79: GS1 DataBar Stack 136: Comp UPC-E\n" + "31: GS1 DataBar ExpOm 80: GS1 DataBar Stack Omni 137: Comp DataBar Stack\n" + "32: Telepen Alpha 81: GS1 DataBar ESO 138: Comp DataBar Stack Omni\n" + "34: UPC-A 82: Planet 1139: Comp DataBar ESO\n" + "35: UPC-A + Check 84: MicroPDF 140: Channel Code\n" + "37: UPC-E 85: USPS OneCode 141: Code One\n" + "38: UPC-E + Check 86: UK Plessey 142: Grid Matrix\n" + "40: Postnet 87: Telepen Numeric 143: UPNQR\n" + "47: MSI Plessey 89: ITF-14 144: Ultracode\n" + "49: FIM 90: KIX Code 145: rMQR\n" + "50: Logmars 92: Aztec Code\n" + "51: Pharma One-Track 93: DAFT Code\n" ); }