From edf7f9248efee5fdf8133ef3b1903a28b76ca730 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Tue, 10 Dec 2019 21:15:23 +0000 Subject: [PATCH 01/13] Ultracode codeword generation Supports Reader Init, ECI, GS1 and handles switching between 8-bit, ASCII and C43 modes with C43 macros --- backend/ultra.c | 581 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 580 insertions(+), 1 deletion(-) diff --git a/backend/ultra.c b/backend/ultra.c index da5cfb38..47c2ea69 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -29,12 +29,591 @@ SUCH DAMAGE. */ + /* This version was developed using AIMD/TSC15032-43 v0.99c Edit 60, dated 4th Nov 2015 */ + +#ifdef _MSC_VER +#include +#endif #include #include #include "common.h" -int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) { +#define EIGHTBIT_MODE 10 +#define ASCII_MODE 20 +#define C43_MODE 30 +#define PREDICT_WINDOW 12 + +static const char fragment[27][14] = {"http://", "https://", "http://www.", "https://www.", + "ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", + ".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp", + ".aspx", ".php", ".htm", ".html", ".shtml", "file:"}; + +static const char ultra_c43_set1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,%"; +static const char ultra_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-"; +static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*"; +static const char ultra_digit[] = "0123456789,/"; + +int ultra_find_fragment(unsigned char source[], int source_length, int position) { + int retval = -1; + int j, k, latch; + + for (j = 0; j < 27; j++) { + latch = 0; + if ((position + strlen(fragment[j])) <= source_length) { + latch = 1; + for (k = 0; k < strlen(fragment[j]); k++) { + if (source[position + k] != fragment[j][k]) { + latch = 0; + } + } + } + + if (latch) { + retval = j; + } + } + + return retval; +} + +/* Encode characters in 8-bit mode */ +float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len) +{ + int codeword_count = 0; + int i; + int letters_encoded = 0; + + if (current_mode != EIGHTBIT_MODE) { + cw[codeword_count] = 282; // Unlatch + codeword_count += 1; + } + + i = in_posn; + do { + cw[codeword_count] = source[i]; + i++; + codeword_count++; + } while ((i < in_length) && (i < end_char)); + + letters_encoded = i - in_posn; + + //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 { + return (float)letters_encoded / (float)codeword_count; + } +} + +/* Encode character in the ASCII mode/submode (including numeric compression) */ +float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char current_mode, int symbol_mode, int end_char, int cw[], int* cw_len){ + int codeword_count = 0; + int i; + int first_digit, second_digit; + int letters_encoded = 0; + + if (current_mode == EIGHTBIT_MODE) { + cw[codeword_count] = 267; // Latch ASCII Submode + codeword_count++; + } + + if (current_mode == C43_MODE) { + cw[codeword_count] = 282; // Unlatch + codeword_count++; + if (symbol_mode == EIGHTBIT_MODE) { + cw[codeword_count] = 267; // Latch ASCII Submode + codeword_count++; + } + } + + i = in_posn; + do { + /* Check for double digits */ + if (in_posn != (in_length - 1)) { + first_digit = posn(ultra_digit, source[i]); + second_digit = posn(ultra_digit, source[i + 1]); + if ((first_digit != -1) && (second_digit != -1)) { + /* Double digit can be encoded */ + if ((first_digit >= 0) && (first_digit <= 9) && (second_digit >= 0) && (second_digit <= 9)) { + /* Double digit numerics */ + cw[codeword_count] = (10 * first_digit) + second_digit + 128; + codeword_count++; + i += 2; + } else if ((first_digit >= 0) && (first_digit <= 9) && (second_digit == 10)) { + /* Single digit followed by selected decimal point character */ + cw[codeword_count] = first_digit + 228; + codeword_count++; + i += 2; + } else if ((first_digit == 10) && (second_digit >= 0) && (second_digit <= 9)) { + /* Selected decimal point character followed by single digit */ + cw[codeword_count] = second_digit + 238; + codeword_count++; + i += 2; + } else if ((first_digit >= 0) && (first_digit <= 10) && (second_digit == 11)) { + /* Single digit or decimal point followed by field deliminator */ + cw[codeword_count] = first_digit + 248; + codeword_count++; + i += 2; + } else if ((first_digit == 11) && (second_digit >= 0) && (second_digit <= 10)) { + /* Field deliminator followed by single digit or decimal point */ + cw[codeword_count] = second_digit + 259; + codeword_count++; + i += 2; + } + } + } + + if (source[i] < 0x7F) { + cw[codeword_count] = source[i]; + codeword_count++; + i++; + } + } while ((i < in_length) && (i < end_char) && (source[i] < 0x80)); + + letters_encoded = i - in_posn; + + //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 { + return (float)letters_encoded / (float)codeword_count; + } +} + +int get_subset(unsigned char source[], int in_length, int in_posn) { + int fragno; + int subset = 0; + + if (posn(ultra_c43_set1, source[in_posn]) != -1) { + subset = 1; + } + + if (posn(ultra_c43_set2, source[in_posn]) != -1) { + subset = 2; + } + + if (posn(ultra_c43_set3, source[in_posn]) != -1) { + subset = 3; + } + + fragno = ultra_find_fragment(source, in_length, in_posn); + if ((fragno != -1) && (fragno != 26)) { + subset = 3; + } + + return subset; +} + +/* Encode characters in the C43 compaction submode */ +float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len){ + int codeword_count = 0; + int subcodeword_count = 0; + int i; + int subset = 0; + int fragno; + int subposn = in_posn; + int new_subset; + int unshift_set; + int base43_value; + int letters_encoded = 0; + int pad; + +#ifndef _MSC_VER + int subcw[in_length]; +#else + int * subcw = (int *) _alloca(in_length * sizeof (int)); +#endif /* _MSC_VER */ + + subset = get_subset(source, in_length, subposn); + + if (subset == 0) { + return 0.0; + } + + if (current_mode == EIGHTBIT_MODE) { + /* Check for permissable URL C43 macro sequences, otherwise encode directly */ + fragno = ultra_find_fragment(source, in_length, subposn); + + if ((fragno == 2) || (fragno == 3)) { + // http://www. > http:// + // https://www. > https:// + fragno -= 2; + } + + switch(fragno) { + case 17: // mailto: + cw[codeword_count] = 276; + subposn += strlen(fragment[fragno]); + codeword_count++; + break; + case 18: // tel: + cw[codeword_count] = 277; + subposn += strlen(fragment[fragno]); + codeword_count++; + break; + case 26: // file: + cw[codeword_count] = 278; + subposn += strlen(fragment[fragno]); + codeword_count++; + break; + case 0: // http:// + cw[codeword_count] = 279; + subposn += strlen(fragment[fragno]); + codeword_count++; + break; + case 1: // https:// + cw[codeword_count] = 280; + subposn += strlen(fragment[fragno]); + codeword_count++; + break; + case 4: // ftp:// + cw[codeword_count] = 281; + subposn += strlen(fragment[fragno]); + codeword_count++; + break; + default: + if (subset == 1) { + cw[codeword_count] = 260; // C43 Compaction Submode C1 + codeword_count++; + } + + if ((subset == 2) || (subset == 3)) { + cw[codeword_count] = 266; // C43 Compaction Submode C2 + codeword_count++; + } + break; + } + } + + if (current_mode == ASCII_MODE) { + if (subset == 1) { + cw[codeword_count] = 278; // C43 Compaction Submode C1 + codeword_count++; + } + + if ((subset == 2) || (subset == 3)) { + cw[codeword_count] = 280; // C43 Compaction Submode C2 + codeword_count++; + } + } + unshift_set = subset; + + do { + if (subset == 1) { + subcw[subcodeword_count] = posn(ultra_c43_set1, source[subposn]); + subcodeword_count++; + subposn++; + } + + if (subset == 2) { + subcw[subcodeword_count] = posn(ultra_c43_set2, source[subposn]); + subcodeword_count++; + subposn++; + } + + if (subset == 3) { + subcw[subcodeword_count] = 41; // Shift to set 3 + subcodeword_count++; + + fragno = ultra_find_fragment(source, in_length, subposn); + if (fragno == 26) { + fragno = -1; + } + if ((fragno >= 0) && (fragno <= 18)) { + subcw[subcodeword_count] = fragno; + subcodeword_count++; + subposn += strlen(fragment[fragno]); + } + if ((fragno >= 18) && (fragno <= 25)) { + subcw[subcodeword_count] = fragno + 17; + subcodeword_count++; + subposn += strlen(fragment[fragno]); + } + if (fragno == -1) { + subcw[subcodeword_count] = posn(ultra_c43_set3, source[subposn]); + subcodeword_count++; + subposn++; + } + subset = unshift_set; + } + + if (subposn < in_length) { + new_subset = get_subset(source, in_length, subposn); + + if (((subset == 1) && (new_subset == 2)) && ((source[subposn] == '.') || (source[subposn] == ','))) { + new_subset = 1; + } + + if ((new_subset != subset) && ((new_subset == 1) || (new_subset == 2))) { + subcw[subcodeword_count] = 42; // Latch to other C43 set + subcodeword_count++; + unshift_set = new_subset; + } + + subset = new_subset; + } + } while ((subposn < in_length) && (subposn < end_char) && (subset != 0)); + + pad = 3 - (subcodeword_count % 3); + 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++; + } + + letters_encoded = subposn - in_posn; + + //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; + codeword_count++; + cw[codeword_count] = base43_value % 282; + 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 { + return (float)letters_encoded / (float)codeword_count; + } +} + +/* Produces a set of codewords which are "somewhat" optimised - this could be improved on */ +int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length, int codewords[]) { + int i; + int crop_length; + int codeword_count = 0; + int input_posn = 0; + char symbol_mode; + char current_mode; + float eightbit_score; + float ascii_score; + float c43_score; + int end_char; + int block_length; + int fragment_length; + int fragno; + +#ifndef _MSC_VER + unsigned char crop_source[in_length]; + char mode[in_length]; + int cw_fragment[in_length]; +#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)); +#endif /* _MSC_VER */ + + /* Section 7.6.2 indicates that ECI \000003 to \811799 are supported */ + /* but this seems to contradict Table 5 which only shows up to \000898 */ + if (symbol->eci > 898) { + strcpy(symbol->errtxt, "ECI value out of range"); + return ZINT_ERROR_INVALID_OPTION; + } + + // Decide start character codeword (from Table 5) + symbol_mode = ASCII_MODE; + for (i = 0; i < in_length; i++) { + if (source[i] >= 0x80) { + symbol_mode = EIGHTBIT_MODE; + } + } + + if (symbol->output_options & READER_INIT) { + /* Reader Initialisation mode */ + if (symbol_mode == ASCII_MODE) { + codewords[0] = 272; // 7-bit ASCII mode + codewords[1] = 271; // FNC3 + } else { + codewords[0] = 257; // 8859-1 + codewords[1] = 269; // FNC3 + } + codeword_count = 2; + } else { + /* Calculate start character codeword */ + if (symbol_mode == ASCII_MODE) { + if (symbol->input_mode == GS1_MODE) { + codewords[0] = 273; + } else { + codewords[0] = 272; + } + } else { + if ((symbol->eci >= 3) && (symbol->eci <= 18) && (symbol->eci != 14)) { + // ECI indicate use of character set within ISO/IEC 8859 + codewords[0] = 257 + (symbol->eci - 3); + if (codewords[0] > 267) { + // Avoids ECI 14 for non-existant ISO/IEC 8859-12 + codewords[0]--; + } + } else if (symbol->eci > 18) { + // ECI indicates use of character set outside ISO/IEC 8859 + codewords[0] = 273 + (symbol->eci / 256); + codewords[1] = symbol->eci % 256; + codeword_count++; + } else { + codewords[0] = 257; // Default is assumed to be ISO/IEC 8859-1 (ECI 3) + } + } + + if ((codewords[0] == 257) || (codewords[0] == 272)) { + fragno = ultra_find_fragment((unsigned char *)source, in_length, 0); + + // Check for http:// at start of input + if ((fragno == 0) || (fragno == 2)) { + codewords[0] = 281; + input_posn = 7; + symbol_mode = EIGHTBIT_MODE; + } + + + // Check for https:// at start of input + if ((fragno == 1) || (fragno == 3)) { + codewords[0] = 282; + input_posn = 8; + symbol_mode = EIGHTBIT_MODE; + } + } + } + + codeword_count++; + + /* TODO: Check for 06 Macro Sequence and crop accordingly */ + + /* Make a cropped version of input data - removes http:// and https:// if needed */ + for (i = input_posn; i < in_length; i++) { + crop_source[i - input_posn] = source[i]; + } + crop_length = in_length - input_posn; + crop_source[crop_length] = '\0'; + + /* Attempt encoding in all three modes to see which offers best compaction and store results */ + current_mode = symbol_mode; + input_posn = 0; + do { + end_char = input_posn + PREDICT_WINDOW; + eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length); + ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length); + c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length); + + mode[input_posn] = 'a'; + current_mode = ASCII_MODE; + + if ((c43_score > ascii_score) && (c43_score > eightbit_score)) { + mode[input_posn] = 'c'; + current_mode = C43_MODE; + } + + if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) { + mode[input_posn] = '8'; + current_mode = EIGHTBIT_MODE; + } + input_posn++; + } while (input_posn < crop_length); + mode[input_posn] = '\0'; + + /* Use results from test to perform actual mode switching */ + current_mode = symbol_mode; + input_posn = 0; + do { + block_length = 0; + do { + block_length++; + } while (mode[input_posn + block_length] == mode[input_posn]); + + switch(mode[input_posn]) { + case 'a': + ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, input_posn + block_length, cw_fragment, &fragment_length); + current_mode = ASCII_MODE; + break; + case 'c': + c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length); + + /* Substitute temporary latch if possible */ + if ((current_mode == EIGHTBIT_MODE) && (cw_fragment[0] == 261) && (fragment_length >= 5) && (fragment_length <= 11)) { + /* Temporary latch to submode 1 from Table 11 */ + cw_fragment[0] = 256 + ((fragment_length - 5) / 2); + } else if ((current_mode == EIGHTBIT_MODE) && (cw_fragment[0] == 266) && (fragment_length >= 5) && (fragment_length <= 11)) { + /* Temporary latch to submode 2 from Table 11 */ + cw_fragment[0] = 262 + ((fragment_length - 5) / 2); + } else if ((current_mode == ASCII_MODE) && (cw_fragment[0] == 278) && (fragment_length >= 5) && (fragment_length <= 11)) { + /* Temporary latch to submode 1 from Table 9 */ + cw_fragment[0] = 274 + ((fragment_length - 5) / 2); + } else { + current_mode = C43_MODE; + } + break; + case '8': + eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length); + current_mode = EIGHTBIT_MODE; + break; + } + + for (i = 0; i < fragment_length; i++) { + codewords[codeword_count + i] = cw_fragment[i]; + } + codeword_count += fragment_length; + + input_posn += block_length; + } while (input_posn < crop_length); + + //printf("RED: %s\n", crop_source); + //printf("MOD: %s\n", mode); + + return codeword_count; +} + +int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) { + int data_cw_count = 0; + +#ifndef _MSC_VER + int data_codewords[in_length * 2]; +#else + int* data_codewords = (int *) _alloca(in_length * 2 * sizeof (int)); +#endif /* _MSC_VER */ + + 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"); strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!"); return ZINT_ERROR_INVALID_OPTION; From 7216202f063c73925448b94c75d8252ea143e082 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Wed, 11 Dec 2019 21:10:07 +0000 Subject: [PATCH 02/13] Ultracode: Add FNC1 and 06 Macro support and calculate ECC capacity --- backend/ultra.c | 107 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index 47c2ea69..503331ab 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -78,7 +78,7 @@ int ultra_find_fragment(unsigned char source[], int source_length, int position) } /* Encode characters in 8-bit mode */ -float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len) +float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len, int gs1) { int codeword_count = 0; int i; @@ -91,7 +91,11 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, ch i = in_posn; do { - cw[codeword_count] = source[i]; + if ((source[i] == '[') && gs1) { + cw[codeword_count] = 268; // FNC1 + } else { + cw[codeword_count] = source[i]; + } i++; codeword_count++; } while ((i < in_length) && (i < end_char)); @@ -115,7 +119,7 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, ch } /* Encode character in the ASCII mode/submode (including numeric compression) */ -float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char current_mode, int symbol_mode, int end_char, int cw[], int* cw_len){ +float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char current_mode, int symbol_mode, int end_char, int cw[], int* cw_len, int gs1){ int codeword_count = 0; int i; int first_digit, second_digit; @@ -173,7 +177,11 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char } if (source[i] < 0x7F) { - cw[codeword_count] = source[i]; + if ((source[i] == '[') && gs1) { + cw[codeword_count] = 272; // FNC1 + } else { + cw[codeword_count] = source[i]; + } codeword_count++; i++; } @@ -222,7 +230,7 @@ int get_subset(unsigned char source[], int in_length, int in_posn) { } /* Encode characters in the C43 compaction submode */ -float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len){ +float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len, int gs1){ int codeword_count = 0; int subcodeword_count = 0; int i; @@ -234,6 +242,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu int base43_value; int letters_encoded = 0; int pad; + int gs1_latch = 0; #ifndef _MSC_VER int subcw[in_length]; @@ -358,6 +367,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu new_subset = get_subset(source, in_length, subposn); if (((subset == 1) && (new_subset == 2)) && ((source[subposn] == '.') || (source[subposn] == ','))) { + /* and characters available in both subsets */ new_subset = 1; } @@ -369,7 +379,14 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu subset = new_subset; } - } while ((subposn < in_length) && (subposn < end_char) && (subset != 0)); + + /* Check for FNC1 */ + if (subposn < (in_length - 1)) { + if ((source[subposn + 1] == '[') && gs1) { + gs1_latch = 1; + } + } + } while ((subposn < in_length) && (subposn < end_char) && (subset != 0) && (gs1_latch == 0)); pad = 3 - (subcodeword_count % 3); if (pad == 3) { @@ -428,6 +445,7 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou int block_length; int fragment_length; int fragno; + int gs1 = 0; #ifndef _MSC_VER unsigned char crop_source[in_length]; @@ -512,23 +530,45 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou codeword_count++; - /* TODO: Check for 06 Macro Sequence and crop accordingly */ + /* Check for 06 Macro Sequence and crop accordingly */ + if (in_length >= 9 + && source[0] == '[' && source[1] == ')' && source[2] == '>' && source[3] == '\x1e' + && source[4] == '0' && source[5] == '6' && source[6] == '\x1d' + && source[in_length - 2] == '\x1e' && source[in_length - 1] == '\x04') { - /* Make a cropped version of input data - removes http:// and https:// if needed */ - for (i = input_posn; i < in_length; i++) { - crop_source[i - input_posn] = source[i]; + if (symbol_mode == EIGHTBIT_MODE) { + codewords[codeword_count] = 271; // 06 Macro + } else { + codewords[codeword_count] = 273; // 06 Macro + } + codeword_count++; + + for (i = input_posn + 7; i < (in_length - 2); i++) { + crop_source[i - input_posn] = source[i]; + } + crop_length = in_length - 9; + crop_source[crop_length] = '\0'; + } else { + /* Make a cropped version of input data - removes http:// and https:// if needed */ + for (i = input_posn; i < in_length; i++) { + crop_source[i - input_posn] = source[i]; + } + crop_length = in_length - input_posn; + crop_source[crop_length] = '\0'; + } + + if ((symbol->input_mode & 0x07) == GS1_MODE) { + gs1 = 1; } - crop_length = in_length - input_posn; - crop_source[crop_length] = '\0'; /* Attempt encoding in all three modes to see which offers best compaction and store results */ current_mode = symbol_mode; input_posn = 0; do { end_char = input_posn + PREDICT_WINDOW; - eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length); - ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length); - c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length); + eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length, gs1); + ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1); + c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length, gs1); mode[input_posn] = 'a'; current_mode = ASCII_MODE; @@ -557,11 +597,11 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou switch(mode[input_posn]) { case 'a': - ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, input_posn + block_length, cw_fragment, &fragment_length); + ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, input_posn + block_length, cw_fragment, &fragment_length, gs1); current_mode = ASCII_MODE; break; case 'c': - c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length); + c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length, gs1); /* Substitute temporary latch if possible */ if ((current_mode == EIGHTBIT_MODE) && (cw_fragment[0] == 261) && (fragment_length >= 5) && (fragment_length <= 11)) { @@ -578,7 +618,7 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou } break; case '8': - eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length); + eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length, gs1); current_mode = EIGHTBIT_MODE; break; } @@ -599,6 +639,9 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) { int data_cw_count = 0; + int ecc_cw; + int ecc_level; // = Q in section 7.7.1 + int misdecode_cw; // = P in section 7.7.1 #ifndef _MSC_VER int data_codewords[in_length * 2]; @@ -615,6 +658,34 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si } printf("\n"); + /* Default ECC level is EC2 */ + if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) { + ecc_level = 2; + } else { + ecc_level = symbol->option_1 - 1; + } + + if (ecc_level == 0) { + misdecode_cw = 0; + } else { + misdecode_cw = 3; + } + + /* ECC calculation from section 7.7.2 */ + if ((data_cw_count % 25) == 0) { + ecc_cw = (ecc_level * (data_cw_count / 25)) + misdecode_cw + 2; + } else { + ecc_cw = (ecc_level * ((data_cw_count / 25) + 1)) + misdecode_cw + 2; + } + + printf("ECC codewords: %d\n", ecc_cw); + + /* Maximum capacity is 282 codewords */ + if (data_cw_count + ecc_cw > 282) { + strcpy(symbol->errtxt, "Data too long for selected error correction capacity"); + return ZINT_ERROR_TOO_LONG; + } + strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!"); return ZINT_ERROR_INVALID_OPTION; } From 77c8e76bfa4a552709849e8243df8d805dddd713 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 15 Dec 2019 12:58:59 +0000 Subject: [PATCH 03/13] Ultracode: Add error correction --- backend/ultra.c | 177 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 12 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index 503331ab..54190ca9 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -44,6 +44,8 @@ #define PREDICT_WINDOW 12 +#define GFMUL(i, j) ((((i) == 0)||((j) == 0)) ? 0 : gfPwr[(gfLog[i] + gfLog[j])]) + static const char fragment[27][14] = {"http://", "https://", "http://www.", "https://www.", "ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp", @@ -54,6 +56,86 @@ static const char ultra_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-"; static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*"; static const char ultra_digit[] = "0123456789,/"; +/* The following adapted from ECC283.C "RSEC codeword generator" + * from Annex B of Ultracode draft + * originally written by Ted Williams of Symbol Vision Corp. + * Dated 2001-03-09 + * Corrected thanks to input from Terry Burton */ + +/* 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; + + gPoly[0] = 1; + for (i = 1; i < (EccSize + 1); i++) gPoly[i] = 0; + + for (i = 0; i < EccSize; i++) { + for (j = i; j >= 0; j--) + gPoly[j + 1] = (gPoly[j] + GFMUL(gPoly[j + 1], gfPwr[i + 1])) % 283; + gPoly[0] = GFMUL(gPoly[0], gfPwr[i + 1]); + } + for (i = EccSize - 1; i >= 0; i -= 2) gPoly[i] = 283 - gPoly[i]; + + /* gPoly[i] is > 0 so modulo operation not needed */ +} + +/* Generate the log and antilog tables for GF283() multiplication & division */ +void ultra_initLogTables(unsigned short gfPwr[], unsigned short gfLog[]) { + int i, j; + + for (j = 0; j < 283; j++) gfLog[j] = 0; + i = 1; + for (j = 0; j < 282; j++) { + /* j + 282 indicies save doing the modulo operation in GFMUL */ + gfPwr[j + 282] = gfPwr[j] = (short) i; + gfLog[i] = (short) j; + i = (i * 3) % 283; + } +} + +void ultra_gf283(short DataSize, short EccSize, int Message[]) { + /* Input is complete message codewords in array Message[282] + * DataSize is number of message codewords + * EccSize is number of Reed-Solomon GF(283) check codewords to generate + * + * Upon exit, Message[282] contains complete 282 codeword Symbol Message + * including leading zeroes corresponding to each truncated codeword */ + + unsigned short gPoly[283], gfPwr[(282 * 2)], gfLog[283]; + int i, j, n; + unsigned short t; + + /* first build the log & antilog tables used in multiplication & division */ + ultra_initLogTables(gfPwr, gfLog); + + /* then generate the division polynomial of length EccSize */ + ultra_genPoly(EccSize, gPoly, gfPwr, gfLog); + + /* zero all EccSize codeword values */ + for (j = 281; (j > (281 - EccSize)); j--) Message[j] = 0; + + /* shift message codewords to the right, leave space for ECC checkwords */ + for (i = DataSize - 1; (i >= 0); j--, i--) Message[j] = Message[i]; + + /* add zeroes to pad left end Message[] for truncated codewords */ + j++; + for (i = 0; i < j; i++) Message[i] = 0; + + /* generate (EccSize) Reed-Solomon checkwords */ + for (n = j; n < (j + DataSize); n++) { + t = (Message[j + DataSize] + Message[n]) % 283; + for (i = 0; i < (EccSize - 1); i++) { + Message[j + DataSize + i] = (Message[j + DataSize + i + 1] + 283 + - GFMUL(t, gPoly[EccSize - 1 - i])) % 283; + } + Message[j + DataSize + EccSize - 1] = (283 - GFMUL(t, gPoly[0])) % 283; + } + for (i = j + DataSize; i < (j + DataSize + EccSize); i++) + Message[i] = (283 - Message[i]) % 283; +} + +/* End of Ted Williams code */ + int ultra_find_fragment(unsigned char source[], int source_length, int position) { int retval = -1; int j, k, latch; @@ -543,8 +625,8 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou } codeword_count++; - for (i = input_posn + 7; i < (in_length - 2); i++) { - crop_source[i - input_posn] = source[i]; + for (i = 7; i < (in_length - 2); i++) { + crop_source[i - 7] = source[i]; } crop_length = in_length - 9; crop_source[crop_length] = '\0'; @@ -639,24 +721,36 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) { int data_cw_count = 0; - int ecc_cw; - int ecc_level; // = Q in section 7.7.1 + int ecc_cw; // = Q in section 7.7.1 + int ecc_level; int misdecode_cw; // = P in section 7.7.1 + int rows, columns; + int total_cws; + int pads; + int cw_memalloc; + int codeword[283]; + int i, posn; + int acc; + + cw_memalloc = in_length * 2; + if (cw_memalloc < 283) { + cw_memalloc = 283; + } #ifndef _MSC_VER - int data_codewords[in_length * 2]; + int data_codewords[cw_memalloc]; #else - int* data_codewords = (int *) _alloca(in_length * 2 * sizeof (int)); + int* data_codewords = (int *) _alloca(cw_memalloc * sizeof (int)); #endif /* _MSC_VER */ data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords); - printf("Codewords returned = %d\n", data_cw_count); + //printf("Codewords returned = %d\n", data_cw_count); - for (int i = 0; i < data_cw_count; i++) { - printf("%d ", data_codewords[i]); - } - printf("\n"); + //for (int i = 0; i < data_cw_count; i++) { + // printf("%d ", data_codewords[i]); + //} + //printf("\n"); /* Default ECC level is EC2 */ if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) { @@ -678,7 +772,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si ecc_cw = (ecc_level * ((data_cw_count / 25) + 1)) + misdecode_cw + 2; } - printf("ECC codewords: %d\n", ecc_cw); + //printf("ECC codewords: %d\n", ecc_cw); /* Maximum capacity is 282 codewords */ if (data_cw_count + ecc_cw > 282) { @@ -686,6 +780,65 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si return ZINT_ERROR_TOO_LONG; } + total_cws = data_cw_count + ecc_cw; + + rows = 5; + if (total_cws < 164) { + rows = 4; + } + if (total_cws < 84) { + rows = 3; + } + if (total_cws < 40) { + rows = 2; + } + + if ((total_cws % rows) == 0) { + pads = 0; + columns = total_cws / rows; + } else { + pads = rows - (total_cws % rows); + columns = (total_cws + pads) / rows; + } + + printf("Calculated size is %d rows by %d columns\n", rows, columns); + + acc = ecc_cw - misdecode_cw; // ACC = (Q-P) - section 6.11.6 + + /* Insert MCC and ACC into data codewords */ + for (i = 282; i > 2; i--) { + data_codewords[i] = data_codewords[i - 2]; + } + data_codewords[1] = data_cw_count += 2; // MCC + data_codewords[2] = acc; // ACC + + /* Calculate error correction codewords (RSEC) */ + ultra_gf283((short) data_cw_count, (short) ecc_cw, data_codewords); + + /* Rearrange to make final codeword sequence */ + posn = 0; + codeword[posn++] = data_codewords[282 - (data_cw_count + ecc_cw)]; // Start Character + codeword[posn++] = data_cw_count; // MCC + for (i = 0; i < ecc_cw; i++) { + codeword[posn++] = data_codewords[(282 - ecc_cw) + i]; // RSEC Region + } + codeword[posn++] = data_cw_count + ecc_cw; // TCC = C + Q - section 6.11.4 + codeword[posn++] = 283; // Separator + codeword[posn++] = acc; // ACC + for (i = 0; i < (data_cw_count - 3); i++) { + codeword[posn++] = data_codewords[(282 - ((data_cw_count - 3) + ecc_cw)) + i]; // Data Region + } + for (i = 0; i < pads; i++) { + codeword[posn++] = 284; // Pad pattern + } + codeword[posn++] = ecc_cw; // QCC + + printf("Rearranged codewords with ECC:\n"); + for (i = 0; i < posn; i++) { + printf("%d ", codeword[i]); + } + printf("\n"); + strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!"); return ZINT_ERROR_INVALID_OPTION; } From cfdc7cc262f601fcada99d340eba44d76cca22b9 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 15 Dec 2019 13:48:45 +0000 Subject: [PATCH 04/13] Ultra: Adjusted to allow 79-82 codeword range in 3-row symbols --- backend/ultra.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index 54190ca9..4a42e713 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -56,6 +56,9 @@ static const char ultra_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-"; static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*"; static const char ultra_digit[] = "0123456789,/"; +//static const int ultra_maxsize[] = {34, 78, 158, 282}; // According to Table 1 +static const int ultra_maxsize[] = {34, 82, 158, 282}; // Adjusted to allow 79-82 codeword range in 3-row symbols + /* The following adapted from ECC283.C "RSEC codeword generator" * from Annex B of Ultracode draft * originally written by Ted Williams of Symbol Vision Corp. @@ -783,14 +786,10 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si total_cws = data_cw_count + ecc_cw; rows = 5; - if (total_cws < 164) { - rows = 4; - } - if (total_cws < 84) { - rows = 3; - } - if (total_cws < 40) { - rows = 2; + for (i = 2; i >= 0; i--) { + if (total_cws < ultra_maxsize[i]) { + rows--; + } } if ((total_cws % rows) == 0) { From ea6902c817d84ba628081615179c8dcb501b3230 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 15 Dec 2019 22:26:57 +0000 Subject: [PATCH 05/13] Ultra: Convert codewords to tiles and place in grid --- backend/ultra.c | 146 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 8 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index 4a42e713..32634f20 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -55,10 +55,57 @@ static const char ultra_c43_set1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,%"; static const char ultra_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-"; static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*"; static const char ultra_digit[] = "0123456789,/"; +static const char ultra_colour[] = "WCBMRYGK"; //static const int ultra_maxsize[] = {34, 78, 158, 282}; // According to Table 1 static const int ultra_maxsize[] = {34, 82, 158, 282}; // Adjusted to allow 79-82 codeword range in 3-row symbols +static const int dccu[] = { + 051363, 051563, 051653, 053153, 053163, 053513, 053563, 053613, // 0-7 + 053653, 056153, 056163, 056313, 056353, 056363, 056513, 056563, // 8-15 + 051316, 051356, 051536, 051616, 053156, 053516, 053536, 053616, // 16-23 + 053636, 053656, 056136, 056156, 056316, 056356, 056516, 056536 // 24-31 +}; + +static const int dccl[] = { + 061351, 061361, 061531, 061561, 061631, 061651, 063131, 063151, // 0-7 + 063161, 063531, 063561, 063631, 065131, 065161, 065351, 065631, // 8-15 + 031351, 031361, 031531, 031561, 031631, 031651, 035131, 035151, // 16-23 + 035161, 035361, 035631, 035651, 036131, 036151, 036351, 036531 // 24-31 +}; + +static const int tiles[] = { + 013135, 013136, 013153, 013156, 013163, 013165, 013513, 013515, 013516, 013531, // 0-9 + 013535, 013536, 013561, 013563, 013565, 013613, 013615, 013616, 013631, 013635, // 10-19 + 013636, 013651, 013653, 013656, 015135, 015136, 015153, 015163, 015165, 015313, // 20-29 + 015315, 015316, 015351, 015353, 015356, 015361, 015363, 015365, 015613, 015615, // 30-39 + 015616, 015631, 015635, 015636, 015651, 015653, 015656, 016135, 016136, 016153, // 40-49 + 016156, 016165, 016313, 016315, 016316, 016351, 016353, 016356, 016361, 016363, // 50-59 + 016365, 016513, 016515, 016516, 016531, 016535, 016536, 016561, 016563, 016565, // 60-69 + 031315, 031316, 031351, 031356, 031361, 031365, 031513, 031515, 031516, 031531, // 70-79 + 031535, 031536, 031561, 031563, 031565, 031613, 031615, 031631, 031635, 031636, // 80-89 + 031651, 031653, 031656, 035131, 035135, 035136, 035151, 035153, 035156, 035161, // 90-99 + 035163, 035165, 035315, 035316, 035351, 035356, 035361, 035365, 035613, 035615, // 100-109 + 035616, 035631, 035635, 035636, 035651, 035653, 035656, 036131, 036135, 036136, // 110-119 + 036151, 036153, 036156, 036163, 036165, 036315, 036316, 036351, 036356, 036361, // 120-129 + 036365, 036513, 036515, 036516, 036531, 036535, 036536, 036561, 036563, 036565, // 130-139 + 051313, 051315, 051316, 051351, 051353, 051356, 051361, 051363, 051365, 051513, // 140-149 + 051516, 051531, 051536, 051561, 051563, 051613, 051615, 051616, 051631, 051635, // 150-159 + 051636, 051651, 051653, 051656, 053131, 053135, 053136, 053151, 053153, 053156, // 160-169 + 053161, 053163, 053165, 053513, 053516, 053531, 053536, 053561, 053563, 053613, // 170-179 + 053615, 053616, 053631, 053635, 053636, 053651, 053653, 053656, 056131, 056135, // 180-189 + 056136, 056151, 056153, 056156, 056161, 056163, 056165, 056313, 056315, 056316, // 190-199 + 056351, 056353, 056356, 056361, 056363, 056365, 056513, 056516, 056531, 056536, // 200-209 + 056561, 056563, 061313, 061315, 061316, 061351, 061353, 061356, 061361, 061363, // 210-219 + 061365, 061513, 061515, 061516, 061531, 061535, 061536, 061561, 061563, 061565, // 220-229 + 061615, 061631, 061635, 061651, 061653, 063131, 063135, 063136, 063151, 063153, // 230-239 + 063156, 063161, 063163, 063165, 063513, 063515, 063516, 063531, 063535, 063536, // 240-249 + 063561, 063563, 063565, 063613, 063615, 063631, 063635, 063651, 063653, 065131, // 250-259 + 065135, 065136, 065151, 065153, 065156, 065161, 065163, 065165, 065313, 065315, // 260-269 + 065316, 065351, 065353, 065356, 065361, 065363, 065365, 065613, 065615, 065631, // 270-279 + 065635, 065651, 065653, 056565, 051515 // 280-284 +}; + /* The following adapted from ECC283.C "RSEC codeword generator" * from Annex B of Ultracode draft * originally written by Ted Williams of Symbol Vision Corp. @@ -330,9 +377,9 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu int gs1_latch = 0; #ifndef _MSC_VER - int subcw[in_length]; + int subcw[(in_length + 3) * 2]; #else - int * subcw = (int *) _alloca(in_length * sizeof (int)); + int * subcw = (int *) _alloca((in_length + 3) * 2 * sizeof (int)); #endif /* _MSC_VER */ subset = get_subset(source, in_length, subposn); @@ -487,7 +534,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu //printf("C43 SUBFRAG: "); //for (i = 0; i < subcodeword_count; i++) { - // printf("%d ", subcw[i]); + // printf("%d ", subcw[i]); //} //printf("\n"); @@ -499,9 +546,9 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu codeword_count++; } - //printf("C43 FRAG: "); + // printf("C43 FRAG: "); //for (i = 0; i < codeword_count; i++) { - // printf("%d ", cw[i]); + // printf("%d ", cw[i]); //} //printf("\n"); @@ -732,8 +779,11 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si int pads; int cw_memalloc; int codeword[283]; - int i, posn; + int i, j, posn; int acc; + int total_height, total_width; + char tilepat[6]; + int tilex, tiley; cw_memalloc = in_length * 2; if (cw_memalloc < 283) { @@ -783,7 +833,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si return ZINT_ERROR_TOO_LONG; } - total_cws = data_cw_count + ecc_cw; + total_cws = data_cw_count + ecc_cw + 2 + misdecode_cw; rows = 5; for (i = 2; i >= 0; i--) { @@ -797,7 +847,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si columns = total_cws / rows; } else { pads = rows - (total_cws % rows); - columns = (total_cws + pads) / rows; + columns = (total_cws / rows) + 1; } printf("Calculated size is %d rows by %d columns\n", rows, columns); @@ -838,6 +888,86 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si } printf("\n"); + total_height = (rows * 6) + 1; + total_width = columns + 6 + (columns / 15); + + /* Build symbol */ +#ifndef _MSC_VER + char pattern[total_height * total_width]; +#else + char* pattern = (char *) _alloca(total_height * toal_width * sizeof (char)); +#endif /* _MSC_VER */ + + for (i = 0; i < (total_height * total_width); i++) { + pattern[i] = 'W'; + } + + /* Border */ + for (i = 0; i < total_width; i++) { + pattern[i] = 'K'; // Top + pattern[(total_height * total_width) - i - 1] = 'K'; // Bottom + } + for (i = 0; i < total_height; i++) { + pattern[total_width * i] = 'K'; // Left + pattern[(total_width * i) + 3] = 'K'; + pattern[(total_width * i) + (total_width - 1)] = 'K'; // Right + } + + /* Clock tracks */ + for (i = 0; i < total_height; i += 2) { + pattern[(total_width * i) + 1] = 'K'; // Primary vertical clock track + if (total_width > 20) { + pattern[(total_width * i) + 20] = 'K'; // Secondary vertical clock track + } + if (total_width > 36) { + pattern[(total_width * i) + 36] = 'K'; // Secondary vertical clock track + } + if (total_width > 52) { + pattern[(total_width * i) + 52] = 'K'; // Secondary vertical clock track + } + } + for (i = 6; i < total_height; i += 6) { + for (j = 5; j < total_width; j += 2) { + pattern[(total_width * i) + j] = 'K'; // Horizontal clock track + } + } + + /* Place tiles */ + tilepat[5] = '\0'; + tilex = 0; + tiley = 0; + for (i = 0; i < posn; i++) { + for (j = 0; j < 5; j++) { + tilepat[4 - j] = ultra_colour[(tiles[codeword[i]] >> (3 * j)) & 0x07]; + } + if ((tiley + 1) >= total_height) { + tiley = 0; + tilex++; + + if (tilex == 15) { + tilex++; + } + if (tilex == 31) { + tilex++; + } + if (tilex == 47) { + tilex++; + } + } + //printf("[%d] = %s\n", codeword[i], tilepat); + for (j = 0; j < 5; j++) { + pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[j]; + } + tiley += 6; + } + + for (i = 0; i < (total_height * total_width); i++) { + printf("%c", pattern[i]); + if ((i + 1) % total_width == 0) { + printf("\n"); + } + } + strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!"); return ZINT_ERROR_INVALID_OPTION; } From e6ab17086ce5e93ae8b166580803a9813b02a2e4 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Tue, 17 Dec 2019 20:22:16 +0000 Subject: [PATCH 06/13] Ultra: Add UCC, Correct ECC calculation for EC0, Expand ECI support to all values --- backend/ultra.c | 101 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index 32634f20..fb03ec9b 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -60,6 +60,10 @@ static const char ultra_colour[] = "WCBMRYGK"; //static const int ultra_maxsize[] = {34, 78, 158, 282}; // According to Table 1 static const int ultra_maxsize[] = {34, 82, 158, 282}; // Adjusted to allow 79-82 codeword range in 3-row symbols +static const int ultra_mincols[] = {5, 13, 23, 30}; // # Total Tile Columns from Table 1 + +static const int kec[] = {0, 1, 2, 4, 6, 8}; // Value K(EC) from Table 12 + static const int dccu[] = { 051363, 051563, 051653, 053153, 053163, 053513, 053563, 053613, // 0-7 053653, 056153, 056163, 056313, 056353, 056363, 056513, 056563, // 8-15 @@ -630,11 +634,27 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou // Avoids ECI 14 for non-existant ISO/IEC 8859-12 codewords[0]--; } - } else if (symbol->eci > 18) { + } else if ((symbol->eci > 18) && (symbol->eci <= 898)) { // ECI indicates use of character set outside ISO/IEC 8859 codewords[0] = 273 + (symbol->eci / 256); codewords[1] = symbol->eci % 256; codeword_count++; + } else if ((symbol->eci > 898) && (symbol->eci <= 9999)) { + // ECI beyond 898 needs to use fixed length encodable ECI invocation (section 7.6.2) + // Encode as 3 codewords + codewords[0] = 257; // ISO/IEC 8859-1 used to enter 8-bit mode + codewords[1] = 274; // Encode ECI as 3 codewords + codewords[2] = (symbol->eci / 100) + 128; + codewords[3] = (symbol->eci % 100) + 128; + codeword_count += 3; + } else if (symbol->eci >= 10000) { + // Encode as 4 codewords + codewords[0] = 257; // ISO/IEC 8859-1 used to enter 8-bit mode + codewords[1] = 275; // Encode ECI as 4 codewords + codewords[2] = (symbol->eci / 10000) + 128; + codewords[3] = ((symbol->eci % 10000) / 100) + 128; + codewords[4] = (symbol->eci % 100) + 128; + codeword_count += 4; } else { codewords[0] = 257; // Default is assumed to be ISO/IEC 8859-1 (ECI 3) } @@ -771,25 +791,29 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) { int data_cw_count = 0; - int ecc_cw; // = Q in section 7.7.1 + int acc, qcc; int ecc_level; - int misdecode_cw; // = P in section 7.7.1 int rows, columns; int total_cws; int pads; int cw_memalloc; int codeword[283]; int i, j, posn; - int acc; int total_height, total_width; char tilepat[6]; int tilex, tiley; + int dcc; cw_memalloc = in_length * 2; if (cw_memalloc < 283) { cw_memalloc = 283; } + if (symbol->eci > 811799) { + strcpy(symbol->errtxt, "ECI value not supported by Ultracode"); + return ZINT_ERROR_INVALID_OPTION; + } + #ifndef _MSC_VER int data_codewords[cw_memalloc]; #else @@ -798,7 +822,7 @@ 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); + printf("Codewords returned = %d\n", data_cw_count); //for (int i = 0; i < data_cw_count; i++) { // printf("%d ", data_codewords[i]); @@ -812,29 +836,28 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si ecc_level = symbol->option_1 - 1; } - if (ecc_level == 0) { - misdecode_cw = 0; - } else { - misdecode_cw = 3; - } - /* ECC calculation from section 7.7.2 */ - if ((data_cw_count % 25) == 0) { - ecc_cw = (ecc_level * (data_cw_count / 25)) + misdecode_cw + 2; + if (ecc_level == 0) { + qcc = 3; } else { - ecc_cw = (ecc_level * ((data_cw_count / 25) + 1)) + misdecode_cw + 2; - } + if ((data_cw_count % 25) == 0) { + qcc = (kec[ecc_level] * (data_cw_count / 25)) + 3 + 2; + } else { + qcc = (kec[ecc_level] * ((data_cw_count / 25) + 1)) + 3 + 2; + } - //printf("ECC codewords: %d\n", ecc_cw); + } + acc = qcc - 3; + + printf("ECC codewords: %d\n", qcc); /* Maximum capacity is 282 codewords */ - if (data_cw_count + ecc_cw > 282) { + total_cws = data_cw_count + qcc + 5; + if (total_cws > 282) { strcpy(symbol->errtxt, "Data too long for selected error correction capacity"); return ZINT_ERROR_TOO_LONG; } - total_cws = data_cw_count + ecc_cw + 2 + misdecode_cw; - rows = 5; for (i = 2; i >= 0; i--) { if (total_cws < ultra_maxsize[i]) { @@ -852,8 +875,6 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si printf("Calculated size is %d rows by %d columns\n", rows, columns); - acc = ecc_cw - misdecode_cw; // ACC = (Q-P) - section 6.11.6 - /* Insert MCC and ACC into data codewords */ for (i = 282; i > 2; i--) { data_codewords[i] = data_codewords[i - 2]; @@ -861,26 +882,26 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si data_codewords[1] = data_cw_count += 2; // MCC data_codewords[2] = acc; // ACC + posn = 0; /* Calculate error correction codewords (RSEC) */ - ultra_gf283((short) data_cw_count, (short) ecc_cw, data_codewords); + ultra_gf283((short) data_cw_count, (short) qcc, data_codewords); /* Rearrange to make final codeword sequence */ - posn = 0; - codeword[posn++] = data_codewords[282 - (data_cw_count + ecc_cw)]; // Start Character + codeword[posn++] = data_codewords[282 - (data_cw_count + qcc)]; // Start Character codeword[posn++] = data_cw_count; // MCC - for (i = 0; i < ecc_cw; i++) { - codeword[posn++] = data_codewords[(282 - ecc_cw) + i]; // RSEC Region + for (i = 0; i < qcc; i++) { + codeword[posn++] = data_codewords[(282 - qcc) + i]; // RSEC Region } - codeword[posn++] = data_cw_count + ecc_cw; // TCC = C + Q - section 6.11.4 + codeword[posn++] = data_cw_count + qcc; // TCC = C + Q - section 6.11.4 codeword[posn++] = 283; // Separator codeword[posn++] = acc; // ACC for (i = 0; i < (data_cw_count - 3); i++) { - codeword[posn++] = data_codewords[(282 - ((data_cw_count - 3) + ecc_cw)) + i]; // Data Region + codeword[posn++] = data_codewords[(282 - ((data_cw_count - 3) + qcc)) + i]; // Data Region } for (i = 0; i < pads; i++) { codeword[posn++] = 284; // Pad pattern } - codeword[posn++] = ecc_cw; // QCC + codeword[posn++] = qcc; // QCC printf("Rearranged codewords with ECC:\n"); for (i = 0; i < posn; i++) { @@ -961,6 +982,28 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si tiley += 6; } + /* Add data column count */ + dcc = columns - ultra_mincols[rows - 2]; + tilex = 2; + tiley = (total_height - 11) / 2; + /* DCCU */ + for (j = 0; j < 5; j++) { + tilepat[4 - j] = ultra_colour[(dccu[dcc] >> (3 * j)) & 0x07]; + } + for (j = 0; j < 5; j++) { + pattern[((tiley + j) * total_width) + tilex] = tilepat[j]; + } + /* DCCL */ + tiley += 6; + for (j = 0; j < 5; j++) { + tilepat[4 - j] = ultra_colour[(dccl[dcc] >> (3 * j)) & 0x07]; + } + for (j = 0; j < 5; j++) { + pattern[((tiley + j) * total_width) + tilex] = tilepat[j]; + } + + printf("DCC: %d\n", dcc); + for (i = 0; i < (total_height * total_width); i++) { printf("%c", pattern[i]); if ((i + 1) % total_width == 0) { From d370f3c0c70c794673acd5c063b05c9bd682a5bf Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Wed, 18 Dec 2019 18:33:18 +0000 Subject: [PATCH 07/13] Ultra: Correct clock pattern generation, add work around to avoid negative UCC and output to colour SVG --- backend/common.c | 6 +- backend/svg.c | 38 +++++++++- backend/ultra.c | 185 +++++++++++++++++++++++++---------------------- backend/vector.c | 30 ++++---- 4 files changed, 156 insertions(+), 103 deletions(-) diff --git a/backend/common.c b/backend/common.c index 69e4ce64..0b2cd486 100644 --- a/backend/common.c +++ b/backend/common.c @@ -148,7 +148,11 @@ int ustrchr_cnt(const unsigned char string[], const size_t length, const unsigne /* Return true (1) if a module is dark/black, otherwise false (0) */ int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord) { - return (symbol->encoded_data[y_coord][x_coord / 7] >> (x_coord % 7)) & 1; + if (symbol->symbology == BARCODE_ULTRA) { + return symbol->encoded_data[y_coord][x_coord]; + } else { + return (symbol->encoded_data[y_coord][x_coord / 7] >> (x_coord % 7)) & 1; + } } /* Set a module to dark/black */ diff --git a/backend/svg.c b/backend/svg.c index e7aefff4..eae0b287 100644 --- a/backend/svg.c +++ b/backend/svg.c @@ -42,6 +42,35 @@ #include "common.h" +void pick_colour(int colour, char colour_code[]) { + switch(colour) { + case 0: // White + strcpy(colour_code, "ffffff"); + break; + case 1: // Cyan + strcpy(colour_code, "00ffff"); + break; + case 2: // Blue + strcpy(colour_code, "0000ff"); + break; + case 3: // Magenta + strcpy(colour_code, "ff00ff"); + break; + case 4: // Red + strcpy(colour_code, "ff0000"); + break; + case 5: // Yellow + strcpy(colour_code, "ffff00"); + break; + case 6: // Green + strcpy(colour_code, "00ff00"); + break; + default: // Black + strcpy(colour_code, "000000"); + break; + } +} + void make_html_friendly(unsigned char * string, char * html_version) { /* Converts text to use HTML entity codes */ @@ -99,6 +128,8 @@ int svg_plot(struct zint_symbol *symbol) { struct zint_vector_circle *circle; struct zint_vector_string *string; + char colour_code[7]; + #ifdef _MSC_VER char* html_string; #endif @@ -154,7 +185,12 @@ int svg_plot(struct zint_symbol *symbol) { rect = symbol->vector->rectangles; while (rect) { - fprintf(fsvg, " \n", rect->x, rect->y, rect->width, rect->height); + if (rect->colour == -1) { + fprintf(fsvg, " \n", rect->x, rect->y, rect->width, rect->height); + } else { + pick_colour(rect->colour, colour_code); + fprintf(fsvg, " \n", rect->x, rect->y, rect->width, rect->height, colour_code); + } rect = rect->next; } diff --git a/backend/ultra.c b/backend/ultra.c index fb03ec9b..938a01bb 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -58,7 +58,8 @@ static const char ultra_digit[] = "0123456789,/"; static const char ultra_colour[] = "WCBMRYGK"; //static const int ultra_maxsize[] = {34, 78, 158, 282}; // According to Table 1 -static const int ultra_maxsize[] = {34, 82, 158, 282}; // Adjusted to allow 79-82 codeword range in 3-row symbols +//static const int ultra_maxsize[] = {34, 82, 158, 282}; // Adjusted to allow 79-82 codeword range in 3-row symbols +static const int ultra_maxsize[] = {38, 91, 158, 282}; // Adjusted again to ensure DCC is never negative static const int ultra_mincols[] = {5, 13, 23, 30}; // # Total Tile Columns from Table 1 @@ -214,7 +215,7 @@ int ultra_find_fragment(unsigned char source[], int source_length, int position) } /* Encode characters in 8-bit mode */ -float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len, int gs1) +float look_ahead_eightbit(unsigned char source[], int in_length, int in_locn, char current_mode, int end_char, int cw[], int* cw_len, int gs1) { int codeword_count = 0; int i; @@ -225,7 +226,7 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, ch codeword_count += 1; } - i = in_posn; + i = in_locn; do { if ((source[i] == '[') && gs1) { cw[codeword_count] = 268; // FNC1 @@ -236,7 +237,7 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, ch codeword_count++; } while ((i < in_length) && (i < end_char)); - letters_encoded = i - in_posn; + letters_encoded = i - in_locn; //printf("8BIT FRAG: "); //for (i = 0; i < codeword_count; i++) { @@ -255,7 +256,7 @@ float look_ahead_eightbit(unsigned char source[], int in_length, int in_posn, ch } /* Encode character in the ASCII mode/submode (including numeric compression) */ -float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char current_mode, int symbol_mode, int end_char, int cw[], int* cw_len, int gs1){ +float look_ahead_ascii(unsigned char source[], int in_length, int in_locn, char current_mode, int symbol_mode, int end_char, int cw[], int* cw_len, int gs1){ int codeword_count = 0; int i; int first_digit, second_digit; @@ -275,10 +276,10 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char } } - i = in_posn; + i = in_locn; do { /* Check for double digits */ - if (in_posn != (in_length - 1)) { + if (in_locn != (in_length - 1)) { first_digit = posn(ultra_digit, source[i]); second_digit = posn(ultra_digit, source[i + 1]); if ((first_digit != -1) && (second_digit != -1)) { @@ -323,7 +324,7 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char } } while ((i < in_length) && (i < end_char) && (source[i] < 0x80)); - letters_encoded = i - in_posn; + letters_encoded = i - in_locn; //printf("ASCII FRAG: "); //for (i = 0; i < codeword_count; i++) { @@ -341,23 +342,23 @@ float look_ahead_ascii(unsigned char source[], int in_length, int in_posn, char } } -int get_subset(unsigned char source[], int in_length, int in_posn) { +int get_subset(unsigned char source[], int in_length, int in_locn) { int fragno; int subset = 0; - if (posn(ultra_c43_set1, source[in_posn]) != -1) { + if (posn(ultra_c43_set1, source[in_locn]) != -1) { subset = 1; } - if (posn(ultra_c43_set2, source[in_posn]) != -1) { + if (posn(ultra_c43_set2, source[in_locn]) != -1) { subset = 2; } - if (posn(ultra_c43_set3, source[in_posn]) != -1) { + if (posn(ultra_c43_set3, source[in_locn]) != -1) { subset = 3; } - fragno = ultra_find_fragment(source, in_length, in_posn); + fragno = ultra_find_fragment(source, in_length, in_locn); if ((fragno != -1) && (fragno != 26)) { subset = 3; } @@ -366,13 +367,13 @@ int get_subset(unsigned char source[], int in_length, int in_posn) { } /* Encode characters in the C43 compaction submode */ -float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char current_mode, int end_char, int cw[], int* cw_len, int gs1){ +float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char current_mode, int end_char, int cw[], int* cw_len, int gs1){ int codeword_count = 0; int subcodeword_count = 0; int i; int subset = 0; int fragno; - int subposn = in_posn; + int sublocn = in_locn; int new_subset; int unshift_set; int base43_value; @@ -386,7 +387,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu int * subcw = (int *) _alloca((in_length + 3) * 2 * sizeof (int)); #endif /* _MSC_VER */ - subset = get_subset(source, in_length, subposn); + subset = get_subset(source, in_length, sublocn); if (subset == 0) { return 0.0; @@ -394,7 +395,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu if (current_mode == EIGHTBIT_MODE) { /* Check for permissable URL C43 macro sequences, otherwise encode directly */ - fragno = ultra_find_fragment(source, in_length, subposn); + fragno = ultra_find_fragment(source, in_length, sublocn); if ((fragno == 2) || (fragno == 3)) { // http://www. > http:// @@ -405,32 +406,32 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu switch(fragno) { case 17: // mailto: cw[codeword_count] = 276; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); codeword_count++; break; case 18: // tel: cw[codeword_count] = 277; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); codeword_count++; break; case 26: // file: cw[codeword_count] = 278; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); codeword_count++; break; case 0: // http:// cw[codeword_count] = 279; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); codeword_count++; break; case 1: // https:// cw[codeword_count] = 280; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); codeword_count++; break; case 4: // ftp:// cw[codeword_count] = 281; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); codeword_count++; break; default: @@ -462,47 +463,47 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu do { if (subset == 1) { - subcw[subcodeword_count] = posn(ultra_c43_set1, source[subposn]); + subcw[subcodeword_count] = posn(ultra_c43_set1, source[sublocn]); subcodeword_count++; - subposn++; + sublocn++; } if (subset == 2) { - subcw[subcodeword_count] = posn(ultra_c43_set2, source[subposn]); + subcw[subcodeword_count] = posn(ultra_c43_set2, source[sublocn]); subcodeword_count++; - subposn++; + sublocn++; } if (subset == 3) { subcw[subcodeword_count] = 41; // Shift to set 3 subcodeword_count++; - fragno = ultra_find_fragment(source, in_length, subposn); + fragno = ultra_find_fragment(source, in_length, sublocn); if (fragno == 26) { fragno = -1; } if ((fragno >= 0) && (fragno <= 18)) { subcw[subcodeword_count] = fragno; subcodeword_count++; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); } if ((fragno >= 18) && (fragno <= 25)) { subcw[subcodeword_count] = fragno + 17; subcodeword_count++; - subposn += strlen(fragment[fragno]); + sublocn += strlen(fragment[fragno]); } if (fragno == -1) { - subcw[subcodeword_count] = posn(ultra_c43_set3, source[subposn]); + subcw[subcodeword_count] = posn(ultra_c43_set3, source[sublocn]); subcodeword_count++; - subposn++; + sublocn++; } subset = unshift_set; } - if (subposn < in_length) { - new_subset = get_subset(source, in_length, subposn); + if (sublocn < in_length) { + new_subset = get_subset(source, in_length, sublocn); - if (((subset == 1) && (new_subset == 2)) && ((source[subposn] == '.') || (source[subposn] == ','))) { + if (((subset == 1) && (new_subset == 2)) && ((source[sublocn] == '.') || (source[sublocn] == ','))) { /* and characters available in both subsets */ new_subset = 1; } @@ -517,12 +518,12 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu } /* Check for FNC1 */ - if (subposn < (in_length - 1)) { - if ((source[subposn + 1] == '[') && gs1) { + if (sublocn < (in_length - 1)) { + if ((source[sublocn + 1] == '[') && gs1) { gs1_latch = 1; } } - } while ((subposn < in_length) && (subposn < end_char) && (subset != 0) && (gs1_latch == 0)); + } while ((sublocn < in_length) && (sublocn < end_char) && (subset != 0) && (gs1_latch == 0)); pad = 3 - (subcodeword_count % 3); if (pad == 3) { @@ -534,7 +535,7 @@ float look_ahead_c43(unsigned char source[], int in_length, int in_posn, char cu subcodeword_count++; } - letters_encoded = subposn - in_posn; + letters_encoded = sublocn - in_locn; //printf("C43 SUBFRAG: "); //for (i = 0; i < subcodeword_count; i++) { @@ -571,7 +572,7 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou int i; int crop_length; int codeword_count = 0; - int input_posn = 0; + int input_locn = 0; char symbol_mode; char current_mode; float eightbit_score; @@ -666,7 +667,7 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou // Check for http:// at start of input if ((fragno == 0) || (fragno == 2)) { codewords[0] = 281; - input_posn = 7; + input_locn = 7; symbol_mode = EIGHTBIT_MODE; } @@ -674,7 +675,7 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou // Check for https:// at start of input if ((fragno == 1) || (fragno == 3)) { codewords[0] = 282; - input_posn = 8; + input_locn = 8; symbol_mode = EIGHTBIT_MODE; } } @@ -702,10 +703,10 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou crop_source[crop_length] = '\0'; } else { /* Make a cropped version of input data - removes http:// and https:// if needed */ - for (i = input_posn; i < in_length; i++) { - crop_source[i - input_posn] = source[i]; + for (i = input_locn; i < in_length; i++) { + crop_source[i - input_locn] = source[i]; } - crop_length = in_length - input_posn; + crop_length = in_length - input_locn; crop_source[crop_length] = '\0'; } @@ -715,45 +716,45 @@ 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_posn = 0; + input_locn = 0; do { - end_char = input_posn + PREDICT_WINDOW; - eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length, gs1); - ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, gs1); - c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, end_char, cw_fragment, &fragment_length, gs1); + 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_posn] = 'a'; + mode[input_locn] = 'a'; current_mode = ASCII_MODE; if ((c43_score > ascii_score) && (c43_score > eightbit_score)) { - mode[input_posn] = 'c'; + mode[input_locn] = 'c'; current_mode = C43_MODE; } if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) { - mode[input_posn] = '8'; + mode[input_locn] = '8'; current_mode = EIGHTBIT_MODE; } - input_posn++; - } while (input_posn < crop_length); - mode[input_posn] = '\0'; + input_locn++; + } while (input_locn < crop_length); + mode[input_locn] = '\0'; /* Use results from test to perform actual mode switching */ current_mode = symbol_mode; - input_posn = 0; + input_locn = 0; do { block_length = 0; do { block_length++; - } while (mode[input_posn + block_length] == mode[input_posn]); + } while (mode[input_locn + block_length] == mode[input_locn]); - switch(mode[input_posn]) { + switch(mode[input_locn]) { case 'a': - ascii_score = look_ahead_ascii(crop_source, crop_length, input_posn, current_mode, symbol_mode, input_posn + block_length, cw_fragment, &fragment_length, gs1); + ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, input_locn + block_length, cw_fragment, &fragment_length, gs1); current_mode = ASCII_MODE; break; case 'c': - c43_score = look_ahead_c43(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length, gs1); + c43_score = look_ahead_c43(crop_source, crop_length, input_locn, current_mode, input_locn + block_length, cw_fragment, &fragment_length, gs1); /* Substitute temporary latch if possible */ if ((current_mode == EIGHTBIT_MODE) && (cw_fragment[0] == 261) && (fragment_length >= 5) && (fragment_length <= 11)) { @@ -770,7 +771,7 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou } break; case '8': - eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_posn, current_mode, input_posn + block_length, cw_fragment, &fragment_length, gs1); + eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, input_locn + block_length, cw_fragment, &fragment_length, gs1); current_mode = EIGHTBIT_MODE; break; } @@ -780,8 +781,8 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou } codeword_count += fragment_length; - input_posn += block_length; - } while (input_posn < crop_length); + input_locn += block_length; + } while (input_locn < crop_length); //printf("RED: %s\n", crop_source); //printf("MOD: %s\n", mode); @@ -798,7 +799,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si int pads; int cw_memalloc; int codeword[283]; - int i, j, posn; + int i, j, locn; int total_height, total_width; char tilepat[6]; int tilex, tiley; @@ -882,29 +883,29 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si data_codewords[1] = data_cw_count += 2; // MCC data_codewords[2] = acc; // ACC - posn = 0; + locn = 0; /* Calculate error correction codewords (RSEC) */ ultra_gf283((short) data_cw_count, (short) qcc, data_codewords); /* Rearrange to make final codeword sequence */ - codeword[posn++] = data_codewords[282 - (data_cw_count + qcc)]; // Start Character - codeword[posn++] = data_cw_count; // MCC + codeword[locn++] = data_codewords[282 - (data_cw_count + qcc)]; // Start Character + codeword[locn++] = data_cw_count; // MCC for (i = 0; i < qcc; i++) { - codeword[posn++] = data_codewords[(282 - qcc) + i]; // RSEC Region + codeword[locn++] = data_codewords[(282 - qcc) + i]; // RSEC Region } - codeword[posn++] = data_cw_count + qcc; // TCC = C + Q - section 6.11.4 - codeword[posn++] = 283; // Separator - codeword[posn++] = acc; // ACC + codeword[locn++] = data_cw_count + qcc; // TCC = C + Q - section 6.11.4 + codeword[locn++] = 283; // Separator + codeword[locn++] = acc; // ACC for (i = 0; i < (data_cw_count - 3); i++) { - codeword[posn++] = data_codewords[(282 - ((data_cw_count - 3) + qcc)) + i]; // Data Region + codeword[locn++] = data_codewords[(282 - ((data_cw_count - 3) + qcc)) + i]; // Data Region } for (i = 0; i < pads; i++) { - codeword[posn++] = 284; // Pad pattern + codeword[locn++] = 284; // Pad pattern } - codeword[posn++] = qcc; // QCC + codeword[locn++] = qcc; // QCC printf("Rearranged codewords with ECC:\n"); - for (i = 0; i < posn; i++) { + for (i = 0; i < locn; i++) { printf("%d ", codeword[i]); } printf("\n"); @@ -938,13 +939,13 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si for (i = 0; i < total_height; i += 2) { pattern[(total_width * i) + 1] = 'K'; // Primary vertical clock track if (total_width > 20) { - pattern[(total_width * i) + 20] = 'K'; // Secondary vertical clock track + pattern[(total_width * i) + 19] = 'K'; // Secondary vertical clock track } if (total_width > 36) { - pattern[(total_width * i) + 36] = 'K'; // Secondary vertical clock track + pattern[(total_width * i) + 35] = 'K'; // Secondary vertical clock track } if (total_width > 52) { - pattern[(total_width * i) + 52] = 'K'; // Secondary vertical clock track + pattern[(total_width * i) + 51] = 'K'; // Secondary vertical clock track } } for (i = 6; i < total_height; i += 6) { @@ -957,7 +958,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si tilepat[5] = '\0'; tilex = 0; tiley = 0; - for (i = 0; i < posn; i++) { + for (i = 0; i < locn; i++) { for (j = 0; j < 5; j++) { tilepat[4 - j] = ultra_colour[(tiles[codeword[i]] >> (3 * j)) & 0x07]; } @@ -965,13 +966,13 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si tiley = 0; tilex++; - if (tilex == 15) { + if (tilex == 14) { tilex++; } - if (tilex == 31) { + if (tilex == 30) { tilex++; } - if (tilex == 47) { + if (tilex == 46) { tilex++; } } @@ -1011,6 +1012,20 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si } } - strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!"); - return ZINT_ERROR_INVALID_OPTION; + /* Put pattern into symbol */ + symbol->rows = total_height; + symbol->width = total_width; + + for (i = 0; i < total_height; i++) { + symbol->row_height[i] = 1; + for(j = 0; j < total_width; j++) { + symbol->encoded_data[i][j] = posn(ultra_colour, pattern[(i * total_width) + j]); + } + } + + /* Override any user selected colours */ + strcpy(symbol->fgcolour, "000000"); + strcpy(symbol->bgcolour, "ffffff"); + + return 0; } diff --git a/backend/vector.c b/backend/vector.c index 852e6145..d363d563 100644 --- a/backend/vector.c +++ b/backend/vector.c @@ -247,10 +247,9 @@ void vector_reduce_rectangles(struct zint_symbol *symbol) { while (rect) { prev = rect; target = prev->next; - + while (target) { - - if ((rect->x == target->x) && (rect->width == target->width) && ((rect->y + rect->height) == target->y)) { + if ((rect->x == target->x) && (rect->width == target->width) && ((rect->y + rect->height) == target->y) && (rect->colour == target->colour)) { rect->height += target->height; prev->next = target->next; free(target); @@ -331,7 +330,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { addon_text_posn = 0.0; rect_count = 0; last_row_start = 0; - + /* * Determine if there will be any addon texts and text height */ @@ -442,6 +441,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { // Plot rectangles - most symbols created here if ((symbol->symbology != BARCODE_MAXICODE) && ((symbol->output_options & BARCODE_DOTTY_MODE) == 0)) { + printf("Got symbol %d\n", symbol->symbology); for (r = 0; r < symbol->rows; r++) { this_row = r; last_row_start = rect_count; @@ -476,20 +476,18 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { addon_text_posn = row_posn + 8.0f; addon_latch = 1; } - if (latch == 1) { - /* a bar */ + if (module_is_set(symbol, this_row, i)) { + /* a bar or colour block */ if (addon_latch == 0) { rectangle = vector_plot_create_rect((float)(i + xoffset), row_posn, (float)block_width, row_height); + if (symbol->symbology == BARCODE_ULTRA) { + rectangle->colour = module_is_set(symbol, this_row, i); + } } else { rectangle = vector_plot_create_rect((float)(i + xoffset), row_posn + 10.0f, (float)block_width, row_height - 5.0f); } - latch = 0; - vector_plot_add_rect(symbol, rectangle, &last_rectangle); rect_count++; - } else { - /* a space */ - latch = 1; } i += block_width; @@ -522,7 +520,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { for (i = 0; i < symbol->width; i++) { if (module_is_set(symbol, r, i)) { //struct zint_vector_hexagon *hexagon = vector_plot_create_hexagon(((i * 0.88) + ((r & 1) ? 1.76 : 1.32)), ((r * 0.76) + 0.76), symbol->dot_size); - struct zint_vector_hexagon *hexagon = vector_plot_create_hexagon(((i * 1.23f) + 0.615f + ((r & 1) ? 0.615f : 0.0f)) + xoffset, + struct zint_vector_hexagon *hexagon = vector_plot_create_hexagon(((i * 1.23f) + 0.615f + ((r & 1) ? 0.615f : 0.0f)) + xoffset, ((r * 1.067f) + 0.715f) + yoffset, symbol->dot_size); vector_plot_add_hexagon(symbol, hexagon, &last_hexagon); } @@ -558,7 +556,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { i++; } } - + if (upceanflag == 8) { i = 0; for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { @@ -575,7 +573,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { i++; } } - + if (upceanflag == 12) { i = 0; for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { @@ -596,7 +594,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { i++; } } - + if (upceanflag == 13) { i = 0; for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { @@ -613,7 +611,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { i++; } } - + /* Add the text */ if (!hide_text) { From 6181885e2e4e47d5e7df5c5cd325643ab7970ab4 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Mon, 6 Jan 2020 18:00:43 +0000 Subject: [PATCH 08/13] Ultra: Add colour rectangle output to EPS --- backend/ps.c | 119 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 15 deletions(-) diff --git a/backend/ps.c b/backend/ps.c index a8006ff5..9fa13827 100644 --- a/backend/ps.c +++ b/backend/ps.c @@ -37,6 +37,70 @@ #include #include "common.h" +void colour_to_pscolor(int option, int colour, char* output) { + + strcpy(output, ""); + if ((option & CMYK_COLOUR) == 0) { + // Use RGB colour space + switch(colour) { + case 0: // White + strcat(output, "1.00 1.00 1.00"); + break; + case 1: // Cyan + strcat(output, "0.00 1.00 1.00"); + break; + case 2: // Blue + strcat(output, "0.00 0.00 1.00"); + break; + case 3: // Magenta + strcat(output, "1.00 0.00 1.00"); + break; + case 4: // Red + strcat(output, "1.00 0.00 0.00"); + break; + case 5: // Yellow + strcat(output, "1.00 1.00 0.00"); + break; + case 6: // Green + strcat(output, "0.00 1.00 0.00"); + break; + default: // Black + strcat(output, "0.00 0.00 0.00"); + break; + } + strcat(output, " setrgbcolor"); + } else { + // Use CMYK colour space + switch(colour) { + case 0: // White + strcat(output, "0.00 0.00 0.00 0.00"); + break; + case 1: // Cyan + strcat(output, "1.00 0.00 0.00 0.00"); + break; + case 2: // Blue + strcat(output, "1.00 1.00 0.00 0.00"); + break; + case 3: // Magenta + strcat(output, "0.00 1.00 0.00 0.00"); + break; + case 4: // Red + strcat(output, "0.00 1.00 1.00 0.00"); + break; + case 5: // Yellow + strcat(output, "0.00 0.00 1.00 0.00"); + break; + case 6: // Green + strcat(output, "1.00 0.00 1.00 0.00"); + break; + default: // Black + strcat(output, "0.00 0.00 0.00 1.00"); + break; + } + strcat(output, " setcmykcolor"); + } +} + int ps_plot(struct zint_symbol *symbol) { FILE *feps; int fgred, fggrn, fgblu, bgred, bggrn, bgblu; @@ -46,7 +110,9 @@ int ps_plot(struct zint_symbol *symbol) { int error_number = 0; float ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy; float radius; - + int colour_index, colour_rect_counter; + char ps_color[30]; + struct zint_vector_rect *rect; struct zint_vector_hexagon *hex; struct zint_vector_circle *circle; @@ -152,19 +218,42 @@ int ps_plot(struct zint_symbol *symbol) { fprintf(feps, "%.2f 0.00 TB 0.00 %.2f TR\n", symbol->vector->height, symbol->vector->width); fprintf(feps, "TE\n"); - if ((symbol->output_options & CMYK_COLOUR) == 0) { - fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink); - } else { - fprintf(feps, "%.2f %.2f %.2f %.2f setcmykcolor\n", cyan_ink, magenta_ink, yellow_ink, black_ink); + if (symbol->symbology != BARCODE_ULTRA) { + if ((symbol->output_options & CMYK_COLOUR) == 0) { + fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink); + } else { + fprintf(feps, "%.2f %.2f %.2f %.2f setcmykcolor\n", cyan_ink, magenta_ink, yellow_ink, black_ink); + } } - + // Rectangles - rect = symbol->vector->rectangles; - while (rect) { - fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", rect->height, (symbol->vector->height - rect->y) - rect->height, rect->x, rect->width); - rect = rect->next; + if (symbol->symbology == BARCODE_ULTRA) { + for (colour_index = 0; colour_index <= 7; colour_index++) { + colour_rect_counter = 0; + rect = symbol->vector->rectangles; + while (rect) { + if (rect->colour == colour_index) { + if (colour_rect_counter == 0) { + //Set new colour + colour_to_pscolor(symbol->output_options, colour_index, ps_color); + fprintf(feps, "%s\n", ps_color); + } + colour_rect_counter++; + fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", rect->height, (symbol->vector->height - rect->y) - rect->height, rect->x, rect->width); + fprintf(feps, "TE\n"); + } + rect = rect->next; + } + } + } else { + rect = symbol->vector->rectangles; + while (rect) { + fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", rect->height, (symbol->vector->height - rect->y) - rect->height, rect->x, rect->width); + fprintf(feps, "TE\n"); + rect = rect->next; + } } - + // Hexagons hex = symbol->vector->hexagons; while (hex) { @@ -184,7 +273,7 @@ int ps_plot(struct zint_symbol *symbol) { fprintf(feps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f TH\n", ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy); hex = hex->next; } - + // Circles circle = symbol->vector->circles; while (circle) { @@ -209,7 +298,7 @@ int ps_plot(struct zint_symbol *symbol) { } circle = circle->next; } - + // Text string = symbol->vector->strings; while (string) { @@ -224,8 +313,8 @@ int ps_plot(struct zint_symbol *symbol) { fprintf(feps, "setmatrix\n"); string = string->next; } - - fprintf(feps, "\nshowpage\n"); + + //fprintf(feps, "\nshowpage\n"); if (symbol->output_options & BARCODE_STDOUT) { fflush(feps); From 5861ad3c3b163a27bfd89016193e223c3901bcc8 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Mon, 6 Jan 2020 20:01:48 +0000 Subject: [PATCH 09/13] Ultra: Extend colour support to PNG PCX BMP and TIF Implementation needs improvement, but colour output is now achieved in most formats --- backend/bmp.c | 40 ++++++++++ backend/pcx.c | 69 ++++++++++++++--- backend/png.c | 40 ++++++++++ backend/raster.c | 192 +++++++++++++++++++++++++++++------------------ backend/tif.c | 69 +++++++++++++---- backend/vector.c | 1 - 6 files changed, 310 insertions(+), 101 deletions(-) diff --git a/backend/bmp.c b/backend/bmp.c index 69dd9551..ad67a898 100644 --- a/backend/bmp.c +++ b/backend/bmp.c @@ -73,6 +73,46 @@ int bmp_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) { for (column = 0; column < symbol->bitmap_width; column++) { i = (3 * column) + (row * row_size); switch (*(pixelbuf + (symbol->bitmap_width * (symbol->bitmap_height - row - 1)) + column)) { + case 'W': // White + bitmap[i] = 255; + bitmap[i + 1] = 255; + bitmap[i + 2] = 255; + break; + case 'C': // Cyan + bitmap[i] = 255; + bitmap[i + 1] = 255; + bitmap[i + 2] = 0; + break; + case 'B': // Blue + bitmap[i] = 255; + bitmap[i + 1] = 0; + bitmap[i + 2] = 0; + break; + case 'M': // Magenta + bitmap[i] = 255; + bitmap[i + 1] = 0; + bitmap[i + 2] = 255; + break; + case 'R': // Red + bitmap[i] = 0; + bitmap[i + 1] = 0; + bitmap[i + 2] = 255; + break; + case 'Y': // Yellow + bitmap[i] = 0; + bitmap[i + 1] = 255; + bitmap[i + 2] = 255; + break; + case 'G': // Green + bitmap[i] = 0; + bitmap[i + 1] = 255; + bitmap[i + 2] = 0; + break; + case 'K': // Black + bitmap[i] = 0; + bitmap[i + 1] = 0; + bitmap[i + 2] = 0; + break; case '1': bitmap[i] = fgblu; bitmap[i + 1] = fggrn; diff --git a/backend/pcx.c b/backend/pcx.c index 4505a53b..9fc1effe 100644 --- a/backend/pcx.c +++ b/backend/pcx.c @@ -123,24 +123,69 @@ int pcx_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) { for (column = 0; column < symbol->bitmap_width; column++) { switch (colour) { case 0: - if (pixelbuf[(row * symbol->bitmap_width) + column] == '1') { - rle_row[column] = fgred; - } else { - rle_row[column] = bgred; + switch(pixelbuf[(row * symbol->bitmap_width) + column]) { + case 'W': // White + case 'M': // Magenta + case 'R': // Red + case 'Y': // Yellow + rle_row[column] = 255; + break; + case 'C': // Cyan + case 'B': // Blue + case 'G': // Green + case 'K': // Black + rle_row[column] = 0; + break; + case '1': + rle_row[column] = fgred; + break; + default: + rle_row[column] = bgred; + break; } break; case 1: - if (pixelbuf[(row * symbol->bitmap_width) + column] == '1') { - rle_row[column] = fggrn; - } else { - rle_row[column] = bggrn; + switch(pixelbuf[(row * symbol->bitmap_width) + column]) { + case 'W': // White + case 'C': // Cyan + case 'Y': // Yellow + case 'G': // Green + rle_row[column] = 255; + break; + case 'B': // Blue + case 'M': // Magenta + case 'R': // Red + case 'K': // Black + rle_row[column] = 0; + break; + case '1': + rle_row[column] = fggrn; + break; + default: + rle_row[column] = bggrn; + break; } break; case 2: - if (pixelbuf[(row * symbol->bitmap_width) + column] == '1') { - rle_row[column] = fgblu; - } else { - rle_row[column] = bgblu; + switch(pixelbuf[(row * symbol->bitmap_width) + column]) { + case 'W': // White + case 'C': // Cyan + case 'B': // Blue + case 'M': // Magenta + rle_row[column] = 255; + break; + case 'R': // Red + case 'Y': // Yellow + case 'G': // Green + case 'K': // Black + rle_row[column] = 0; + break; + case '1': + rle_row[column] = fgblu; + break; + default: + rle_row[column] = bgblu; + break; } break; } diff --git a/backend/png.c b/backend/png.c index 62ccf2f0..aecce224 100644 --- a/backend/png.c +++ b/backend/png.c @@ -158,6 +158,46 @@ int png_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) { for (column = 0; column < symbol->bitmap_width; column++) { i = column * 3; switch (*(pixelbuf + (symbol->bitmap_width * row) + column)) { + case 'W': // White + outdata[i] = 255; + outdata[i + 1] = 255; + outdata[i + 2] = 255; + break; + case 'C': // Cyan + outdata[i] = 0; + outdata[i + 1] = 255; + outdata[i + 2] = 255; + break; + case 'B': // Blue + outdata[i] = 0; + outdata[i + 1] = 0; + outdata[i + 2] = 255; + break; + case 'M': // Magenta + outdata[i] = 255; + outdata[i + 1] = 0; + outdata[i + 2] = 255; + break; + case 'R': // Red + outdata[i] = 255; + outdata[i + 1] = 0; + outdata[i + 2] = 0; + break; + case 'Y': // Yellow + outdata[i] = 255; + outdata[i + 1] = 255; + outdata[i + 2] = 0; + break; + case 'G': // Green + outdata[i] = 0; + outdata[i + 1] = 255; + outdata[i + 2] = 0; + break; + case 'K': // Black + outdata[i] = 0; + outdata[i + 1] = 0; + outdata[i + 2] = 0; + break; case '1': outdata[i] = fgred; outdata[i + 1] = fggrn; diff --git a/backend/raster.c b/backend/raster.c index d609e305..7a36c17d 100644 --- a/backend/raster.c +++ b/backend/raster.c @@ -48,6 +48,9 @@ #define SSET "0123456789ABCDEF" +#define DEFAULT_INK '1' +#define DEFAULT_PAPER '0' + #ifndef NO_PNG extern int png_pixel_plot(struct zint_symbol *symbol, char *pixelbuf); #endif /* NO_PNG */ @@ -56,6 +59,8 @@ extern int pcx_pixel_plot(struct zint_symbol *symbol, char *pixelbuf); extern int gif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf); extern int tif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf); +static const char ultra_colour[] = "WCBMRYGK"; + void buffer_plot(struct zint_symbol *symbol, char *pixelbuf) { /* Place pixelbuffer into symbol */ int fgred, fggrn, fgblu, bgred, bggrn, bgblu; @@ -74,12 +79,52 @@ void buffer_plot(struct zint_symbol *symbol, char *pixelbuf) { for (column = 0; column < symbol->bitmap_width; column++) { i = ((row * symbol->bitmap_width) + column) * 3; switch (*(pixelbuf + (symbol->bitmap_width * row) + column)) { - case '1': + case 'W': // White + symbol->bitmap[i] = 255; + symbol->bitmap[i + 1] = 255; + symbol->bitmap[i + 2] = 255; + break; + case 'C': // Cyan + symbol->bitmap[i] = 0; + symbol->bitmap[i + 1] = 255; + symbol->bitmap[i + 2] = 255; + break; + case 'B': // Blue + symbol->bitmap[i] = 0; + symbol->bitmap[i + 1] = 0; + symbol->bitmap[i + 2] = 255; + break; + case 'M': // Magenta + symbol->bitmap[i] = 255; + symbol->bitmap[i + 1] = 0; + symbol->bitmap[i + 2] = 255; + break; + case 'R': // Red + symbol->bitmap[i] = 255; + symbol->bitmap[i + 1] = 0; + symbol->bitmap[i + 2] = 0; + break; + case 'Y': // Yellow + symbol->bitmap[i] = 255; + symbol->bitmap[i + 1] = 255; + symbol->bitmap[i + 2] = 0; + break; + case 'G': // Green + symbol->bitmap[i] = 0; + symbol->bitmap[i + 1] = 255; + symbol->bitmap[i + 2] = 0; + break; + case 'K': // Black + symbol->bitmap[i] = 0; + symbol->bitmap[i + 1] = 0; + symbol->bitmap[i + 2] = 0; + break; + case DEFAULT_INK: symbol->bitmap[i] = fgred; symbol->bitmap[i + 1] = fggrn; symbol->bitmap[i + 2] = fgblu; break; - default: + default: // DEFAULT_PAPER symbol->bitmap[i] = bgred; symbol->bitmap[i + 1] = bggrn; symbol->bitmap[i + 2] = bgblu; @@ -208,7 +253,7 @@ int save_raster_image_to_file(struct zint_symbol *symbol, int image_height, int return error_number; } -void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_width, int image_height) { +void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_width, int image_height, char fill) { /* Draw a rectangle */ int i, j, png_ypos; @@ -218,7 +263,7 @@ void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_ for (i = (xpos); i < (xpos + xlen); i++) { for (j = (png_ypos); j < (png_ypos + ylen); j++) { - *(pixelbuf + (image_width * j) + i) = '1'; + *(pixelbuf + (image_width * j) + i) = fill; } } } @@ -247,13 +292,13 @@ void draw_bullseye(char *pixelbuf, int image_width, int image_height, int xoffse x = 16.0 * scaler; y = 16.5 * scaler; } - - draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (4.571 * scaler) + 1, '1'); - draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (3.779 * scaler) + 1, '0'); - draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (2.988 * scaler) + 1, '1'); - draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (2.196 * scaler) + 1, '0'); - draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (1.394 * scaler) + 1, '1'); - draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (0.602 * scaler) + 1, '0'); + + draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (4.571 * scaler) + 1, DEFAULT_INK); + draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (3.779 * scaler) + 1, DEFAULT_PAPER); + draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (2.988 * scaler) + 1, DEFAULT_INK); + draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (2.196 * scaler) + 1, DEFAULT_PAPER); + draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (1.394 * scaler) + 1, DEFAULT_INK); + draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (0.602 * scaler) + 1, DEFAULT_PAPER); } void draw_hexagon(char *pixelbuf, int image_width, char *scaled_hexagon, int hexagon_size, int xposn, int yposn) { @@ -262,8 +307,8 @@ void draw_hexagon(char *pixelbuf, int image_width, char *scaled_hexagon, int hex for (i = 0; i < hexagon_size; i++) { for (j = 0; j < hexagon_size; j++) { - if (scaled_hexagon[(i * hexagon_size) + j] == '1') { - *(pixelbuf + (image_width * i) + (image_width * yposn) + xposn + j) = '1'; + if (scaled_hexagon[(i * hexagon_size) + j] == DEFAULT_INK) { + *(pixelbuf + (image_width * i) + (image_width * yposn) + xposn + j) = DEFAULT_INK; } } } @@ -314,7 +359,7 @@ void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int for (y = 0; y < max_y; y++) { for (x = 0; x < max_x; x++) { if (small_font[(glyph_no * 9) + y] & (0x10 >> x)) { - *(pixelbuf + (y * image_width) + (yposn * image_width) + xposn + x) = '1'; + *(pixelbuf + (y * image_width) + (yposn * image_width) + xposn + x) = DEFAULT_INK; } } } @@ -340,11 +385,11 @@ void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int int extra_dot = 0; for (x = 0; x < 7; x++) { if (ascii_font[(glyph_no * 14) + y] & (0x40 >> x)) { - *pixelPtr = '1'; + *pixelPtr = DEFAULT_INK; extra_dot = 1; } else { if (extra_dot) { - *pixelPtr = '1'; + *pixelPtr = DEFAULT_INK; } extra_dot = 0; @@ -354,7 +399,7 @@ void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int } if (extra_dot) { - *pixelPtr = '1'; + *pixelPtr = DEFAULT_INK; } linePtr += image_width; @@ -377,7 +422,7 @@ void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int for (y = 0; y < max_y; y++) { for (x = 0; x < 7; x++) { if (ascii_font[(glyph_no * 14) + y] & (0x40 >> x)) { - *(pixelbuf + (y * image_width) + (yposn * image_width) + xposn + x) = '1'; + *(pixelbuf + (y * image_width) + (yposn * image_width) + xposn + x) = DEFAULT_INK; } } } @@ -425,7 +470,7 @@ void plot_hexline(char *scaled_hexagon, int hexagon_size, float start_x, float s float this_x = start_x + ((float)i * inc_x); float this_y = start_y + ((float)i * inc_y); if (((this_x >= 0) && (this_x < hexagon_size)) && ((this_y >= 0) && (this_y < hexagon_size))) { - scaled_hexagon[(hexagon_size * (int)this_y) + (int)this_x] = '1'; + scaled_hexagon[(hexagon_size * (int)this_y) + (int)this_x] = DEFAULT_INK; } } } @@ -469,17 +514,17 @@ void plot_hexagon(char *scaled_hexagon, int hexagon_size) { /* Fill hexagon */ for (line = 0; line < hexagon_size; line++) { - char ink = '0'; + char ink = DEFAULT_PAPER; for (i = 0; i < hexagon_size; i++) { - if (scaled_hexagon[(hexagon_size * line) + i] == '1') { + if (scaled_hexagon[(hexagon_size * line) + i] == DEFAULT_INK) { if (i < (hexagon_size / 2)) { - ink = '1'; + ink = DEFAULT_INK; } else { - ink = '0'; + ink = DEFAULT_PAPER; } } - if (ink == '1') { + if (ink == DEFAULT_INK) { scaled_hexagon[(hexagon_size * line) + i] = ink; } } @@ -507,7 +552,7 @@ int plot_raster_maxicode(struct zint_symbol *symbol, int rotate_angle, int data_ return ZINT_ERROR_ENCODING_PROBLEM; } else { for (i = 0; i < (image_width * image_height); i++) { - *(pixelbuf + i) = '0'; + *(pixelbuf + i) = DEFAULT_PAPER; } } @@ -519,7 +564,7 @@ int plot_raster_maxicode(struct zint_symbol *symbol, int rotate_angle, int data_ return ZINT_ERROR_ENCODING_PROBLEM; } else { for (i = 0; i < (hexagon_size * hexagon_size); i++) { - *(scaled_hexagon + i) = '0'; + *(scaled_hexagon + i) = DEFAULT_PAPER; } } @@ -549,14 +594,14 @@ int plot_raster_maxicode(struct zint_symbol *symbol, int rotate_angle, int data_ if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) { /* boundary bars */ - draw_bar(pixelbuf, 0, image_width, 0, symbol->border_width * 2, image_width, image_height); - draw_bar(pixelbuf, 0, image_width, 300 + (symbol->border_width * 2), symbol->border_width * 2, image_width, image_height); + draw_bar(pixelbuf, 0, image_width, 0, symbol->border_width * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, 0, image_width, 300 + (symbol->border_width * 2), symbol->border_width * 2, image_width, image_height, DEFAULT_INK); } if (symbol->output_options & BARCODE_BOX) { /* side bars */ - draw_bar(pixelbuf, 0, symbol->border_width * 2, 0, image_height, image_width, image_height); - draw_bar(pixelbuf, 300 + ((symbol->border_width + symbol->whitespace_width + symbol->whitespace_width) * 2), symbol->border_width * 2, 0, image_height, image_width, image_height); + draw_bar(pixelbuf, 0, symbol->border_width * 2, 0, image_height, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, 300 + ((symbol->border_width + symbol->whitespace_width + symbol->whitespace_width) * 2), symbol->border_width * 2, 0, image_height, image_width, image_height, DEFAULT_INK); } error_number = save_raster_image_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type); @@ -631,7 +676,7 @@ int plot_raster_dotty(struct zint_symbol *symbol, int rotate_angle, int data_typ return ZINT_ERROR_ENCODING_PROBLEM; } else { for (i = 0; i < (scale_width * scale_height); i++) { - *(scaled_pixelbuf + i) = '0'; + *(scaled_pixelbuf + i) = DEFAULT_PAPER; } } @@ -643,7 +688,7 @@ int plot_raster_dotty(struct zint_symbol *symbol, int rotate_angle, int data_typ (int) ((i + xoffset) * scaler) + (scaler / 2.0), (int) ((r + yoffset) * scaler) + (scaler / 2.0), (symbol->dot_size / 2.0) * scaler, - '1'); + DEFAULT_INK); } } } @@ -797,7 +842,7 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t return ZINT_ERROR_ENCODING_PROBLEM; } else { for (i = 0; i < (image_width * image_height); i++) { - *(pixelbuf + i) = '0'; + *(pixelbuf + i) = DEFAULT_PAPER; } } @@ -816,6 +861,7 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t int plot_yposn; int plot_height; int this_row = symbol->rows - r - 1; /* invert r otherwise plots upside down */ + int module_fill; row_posn += row_height; plot_yposn = next_yposn; if (symbol->row_height[this_row] == 0) { @@ -827,30 +873,26 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t plot_height = next_yposn - plot_yposn; i = 0; - if (module_is_set(symbol, this_row, 0)) { - latch = 1; - } else { - latch = 0; - } do { + module_fill = module_is_set(symbol, this_row, i); block_width = 0; do { block_width++; - } while ((i + block_width < symbol->width )&& module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i)); + } while ((i + block_width < symbol->width )&& module_is_set(symbol, this_row, i + block_width) == module_fill); if ((addon_latch == 0) && (r == 0) && (i > main_width)) { plot_height = (int) (row_height - 5.0); plot_yposn = (int) (row_posn - 5.0); addon_text_posn = row_posn + row_height - 8.0; addon_latch = 1; } - if (latch == 1) { + if (module_fill) { /* a bar */ - draw_bar(pixelbuf, (i + xoffset) * 2, block_width * 2, plot_yposn * 2, plot_height * 2, image_width, image_height); - latch = 0; - } else { - /* a space */ - latch = 1; + if (symbol->symbology == BARCODE_ULTRA) { + draw_bar(pixelbuf, (i + xoffset) * 2, block_width * 2, plot_yposn * 2, plot_height * 2, image_width, image_height, ultra_colour[module_fill]); + } else { + draw_bar(pixelbuf, (i + xoffset) * 2, block_width * 2, plot_yposn * 2, plot_height * 2, image_width, image_height, DEFAULT_INK); + } } i += block_width; @@ -866,12 +908,12 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t case 8: /* EAN-8 */ case 11: case 14: - draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (32 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (34 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (64 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (66 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); + draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (32 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (34 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (64 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (66 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); for (i = 0; i < 4; i++) { textpart[i] = local_text[i]; } @@ -901,12 +943,12 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t case 13: /* EAN 13 */ case 16: case 19: - draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (92 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (94 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); + draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (92 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (94 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); textpart[0] = local_text[0]; textpart[1] = '\0'; @@ -952,7 +994,7 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t } while (module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i)); if (latch == 1) { /* a bar */ - draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); + draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); latch = 0; } else { /* a space */ @@ -960,8 +1002,8 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t } i += block_width; } while (i < 11 + comp_offset); - draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); + draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); latch = 1; i = 85 + comp_offset; do { @@ -971,7 +1013,7 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t } while (module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i)); if (latch == 1) { /* a bar */ - draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); + draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); latch = 0; } else { /* a space */ @@ -1014,11 +1056,11 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t } else if ((symbol->symbology == BARCODE_UPCE) || (symbol->symbology == BARCODE_UPCE_CHK) || (symbol->symbology == BARCODE_UPCE_CC)) { /* guard bar extensions and text formatting for UPCE */ - draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); - draw_bar(pixelbuf, (50 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height); + draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (50 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK); textpart[0] = local_text[0]; textpart[1] = '\0'; @@ -1054,22 +1096,22 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) { /* boundary bars */ if (symbol->symbology != BARCODE_CODABLOCKF) { - draw_bar(pixelbuf, 0, (symbol->width + xoffset + xoffset) * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height); - draw_bar(pixelbuf, 0, (symbol->width + xoffset + xoffset) * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height); + draw_bar(pixelbuf, 0, (symbol->width + xoffset + xoffset) * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, 0, (symbol->width + xoffset + xoffset) * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK); } else { - draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height); - draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height); + draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK); } if ((symbol->output_options & BARCODE_BIND) != 0) { if ((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) { /* row binding */ if (symbol->symbology != BARCODE_CODABLOCKF) { for (r = 1; r < symbol->rows; r++) { - draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, ((r * row_height) + textoffset + yoffset - 1) * 2, 2 * 2, image_width, image_height); + draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, ((r * row_height) + textoffset + yoffset - 1) * 2, 2 * 2, image_width, image_height, DEFAULT_INK); } } else { for (r = 1; r < symbol->rows; r++) { - draw_bar(pixelbuf, (xoffset + 11) * 2 , (symbol->width - 25) * 2, ((r * row_height) + textoffset + yoffset - 1) * 2, 2 * 2, image_width, image_height); + draw_bar(pixelbuf, (xoffset + 11) * 2 , (symbol->width - 25) * 2, ((r * row_height) + textoffset + yoffset - 1) * 2, 2 * 2, image_width, image_height, DEFAULT_INK); } } } @@ -1078,8 +1120,8 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t if (symbol->output_options & BARCODE_BOX) { /* side bars */ - draw_bar(pixelbuf, 0, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height); - draw_bar(pixelbuf, (symbol->width + xoffset + xoffset - symbol->border_width) * 2, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height); + draw_bar(pixelbuf, 0, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height, DEFAULT_INK); + draw_bar(pixelbuf, (symbol->width + xoffset + xoffset - symbol->border_width) * 2, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height, DEFAULT_INK); } /* Put the human readable text at the bottom */ @@ -1102,7 +1144,7 @@ int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_t return ZINT_ERROR_ENCODING_PROBLEM; } else { for (i = 0; i < (scale_width * scale_height); i++) { - *(scaled_pixelbuf + i) = '0'; + *(scaled_pixelbuf + i) = DEFAULT_PAPER; } } diff --git a/backend/tif.c b/backend/tif.c index 83f86ea7..7d38f600 100644 --- a/backend/tif.c +++ b/backend/tif.c @@ -83,16 +83,16 @@ int tif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) { if ((symbol->bitmap_height % rows_per_strip) != 0) { strip_count++; } - + if (rows_per_strip > symbol->bitmap_height) { rows_per_strip = symbol->bitmap_height; } - + if (strip_count == 1) { rows_per_strip = (rows_per_strip / 2) + 1; strip_count++; } - + #ifndef _MSC_VER uint32_t strip_offset[strip_count]; uint32_t strip_bytes[strip_count]; @@ -151,24 +151,67 @@ int tif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) { fwrite(&header, sizeof(tiff_header_t), 1, tif_file); free_memory += sizeof(tiff_ifd_t); - + /* Pixel data */ strip = 0; bytes_put = 0; for (row = 0; row < symbol->bitmap_height; row++) { for (column = 0; column < symbol->bitmap_width; column++) { - if (pixelbuf[(row * symbol->bitmap_width) + column] == '1') { - putc(fgred, tif_file); - putc(fggrn, tif_file); - putc(fgblu, tif_file); - } else { - putc(bgred, tif_file); - putc(bggrn, tif_file); - putc(bgblu, tif_file); + switch(pixelbuf[(row * symbol->bitmap_width) + column]) { + case 'W': // White + putc(255, tif_file); + putc(255, tif_file); + putc(255, tif_file); + break; + case 'C': // Cyan + putc(0, tif_file); + putc(255, tif_file); + putc(255, tif_file); + break; + case 'B': // Blue + putc(0, tif_file); + putc(0, tif_file); + putc(255, tif_file); + break; + case 'M': // Magenta + putc(255, tif_file); + putc(0, tif_file); + putc(255, tif_file); + break; + case 'R': // Red + putc(255, tif_file); + putc(0, tif_file); + putc(0, tif_file); + break; + case 'Y': // Yellow + putc(255, tif_file); + putc(255, tif_file); + putc(0, tif_file); + break; + case 'G': // Green + putc(0, tif_file); + putc(255, tif_file); + putc(0, tif_file); + break; + case 'K': // Black + putc(0, tif_file); + putc(0, tif_file); + putc(0, tif_file); + break; + case '1': + putc(fgred, tif_file); + putc(fggrn, tif_file); + putc(fgblu, tif_file); + break; + default: + putc(bgred, tif_file); + putc(bggrn, tif_file); + putc(bgblu, tif_file); + break; } bytes_put += 3; } - + if ((bytes_put + 3) >= strip_bytes[strip]) { // End of strip, pad if strip length is odd if (strip_bytes[strip] % 2 == 1) { diff --git a/backend/vector.c b/backend/vector.c index d363d563..b2e11f1e 100644 --- a/backend/vector.c +++ b/backend/vector.c @@ -441,7 +441,6 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { // Plot rectangles - most symbols created here if ((symbol->symbology != BARCODE_MAXICODE) && ((symbol->output_options & BARCODE_DOTTY_MODE) == 0)) { - printf("Got symbol %d\n", symbol->symbology); for (r = 0; r < symbol->rows; r++) { this_row = r; last_row_start = rect_count; From c57b74a7e657c6986c2672e5e04f987052410ebb Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Mon, 13 Jan 2020 19:24:01 +0000 Subject: [PATCH 10/13] Ultra: add colour output to EMF --- backend/emf.c | 174 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 147 insertions(+), 27 deletions(-) diff --git a/backend/emf.c b/backend/emf.c index e6c799db..ef20f48c 100644 --- a/backend/emf.c +++ b/backend/emf.c @@ -41,6 +41,51 @@ #include "common.h" #include "emf.h" +int colour_to_red(int colour) { + int return_val = 0; + + switch(colour) { + case 0: // White + case 3: // Magenta + case 4: // Red + case 5: // Yellow + return_val = 255; + break; + } + + return return_val; +} + +int colour_to_green(int colour) { + int return_val = 0; + + switch(colour) { + case 0: // White + case 1: // Cyan + case 5: // Yellow + case 6: // Green + return_val = 255; + break; + } + + return return_val; +} + +int colour_to_blue(int colour) { + int return_val = 0; + + switch(colour) { + case 0: // White + case 1: // Cyan + case 2: // Blue + case 3: // Magenta + return_val = 255; + break; + } + + return return_val; +} + int count_rectangles(struct zint_symbol *symbol) { int rectangles = 0; struct zint_vector_rect *rect; @@ -136,6 +181,8 @@ int emf_plot(struct zint_symbol *symbol) { int string_count, this_text; int bytecount, recordcount; float radius; + int colours_used = 0; + int rectangle_count_bycolour[8]; unsigned char *this_string[6]; uint32_t spacing; @@ -150,8 +197,10 @@ int emf_plot(struct zint_symbol *symbol) { emr_eof_t emr_eof; emr_createbrushindirect_t emr_createbrushindirect_fg; emr_createbrushindirect_t emr_createbrushindirect_bg; + emr_createbrushindirect_t emr_createbrushindirect_colour[8]; // Used for colour symbols only emr_selectobject_t emr_selectobject_fgbrush; emr_selectobject_t emr_selectobject_bgbrush; + emr_selectobject_t emr_selectobject_colour[8]; // Used for colour symbols only emr_createpen_t emr_createpen; emr_selectobject_t emr_selectobject_pen; emr_rectangle_t background; @@ -190,7 +239,24 @@ int emf_plot(struct zint_symbol *symbol) { hexagon = (emr_polygon_t*) _alloca(hexagon_count * sizeof (emr_polygon_t)); text = (emr_exttextoutw_t*) _alloca(string_count * sizeof (emr_exttextoutw_t)); #endif - + + //Calculate how many coloured rectangles + if (symbol->symbology == BARCODE_ULTRA) { + for (i = 0; i < 8; i++) { + rectangle_count_bycolour[i] = 0; + } + + rect = symbol->vector->rectangles; + this_rectangle = 0; + while (rect) { + if (rectangle_count_bycolour[rect->colour] == 0) { + colours_used++; + } + rectangle_count_bycolour[rect->colour]++; + rect = rect->next; + } + } + /* Header */ emr_header.type = 0x00000001; // EMR_HEADER emr_header.size = 88; // Assuming no additional data in header @@ -217,21 +283,9 @@ int emf_plot(struct zint_symbol *symbol) { recordcount = 1; /* Create Brushes */ - emr_createbrushindirect_fg.type = 0x00000027; // EMR_CREATEBRUSHINDIRECT - emr_createbrushindirect_fg.size = 24; - emr_createbrushindirect_fg.ih_brush = 1; - emr_createbrushindirect_fg.log_brush.brush_style = 0x0000; // BS_SOLID - emr_createbrushindirect_fg.log_brush.color.red = fgred; - emr_createbrushindirect_fg.log_brush.color.green = fggrn; - emr_createbrushindirect_fg.log_brush.color.blue = fgblu; - emr_createbrushindirect_fg.log_brush.color.reserved = 0; - emr_createbrushindirect_fg.log_brush.brush_hatch = 0x0006; // HS_SOLIDCLR - bytecount += 24; - recordcount++; - emr_createbrushindirect_bg.type = 0x00000027; // EMR_CREATEBRUSHINDIRECT emr_createbrushindirect_bg.size = 24; - emr_createbrushindirect_bg.ih_brush = 2; + emr_createbrushindirect_bg.ih_brush = 1; emr_createbrushindirect_bg.log_brush.brush_style = 0x0000; // BS_SOLID emr_createbrushindirect_bg.log_brush.color.red = bgred; emr_createbrushindirect_bg.log_brush.color.green = bggrn; @@ -241,22 +295,60 @@ int emf_plot(struct zint_symbol *symbol) { bytecount += 24; recordcount++; - emr_selectobject_fgbrush.type = 0x00000025; // EMR_SELECTOBJECT - emr_selectobject_fgbrush.size = 12; - emr_selectobject_fgbrush.ih_object = 1; - bytecount += 12; - recordcount++; + if (symbol->symbology == BARCODE_ULTRA) { + for (i = 0; i < 8; i++) { + emr_createbrushindirect_colour[i].type = 0x00000027; // EMR_CREATEBRUSHINDIRECT + emr_createbrushindirect_colour[i].size = 24; + emr_createbrushindirect_colour[i].ih_brush = 2 + i; + emr_createbrushindirect_colour[i].log_brush.brush_style = 0x0000; // BS_SOLID + emr_createbrushindirect_colour[i].log_brush.color.red = colour_to_red(i); + emr_createbrushindirect_colour[i].log_brush.color.green = colour_to_green(i); + emr_createbrushindirect_colour[i].log_brush.color.blue = colour_to_blue(i); + emr_createbrushindirect_colour[i].log_brush.color.reserved = 0; + emr_createbrushindirect_colour[i].log_brush.brush_hatch = 0x0006; // HS_SOLIDCLR + } + bytecount += colours_used * 24; + recordcount += colours_used; + } else { + emr_createbrushindirect_fg.type = 0x00000027; // EMR_CREATEBRUSHINDIRECT + emr_createbrushindirect_fg.size = 24; + emr_createbrushindirect_fg.ih_brush = 2; + emr_createbrushindirect_fg.log_brush.brush_style = 0x0000; // BS_SOLID + emr_createbrushindirect_fg.log_brush.color.red = fgred; + emr_createbrushindirect_fg.log_brush.color.green = fggrn; + emr_createbrushindirect_fg.log_brush.color.blue = fgblu; + emr_createbrushindirect_fg.log_brush.color.reserved = 0; + emr_createbrushindirect_fg.log_brush.brush_hatch = 0x0006; // HS_SOLIDCLR + bytecount += 24; + recordcount++; + } emr_selectobject_bgbrush.type = 0x00000025; // EMR_SELECTOBJECT emr_selectobject_bgbrush.size = 12; - emr_selectobject_bgbrush.ih_object = 2; + emr_selectobject_bgbrush.ih_object = 1; bytecount += 12; recordcount++; + if (symbol->symbology == BARCODE_ULTRA) { + for (i = 0; i < 8; i++) { + emr_selectobject_colour[i].type = 0x00000025; // EMR_SELECTOBJECT + emr_selectobject_colour[i].size = 12; + emr_selectobject_colour[i].ih_object = 2 + i; + } + bytecount += colours_used * 12; + recordcount += colours_used; + } else { + emr_selectobject_fgbrush.type = 0x00000025; // EMR_SELECTOBJECT + emr_selectobject_fgbrush.size = 12; + emr_selectobject_fgbrush.ih_object = 2; + bytecount += 12; + recordcount++; + } + /* Create Pens */ emr_createpen.type = 0x00000026; // EMR_CREATEPEN emr_createpen.size = 28; - emr_createpen.ih_pen = 3; + emr_createpen.ih_pen = 10; emr_createpen.log_pen.pen_style = 0x00000005; // PS_NULL emr_createpen.log_pen.width.x = 1; emr_createpen.log_pen.width.y = 0; // ignored @@ -269,7 +361,7 @@ int emf_plot(struct zint_symbol *symbol) { emr_selectobject_pen.type = 0x00000025; // EMR_SELECTOBJECT emr_selectobject_pen.size = 12; - emr_selectobject_pen.ih_object = 3; + emr_selectobject_pen.ih_object = 10; bytecount += 12; recordcount++; @@ -459,8 +551,18 @@ int emf_plot(struct zint_symbol *symbol) { fwrite(&emr_header, sizeof (emr_header_t), 1, emf_file); - fwrite(&emr_createbrushindirect_fg, sizeof (emr_createbrushindirect_t), 1, emf_file); fwrite(&emr_createbrushindirect_bg, sizeof (emr_createbrushindirect_t), 1, emf_file); + + if (symbol->symbology == BARCODE_ULTRA) { + for (i = 0; i < 8; i++) { + if (rectangle_count_bycolour[i]) { + fwrite(&emr_createbrushindirect_colour[i], sizeof (emr_createbrushindirect_t), 1, emf_file); + } + } + } else { + fwrite(&emr_createbrushindirect_fg, sizeof (emr_createbrushindirect_t), 1, emf_file); + } + fwrite(&emr_createpen, sizeof (emr_createpen_t), 1, emf_file); if (symbol->vector->strings) { @@ -471,11 +573,29 @@ int emf_plot(struct zint_symbol *symbol) { fwrite(&emr_selectobject_pen, sizeof (emr_selectobject_t), 1, emf_file); fwrite(&background, sizeof (emr_rectangle_t), 1, emf_file); - fwrite(&emr_selectobject_fgbrush, sizeof (emr_selectobject_t), 1, emf_file); + if (symbol->symbology == BARCODE_ULTRA) { + for(i = 0; i < 8; i++) { + if (rectangle_count_bycolour[i]) { + fwrite(&emr_selectobject_colour[i], sizeof (emr_selectobject_t), 1, emf_file); - // Rectangles - for (i = 0; i < rectangle_count; i++) { - fwrite(&rectangle[i], sizeof (emr_rectangle_t), 1, emf_file); + rect = symbol->vector->rectangles; + this_rectangle = 0; + while (rect) { + if (rect->colour == i) { + fwrite(&rectangle[this_rectangle], sizeof (emr_rectangle_t), 1, emf_file); + } + this_rectangle++; + rect = rect->next; + } + } + } + } else { + fwrite(&emr_selectobject_fgbrush, sizeof (emr_selectobject_t), 1, emf_file); + + // Rectangles + for (i = 0; i < rectangle_count; i++) { + fwrite(&rectangle[i], sizeof (emr_rectangle_t), 1, emf_file); + } } // Hexagons From b572bb513d931bf873f1c323de6e3dde4a15bea1 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 29 Mar 2020 22:23:07 +0100 Subject: [PATCH 11/13] 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" ); } From c23b4b9ef1edf4c68ccba59b364ec0b4d6100db2 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 29 Mar 2020 22:35:25 +0100 Subject: [PATCH 12/13] Ultra: typos-- --- backend/ultra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/ultra.c b/backend/ultra.c index cc3a43ef..cbad8832 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -125,7 +125,7 @@ static const int tiles[] = { * * symbol->option_1 = ULTRA_COMPRESSION; * - * Code compression should be enabled by default when is has been implemented according to + * Code compression should be enabled by default when it has been implemented according to * a more reliable version of the specification. */ @@ -705,7 +705,7 @@ 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 */ - if (symbol->option_1 != ULTRA_COMPRESSION) { + if (symbol->option_1 == ULTRA_COMPRESSION) { current_mode = symbol_mode; input_locn = 0; do { From a63f3af6a44380611f9d5cc5db4ec98e053d8734 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Mon, 6 Apr 2020 16:37:34 +0100 Subject: [PATCH 13/13] Add Ultracode to Qt frontend --- backend_qt/qzint.cpp | 33 +++++++++++++++++++++++++++++++-- frontend_qt/mainwindow.cpp | 3 ++- frontend_qt/mainwindow.h | 3 ++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/backend_qt/qzint.cpp b/backend_qt/qzint.cpp index 65d386f1..e22b5b44 100644 --- a/backend_qt/qzint.cpp +++ b/backend_qt/qzint.cpp @@ -1,7 +1,7 @@ /*************************************************************************** * Copyright (C) 2008 by BogDan Vatra * * bogdan@licentia.eu * - * Copyright (C) 2010-2017 Robin Stuart * + * Copyright (C) 2010-2020 Robin Stuart * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -333,7 +333,36 @@ namespace Zint { // Plot rectangles rect = m_zintSymbol->vector->rectangles; while (rect) { - painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(m_fgColor)); + if (rect->colour == -1) { + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(m_fgColor)); + } else { + switch(rect->colour) { + case 0: // White + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::white)); + break; + case 1: // Cyan + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::cyan)); + break; + case 2: // Blue + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::blue)); + break; + case 3: // Magenta + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::magenta)); + break; + case 4: // Red + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::red)); + break; + case 5: // Yellow + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::yellow)); + break; + case 6: // Green + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::green)); + break; + default: + painter.fillRect(rect->x, rect->y, rect->width, rect->height, QBrush(Qt::black)); + break; + } + } rect = rect->next; } diff --git a/frontend_qt/mainwindow.cpp b/frontend_qt/mainwindow.cpp index f97586e3..183fcc85 100644 --- a/frontend_qt/mainwindow.cpp +++ b/frontend_qt/mainwindow.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (C) 2008 by BogDan Vatra * - * Copyright (C) 2009-2019 by Robin Stuart * + * Copyright (C) 2009-2020 by Robin Stuart * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -107,6 +107,7 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags fl) "Telepen", "Telepen Numeric", "UK Plessey", + "Ultracode", "UPNQR", "Universal Product Code (UPC-A)", "Universal Product Code (UPC-E)", diff --git a/frontend_qt/mainwindow.h b/frontend_qt/mainwindow.h index 0da976d4..f1c67601 100644 --- a/frontend_qt/mainwindow.h +++ b/frontend_qt/mainwindow.h @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (C) 2008 by BogDan Vatra * - * Copyright (C) 2009-2019 by Robin Stuart * + * Copyright (C) 2009-2020 by Robin Stuart * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -102,6 +102,7 @@ public: TELEPEN = 32, TELEPEN_NUM = 87, PLESSEY = 86, + ULTRA = 144, UPNQR = 143, UPCA = 34, UPCE = 37,