Ultra: Disable code compression by default

Ensures symbols are valid until better version of specification is available
This commit is contained in:
Robin Stuart 2020-03-29 22:23:07 +01:00
parent c57b74a7e6
commit b572bb513d
3 changed files with 107 additions and 104 deletions

View File

@ -1,7 +1,7 @@
/* ultra.c - Ultracode /* ultra.c - Ultracode
libzint - the open source barcode library libzint - the open source barcode library
Copyright (C) 2019 Robin Stuart <rstuart114@gmail.com> Copyright (C) 2020 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@ -117,6 +117,18 @@ static const int tiles[] = {
* Dated 2001-03-09 * Dated 2001-03-09
* Corrected thanks to input from Terry Burton */ * 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 */ /* 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[]) { void ultra_genPoly(short EccSize, unsigned short gPoly[], unsigned short gfPwr[], unsigned short gfLog[]) {
int i, j; 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; 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; *cw_len = codeword_count;
//printf("%d letters in %d codewords\n", letters_encoded, codeword_count);
if (codeword_count == 0) { if (codeword_count == 0) {
return 0.0; return 0.0;
} else { } else {
@ -326,15 +331,8 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_locn, char
letters_encoded = i - in_locn; 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; *cw_len = codeword_count;
//printf("%d letters in %d codewords\n", letters_encoded, codeword_count);
if (codeword_count == 0) { if (codeword_count == 0) {
return 0.0; return 0.0;
} else { } else {
@ -529,7 +527,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char cu
if (pad == 3) { if (pad == 3) {
pad = 0; pad = 0;
} }
//printf("Pad = %d\n", pad);
for (i = 0; i < pad; i++) { for (i = 0; i < pad; i++) {
subcw[subcodeword_count] = 42; // Latch to other C43 set used as pad subcw[subcodeword_count] = 42; // Latch to other C43 set used as pad
subcodeword_count++; 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; 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) { for (i = 0; i < subcodeword_count; i += 3) {
base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2]; base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2];
cw[codeword_count] = base43_value / 282; 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++; codeword_count++;
} }
// printf("C43 FRAG: ");
//for (i = 0; i < codeword_count; i++) {
// printf("%d ", cw[i]);
//}
//printf("\n");
*cw_len = codeword_count; *cw_len = codeword_count;
//printf("%d letters in %d codewords\n", letters_encoded, codeword_count);
if (codeword_count == 0) { if (codeword_count == 0) {
return 0.0; return 0.0;
} else { } else {
@ -585,13 +570,13 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
int gs1 = 0; int gs1 = 0;
#ifndef _MSC_VER #ifndef _MSC_VER
unsigned char crop_source[in_length]; unsigned char crop_source[in_length + 1];
char mode[in_length]; char mode[in_length + 1];
int cw_fragment[in_length]; int cw_fragment[in_length + 1];
#else #else
unsigned char * crop_source = (unsigned char *) _alloca(in_length * sizeof (unsigned char)); unsigned char * crop_source = (unsigned char *) _alloca((in_length + 1) * sizeof (unsigned char));
char * mode = (char *) _alloca(in_length * sizeof (char)); char * mode = (char *) _alloca(in_length + 1 * sizeof (char));
int * cw_fragment = (int *) _alloca(in_length * sizeof (int)); int * cw_fragment = (int *) _alloca(in_length + 1 * sizeof (int));
#endif /* _MSC_VER */ #endif /* _MSC_VER */
/* Section 7.6.2 indicates that ECI \000003 to \811799 are supported */ /* 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; 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) { if (symbol->output_options & READER_INIT) {
/* Reader Initialisation mode */ /* 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 */ /* Attempt encoding in all three modes to see which offers best compaction and store results */
current_mode = symbol_mode; if (symbol->option_1 != ULTRA_COMPRESSION) {
input_locn = 0; current_mode = symbol_mode;
do { input_locn = 0;
end_char = input_locn + PREDICT_WINDOW; do {
eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1); end_char = input_locn + PREDICT_WINDOW;
ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1); eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_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); 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'; mode[input_locn] = 'a';
current_mode = ASCII_MODE; current_mode = ASCII_MODE;
if ((c43_score > ascii_score) && (c43_score > eightbit_score)) { if ((c43_score > ascii_score) && (c43_score > eightbit_score)) {
mode[input_locn] = 'c'; mode[input_locn] = 'c';
current_mode = C43_MODE; 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'; mode[input_locn] = '8';
current_mode = EIGHTBIT_MODE;
} }
input_locn++; }
} while (input_locn < crop_length);
mode[input_locn] = '\0'; mode[input_locn] = '\0';
/* Use results from test to perform actual mode switching */ /* 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; input_locn += block_length;
} while (input_locn < crop_length); } while (input_locn < crop_length);
//printf("RED: %s\n", crop_source);
//printf("MOD: %s\n", mode);
return codeword_count; 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); data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords);
printf("Codewords returned = %d\n", data_cw_count); if (symbol->debug) {
printf("Codewords returned = %d\n", data_cw_count);
//for (int i = 0; i < data_cw_count; i++) { }
// printf("%d ", data_codewords[i]);
//}
//printf("\n");
/* Default ECC level is EC2 */ /* Default ECC level is EC2 */
if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) { 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; acc = qcc - 3;
printf("ECC codewords: %d\n", qcc); if (symbol->debug) {
printf("ECC codewords: %d\n", qcc);
}
/* Maximum capacity is 282 codewords */ /* Maximum capacity is 282 codewords */
total_cws = data_cw_count + qcc + 5; 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; 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 */ /* Insert MCC and ACC into data codewords */
for (i = 282; i > 2; i--) { 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 codeword[locn++] = qcc; // QCC
printf("Rearranged codewords with ECC:\n"); if (symbol->debug) {
for (i = 0; i < locn; i++) { printf("Rearranged codewords with ECC:\n");
printf("%d ", codeword[i]); for (i = 0; i < locn; i++) {
printf("%d ", codeword[i]);
}
printf("\n");
} }
printf("\n");
total_height = (rows * 6) + 1; total_height = (rows * 6) + 1;
total_width = columns + 6 + (columns / 15); total_width = columns + 6 + (columns / 15);
@ -976,7 +973,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
tilex++; tilex++;
} }
} }
//printf("[%d] = %s\n", codeword[i], tilepat);
for (j = 0; j < 5; j++) { for (j = 0; j < 5; j++) {
pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[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]; 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++) { for (i = 0; i < (total_height * total_width); i++) {
printf("%c", pattern[i]); printf("%c", pattern[i]);
if ((i + 1) % total_width == 0) { if ((i + 1) % total_width == 0) {
printf("\n"); printf("\n");
}
} }
} }

