From 340bcd2833c43d79c09ced636c32ce25e9d02575 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Mon, 25 Jul 2016 22:52:29 +0100 Subject: [PATCH 1/4] DotCode: New symbology added and encoding to codewords as set out in Annex F Does not produce DotCode symbols yet --- backend/CMakeLists.txt | 2 +- backend/dotcode.c | 716 +++++++++++++++++++++++++++++++++++++++++ backend/library.c | 11 +- frontend/main.c | 34 +- 4 files changed, 741 insertions(+), 22 deletions(-) create mode 100644 backend/dotcode.c diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 191d50bf..f539df40 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -7,7 +7,7 @@ find_package(PNG) set(zint_COMMON_SRCS common.c library.c render.c large.c reedsol.c gs1.c) set(zint_ONEDIM_SRCS code.c code128.c 2of5.c upcean.c telepen.c medical.c plessey.c rss.c) set(zint_POSTAL_SRCS postal.c auspost.c imail.c) -set(zint_TWODIM_SRCS code16k.c dmatrix.c pdf417.c qr.c maxicode.c composite.c aztec.c code49.c code1.c gridmtx.c hanxin.c) +set(zint_TWODIM_SRCS code16k.c dmatrix.c pdf417.c qr.c maxicode.c composite.c aztec.c code49.c code1.c gridmtx.c hanxin.c dotcode.c) set(zint_OUTPUT_SRCS render.c ps.c svg.c bmp.c pcx.c png.c raster.c) set(zint_SRCS ${zint_OUTPUT_SRCS} ${zint_COMMON_SRCS} ${zint_ONEDIM_SRCS} ${zint_POSTAL_SRCS} ${zint_TWODIM_SRCS}) diff --git a/backend/dotcode.c b/backend/dotcode.c new file mode 100644 index 00000000..cc91ae66 --- /dev/null +++ b/backend/dotcode.c @@ -0,0 +1,716 @@ +/* dotcode.c - Handles DotCode */ + +/* + libzint - the open source barcode library + Copyright (C) 2016 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ + +/* + * Attempts to encode DotCode according to AIMD013 Rev 1.34a, dated Feb 19, 2009 + */ + +#include +#include +#include +#ifndef _MSC_VER +#include +#else +#include +#include "ms_stdint.h" +#endif +#include "common.h" +#include "gs1.h" + +/* +static const char *C128Table[107] = { + // Code 128 character encodation + "212222", "222122", "222221", "121223", "121322", "131222", "122213", + "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222", + "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222", + "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323", + "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133", + "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113", + "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111", + "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214", + "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", + "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", + "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311", + "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232", + "2331112" +}; +*/ + +/* Check if the next character is directly encodable in code set A (Annex F.II.D) */ +int datum_a(unsigned char source[], int position, int length) { + int retval = 0; + + if (position < length) { + if (source[position] <= 95) { + retval = 1; + } + } + + return retval; +} + +/* Check if the next character is directly encodable in code set B (Annex F.II.D) */ +int datum_b(unsigned char source[], int position, int length) { + int retval = 0; + + if (position < length) { + if (source[position] >= 32) { + retval = 1; + } + + switch(source[position]) { + case 9: // HT + case 28: // FS + case 29: // GS + case 30: // RS + retval = 1; + } + + if (position != length - 2) { + if ((source[position] == 13) && (source[position + 1] == 10)) { // CRLF + retval = 1; + } + } + } + + return retval; +} + +/* Check if the next characters are directly encodable in code set C (Annex F.II.D) */ +int datum_c(unsigned char source[], int position, int length) { + int retval = 0; + + if (position < length - 2) { + if (((source[position] >= '0') && (source[position] <= '9')) + && ((source[position + 1] >= '0') && (source[position + 1] <= '9'))) + retval = 1; + } + + return retval; +} + +/* Returns how many consecutive digits lie immediately ahead (Annex F.II.A) */ +int n_digits(unsigned char source[], int position, int length) { + int i; + + for(i = position; ((source[i] >= '0') && (source[i] <= '9')) && (i < length); i++); + + return i - position; +} + +/* checks ahead for 10 or more digits starting "17xxxxxx10..." (annex F.II.B) */ +int seventeen_ten(unsigned char source[], int position, int length) { + int found = 0; + + if(n_digits(source, position, length) >= 10) { + if(((source[position] == '1') && (source[position + 1] == '7')) + && ((source[position + 8] == '1') && (source[position + 9] == '0'))) { + found = 1; + } + } + + return found; +} + +/* checks how many characters ahead can be reached while datum_c is true, + * returning the resulting number of codewords (Annex F.II.E) + */ +int ahead_c(unsigned char source[], int position, int length) { + int count = 0; + + for(int i = position; (i < length) && datum_c(source, i, length); i+= 2) { + count++; + } + + return count; +} + +/* Annex F.II.F */ +int try_c(unsigned char source[], int position, int length) { + int retval = 0; + + if(n_digits(source, position, length) > 0) { + if(ahead_c(source, position, length) > ahead_c(source, position + 1, length)) { + retval = ahead_c(source, position, length); + } + } + + return retval; +} + +/* Annex F.II.G */ +int ahead_a(unsigned char source[], int position, int length) { + int count = 0; + + for(int i = position; ((i < length) && datum_a(source, i, length)) + && (try_c(source, i, length) < 2); i++) { + count++; + } + + return count; +} + +/* Annex F.II.H */ +int ahead_b(unsigned char source[], int position, int length) { + int count = 0; + + for(int i = position; ((i < length) && datum_b(source, i, length)) + && (try_c(source, i, length) < 2); i++) { + count++; + } + + return count; +} + +/* checks if the next character is in the range 128 to 255 (Annex F.II.I) */ +int binary(unsigned char source[], int position, int length) { + int retval = 0; + + if(source[position] >= 128) { + retval = 1; + } + + return retval; +} + +int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { + int input_position, array_length, i; + char encoding_mode; + int inside_macro, done; + int ecc_length; + int debug = 1; + int binary_buffer_size = 0; + int lawrencium[6]; // Reversed radix 103 values + + /* Test data */ +/* + symbol->input_mode = GS1_MODE; + length = 15; + source[0] = '0'; + source[1] = '2'; + source[2] = '['; + source[3] = 0x80; + source[4] = 0xd0; + source[5] = 0x20; + source[6] = 0xd2; + source[7] = 0x00; + source[8] = 0x00; + source[9] = 0x00; + source[10] = 0x00; + source[11] = 48; + source[12] = 0xcc; + source[13] = 49; + source[14] = 0x1f; +*/ + +#ifndef _MSC_VER + int codeword_array[length * 2]; +#else + int* codeword_array = (int *) _alloca(length * 2 * sizeof(int)); +#endif /* _MSC_VER */ + +#if defined(_MSC_VER) && _MSC_VER == 1200 + uint64_t binary_buffer = 0; +#else + uint64_t binary_buffer = 0ULL; +#endif + + /* Analyse input data stream and encode using algorithm from Annex F */ + input_position = 0; + array_length = 0; + encoding_mode = 'C'; + inside_macro = 0; + + if (symbol->output_options & READER_INIT) { + codeword_array[array_length] = 109; // FNC3 + array_length++; + } + + if (symbol->input_mode != GS1_MODE) { + codeword_array[array_length] = 107; // FNC1 + array_length++; + } + + do { + done = 0; + printf("[%c] ", encoding_mode); + + /* Step A */ + if ((input_position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) { + // inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT + input_position += 2; + done = 1; + if (debug) { printf("A "); } + } + + if ((input_position == length - 1) && (inside_macro == 100)) { + // inside_macro only gets set to 100 if the last character is EOT + input_position++; + done = 1; + if (debug) { printf("A "); } + } + + /* Step B1 */ + if ((!done) && (encoding_mode == 'C')) { + if ((array_length == 0) && (length > 9)) { + if((source[input_position] == '[') + && (source[input_position + 1] == ')') + && (source[input_position + 2] == '>') + && (source[input_position + 3] == 30) // RS + && (source[length - 1] == 04)) { // EOT + + codeword_array[array_length] = 106; // Latch B + array_length++; + encoding_mode = 'B'; + + if ((source[input_position + 6] == 29) && (source[length - 2] == 30)) { // GS/RS + if ((source[input_position + 4] == '0') && (source[input_position + 5] == '5')) { + codeword_array[array_length] = 97; // Macro + array_length++; + input_position += 7; + inside_macro = 97; + done = 1; + if (debug) { printf("B1/1 "); } + } + + if ((source[input_position + 4] == '0') && (source[input_position + 5] == '6')) { + codeword_array[array_length] = 98; // Macro + array_length++; + input_position += 7; + inside_macro = 98; + done = 1; + if (debug) { printf("B1/2 "); } + } + + if ((source[input_position + 4] == '1') && (source[input_position + 5] == '2')) { + codeword_array[array_length] = 99; // Macro + array_length++; + input_position += 7; + inside_macro = 99; + done = 1; + if (debug) { printf("B1/3 "); } + } + } + + if (!done) { + codeword_array[array_length] = 100; // Macro + array_length++; + input_position += 4; + inside_macro = 100; + done = 1; + if (debug) { printf("B1/4 "); } + } + } + } + } + + /* Step B2 */ + if ((!done) && (encoding_mode == 'C')) { + if (seventeen_ten(source, input_position, length)) { + codeword_array[array_length] = 100; // (17)...(10) + array_length++; + codeword_array[array_length] = ((source[input_position + 2] - '0') * 10) + (source[input_position + 3] - '0'); + array_length++; + codeword_array[array_length] = ((source[input_position + 4] - '0') * 10) + (source[input_position + 5] - '0'); + array_length++; + codeword_array[array_length] = ((source[input_position + 6] - '0') * 10) + (source[input_position + 7] - '0'); + array_length++; + input_position += 10; + done = 1; + if (debug) { printf("B2/1 "); } + } + } + + if ((!done) && (encoding_mode == 'C')) { + if (datum_c(source, input_position, length) || ((source[input_position] == '[') && (symbol->input_mode == GS1_MODE))) { + if (source[input_position] == '[') { + codeword_array[array_length] = 107; // FNC1 + input_position++; + } else { + codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); + input_position += 2; + } + array_length++; + done = 1; + if (debug) { printf("B2/2 "); } + } + } + + /* Setp B3 */ + if ((!done) && (encoding_mode == 'C')) { + if (binary(source, input_position, length)) { + if (n_digits(source, input_position + 1, length) > 0) { + if ((source[input_position] - 128) < 32) { + codeword_array[array_length] = 110; // Bin Shift A + array_length++; + codeword_array[array_length] = source[input_position] - 128 + 64; + array_length++; + } else { + codeword_array[array_length] = 111; // Bin Shift B + array_length++; + codeword_array[array_length] = source[input_position] - 128 - 32; + array_length++; + } + input_position++; + } else { + codeword_array[array_length] = 112; // Bin Latch + array_length++; + encoding_mode = 'X'; + } + done = 1; + if (debug) { printf("B3 "); } + } + } + + /* Step B4 */ + if ((!done) && (encoding_mode == 'C')) { + int m = ahead_a(source, input_position, length); + int n = ahead_b(source, input_position, length); + if (m > n) { + codeword_array[array_length] = 101; // Latch A + array_length++; + encoding_mode = 'A'; + } else { + if (n <= 4) { + codeword_array[array_length] = 101 + n; // nx Shift B + array_length++; + + for(i = 0; i < n; i++) { + codeword_array[array_length] = source[input_position] - 32; + array_length++; + input_position++; + } + } else { + codeword_array[array_length] = 106; // Latch B + array_length++; + encoding_mode = 'B'; + } + } + done = 1; + if (debug) { printf("B4 "); } + } + + /* Step C1 */ + if ((!done) && (encoding_mode == 'B')) { + int n = try_c(source, input_position, length); + + if (n >= 2) { + if (n <= 4) { + codeword_array[array_length] = 103 + (n - 2); // nx Shift C + array_length++; + for(i = 0; i < n; i++) { + codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); + array_length++; + input_position += 2; + } + } else { + codeword_array[array_length] = 106; // Latch C + array_length++; + encoding_mode = 'C'; + } + done = 1; + if (debug) { printf("C1 "); } + } + } + + /* Step C2 */ + if ((!done) && (encoding_mode == 'B')) { + if ((source[input_position] == '[') && (symbol->input_mode == GS1_MODE)) { + codeword_array[array_length] = 107; // FNC1 + array_length++; + input_position++; + done = 1; + if (debug) { printf("C2/1 "); } + } else { + if (datum_b(source, input_position, length)) { + codeword_array[array_length] = source[input_position] - 32; + array_length++; + input_position++; + done = 1; + if (debug) { printf("C2/2 "); } + } + } + } + + /* Step C3 */ + if ((!done) && (encoding_mode == 'B')) { + if (binary(source, input_position, length)) { + if (datum_b(source, input_position + 1, length)) { + if ((source[input_position] - 128) < 32) { + codeword_array[array_length] = 110; // Bin Shift A + array_length++; + codeword_array[array_length] = source[input_position] - 128 + 64; + array_length++; + } else { + codeword_array[array_length] = 111; // Bin Shift B + array_length++; + codeword_array[array_length] = source[input_position] - 128 - 32; + array_length++; + } + input_position++; + } else { + codeword_array[array_length] = 112; // Bin Latch + array_length++; + encoding_mode = 'X'; + } + done = 1; + if (debug) { printf("C3 "); } + } + } + + /* Step C4 */ + if ((!done) && (encoding_mode == 'B')) { + if (ahead_a(source, input_position, length) == 1) { + codeword_array[array_length] = 101; // Shift A + array_length++; + if (source[input_position] < 32) { + codeword_array[array_length] = source[input_position] + 64; + } else { + codeword_array[array_length] = source[input_position] - 32; + } + array_length++; + input_position++; + } else { + codeword_array[array_length] = 102; // Latch A + array_length++; + encoding_mode = 'A'; + } + done = 1; + if (debug) { printf("C4 "); } + } + + /* Step D1 */ + if ((!done) && (encoding_mode == 'A')) { + int n = try_c(source, input_position, length); + if (n >= 2) { + if (n <= 4) { + codeword_array[array_length] = 103 + (n - 2); // nx Shift C + array_length++; + for(i = 0; i < n; i++) { + codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); + array_length++; + input_position += 2; + } + } else { + codeword_array[array_length] = 106; // Latch C + array_length++; + encoding_mode = 'C'; + } + done = 1; + if (debug) { printf("D1 "); } + } + } + + /* Step D2 */ + if ((!done) && (encoding_mode == 'A')) { + if ((source[input_position] == '[') && (symbol->input_mode == GS1_MODE)) { + codeword_array[array_length] = 107; // FNC1 + array_length++; + input_position++; + done = 1; + if (debug) { printf("D2/1 "); } + } else { + if (datum_a(source, input_position, length)) { + if (source[input_position] < 32) { + codeword_array[array_length] = source[input_position] +64; + } else { + codeword_array[array_length] = source[input_position] - 32; + } + array_length++; + input_position++; + done = 1; + if (debug) { printf("D2/2 "); } + } + } + } + + /* Step D3 */ + if ((!done) && (encoding_mode == 'A')) { + if (binary(source, input_position, length)) { + if (datum_a(source, input_position + 1, length)) { + if ((source[input_position] - 128) < 32) { + codeword_array[array_length] = 110; // Bin Shift A + array_length++; + codeword_array[array_length] = source[input_position] - 128 + 64; + array_length++; + } else { + codeword_array[array_length] = 111; // Bin Shift B + array_length++; + codeword_array[array_length] = source[input_position] - 128 - 32; + array_length++; + } + input_position++; + } else { + codeword_array[array_length] = 112; // Bin Latch + array_length++; + encoding_mode = 'X'; + } + done = 1; + if (debug) { printf("D3 "); } + } + } + + /* Step D4 */ + if ((!done) && (encoding_mode == 'A')) { + int n = ahead_b(source, input_position, length); + + if (n <= 6) { + codeword_array[array_length] = 95 + n; // nx Shift B + array_length++; + for(i = 0; i < n; i++) { + codeword_array[array_length] = source[input_position] - 32; + array_length++; + input_position++; + } + } else { + codeword_array[array_length] = 102; // Latch B + array_length++; + encoding_mode = 'B'; + } + done = 1; + if (debug) { printf("D4 "); } + } + + /* Step E1 */ + if ((!done) && (encoding_mode == 'X')) { + int n = try_c(source, input_position, length); + + if (n >= 2) { + /* Empty binary buffer */ + for(i = 0; i < (binary_buffer_size + 1); i++) { + lawrencium[i] = binary_buffer % 103; + binary_buffer /= 103; + } + + for(i = 0; i < (binary_buffer_size + 1); i++) { + codeword_array[array_length] = lawrencium[binary_buffer_size - i]; + array_length++; + } + binary_buffer = 0; + binary_buffer_size = 0; + + if (n <= 7) { + codeword_array[array_length] = 101 + n; // Interrupt for nx Shift C + array_length++; + for(i = 0; i < n; i++) { + codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); + array_length++; + input_position += 2; + } + } else { + codeword_array[array_length] = 111; // Terminate with Latch to C + array_length++; + encoding_mode = 'C'; + } + done = 1; + if (debug) { printf("E1 "); } + } + } + + /* Step E2 */ + /* Section 5.2.1.1 para D.2.i states: + * "Groups of six codewords, each valued between 0 and 102, are radix converted from + * base 103 into five base 259 values..." + */ + if ((!done) && (encoding_mode == 'X')) { + if(binary(source, input_position, length) + || binary(source, input_position + 1, length) + || binary(source, input_position + 2, length) + || binary(source, input_position + 3, length)) { + binary_buffer *= 259; + binary_buffer += source[input_position]; + binary_buffer_size++; + + if (binary_buffer_size == 5) { + for(i = 0; i < 6; i++) { + lawrencium[i] = binary_buffer % 103; + binary_buffer /= 103; + } + + for(i = 0; i < 6; i++) { + codeword_array[array_length] = lawrencium[5 - i]; + array_length++; + } + binary_buffer = 0; + binary_buffer_size = 0; + } + input_position++; + done = 1; + if (debug) { printf("E2 "); } + } + } + + /* Step E3 */ + if ((!done) && (encoding_mode == 'X')) { + /* Empty binary buffer */ + for(i = 0; i < (binary_buffer_size + 1); i++) { + lawrencium[i] = binary_buffer % 103; + binary_buffer /= 103; + } + + for(i = 0; i < (binary_buffer_size + 1); i++) { + codeword_array[array_length] = lawrencium[binary_buffer_size - i]; + array_length++; + } + binary_buffer = 0; + binary_buffer_size = 0; + + if (ahead_a(source, input_position, length) > ahead_b(source, input_position, length)) { + codeword_array[array_length] = 109; // Terminate with Latch to A + encoding_mode = 'A'; + } else { + codeword_array[array_length] = 110; // Terminate with Latch to B + encoding_mode = 'B'; + } + array_length++; + done = 1; + if (debug) { printf("E3 "); } + } + } while (input_position < length); + + if (debug) { printf("\n\n"); } + + printf("ip = %d, len = %d\n", input_position, length); + + ecc_length = 3 + (array_length / 2); + + printf("Codeword length = %d, ECC length = %d\n", array_length, ecc_length); + printf("Data codewords: "); + for (i = 0; i < array_length; i++) { + printf(" %d ", codeword_array[i]); + } + printf("\n"); + + printf("Dot code, coming soon!\n"); + + return ZINT_ERROR_INVALID_OPTION; +} \ No newline at end of file diff --git a/backend/library.c b/backend/library.c index 0a5e3634..befbfe84 100644 --- a/backend/library.c +++ b/backend/library.c @@ -182,8 +182,9 @@ extern int channel_code(struct zint_symbol *symbol, unsigned char source[], int extern int code_one(struct zint_symbol *symbol, unsigned char source[], int length); /* Code One */ extern int grid_matrix(struct zint_symbol *symbol, const unsigned char source[], int length); /* Grid Matrix */ extern int han_xin(struct zint_symbol * symbol, const unsigned char source[], int length); /* Han Xin */ +extern int dotcode(struct zint_symbol * symbol, const unsigned char source[], int length); /* DotCode */ -extern int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type); /* Plot to PNG or BMP */ +extern int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type); /* Plot to PNG/BMP/PCX */ extern int render_plot(struct zint_symbol *symbol, float width, float height); /* Plot to gLabels */ extern int ps_plot(struct zint_symbol *symbol); /* Plot to EPS */ extern int svg_plot(struct zint_symbol *symbol); /* Plot to SVG */ @@ -374,6 +375,7 @@ static int gs1_compliant(const int symbology) { case BARCODE_CODEONE: case BARCODE_CODE49: case BARCODE_QRCODE: + case BARCODE_DOTCODE: result = 1; break; } @@ -470,6 +472,7 @@ int ZBarcode_ValidID(int symbol_id) { case BARCODE_CODEONE: case BARCODE_GRIDMATRIX: case BARCODE_HANXIN: + case BARCODE_DOTCODE: result = 1; break; } @@ -690,6 +693,8 @@ static int reduced_charset(struct zint_symbol *symbol, const unsigned char *sour break; case BARCODE_AZTEC: error_number = aztec(symbol, preprocessed, length); break; + case BARCODE_DOTCODE: error_number = dotcode(symbol, preprocessed, length); + break; } return error_number; @@ -834,9 +839,7 @@ int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *source, int lengt error_number = ZINT_WARN_INVALID_OPTION; } if (symbol->symbology == 115) { - strcpy(symbol->errtxt, "Dot Code not supported"); - symbol->symbology = BARCODE_CODE128; - error_number = ZINT_WARN_INVALID_OPTION; + symbol->symbology = BARCODE_DOTCODE; } if ((symbol->symbology >= 117) && (symbol->symbology <= 127)) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128"); diff --git a/frontend/main.c b/frontend/main.c index efffef5c..1e2c8826 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -48,23 +48,23 @@ void types(void) { "13: EAN 63: AP Standard Customer 106: HIBC PDF417\n" "16: GS1-128 66: AP Reply Paid 108: HIBC MicroPDF417\n" "18: Codabar 67: AP Routing 112: HIBC Aztec Code\n" - "20: Code 128 68: AP Redirection 116: Han Xin Code\n" - "21: Leitcode 69: ISBN 128: Aztec Runes\n" - "22: Identcode 70: RM4SCC 129: Code 32\n" - "23: Code 16k 71: Data Matrix 130: Comp EAN\n" - "24: Code 49 72: EAN-14 131: Comp GS1-128\n" - "25: Code 93 75: NVE-18 132: Comp DataBar Omni\n" - "28: Flattermarken 76: Japanese Post 133: Comp DataBar Ltd\n" - "29: GS1 DataBar Omni 77: Korea Post 134: Comp DataBar ExpOm\n" - "30: GS1 DataBar Ltd 79: GS1 DataBar Stack 135: Comp UPC-A\n" - "31: GS1 DataBar ExpOm 80: GS1 DataBar Stack Omni 136: Comp UPC-E\n" - "32: Telepen Alpha 81: GS1 DataBar ESO 137: Comp DataBar Stack\n" - "34: UPC-A 82: Planet 138: Comp DataBar Stack Omni\n" - "37: UPC-E 84: MicroPDF 139: Comp DataBar ESO\n" - "40: Postnet 85: USPS OneCode 140: Channel Code\n" - "47: MSI Plessey 86: UK Plessey 141: Code One\n" - "49: FIM 87: Telepen Numeric 142: Grid Matrix\n" - "50: Logmars 89: ITF-14\n" + "20: Code 128 68: AP Redirection 115: DotCode\n" + "21: Leitcode 69: ISBN 116: Han Xin Code\n" + "22: Identcode 70: RM4SCC 128: Aztec Runes\n" + "23: Code 16k 71: Data Matrix 129: Code 32\n" + "24: Code 49 72: EAN-14 130: Comp EAN\n" + "25: Code 93 75: NVE-18 131: Comp GS1-128\n" + "28: Flattermarken 76: Japanese Post 132: Comp DataBar Omni\n" + "29: GS1 DataBar Omni 77: Korea Post 133: Comp DataBar Ltd\n" + "30: GS1 DataBar Ltd 79: GS1 DataBar Stack 134: Comp DataBar ExpOm\n" + "31: GS1 DataBar ExpOm 80: GS1 DataBar Stack Omni 135: Comp UPC-A\n" + "32: Telepen Alpha 81: GS1 DataBar ESO 136: Comp UPC-E\n" + "34: UPC-A 82: Planet 137: Comp DataBar Stack\n" + "37: UPC-E 84: MicroPDF 138: Comp DataBar Stack Omni\n" + "40: Postnet 85: USPS OneCode 139: Comp DataBar ESO\n" + "47: MSI Plessey 86: UK Plessey 140: Channel Code\n" + "49: FIM 87: Telepen Numeric 141: Code One\n" + "50: Logmars 89: ITF-14 142: Grid Matrix\n" ); } From 70fb17fcb4b1f60cf590771708635f2509806b1b Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Wed, 27 Jul 2016 12:18:53 +0100 Subject: [PATCH 2/4] DotCode: Calculate masks and Reed-Solomon error bytes --- backend/dotcode.c | 232 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 193 insertions(+), 39 deletions(-) diff --git a/backend/dotcode.c b/backend/dotcode.c index cc91ae66..476fe6fd 100644 --- a/backend/dotcode.c +++ b/backend/dotcode.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef _MSC_VER #include #else @@ -65,6 +66,53 @@ static const char *C128Table[107] = { }; */ +#define GF 113 +#define PM 3 +//------------------------------------------------------------------------- +// "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[] +// employing Galois Field GF, where GF is prime, with a prime modulus of PM +//------------------------------------------------------------------------- +void rsencode (int nd, int nc, unsigned char *wd) { + int i, j, k, nw, start, step, root[GF], c[GF]; + + // Start by generating "nc" roots (antilogs): + root[0] = 1; + for (i=1; i<=nc; i++) + root[i] = (PM * root[i-1]) % GF; + + // Here we compute how many interleaved R-S blocks will be needed + nw = nd + nc; step = (nw + GF - 2)/(GF - 1); + + // ...& then for each such block: + for (start=0; start=1; j--) { + c[j] = (GF + c[j] - (root[i] * c[j-1]) % GF) % GF; + } + } + + // & then compute the corresponding checkword values into wd[] + // ... (a) starting at wd[start] & (b) stepping by step + for (i=ND; iinput_mode = GS1_MODE; - length = 15; - source[0] = '0'; - source[1] = '2'; - source[2] = '['; - source[3] = 0x80; - source[4] = 0xd0; - source[5] = 0x20; - source[6] = 0xd2; - source[7] = 0x00; - source[8] = 0x00; - source[9] = 0x00; - source[10] = 0x00; - source[11] = 48; - source[12] = 0xcc; - source[13] = 49; - source[14] = 0x1f; -*/ - -#ifndef _MSC_VER - int codeword_array[length * 2]; -#else - int* codeword_array = (int *) _alloca(length * 2 * sizeof(int)); -#endif /* _MSC_VER */ - #if defined(_MSC_VER) && _MSC_VER == 1200 uint64_t binary_buffer = 0; #else @@ -262,7 +282,6 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { do { done = 0; - printf("[%c] ", encoding_mode); /* Step A */ if ((input_position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) { @@ -699,18 +718,153 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { if (debug) { printf("\n\n"); } - printf("ip = %d, len = %d\n", input_position, length); + return array_length; +} + +int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, j; + int data_length, ecc_length; + int min_dots, n_dots; + int height, width, pad_chars; + int mask_score[4]; + int weight; - ecc_length = 3 + (array_length / 2); + /* Test data */ +/* + symbol->input_mode = GS1_MODE; + length = 15; + source[0] = '0'; + source[1] = '2'; + source[2] = '['; + source[3] = 0x80; + source[4] = 0xd0; + source[5] = 0x20; + source[6] = 0xd2; + source[7] = 0x00; + source[8] = 0x00; + source[9] = 0x00; + source[10] = 0x00; + source[11] = 48; + source[12] = 0xcc; + source[13] = 49; + source[14] = 0x1f; +*/ - printf("Codeword length = %d, ECC length = %d\n", array_length, ecc_length); - printf("Data codewords: "); - for (i = 0; i < array_length; i++) { - printf(" %d ", codeword_array[i]); +#ifndef _MSC_VER + unsigned char codeword_array[length * 3]; + unsigned char masked_codeword_array[length * 3]; +#else + unsigned char* codeword_array = (unsigned char *) _alloca(length * 3 * sizeof(unsigned char)); + unsigned char* masked_codeword_array = (unsigned char *) _alloca(length * 3 * sizeof(unsigned char)); +#endif /* _MSC_VER */ + + data_length = dotcode_encode_message(symbol, source, length, codeword_array); + + ecc_length = 3 + (data_length / 2); + + printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length); + + min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2; + printf("Min Dots %d\n", min_dots); + + //FIXME: Listen to user preferences here + height = sqrt(2 * min_dots); + if ((height % 2) == 1) { + height++; } - printf("\n"); - printf("Dot code, coming soon!\n"); + width = (2 * min_dots) / height; + + if ((width % 2) != 1) { + width++; + } + + n_dots = (height * width) / 2; + + /* Add pad characters */ + for(pad_chars = 0; 9 * ((data_length + pad_chars + 3 + ((data_length + pad_chars) / 2)) + 2) < n_dots; pad_chars++); + + printf("Pad characters %d\n", pad_chars); + + if (pad_chars > 0) { + codeword_array[data_length] = 109; // Latch to Code Set A + data_length++; + pad_chars--; + } + + for (i = 0; i < pad_chars; i++) { + codeword_array[data_length] = 106; // Pad + data_length++; + } + + ecc_length = 3 + (data_length / 2); + + /* Evaluate data mask options */ + for (i = 0; i < 4; i++) { + switch(i) { + case 0: + masked_codeword_array[0] = 0; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = codeword_array[j]; + } + printf("Masked Data codewords: "); + for (j = 0; j <= data_length; j++) { + printf(" %d ", (int) masked_codeword_array[j]); + } + printf("\n"); + break; + case 1: + weight = 0; + masked_codeword_array[0] = 1; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; + weight += 3; + } + printf("Masked Data codewords: "); + for (j = 0; j <= data_length; j++) { + printf(" %d ", (int) masked_codeword_array[j]); + } + printf("\n"); + break; + case 2: + weight = 0; + masked_codeword_array[0] = 2; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; + weight += 7; + } + printf("Masked Data codewords: "); + for (j = 0; j <= data_length; j++) { + printf(" %d ", (int) masked_codeword_array[j]); + } + printf("\n"); + break; + case 3: + weight = 0; + masked_codeword_array[0] = 3; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; + weight += 17; + } + printf("Masked Data codewords: "); + for (j = 0; j <= data_length; j++) { + printf(" %d ", (int) masked_codeword_array[j]); + } + printf("\n"); + break; + } + + rsencode(data_length + 1, ecc_length, masked_codeword_array); + + printf("Full code stream: "); + for (j = 0; j < (data_length + ecc_length + 1); j++) { + printf("%d ", (int) masked_codeword_array[j]); + } + printf("\n"); + + } + + printf("Proposed size = height %d, width %d, (total usable dots %d)\n", height, width, n_dots); return ZINT_ERROR_INVALID_OPTION; } \ No newline at end of file From 0c5f9191e6fcc59a1818f3927ce281a3261a0cb0 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sat, 6 Aug 2016 22:03:36 +0100 Subject: [PATCH 3/4] DotCode: Place data in symbol and evaluate bitmask --- backend/dotcode.c | 446 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 371 insertions(+), 75 deletions(-) diff --git a/backend/dotcode.c b/backend/dotcode.c index 476fe6fd..ab81b49d 100644 --- a/backend/dotcode.c +++ b/backend/dotcode.c @@ -47,27 +47,132 @@ #include "common.h" #include "gs1.h" -/* -static const char *C128Table[107] = { - // Code 128 character encodation - "212222", "222122", "222221", "121223", "121322", "131222", "122213", - "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222", - "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222", - "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323", - "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133", - "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113", - "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111", - "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214", - "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", - "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", - "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311", - "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232", - "2331112" -}; -*/ - #define GF 113 #define PM 3 + +/* DotCode symbol character dot patterns, from Annex C */ +static const int dot_patterns[113] = { + 0x155,0x0ab,0x0ad,0x0b5,0x0d5,0x156,0x15a,0x16a,0x1aa,0x0ae, + 0x0b6,0x0ba,0x0d6,0x0da,0x0ea,0x12b,0x12d,0x135,0x14b,0x14d, + 0x153,0x159,0x165,0x169,0x195,0x1a5,0x1a9,0x057,0x05b,0x05d, + 0x06b,0x06d,0x075,0x097,0x09b,0x09d,0x0a7,0x0b3,0x0b9,0x0cb, + 0x0cd,0x0d3,0x0d9,0x0e5,0x0e9,0x12e,0x136,0x13a,0x14e,0x15c, + 0x166,0x16c,0x172,0x174,0x196,0x19a,0x1a6,0x1ac,0x1b2,0x1b4, + 0x1ca,0x1d2,0x1d4,0x05e,0x06e,0x076,0x07a,0x09e,0x0bc,0x0ce, + 0x0dc,0x0e6,0x0ec,0x0f2,0x0f4,0x117,0x11b,0x11d,0x127,0x133, + 0x139,0x147,0x163,0x171,0x18b,0x18d,0x193,0x199,0x1a3,0x1b1, + 0x1c5,0x1c9,0x1d1,0x02f,0x037,0x03b,0x03d,0x04f,0x067,0x073, + 0x079,0x08f,0x0c7,0x0e3,0x0f1,0x11e,0x13c,0x178,0x18e,0x19c, + 0x1b8,0x1c6,0x1cc +}; + +int get_dot (char Dots[], int Hgt, int Wid, int x, int y) { + int retval = 0; + + if ((x >= 0) && (x < Wid) && (y >= 0) && (y < Hgt)) { + if (Dots[(y * Wid) + x] == '1') { + retval = 1; + } + } + + return retval; +} + +/* Dot pattern scoring routine from Annex A */ +int score_array (char Dots[], int Hgt, int Wid) { + int x, y, worstedge, first, last, sum; + + sum = 0; + first = -1; + + // across the top edge, count printed dots and measure their extent + for (x = 0; x < Wid; x += 2) + if (get_dot(Dots,Hgt,Wid,x,0)) { + if (first < 0) { + first = x; + } + last = x; + sum++; + } + worstedge = sum + last-first; + worstedge *= Hgt; + + sum = 0; + first = -1; + + //across the bottom edge, ditto + for (x = Wid & 1; x < Wid; x += 2) + if (get_dot(Dots,Hgt,Wid,x,Hgt-1)) { + if (first < 0) { + first = x; + } + last = x; + sum++; + } + sum += last-first; + sum *= Hgt; + if (sum < worstedge) { + worstedge = sum; + } + + sum = 0; + first = -1; + + //down the left edge, ditto + for (y = 0; y < Hgt; y += 2) + if (get_dot(Dots,Hgt,Wid,0,y)) { + if (first < 0) { + first = y; + } + last = y; + sum++; + } + sum += last-first; + sum *= Wid; + if (sum < worstedge) { + worstedge = sum; + } + + sum = 0; + first = -1; + + //down the right edge, ditto + for (y = Hgt & 1; y < Hgt; y += 2) + if (get_dot(Dots,Hgt,Wid,Wid-1,y)) { + if (first < 0) { + first = y; + } + last = y; + sum++; + } + sum += last-first; + sum *= Wid; + if (sum < worstedge) { + worstedge = sum; + } + + // throughout the array, count the # of unprinted 5-somes (cross patterns) + // plus the # of printed dots surrounded by 8 unprinted neighbors + sum = 0; + for (y = 0; y < Hgt; y++) { + for (x = y & 1; x < Wid; x += 2) { + if ((!get_dot(Dots,Hgt,Wid,x-1,y-1)) + && (!get_dot(Dots,Hgt,Wid,x+1,y-1)) + && (!get_dot(Dots,Hgt,Wid,x-1,y+1)) + &&(!get_dot(Dots,Hgt,Wid,x+1,y+1)) + && ((!get_dot(Dots,Hgt,Wid,x,y)) + || ((!get_dot(Dots,Hgt,Wid,x-2,y)) + && (!get_dot(Dots,Hgt,Wid,x,y-2)) + && (!get_dot(Dots,Hgt,Wid,x+2,y)) + && (!get_dot(Dots,Hgt,Wid,x,y+2))))) { + sum++; + } + } + } + + return (worstedge - sum * sum); +} + //------------------------------------------------------------------------- // "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[] // employing Galois Field GF, where GF is prime, with a prime modulus of PM @@ -175,7 +280,7 @@ int n_digits(unsigned char source[], int position, int length) { return i - position; } -/* checks ahead for 10 or more digits starting "17xxxxxx10..." (annex F.II.B) */ +/* checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */ int seventeen_ten(unsigned char source[], int position, int length) { int found = 0; @@ -250,6 +355,7 @@ int binary(unsigned char source[], int position, int length) { return retval; } +/* Analyse input data stream and encode using algorithm from Annex F */ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], int length, unsigned char *codeword_array) { int input_position, array_length, i; char encoding_mode; @@ -264,7 +370,6 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i uint64_t binary_buffer = 0ULL; #endif - /* Analyse input data stream and encode using algorithm from Annex F */ input_position = 0; array_length = 0; encoding_mode = 'C'; @@ -721,34 +826,162 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i return array_length; } -int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { +/* Convert codewords to binary data stream */ +int make_dotstream(unsigned char masked_array[], int array_length, char dot_stream[]) { int i, j; + int mask = 0x100; + + dot_stream[0] = '\0'; + + /* Mask value is encoded as two dots */ + switch(masked_array[0]) { + case 0: + strcat(dot_stream, "00"); + break; + case 1: + strcat(dot_stream, "01"); + break; + case 2: + strcat(dot_stream, "10"); + break; + case 3: + strcat(dot_stream, "11"); + break; + } + + /* The rest of the data uses 9-bit dot patterns from Annex C */ + for (i = 1; i < array_length; i++) { + for(j = 0; j < 9; j++) { + if (dot_patterns[masked_array[i]] & (mask >> j)) { + strcat(dot_stream, "1"); + } else { + strcat(dot_stream, "0"); + } + } + } + + return strlen(dot_stream); +} + +/* Determines if a given dot is a reserved corner dot + * to be used by one of the last six bits */ +int is_corner(int column, int row, int width, int height) { + int corner = 0; + + /* Top Left */ + if ((column == 0) && (row == 0)) { + corner = 1; + } + + /* Top Right */ + if (height % 2) { + if (((column == width - 2) && (row == 0)) + || ((column == width - 1) && (row == 1))) { + corner = 1; + } + } else { + if ((column == width - 1) && (row == 0)) { + corner = 1; + } + } + + /* Bottom Left */ + if (height % 2) { + if ((column == 0) && (row == height - 1)) { + corner = 1; + } + } else { + if (((column == 0) && (row == height - 2)) + || ((column == 1) && (row == height - 1))) { + corner = 1; + } + } + + /* Bottom Right */ + if (((column == width - 2) && (row == height - 1)) + || ((column == width - 1) && (row == height - 2))) { + corner = 1; + } + + return corner; +} + +/* Place the dots in the symbol*/ +void fold_dotstream(char dot_stream[], int width, int height, char dot_array[]) { + int column, row; + int input_position = 0; + + if (height % 2) { + /* Horizontal folding */ + for (row = 0; row < height; row++) { + for (column = 0; column < width; column++) { + if (!((column + row) % 2)) { + if (is_corner(column, row, width, height)) { + dot_array[(row * width) + column] = 'C'; + } else { + dot_array[((height - row - 1) * width) + column] = dot_stream[input_position]; + input_position++; + } + } else { + dot_array[((height - row - 1) * width) + column] = ' '; // Non-data position + } + } + } + + /* Corners */ + dot_array[width - 2] = dot_stream[input_position]; + input_position++; + dot_array[(height * width) - 2] = dot_stream[input_position]; + input_position++; + dot_array[(width * 2) - 1] = dot_stream[input_position]; + input_position++; + dot_array[((height - 1) * width) - 1] = dot_stream[input_position]; + input_position++; + dot_array[0] = dot_stream[input_position]; + input_position++; + dot_array[(height - 1) * width] = dot_stream[input_position]; + } else { + /* Vertical folding */ + for (column = 0; column < width; column++) { + for (row = 0; row < height; row++) { + if (!((column + row) % 2)) { + if (is_corner(column, row, width, height)) { + dot_array[(row * width) + column] = 'C'; + } else { + dot_array[(row * width) + column] = dot_stream[input_position]; + input_position++; + } + } else { + dot_array[(row * width) + column] = ' '; // Non-data position + } + } + } + + /* Corners */ + dot_array[((height - 1) * width) - 1] = dot_stream[input_position]; + input_position++; + dot_array[(height - 2) * width] = dot_stream[input_position]; + input_position++; + dot_array[(height * width) - 2] = dot_stream[input_position]; + input_position++; + dot_array[((height - 1) * width) + 1] = dot_stream[input_position]; + input_position++; + dot_array[width - 1] = dot_stream[input_position]; + input_position++; + dot_array[0] = dot_stream[input_position]; + } +} + +int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, j, k; int data_length, ecc_length; int min_dots, n_dots; int height, width, pad_chars; int mask_score[4]; int weight; - - /* Test data */ -/* - symbol->input_mode = GS1_MODE; - length = 15; - source[0] = '0'; - source[1] = '2'; - source[2] = '['; - source[3] = 0x80; - source[4] = 0xd0; - source[5] = 0x20; - source[6] = 0xd2; - source[7] = 0x00; - source[8] = 0x00; - source[9] = 0x00; - source[10] = 0x00; - source[11] = 48; - source[12] = 0xcc; - source[13] = 49; - source[14] = 0x1f; -*/ + int dot_stream_length; + int high_score, best_mask; + int debug = 0; #ifndef _MSC_VER unsigned char codeword_array[length * 3]; @@ -762,10 +995,11 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { ecc_length = 3 + (data_length / 2); - printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length); + if (debug) { + printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length); + } min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2; - printf("Min Dots %d\n", min_dots); //FIXME: Listen to user preferences here height = sqrt(2 * min_dots); @@ -781,17 +1015,23 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { n_dots = (height * width) / 2; +#ifndef _MSC_VER + char dot_stream[n_dots + 3]; + char dot_array[width * height]; +#else + char* dot_stream = (char *) _alloca((n_dots + 3) * sizeof(char)); + char* dot_array = (char *) _alloca(width * height * sizeof(char)); +#endif /* _MSC_VER */ + /* Add pad characters */ for(pad_chars = 0; 9 * ((data_length + pad_chars + 3 + ((data_length + pad_chars) / 2)) + 2) < n_dots; pad_chars++); - printf("Pad characters %d\n", pad_chars); - if (pad_chars > 0) { codeword_array[data_length] = 109; // Latch to Code Set A data_length++; pad_chars--; } - + for (i = 0; i < pad_chars; i++) { codeword_array[data_length] = 106; // Pad data_length++; @@ -807,11 +1047,6 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { for(j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = codeword_array[j]; } - printf("Masked Data codewords: "); - for (j = 0; j <= data_length; j++) { - printf(" %d ", (int) masked_codeword_array[j]); - } - printf("\n"); break; case 1: weight = 0; @@ -820,11 +1055,6 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 3; } - printf("Masked Data codewords: "); - for (j = 0; j <= data_length; j++) { - printf(" %d ", (int) masked_codeword_array[j]); - } - printf("\n"); break; case 2: weight = 0; @@ -833,11 +1063,6 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 7; } - printf("Masked Data codewords: "); - for (j = 0; j <= data_length; j++) { - printf(" %d ", (int) masked_codeword_array[j]); - } - printf("\n"); break; case 3: weight = 0; @@ -845,26 +1070,97 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { for(j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 17; - } - printf("Masked Data codewords: "); - for (j = 0; j <= data_length; j++) { - printf(" %d ", (int) masked_codeword_array[j]); } - printf("\n"); break; } rsencode(data_length + 1, ecc_length, masked_codeword_array); - printf("Full code stream: "); - for (j = 0; j < (data_length + ecc_length + 1); j++) { - printf("%d ", (int) masked_codeword_array[j]); - } - printf("\n"); + dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream); + /* Add pad bits */ + for(j = dot_stream_length; j < n_dots; j++) { + strcat(dot_stream, "1"); + } + + fold_dotstream(dot_stream, width, height, dot_array); + + mask_score[i] = score_array(dot_array, height, width); + + if (debug) { + printf("Mask %d score is %d\n", i, mask_score[i]); + } } - printf("Proposed size = height %d, width %d, (total usable dots %d)\n", height, width, n_dots); + high_score = mask_score[0]; + best_mask = 0; - return ZINT_ERROR_INVALID_OPTION; + for(i = 1; i < 4; i++) { + if (mask_score[i] > high_score) { + high_score = mask_score[i]; + best_mask = i; + } + } + + if (best_mask != 3) { + /* Reprocess to get symbol with best mask */ + switch(best_mask) { + case 0: + masked_codeword_array[0] = 0; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = codeword_array[j]; + } + break; + case 1: + weight = 0; + masked_codeword_array[0] = 1; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; + weight += 3; + } + break; + case 2: + weight = 0; + masked_codeword_array[0] = 2; + for(j = 0; j < data_length; j++) { + masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; + weight += 7; + } + break; + } + + rsencode(data_length + 1, ecc_length, masked_codeword_array); + dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream); + + /* Add pad bits */ + for(j = dot_stream_length; j < n_dots; j++) { + strcat(dot_stream, "1"); + } + + fold_dotstream(dot_stream, width, height, dot_array); + } /* else { the version with the best mask is already in memory } */ + + if (debug) { + for(k = 0; k < height; k++) { + for (j = 0; j < width; j++) { + printf("%c", dot_array[(k * width) + j]); + } + printf("\n"); + } + } + + /* Copy values to symbol */ + symbol->width = width; + symbol->rows = height; + + for (k = 0; k < height; k++) { + for (j = 0; j < width; j++) { + if (dot_array[(k * width) + j] == '1') { + set_module(symbol, k, j); + } + } + symbol->row_height[k] = 1; + } + + return 0; } \ No newline at end of file From 674a491a5669be632f6c20d019a1fd7d36cd18e7 Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sun, 7 Aug 2016 20:11:51 +0100 Subject: [PATCH 4/4] Dotcode: Add custom height setting and format code --- backend/dotcode.c | 578 +++++++++++++++++++++++++--------------------- 1 file changed, 321 insertions(+), 257 deletions(-) diff --git a/backend/dotcode.c b/backend/dotcode.c index ab81b49d..00195dc4 100644 --- a/backend/dotcode.c +++ b/backend/dotcode.c @@ -52,101 +52,101 @@ /* DotCode symbol character dot patterns, from Annex C */ static const int dot_patterns[113] = { - 0x155,0x0ab,0x0ad,0x0b5,0x0d5,0x156,0x15a,0x16a,0x1aa,0x0ae, - 0x0b6,0x0ba,0x0d6,0x0da,0x0ea,0x12b,0x12d,0x135,0x14b,0x14d, - 0x153,0x159,0x165,0x169,0x195,0x1a5,0x1a9,0x057,0x05b,0x05d, - 0x06b,0x06d,0x075,0x097,0x09b,0x09d,0x0a7,0x0b3,0x0b9,0x0cb, - 0x0cd,0x0d3,0x0d9,0x0e5,0x0e9,0x12e,0x136,0x13a,0x14e,0x15c, - 0x166,0x16c,0x172,0x174,0x196,0x19a,0x1a6,0x1ac,0x1b2,0x1b4, - 0x1ca,0x1d2,0x1d4,0x05e,0x06e,0x076,0x07a,0x09e,0x0bc,0x0ce, - 0x0dc,0x0e6,0x0ec,0x0f2,0x0f4,0x117,0x11b,0x11d,0x127,0x133, - 0x139,0x147,0x163,0x171,0x18b,0x18d,0x193,0x199,0x1a3,0x1b1, - 0x1c5,0x1c9,0x1d1,0x02f,0x037,0x03b,0x03d,0x04f,0x067,0x073, - 0x079,0x08f,0x0c7,0x0e3,0x0f1,0x11e,0x13c,0x178,0x18e,0x19c, - 0x1b8,0x1c6,0x1cc + 0x155, 0x0ab, 0x0ad, 0x0b5, 0x0d5, 0x156, 0x15a, 0x16a, 0x1aa, 0x0ae, + 0x0b6, 0x0ba, 0x0d6, 0x0da, 0x0ea, 0x12b, 0x12d, 0x135, 0x14b, 0x14d, + 0x153, 0x159, 0x165, 0x169, 0x195, 0x1a5, 0x1a9, 0x057, 0x05b, 0x05d, + 0x06b, 0x06d, 0x075, 0x097, 0x09b, 0x09d, 0x0a7, 0x0b3, 0x0b9, 0x0cb, + 0x0cd, 0x0d3, 0x0d9, 0x0e5, 0x0e9, 0x12e, 0x136, 0x13a, 0x14e, 0x15c, + 0x166, 0x16c, 0x172, 0x174, 0x196, 0x19a, 0x1a6, 0x1ac, 0x1b2, 0x1b4, + 0x1ca, 0x1d2, 0x1d4, 0x05e, 0x06e, 0x076, 0x07a, 0x09e, 0x0bc, 0x0ce, + 0x0dc, 0x0e6, 0x0ec, 0x0f2, 0x0f4, 0x117, 0x11b, 0x11d, 0x127, 0x133, + 0x139, 0x147, 0x163, 0x171, 0x18b, 0x18d, 0x193, 0x199, 0x1a3, 0x1b1, + 0x1c5, 0x1c9, 0x1d1, 0x02f, 0x037, 0x03b, 0x03d, 0x04f, 0x067, 0x073, + 0x079, 0x08f, 0x0c7, 0x0e3, 0x0f1, 0x11e, 0x13c, 0x178, 0x18e, 0x19c, + 0x1b8, 0x1c6, 0x1cc }; -int get_dot (char Dots[], int Hgt, int Wid, int x, int y) { +int get_dot(char Dots[], int Hgt, int Wid, int x, int y) { int retval = 0; - + if ((x >= 0) && (x < Wid) && (y >= 0) && (y < Hgt)) { if (Dots[(y * Wid) + x] == '1') { retval = 1; } } - + return retval; } /* Dot pattern scoring routine from Annex A */ -int score_array (char Dots[], int Hgt, int Wid) { +int score_array(char Dots[], int Hgt, int Wid) { int x, y, worstedge, first, last, sum; - + sum = 0; first = -1; - + // across the top edge, count printed dots and measure their extent for (x = 0; x < Wid; x += 2) - if (get_dot(Dots,Hgt,Wid,x,0)) { + if (get_dot(Dots, Hgt, Wid, x, 0)) { if (first < 0) { first = x; } - last = x; + last = x; sum++; } - worstedge = sum + last-first; + worstedge = sum + last - first; worstedge *= Hgt; - + sum = 0; first = -1; - + //across the bottom edge, ditto - for (x = Wid & 1; x < Wid; x += 2) - if (get_dot(Dots,Hgt,Wid,x,Hgt-1)) { + for (x = Wid & 1; x < Wid; x += 2) + if (get_dot(Dots, Hgt, Wid, x, Hgt - 1)) { if (first < 0) { first = x; } - last = x; + last = x; sum++; } - sum += last-first; + sum += last - first; sum *= Hgt; if (sum < worstedge) { worstedge = sum; } - + sum = 0; first = -1; - + //down the left edge, ditto - for (y = 0; y < Hgt; y += 2) - if (get_dot(Dots,Hgt,Wid,0,y)) { + for (y = 0; y < Hgt; y += 2) + if (get_dot(Dots, Hgt, Wid, 0, y)) { if (first < 0) { first = y; } - last = y; + last = y; sum++; } - sum += last-first; + sum += last - first; sum *= Wid; if (sum < worstedge) { worstedge = sum; } - + sum = 0; first = -1; - + //down the right edge, ditto - for (y = Hgt & 1; y < Hgt; y += 2) - if (get_dot(Dots,Hgt,Wid,Wid-1,y)) { + for (y = Hgt & 1; y < Hgt; y += 2) + if (get_dot(Dots, Hgt, Wid, Wid - 1, y)) { if (first < 0) { first = y; } - last = y; + last = y; sum++; } - sum += last-first; - sum *= Wid; + sum += last - first; + sum *= Wid; if (sum < worstedge) { worstedge = sum; } @@ -156,20 +156,20 @@ int score_array (char Dots[], int Hgt, int Wid) { sum = 0; for (y = 0; y < Hgt; y++) { for (x = y & 1; x < Wid; x += 2) { - if ((!get_dot(Dots,Hgt,Wid,x-1,y-1)) - && (!get_dot(Dots,Hgt,Wid,x+1,y-1)) - && (!get_dot(Dots,Hgt,Wid,x-1,y+1)) - &&(!get_dot(Dots,Hgt,Wid,x+1,y+1)) - && ((!get_dot(Dots,Hgt,Wid,x,y)) - || ((!get_dot(Dots,Hgt,Wid,x-2,y)) - && (!get_dot(Dots,Hgt,Wid,x,y-2)) - && (!get_dot(Dots,Hgt,Wid,x+2,y)) - && (!get_dot(Dots,Hgt,Wid,x,y+2))))) { + if ((!get_dot(Dots, Hgt, Wid, x - 1, y - 1)) + && (!get_dot(Dots, Hgt, Wid, x + 1, y - 1)) + && (!get_dot(Dots, Hgt, Wid, x - 1, y + 1)) + &&(!get_dot(Dots, Hgt, Wid, x + 1, y + 1)) + && ((!get_dot(Dots, Hgt, Wid, x, y)) + || ((!get_dot(Dots, Hgt, Wid, x - 2, y)) + && (!get_dot(Dots, Hgt, Wid, x, y - 2)) + && (!get_dot(Dots, Hgt, Wid, x + 2, y)) + && (!get_dot(Dots, Hgt, Wid, x, y + 2))))) { sum++; } } } - + return (worstedge - sum * sum); } @@ -177,70 +177,73 @@ int score_array (char Dots[], int Hgt, int Wid) { // "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[] // employing Galois Field GF, where GF is prime, with a prime modulus of PM //------------------------------------------------------------------------- -void rsencode (int nd, int nc, unsigned char *wd) { + +void rsencode(int nd, int nc, unsigned char *wd) { int i, j, k, nw, start, step, root[GF], c[GF]; - + // Start by generating "nc" roots (antilogs): root[0] = 1; - for (i=1; i<=nc; i++) - root[i] = (PM * root[i-1]) % GF; - + for (i = 1; i <= nc; i++) + root[i] = (PM * root[i - 1]) % GF; + // Here we compute how many interleaved R-S blocks will be needed - nw = nd + nc; step = (nw + GF - 2)/(GF - 1); - + nw = nd + nc; + step = (nw + GF - 2) / (GF - 1); + // ...& then for each such block: - for (start=0; start=1; j--) { - c[j] = (GF + c[j] - (root[i] * c[j-1]) % GF) % GF; + for (i = 1; i <= NC; i++) + c[i] = 0; + c[0] = 1; + + for (i = 1; i <= NC; i++) { + for (j = NC; j >= 1; j--) { + c[j] = (GF + c[j] - (root[i] * c[j - 1]) % GF) % GF; } } - + // & then compute the corresponding checkword values into wd[] // ... (a) starting at wd[start] & (b) stepping by step - for (i=ND; i= 32) { retval = 1; } - switch(source[position]) { + switch (source[position]) { case 9: // HT case 28: // FS case 29: // GS @@ -254,43 +257,43 @@ int datum_b(unsigned char source[], int position, int length) { } } } - + return retval; } /* Check if the next characters are directly encodable in code set C (Annex F.II.D) */ int datum_c(unsigned char source[], int position, int length) { int retval = 0; - + if (position < length - 2) { if (((source[position] >= '0') && (source[position] <= '9')) && ((source[position + 1] >= '0') && (source[position + 1] <= '9'))) retval = 1; } - + return retval; } /* Returns how many consecutive digits lie immediately ahead (Annex F.II.A) */ int n_digits(unsigned char source[], int position, int length) { int i; - - for(i = position; ((source[i] >= '0') && (source[i] <= '9')) && (i < length); i++); - + + for (i = position; ((source[i] >= '0') && (source[i] <= '9')) && (i < length); i++); + return i - position; } /* checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */ int seventeen_ten(unsigned char source[], int position, int length) { int found = 0; - - if(n_digits(source, position, length) >= 10) { - if(((source[position] == '1') && (source[position + 1] == '7')) + + if (n_digits(source, position, length) >= 10) { + if (((source[position] == '1') && (source[position + 1] == '7')) && ((source[position + 8] == '1') && (source[position + 9] == '0'))) { found = 1; } } - + return found; } @@ -299,59 +302,59 @@ int seventeen_ten(unsigned char source[], int position, int length) { */ int ahead_c(unsigned char source[], int position, int length) { int count = 0; - - for(int i = position; (i < length) && datum_c(source, i, length); i+= 2) { + + for (int i = position; (i < length) && datum_c(source, i, length); i += 2) { count++; } - + return count; } /* Annex F.II.F */ int try_c(unsigned char source[], int position, int length) { int retval = 0; - - if(n_digits(source, position, length) > 0) { - if(ahead_c(source, position, length) > ahead_c(source, position + 1, length)) { + + if (n_digits(source, position, length) > 0) { + if (ahead_c(source, position, length) > ahead_c(source, position + 1, length)) { retval = ahead_c(source, position, length); } } - + return retval; } /* Annex F.II.G */ int ahead_a(unsigned char source[], int position, int length) { int count = 0; - - for(int i = position; ((i < length) && datum_a(source, i, length)) + + for (int i = position; ((i < length) && datum_a(source, i, length)) && (try_c(source, i, length) < 2); i++) { count++; } - + return count; } /* Annex F.II.H */ int ahead_b(unsigned char source[], int position, int length) { int count = 0; - - for(int i = position; ((i < length) && datum_b(source, i, length)) + + for (int i = position; ((i < length) && datum_b(source, i, length)) && (try_c(source, i, length) < 2); i++) { count++; } - + return count; } /* checks if the next character is in the range 128 to 255 (Annex F.II.I) */ int binary(unsigned char source[], int position, int length) { int retval = 0; - - if(source[position] >= 128) { + + if (source[position] >= 128) { retval = 1; } - + return retval; } @@ -363,59 +366,63 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i int debug = 0; int binary_buffer_size = 0; int lawrencium[6]; // Reversed radix 103 values - + #if defined(_MSC_VER) && _MSC_VER == 1200 uint64_t binary_buffer = 0; #else uint64_t binary_buffer = 0ULL; #endif - + input_position = 0; array_length = 0; encoding_mode = 'C'; inside_macro = 0; - + if (symbol->output_options & READER_INIT) { codeword_array[array_length] = 109; // FNC3 array_length++; } - + if (symbol->input_mode != GS1_MODE) { codeword_array[array_length] = 107; // FNC1 array_length++; } - + do { done = 0; - + /* Step A */ if ((input_position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) { // inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT input_position += 2; done = 1; - if (debug) { printf("A "); } + if (debug) { + printf("A "); + } } - + if ((input_position == length - 1) && (inside_macro == 100)) { // inside_macro only gets set to 100 if the last character is EOT input_position++; done = 1; - if (debug) { printf("A "); } + if (debug) { + printf("A "); + } } - + /* Step B1 */ if ((!done) && (encoding_mode == 'C')) { if ((array_length == 0) && (length > 9)) { - if((source[input_position] == '[') + if ((source[input_position] == '[') && (source[input_position + 1] == ')') && (source[input_position + 2] == '>') && (source[input_position + 3] == 30) // RS - && (source[length - 1] == 04)) { // EOT - + && (source[length - 1] == 04)) { // EOT + codeword_array[array_length] = 106; // Latch B array_length++; encoding_mode = 'B'; - + if ((source[input_position + 6] == 29) && (source[length - 2] == 30)) { // GS/RS if ((source[input_position + 4] == '0') && (source[input_position + 5] == '5')) { codeword_array[array_length] = 97; // Macro @@ -423,7 +430,9 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i input_position += 7; inside_macro = 97; done = 1; - if (debug) { printf("B1/1 "); } + if (debug) { + printf("B1/1 "); + } } if ((source[input_position + 4] == '0') && (source[input_position + 5] == '6')) { @@ -432,7 +441,9 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i input_position += 7; inside_macro = 98; done = 1; - if (debug) { printf("B1/2 "); } + if (debug) { + printf("B1/2 "); + } } if ((source[input_position + 4] == '1') && (source[input_position + 5] == '2')) { @@ -441,22 +452,26 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i input_position += 7; inside_macro = 99; done = 1; - if (debug) { printf("B1/3 "); } + if (debug) { + printf("B1/3 "); + } } } - + if (!done) { codeword_array[array_length] = 100; // Macro array_length++; input_position += 4; inside_macro = 100; done = 1; - if (debug) { printf("B1/4 "); } + if (debug) { + printf("B1/4 "); + } } } } } - + /* Step B2 */ if ((!done) && (encoding_mode == 'C')) { if (seventeen_ten(source, input_position, length)) { @@ -470,13 +485,15 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i array_length++; input_position += 10; done = 1; - if (debug) { printf("B2/1 "); } + if (debug) { + printf("B2/1 "); + } } } - + if ((!done) && (encoding_mode == 'C')) { if (datum_c(source, input_position, length) || ((source[input_position] == '[') && (symbol->input_mode == GS1_MODE))) { - if (source[input_position] == '[') { + if (source[input_position] == '[') { codeword_array[array_length] = 107; // FNC1 input_position++; } else { @@ -485,15 +502,17 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i } array_length++; done = 1; - if (debug) { printf("B2/2 "); } + if (debug) { + printf("B2/2 "); + } } } - + /* Setp B3 */ if ((!done) && (encoding_mode == 'C')) { if (binary(source, input_position, length)) { if (n_digits(source, input_position + 1, length) > 0) { - if ((source[input_position] - 128) < 32) { + if ((source[input_position] - 128) < 32) { codeword_array[array_length] = 110; // Bin Shift A array_length++; codeword_array[array_length] = source[input_position] - 128 + 64; @@ -509,12 +528,14 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i codeword_array[array_length] = 112; // Bin Latch array_length++; encoding_mode = 'X'; - } + } done = 1; - if (debug) { printf("B3 "); } + if (debug) { + printf("B3 "); + } } } - + /* Step B4 */ if ((!done) && (encoding_mode == 'C')) { int m = ahead_a(source, input_position, length); @@ -527,8 +548,8 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i if (n <= 4) { codeword_array[array_length] = 101 + n; // nx Shift B array_length++; - - for(i = 0; i < n; i++) { + + for (i = 0; i < n; i++) { codeword_array[array_length] = source[input_position] - 32; array_length++; input_position++; @@ -540,18 +561,20 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i } } done = 1; - if (debug) { printf("B4 "); } + if (debug) { + printf("B4 "); + } } - + /* Step C1 */ if ((!done) && (encoding_mode == 'B')) { int n = try_c(source, input_position, length); - + if (n >= 2) { if (n <= 4) { codeword_array[array_length] = 103 + (n - 2); // nx Shift C array_length++; - for(i = 0; i < n; i++) { + for (i = 0; i < n; i++) { codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); array_length++; input_position += 2; @@ -562,10 +585,12 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'C'; } done = 1; - if (debug) { printf("C1 "); } + if (debug) { + printf("C1 "); + } } } - + /* Step C2 */ if ((!done) && (encoding_mode == 'B')) { if ((source[input_position] == '[') && (symbol->input_mode == GS1_MODE)) { @@ -573,23 +598,27 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i array_length++; input_position++; done = 1; - if (debug) { printf("C2/1 "); } + if (debug) { + printf("C2/1 "); + } } else { if (datum_b(source, input_position, length)) { codeword_array[array_length] = source[input_position] - 32; array_length++; input_position++; done = 1; - if (debug) { printf("C2/2 "); } + if (debug) { + printf("C2/2 "); + } } } } - + /* Step C3 */ if ((!done) && (encoding_mode == 'B')) { if (binary(source, input_position, length)) { if (datum_b(source, input_position + 1, length)) { - if ((source[input_position] - 128) < 32) { + if ((source[input_position] - 128) < 32) { codeword_array[array_length] = 110; // Bin Shift A array_length++; codeword_array[array_length] = source[input_position] - 128 + 64; @@ -607,10 +636,12 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'X'; } done = 1; - if (debug) { printf("C3 "); } + if (debug) { + printf("C3 "); + } } } - + /* Step C4 */ if ((!done) && (encoding_mode == 'B')) { if (ahead_a(source, input_position, length) == 1) { @@ -629,9 +660,11 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'A'; } done = 1; - if (debug) { printf("C4 "); } + if (debug) { + printf("C4 "); + } } - + /* Step D1 */ if ((!done) && (encoding_mode == 'A')) { int n = try_c(source, input_position, length); @@ -639,7 +672,7 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i if (n <= 4) { codeword_array[array_length] = 103 + (n - 2); // nx Shift C array_length++; - for(i = 0; i < n; i++) { + for (i = 0; i < n; i++) { codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); array_length++; input_position += 2; @@ -650,10 +683,12 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'C'; } done = 1; - if (debug) { printf("D1 "); } + if (debug) { + printf("D1 "); + } } } - + /* Step D2 */ if ((!done) && (encoding_mode == 'A')) { if ((source[input_position] == '[') && (symbol->input_mode == GS1_MODE)) { @@ -661,27 +696,31 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i array_length++; input_position++; done = 1; - if (debug) { printf("D2/1 "); } + if (debug) { + printf("D2/1 "); + } } else { if (datum_a(source, input_position, length)) { if (source[input_position] < 32) { - codeword_array[array_length] = source[input_position] +64; + codeword_array[array_length] = source[input_position] + 64; } else { codeword_array[array_length] = source[input_position] - 32; } array_length++; input_position++; done = 1; - if (debug) { printf("D2/2 "); } + if (debug) { + printf("D2/2 "); + } } } } - + /* Step D3 */ if ((!done) && (encoding_mode == 'A')) { if (binary(source, input_position, length)) { if (datum_a(source, input_position + 1, length)) { - if ((source[input_position] - 128) < 32) { + if ((source[input_position] - 128) < 32) { codeword_array[array_length] = 110; // Bin Shift A array_length++; codeword_array[array_length] = source[input_position] - 128 + 64; @@ -699,18 +738,20 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'X'; } done = 1; - if (debug) { printf("D3 "); } + if (debug) { + printf("D3 "); + } } } - + /* Step D4 */ if ((!done) && (encoding_mode == 'A')) { int n = ahead_b(source, input_position, length); - + if (n <= 6) { codeword_array[array_length] = 95 + n; // nx Shift B array_length++; - for(i = 0; i < n; i++) { + for (i = 0; i < n; i++) { codeword_array[array_length] = source[input_position] - 32; array_length++; input_position++; @@ -721,31 +762,33 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'B'; } done = 1; - if (debug) { printf("D4 "); } + if (debug) { + printf("D4 "); + } } - + /* Step E1 */ if ((!done) && (encoding_mode == 'X')) { int n = try_c(source, input_position, length); - + if (n >= 2) { /* Empty binary buffer */ - for(i = 0; i < (binary_buffer_size + 1); i++) { + for (i = 0; i < (binary_buffer_size + 1); i++) { lawrencium[i] = binary_buffer % 103; binary_buffer /= 103; } - for(i = 0; i < (binary_buffer_size + 1); i++) { + for (i = 0; i < (binary_buffer_size + 1); i++) { codeword_array[array_length] = lawrencium[binary_buffer_size - i]; array_length++; } binary_buffer = 0; binary_buffer_size = 0; - + if (n <= 7) { codeword_array[array_length] = 101 + n; // Interrupt for nx Shift C array_length++; - for(i = 0; i < n; i++) { + for (i = 0; i < n; i++) { codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0'); array_length++; input_position += 2; @@ -756,31 +799,33 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i encoding_mode = 'C'; } done = 1; - if (debug) { printf("E1 "); } + if (debug) { + printf("E1 "); + } } } - + /* Step E2 */ /* Section 5.2.1.1 para D.2.i states: * "Groups of six codewords, each valued between 0 and 102, are radix converted from * base 103 into five base 259 values..." */ if ((!done) && (encoding_mode == 'X')) { - if(binary(source, input_position, length) + if (binary(source, input_position, length) || binary(source, input_position + 1, length) || binary(source, input_position + 2, length) || binary(source, input_position + 3, length)) { binary_buffer *= 259; binary_buffer += source[input_position]; binary_buffer_size++; - + if (binary_buffer_size == 5) { - for(i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) { lawrencium[i] = binary_buffer % 103; binary_buffer /= 103; } - - for(i = 0; i < 6; i++) { + + for (i = 0; i < 6; i++) { codeword_array[array_length] = lawrencium[5 - i]; array_length++; } @@ -789,25 +834,27 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i } input_position++; done = 1; - if (debug) { printf("E2 "); } + if (debug) { + printf("E2 "); + } } } - + /* Step E3 */ if ((!done) && (encoding_mode == 'X')) { /* Empty binary buffer */ - for(i = 0; i < (binary_buffer_size + 1); i++) { + for (i = 0; i < (binary_buffer_size + 1); i++) { lawrencium[i] = binary_buffer % 103; binary_buffer /= 103; } - for(i = 0; i < (binary_buffer_size + 1); i++) { + for (i = 0; i < (binary_buffer_size + 1); i++) { codeword_array[array_length] = lawrencium[binary_buffer_size - i]; array_length++; } binary_buffer = 0; binary_buffer_size = 0; - + if (ahead_a(source, input_position, length) > ahead_b(source, input_position, length)) { codeword_array[array_length] = 109; // Terminate with Latch to A encoding_mode = 'A'; @@ -817,12 +864,16 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i } array_length++; done = 1; - if (debug) { printf("E3 "); } + if (debug) { + printf("E3 "); + } } } while (input_position < length); - - if (debug) { printf("\n\n"); } - + + if (debug) { + printf("\n\n"); + } + return array_length; } @@ -830,11 +881,11 @@ int dotcode_encode_message(struct zint_symbol *symbol, unsigned char source[], i int make_dotstream(unsigned char masked_array[], int array_length, char dot_stream[]) { int i, j; int mask = 0x100; - + dot_stream[0] = '\0'; - + /* Mask value is encoded as two dots */ - switch(masked_array[0]) { + switch (masked_array[0]) { case 0: strcat(dot_stream, "00"); break; @@ -848,10 +899,10 @@ int make_dotstream(unsigned char masked_array[], int array_length, char dot_stre strcat(dot_stream, "11"); break; } - + /* The rest of the data uses 9-bit dot patterns from Annex C */ for (i = 1; i < array_length; i++) { - for(j = 0; j < 9; j++) { + for (j = 0; j < 9; j++) { if (dot_patterns[masked_array[i]] & (mask >> j)) { strcat(dot_stream, "1"); } else { @@ -859,20 +910,21 @@ int make_dotstream(unsigned char masked_array[], int array_length, char dot_stre } } } - + return strlen(dot_stream); } /* Determines if a given dot is a reserved corner dot - * to be used by one of the last six bits */ + * to be used by one of the last six bits + */ int is_corner(int column, int row, int width, int height) { int corner = 0; - + /* Top Left */ if ((column == 0) && (row == 0)) { corner = 1; - } - + } + /* Top Right */ if (height % 2) { if (((column == width - 2) && (row == 0)) @@ -884,7 +936,7 @@ int is_corner(int column, int row, int width, int height) { corner = 1; } } - + /* Bottom Left */ if (height % 2) { if ((column == 0) && (row == height - 1)) { @@ -896,13 +948,13 @@ int is_corner(int column, int row, int width, int height) { corner = 1; } } - + /* Bottom Right */ if (((column == width - 2) && (row == height - 1)) || ((column == width - 1) && (row == height - 2))) { corner = 1; } - + return corner; } @@ -910,7 +962,7 @@ int is_corner(int column, int row, int width, int height) { void fold_dotstream(char dot_stream[], int width, int height, char dot_array[]) { int column, row; int input_position = 0; - + if (height % 2) { /* Horizontal folding */ for (row = 0; row < height; row++) { @@ -927,7 +979,7 @@ void fold_dotstream(char dot_stream[], int width, int height, char dot_array[]) } } } - + /* Corners */ dot_array[width - 2] = dot_stream[input_position]; input_position++; @@ -956,7 +1008,7 @@ void fold_dotstream(char dot_stream[], int width, int height, char dot_array[]) } } } - + /* Corners */ dot_array[((height - 1) * width) - 1] = dot_stream[input_position]; input_position++; @@ -982,50 +1034,60 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { int dot_stream_length; int high_score, best_mask; int debug = 0; - + #ifndef _MSC_VER unsigned char codeword_array[length * 3]; unsigned char masked_codeword_array[length * 3]; #else - unsigned char* codeword_array = (unsigned char *) _alloca(length * 3 * sizeof(unsigned char)); - unsigned char* masked_codeword_array = (unsigned char *) _alloca(length * 3 * sizeof(unsigned char)); + unsigned char* codeword_array = (unsigned char *) _alloca(length * 3 * sizeof (unsigned char)); + unsigned char* masked_codeword_array = (unsigned char *) _alloca(length * 3 * sizeof (unsigned char)); #endif /* _MSC_VER */ - + data_length = dotcode_encode_message(symbol, source, length, codeword_array); - + ecc_length = 3 + (data_length / 2); - + if (debug) { printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length); } - + min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2; - - //FIXME: Listen to user preferences here - height = sqrt(2 * min_dots); - if ((height % 2) == 1) { - height++; + + if (symbol->option_2 == 0) { + + height = sqrt(2 * min_dots); + if (height % 2) { + height++; + } + + width = (2 * min_dots) / height; + if (!(width % 2)) { + width++; + } + + } else { + width = symbol->option_2; + + height = min_dots / width; + + if (!((width + height) % 2)) { + height++; + } } - - width = (2 * min_dots) / height; - - if ((width % 2) != 1) { - width++; - } - + n_dots = (height * width) / 2; - + #ifndef _MSC_VER char dot_stream[n_dots + 3]; char dot_array[width * height]; #else - char* dot_stream = (char *) _alloca((n_dots + 3) * sizeof(char)); - char* dot_array = (char *) _alloca(width * height * sizeof(char)); + char* dot_stream = (char *) _alloca((n_dots + 3) * sizeof (char)); + char* dot_array = (char *) _alloca(width * height * sizeof (char)); #endif /* _MSC_VER */ - + /* Add pad characters */ - for(pad_chars = 0; 9 * ((data_length + pad_chars + 3 + ((data_length + pad_chars) / 2)) + 2) < n_dots; pad_chars++); - + for (pad_chars = 0; 9 * ((data_length + pad_chars + 3 + ((data_length + pad_chars) / 2)) + 2) < n_dots; pad_chars++); + if (pad_chars > 0) { codeword_array[data_length] = 109; // Latch to Code Set A data_length++; @@ -1036,22 +1098,22 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { codeword_array[data_length] = 106; // Pad data_length++; } - + ecc_length = 3 + (data_length / 2); - + /* Evaluate data mask options */ for (i = 0; i < 4; i++) { - switch(i) { + switch (i) { case 0: masked_codeword_array[0] = 0; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = codeword_array[j]; } break; case 1: weight = 0; masked_codeword_array[0] = 1; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 3; } @@ -1059,7 +1121,7 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { case 2: weight = 0; masked_codeword_array[0] = 2; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 7; } @@ -1067,54 +1129,54 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { case 3: weight = 0; masked_codeword_array[0] = 3; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 17; } break; } - + rsencode(data_length + 1, ecc_length, masked_codeword_array); - + dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream); - + /* Add pad bits */ - for(j = dot_stream_length; j < n_dots; j++) { + for (j = dot_stream_length; j < n_dots; j++) { strcat(dot_stream, "1"); } - + fold_dotstream(dot_stream, width, height, dot_array); - + mask_score[i] = score_array(dot_array, height, width); - + if (debug) { printf("Mask %d score is %d\n", i, mask_score[i]); } } - + high_score = mask_score[0]; best_mask = 0; - - for(i = 1; i < 4; i++) { + + for (i = 1; i < 4; i++) { if (mask_score[i] > high_score) { high_score = mask_score[i]; best_mask = i; } } - + if (best_mask != 3) { /* Reprocess to get symbol with best mask */ - switch(best_mask) { + switch (best_mask) { case 0: masked_codeword_array[0] = 0; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = codeword_array[j]; } break; case 1: weight = 0; masked_codeword_array[0] = 1; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 3; } @@ -1122,33 +1184,33 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { case 2: weight = 0; masked_codeword_array[0] = 2; - for(j = 0; j < data_length; j++) { + for (j = 0; j < data_length; j++) { masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; weight += 7; } break; } - + rsencode(data_length + 1, ecc_length, masked_codeword_array); dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream); - + /* Add pad bits */ - for(j = dot_stream_length; j < n_dots; j++) { + for (j = dot_stream_length; j < n_dots; j++) { strcat(dot_stream, "1"); } - + fold_dotstream(dot_stream, width, height, dot_array); } /* else { the version with the best mask is already in memory } */ - + if (debug) { - for(k = 0; k < height; k++) { + for (k = 0; k < height; k++) { for (j = 0; j < width; j++) { printf("%c", dot_array[(k * width) + j]); } printf("\n"); } } - + /* Copy values to symbol */ symbol->width = width; symbol->rows = height; @@ -1161,6 +1223,8 @@ int dotcode(struct zint_symbol *symbol, unsigned char source[], int length) { } symbol->row_height[k] = 1; } - + + symbol->barcode_options += BARCODE_DOTTY_MODE; + return 0; } \ No newline at end of file