View File

@ -267,6 +267,9 @@ extern "C" {
#define DM_SQUARE 100 #define DM_SQUARE 100
#define DM_DMRE 101 #define DM_DMRE 101
// Ultracode specific option
#define ULTRA_COMPRESSION 128
// Warning and error conditions // Warning and error conditions
#define ZINT_WARN_INVALID_OPTION 2 #define ZINT_WARN_INVALID_OPTION 2
#define ZINT_WARN_USES_ECI 3 #define ZINT_WARN_USES_ECI 3

View File

@ -37,37 +37,38 @@
/* Print list of supported symbologies */ /* Print list of supported symbologies */
void types(void) { void types(void) {
printf( " 1: Code 11 51: Pharma One-Track 92: Aztec Code\n" printf( " 1: Code 11 52: PZN 97: Micro QR Code\n"
" 2: Standard 2of5 52: PZN 93: DAFT Code\n" " 2: Standard 2of5 53: Pharma Two-Track 98: HIBC Code 128\n"
" 3: Interleaved 2of5 53: Pharma Two-Track 97: Micro QR Code\n" " 3: Interleaved 2of5 55: PDF417 99: HIBC Code 39\n"
" 4: IATA 2of5 55: PDF417 98: HIBC Code 128\n" " 4: IATA 2of5 56: PDF417 Trunc 102: HIBC Data Matrix\n"
" 6: Data Logic 56: PDF417 Trunc 99: HIBC Code 39\n" " 6: Data Logic 57: Maxicode 104: HIBC QR Code\n"
" 7: Industrial 2of5 57: Maxicode 102: HIBC Data Matrix\n" " 7: Industrial 2of5 58: QR Code 106: HIBC PDF417\n"
" 8: Code 39 58: QR Code 104: HIBC QR Code\n" " 8: Code 39 60: Code 128-B 108: HIBC MicroPDF417\n"
" 9: Extended Code 39 60: Code 128-B 106: HIBC PDF417\n" " 9: Extended Code 39 63: AP Standard Customer 110: HIBC Codablock-F\n"
"13: EAN 63: AP Standard Customer 108: HIBC MicroPDF417\n" "13: EAN 66: AP Reply Paid 112: HIBC Aztec Code\n"
"14: EAN + Check 66: AP Reply Paid 110: HIBC Codablock-F\n" "14: EAN + Check 67: AP Routing 115: DotCode\n"
"16: GS1-128 67: AP Routing 112: HIBC Aztec Code\n" "16: GS1-128 68: AP Redirection 116: Han Xin Code\n"
"18: Codabar 68: AP Redirection 115: DotCode\n" "18: Codabar 69: ISBN 121: RM Mailmark\n"
"20: Code 128 69: ISBN 116: Han Xin Code\n" "20: Code 128 70: RM4SCC 128: Aztec Runes\n"
"21: Leitcode 70: RM4SCC 121: RM Mailmark\n" "21: Leitcode 71: Data Matrix 129: Code 32\n"
"22: Identcode 71: Data Matrix 128: Aztec Runes\n" "22: Identcode 72: EAN-14 130: Comp EAN\n"
"23: Code 16k 72: EAN-14 129: Code 32\n" "23: Code 16k 73: VIN (North America) 131: Comp GS1-128\n"
"24: Code 49 73: VIN (North America) 130: Comp EAN\n" "24: Code 49 74: Codablock-F 132: Comp DataBar Omni\n"
"25: Code 93 74: Codablock-F 131: Comp GS1-128\n" "25: Code 93 75: NVE-18 133: Comp DataBar Ltd\n"
"28: Flattermarken 75: NVE-18 132: Comp DataBar Omni\n" "28: Flattermarken 76: Japanese Post 134: Comp DataBar ExpOm\n"
"29: GS1 DataBar Omni 76: Japanese Post 133: Comp DataBar Ltd\n" "29: GS1 DataBar Omni 77: Korea Post 135: Comp UPC-A\n"
"30: GS1 DataBar Ltd 77: Korea Post 134: Comp DataBar ExpOm\n" "30: GS1 DataBar Ltd 79: GS1 DataBar Stack 136: Comp UPC-E\n"
"31: GS1 DataBar ExpOm 79: GS1 DataBar Stack 135: Comp UPC-A\n" "31: GS1 DataBar ExpOm 80: GS1 DataBar Stack Omni 137: Comp DataBar Stack\n"
"32: Telepen Alpha 80: GS1 DataBar Stack Omni 136: Comp UPC-E\n" "32: Telepen Alpha 81: GS1 DataBar ESO 138: Comp DataBar Stack Omni\n"
"34: UPC-A 81: GS1 DataBar ESO 137: Comp DataBar Stack\n" "34: UPC-A 82: Planet 1139: Comp DataBar ESO\n"
"35: UPC-A + Check 82: Planet 138: Comp DataBar Stack Omni\n" "35: UPC-A + Check 84: MicroPDF 140: Channel Code\n"
"37: UPC-E 84: MicroPDF 139: Comp DataBar ESO\n" "37: UPC-E 85: USPS OneCode 141: Code One\n"
"38: UPC-E + Check 85: USPS OneCode 140: Channel Code\n" "38: UPC-E + Check 86: UK Plessey 142: Grid Matrix\n"
"40: Postnet 86: UK Plessey 141: Code One\n" "40: Postnet 87: Telepen Numeric 143: UPNQR\n"
"47: MSI Plessey 87: Telepen Numeric 142: Grid Matrix\n" "47: MSI Plessey 89: ITF-14 144: Ultracode\n"
"49: FIM 89: ITF-14 143: UPNQR\n" "49: FIM 90: KIX Code 145: rMQR\n"
"50: Logmars 90: KIX Code 145: rMQR\n" "50: Logmars 92: Aztec Code\n"
"51: Pharma One-Track 93: DAFT Code\n"
); );
} }