diff --git a/backend/dmatrix.c b/backend/dmatrix.c index 571e7c9f..ee27c993 100755 --- a/backend/dmatrix.c +++ b/backend/dmatrix.c @@ -1,1219 +1,1219 @@ -/* dmatrix.c Handles Data Matrix ECC 200 symbols */ - -/* - libzint - the open source barcode library - Copyright (C) 2009 Robin Stuart - - developed from and including some functions from: - IEC16022 bar code generation - Adrian Kennard, Andrews & Arnold Ltd - with help from Cliff Hones on the RS coding - - (c) 2004 Adrian Kennard, Andrews & Arnold Ltd - (c) 2006 Stefan Schmidt - - 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. -*/ - -#include -#include -#include -#include -#include -#include -#ifdef _MSC_VER -#include -#endif -#include "reedsol.h" -#include "common.h" -#include "dmatrix.h" - -// Annex M placement alorithm low level -static void ecc200placementbit(int *array, int NR, int NC, int r, int c, int p, char b) -{ - if (r < 0) { - r += NR; - c += 4 - ((NR + 4) % 8); - } - if (c < 0) { - c += NC; - r += 4 - ((NC + 4) % 8); - } - // Necessary for 26x32,26x40,26x48,36x120,36x144,72x120,72x144 - if (r >= NR) { - #ifdef DEBUG - fprintf(stderr,"r >= NR:%i,%i at r=%i->",p,b,r); - #endif - r -= NR; - #ifdef DEBUG - fprintf(stderr,"%i,c=%i\n",r,c); - #endif - } - #ifdef DEBUG - if(0 != array[r * NC + c] ){ - int a = array[r * NC + c]; - fprintf(stderr,"Double:%i,%i->%i,%i at r=%i,c=%i\n",a >> 3, a & 7, p,b,r,c); - return; - } - #endif - // Check index limits - assert( r < NR ); - assert( c < NC ); - // Check double-assignment - assert( 0 == array[r * NC + c] ); - array[r * NC + c] = (p << 3) + b; -} - -static void ecc200placementblock(int *array, int NR, int NC, int r, - int c, int p) -{ - ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7); - ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6); - ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5); - ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4); - ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3); - ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2); - ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1); - ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0); -} - -static void ecc200placementcornerA(int *array, int NR, int NC, int p) -{ - ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); - ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6); - ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5); - ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); - ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); - ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); - ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); - ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); -} - -static void ecc200placementcornerB(int *array, int NR, int NC, int p) -{ - ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); - ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); - ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); - ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4); - ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3); - ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2); - ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1); - ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); -} - -static void ecc200placementcornerC(int *array, int NR, int NC, int p) -{ - ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); - ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); - ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); - ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); - ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); - ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); - ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); - ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); -} - -static void ecc200placementcornerD(int *array, int NR, int NC, int p) -{ - ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); - ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6); - ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5); - ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); - ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); - ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2); - ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1); - ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); -} - -// Annex M placement alorithm main function -static void ecc200placement(int *array, int NR, int NC) -{ - int r, c, p; - // invalidate - for (r = 0; r < NR; r++) - for (c = 0; c < NC; c++) - array[r * NC + c] = 0; - // start - p = 1; - r = 4; - c = 0; - do { - // check corner - if (r == NR && !c) - ecc200placementcornerA(array, NR, NC, p++); - if (r == NR - 2 && !c && NC % 4) - ecc200placementcornerB(array, NR, NC, p++); - if (r == NR - 2 && !c && (NC % 8) == 4) - ecc200placementcornerC(array, NR, NC, p++); - if (r == NR + 4 && c == 2 && !(NC % 8)) - ecc200placementcornerD(array, NR, NC, p++); - // up/right - do { - if (r < NR && c >= 0 && !array[r * NC + c]) - ecc200placementblock(array, NR, NC, r, c, p++); - r -= 2; - c += 2; - } - while (r >= 0 && c < NC); - r++; - c += 3; - // down/left - do { - if (r >= 0 && c < NC && !array[r * NC + c]) - ecc200placementblock(array, NR, NC, r, c, p++); - r += 2; - c -= 2; - } - while (r < NR && c >= 0); - r += 3; - c++; - } - while (r < NR || c < NC); - // unfilled corner - if (!array[NR * NC - 1]) - array[NR * NC - 1] = array[NR * NC - NC - 2] = 1; -} - -// calculate and append ecc code, and if necessary interleave -static void ecc200(unsigned char *binary, int bytes, int datablock, int rsblock, int skew) -{ - int blocks = (bytes + 2) / datablock, b; - int n, p; - rs_init_gf(0x12d); - rs_init_code(rsblock, 1); - for (b = 0; b < blocks; b++) { - unsigned char buf[256], ecc[256]; - p = 0; - for (n = b; n < bytes; n += blocks) - buf[p++] = binary[n]; - rs_encode(p, buf, ecc); - p = rsblock - 1; // comes back reversed - for (n = b; n < rsblock * blocks; n += blocks) { - if (skew) { - /* Rotate ecc data to make 144x144 size symbols acceptable */ - /* See http://groups.google.com/group/postscriptbarcode/msg/5ae8fda7757477da */ - if(b < 8) { - binary[bytes + n + 2] = ecc[p--]; - } else { - binary[bytes + n - 8] = ecc[p--]; - } - } else { - binary[bytes + n] = ecc[p--]; - } - } - } - rs_free(); -} - -int isX12(unsigned char source) -{ - if(source == 13) { return 1; } - if(source == 42) { return 1; } - if(source == 62) { return 1; } - if(source == 32) { return 1; } - if((source >= '0') && (source <= '9')) { return 1; } - if((source >= 'A') && (source <= 'Z')) { return 1; } - - return 0; -} - -void dminsert(char binary_string[], int posn, char newbit) -{ /* Insert a character into the middle of a string at position posn */ - int i, end; - - end = strlen(binary_string); - for(i = end; i > posn; i--) { - binary_string[i] = binary_string[i - 1]; - } - binary_string[posn] = newbit; -} - -void insert_value(unsigned char binary_stream[], int posn, int streamlen, char newbit) -{ - int i; - - for(i = streamlen; i > posn; i--) { - binary_stream[i] = binary_stream[i - 1]; - } - binary_stream[posn] = newbit; -} - -int p_r_6_2_1(unsigned char inputData[], int position, int sourcelen) { - /* Annex P section (r)(6)(ii)(I) - "If one of the three X12 terminator/separator characters first - occurs in the yet to be processed data before a non-X12 character..." - */ - - int i; - int nonX12Position = 0; - int specialX12Position = 0; - int retval = 0; - - for (i = position; i < sourcelen; i++) { - if (nonX12Position == 0) { - if (isX12(i) == 1) { - nonX12Position = i; - } - } - - if (specialX12Position == 0) { - if ((inputData[i] == (char) 13) || - (inputData[i] == '*') || - (inputData[i] == '>')) { - specialX12Position = i; - } - } - } - - if ((nonX12Position != 0) && (specialX12Position != 0)) { - if (specialX12Position < nonX12Position) { - retval = 1; - } - } - - return retval; -} - -int look_ahead_test(unsigned char inputData[], int sourcelen, int position, int current_mode, int gs1) -{ - /* 'look ahead test' from Annex P */ - - float ascii_count, c40_count, text_count, x12_count, edf_count, b256_count, best_count; - int sp, best_scheme; - - best_scheme = DM_NULL; - - /* step (j) */ - if(current_mode == DM_ASCII) { - ascii_count = 0.0; - c40_count = 1.0; - text_count = 1.0; - x12_count = 1.0; - edf_count = 1.0; - b256_count = 1.25; - } else { - ascii_count = 1.0; - c40_count = 2.0; - text_count = 2.0; - x12_count = 2.0; - edf_count = 2.0; - b256_count = 2.25; - } - - switch(current_mode) { - case DM_C40: c40_count = 0.0; break; - case DM_TEXT: text_count = 0.0; break; - case DM_X12: x12_count = 0.0; break; - case DM_EDIFACT: edf_count = 0.0; break; - case DM_BASE256: b256_count = 0.0; break; - } - - sp = position; - - do { - if(sp == (sourcelen - 1)) { - /* At the end of data ... step (k) */ - ascii_count = ceil(ascii_count); - b256_count = ceil(b256_count); - edf_count = ceil(edf_count); - text_count = ceil(text_count); - x12_count = ceil(x12_count); - c40_count = ceil(c40_count); - - best_count = c40_count; - best_scheme = DM_C40; // (k)(7) - - if (x12_count < best_count) { - best_count = x12_count; - best_scheme = DM_X12; // (k)(6) - } - - if (text_count < best_count) { - best_count = text_count; - best_scheme = DM_TEXT; // (k)(5) - } - - if (edf_count < best_count) { - best_count = edf_count; - best_scheme = DM_EDIFACT; // (k)(4) - } - - if (b256_count < best_count) { - best_count = b256_count; - best_scheme = DM_BASE256; // (k)(3) - } - - if (ascii_count <= best_count) { - best_scheme = DM_ASCII; // (k)(2) - } - } else { - - /* ascii ... step (l) */ - if ((inputData[sp] >= '0') && (inputData[sp] <= '9')) { - ascii_count += 0.5; // (l)(1) - } else { - if (inputData[sp] > 127) { - ascii_count = ceil(ascii_count) + 2.0; // (l)(2) - } else { - ascii_count = ceil(ascii_count) + 1.0; // (l)(3) - } - } - - /* c40 ... step (m) */ - if ((inputData[sp] == ' ') || - (((inputData[sp] >= '0') && (inputData[sp] <= '9')) || - ((inputData[sp] >= 'A') && (inputData[sp] <= 'Z')))) { - c40_count += (2.0 / 3.0); // (m)(1) - } else { - if (inputData[sp] > 127) { - c40_count += (8.0 / 3.0); // (m)(2) - } else { - c40_count += (4.0 / 3.0); // (m)(3) - } - } - - /* text ... step (n) */ - if ((inputData[sp] == ' ') || - (((inputData[sp] >= '0') && (inputData[sp] <= '9')) || - ((inputData[sp] >= 'a') && (inputData[sp] <= 'z')))) { - text_count += (2.0 / 3.0); // (n)(1) - } else { - if (inputData[sp] > 127) { - text_count += (8.0 / 3.0); // (n)(2) - } else { - text_count += (4.0 / 3.0); // (n)(3) - } - } - - /* x12 ... step (o) */ - if (isX12(inputData[sp])) { - x12_count += (2.0 / 3.0); // (o)(1) - } else { - if (inputData[sp] > 127) { - x12_count += (13.0 / 3.0); // (o)(2) - } else { - x12_count += (10.0 / 3.0); // (o)(3) - } - } - - /* edifact ... step (p) */ - if ((inputData[sp] >= ' ') && (inputData[sp] <= '^')) { - edf_count += (3.0 / 4.0); // (p)(1) - } else { - if (inputData[sp] > 127) { - edf_count += (17.0 / 4.0); // (p)(2) - } else { - edf_count += (13.0 / 4.0); // (p)(3) - } - } - if ((gs1 == 1) && (inputData[sp] == '[')) { - edf_count += 6.0; - } - - /* base 256 ... step (q) */ - if ((gs1 == 1) && (inputData[sp] == '[')) { - b256_count += 4.0; // (q)(1) - } else { - b256_count += 1.0; // (q)(2) - } - } - - - if (sp > (position + 3)) { - /* 4 data characters processed ... step (r) */ - - /* step (r)(6) */ - if (((c40_count + 1.0) < ascii_count) && - ((c40_count + 1.0) < b256_count) && - ((c40_count + 1.0) < edf_count) && - ((c40_count + 1.0) < text_count)) { - - if (c40_count < x12_count) { - best_scheme = DM_C40; - } - - if (c40_count == x12_count) { - if (p_r_6_2_1(inputData, sp, sourcelen) == 1) { - // Test (r)(6)(ii)(i) - best_scheme = DM_X12; - } else { - best_scheme = DM_C40; - } - } - } - - /* step (r)(5) */ - if (((x12_count + 1.0) < ascii_count) && - ((x12_count + 1.0) < b256_count) && - ((x12_count + 1.0) < edf_count) && - ((x12_count + 1.0) < text_count) && - ((x12_count + 1.0) < c40_count)) { - best_scheme = DM_X12; - } - - /* step (r)(4) */ - if (((text_count + 1.0) < ascii_count) && - ((text_count + 1.0) < b256_count) && - ((text_count + 1.0) < edf_count) && - ((text_count + 1.0) < x12_count) && - ((text_count + 1.0) < c40_count)) { - best_scheme = DM_TEXT; - } - - /* step (r)(3) */ - if (((edf_count + 1.0) < ascii_count) && - ((edf_count + 1.0) < b256_count) && - ((edf_count + 1.0) < text_count) && - ((edf_count + 1.0) < x12_count) && - ((edf_count + 1.0) < c40_count)) { - best_scheme = DM_EDIFACT; - } - - /* step (r)(2) */ - if (((b256_count + 1.0) <= ascii_count) || - (((b256_count + 1.0) < edf_count) && - ((b256_count + 1.0) < text_count) && - ((b256_count + 1.0) < x12_count) && - ((b256_count + 1.0) < c40_count))) { - best_scheme = DM_BASE256; - } - - /* step (r)(1) */ - if (((ascii_count + 1.0) <= b256_count) && - ((ascii_count + 1.0) <= edf_count) && - ((ascii_count + 1.0) <= text_count) && - ((ascii_count + 1.0) <= x12_count) && - ((ascii_count + 1.0) <= c40_count)) { - best_scheme = DM_ASCII; - } - } - - sp++; - } while (best_scheme == DM_NULL); // step (s) - - return best_scheme; -} - -int dm200encode(struct zint_symbol *symbol, unsigned char source[], unsigned char target[], int *last_mode, int *length_p, int process_buffer[], int *process_p) -{ - /* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate */ - /* Supports encoding FNC1 in supporting systems */ - - int sp, tp, i, gs1; - int current_mode, next_mode; - int inputlen = *length_p; - int debug = 0; -#ifndef _MSC_VER - char binary[2 * inputlen]; -#else - char* binary = (char*)_alloca(2 * inputlen); -#endif - - sp = 0; - tp = 0; - memset(process_buffer, 0, 8); - *process_p = 0; - strcpy(binary, ""); - - /* step (a) */ - current_mode = DM_ASCII; - next_mode = DM_ASCII; - - if(symbol->input_mode == GS1_MODE) { gs1 = 1; } else { gs1 = 0; } - - if(gs1) { - target[tp] = 232; tp++; - concat(binary, " "); - if(debug) printf("FN1 "); - } /* FNC1 */ - - if(symbol->output_options & READER_INIT) { - if(gs1) { - strcpy(symbol->errtxt, "Cannot encode in GS1 mode and Reader Initialisation at the same time"); - return ZINT_ERROR_INVALID_OPTION; - } else { - target[tp] = 234; tp++; /* Reader Programming */ - concat(binary, " "); - if(debug) printf("RP "); - } - } - - /* Check for Macro05/Macro06 */ - /* "[)>[RS]05[GS]...[RS][EOT]" -> CW 236 */ - /* "[)>[RS]06[GS]...[RS][EOT]" -> CW 237 */ - if (tp == 0 && sp == 0 && inputlen >= 9 - && source[0] == '[' && source[1] == ')' && source[2] == '>' - && source[3] == '\x1e' && source[4] == '0' - && (source[5] == '5' || source[5] == '6') - && source[6] == '\x1d' - && source[inputlen-2] == '\x1e' && source[inputlen-1] == '\x04' ) - { - /* Output macro Codeword */ - if (source[5] == '5') { - target[tp] = 236; - if(debug) printf("Macro05 "); - } else { - target[tp] = 237; - if(debug) printf("Macro06 "); - } - tp++; - concat(binary, " "); - /* Remove macro characters from input string */ - sp = 7; - inputlen -= 2; - *length_p -= 2; - } - - - while (sp < inputlen) { - - current_mode = next_mode; - - /* step (b) - ASCII encodation */ - if(current_mode == DM_ASCII) { - next_mode = DM_ASCII; - - if(istwodigits(source, sp) && ((sp + 1) != inputlen)) { - target[tp] = (10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130; - if(debug) printf("N%d ", target[tp] - 130); - tp++; concat(binary, " "); - sp += 2; - } else { - next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); - - if(next_mode != DM_ASCII) { - switch(next_mode) { - case DM_C40: target[tp] = 230; tp++; concat(binary, " "); - if(debug) printf("C40 "); break; - case DM_TEXT: target[tp] = 239; tp++; concat(binary, " "); - if(debug) printf("TEX "); break; - case DM_X12: target[tp] = 238; tp++; concat(binary, " "); - if(debug) printf("X12 "); break; - case DM_EDIFACT: target[tp] = 240; tp++; concat(binary, " "); - if(debug) printf("EDI "); break; - case DM_BASE256: target[tp] = 231; tp++; concat(binary, " "); - if(debug) printf("BAS "); break; - } - } else { - if(source[sp] > 127) { - target[tp] = 235; /* FNC4 */ - if(debug) printf("FN4 "); - tp++; - target[tp] = (source[sp] - 128) + 1; - if(debug) printf("A%02X ", target[tp] - 1); - tp++; concat(binary, " "); - } else { - if(gs1 && (source[sp] == '[')) { - target[tp] = 232; /* FNC1 */ - if(debug) printf("FN1 "); - } else { - target[tp] = source[sp] + 1; - if(debug) printf("A%02X ", target[tp] - 1); - } - tp++; - concat(binary, " "); - } - sp++; - } - } - - } - - /* step (c) C40 encodation */ - if(current_mode == DM_C40) { - int shift_set, value; - - next_mode = DM_C40; - if(*process_p == 0) { - next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); - } - - if(next_mode != DM_C40) { - target[tp] = 254; tp++; concat(binary, " "); /* Unlatch */ - next_mode = DM_ASCII; - if (debug) printf("ASC "); - } else { - if(source[sp] > 127) { - process_buffer[*process_p] = 1; (*process_p)++; - process_buffer[*process_p] = 30; (*process_p)++; /* Upper Shift */ - shift_set = c40_shift[source[sp] - 128]; - value = c40_value[source[sp] - 128]; - } else { - shift_set = c40_shift[source[sp]]; - value = c40_value[source[sp]]; - } - - if(gs1 && (source[sp] == '[')) { - shift_set = 2; - value = 27; /* FNC1 */ - } - - if(shift_set != 0) { - process_buffer[*process_p] = shift_set - 1; (*process_p)++; - } - process_buffer[*process_p] = value; (*process_p)++; - - if(*process_p >= 3) { - int iv; - - iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; - target[tp] = iv / 256; tp++; - target[tp] = iv % 256; tp++; - concat(binary, " "); - if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); - - process_buffer[0] = process_buffer[3]; - process_buffer[1] = process_buffer[4]; - process_buffer[2] = process_buffer[5]; - process_buffer[3] = 0; - process_buffer[4] = 0; - process_buffer[5] = 0; - *process_p -= 3; - } - sp++; - } - } - - /* step (d) Text encodation */ - if(current_mode == DM_TEXT) { - int shift_set, value; - - next_mode = DM_TEXT; - if(*process_p == 0) { - next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); - } - - if(next_mode != DM_TEXT) { - target[tp] = 254; tp++; concat(binary, " ");/* Unlatch */ - next_mode = DM_ASCII; - if (debug) printf("ASC "); - } else { - if(source[sp] > 127) { - process_buffer[*process_p] = 1; (*process_p)++; - process_buffer[*process_p] = 30; (*process_p)++; /* Upper Shift */ - shift_set = text_shift[source[sp] - 128]; - value = text_value[source[sp] - 128]; - } else { - shift_set = text_shift[source[sp]]; - value = text_value[source[sp]]; - } - - if(gs1 && (source[sp] == '[')) { - shift_set = 2; - value = 27; /* FNC1 */ - } - - if(shift_set != 0) { - process_buffer[*process_p] = shift_set - 1; (*process_p)++; - } - process_buffer[*process_p] = value; (*process_p)++; - - if(*process_p >= 3) { - int iv; - - iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; - target[tp] = iv / 256; tp++; - target[tp] = iv % 256; tp++; - concat(binary, " "); - if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); - - process_buffer[0] = process_buffer[3]; - process_buffer[1] = process_buffer[4]; - process_buffer[2] = process_buffer[5]; - process_buffer[3] = 0; - process_buffer[4] = 0; - process_buffer[5] = 0; - *process_p -= 3; - } - sp++; - } - } - - /* step (e) X12 encodation */ - if(current_mode == DM_X12) { - int value = 0; - - next_mode = DM_X12; - if(*process_p == 0) { - next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); - } - - if(next_mode != DM_X12) { - target[tp] = 254; tp++; concat(binary, " ");/* Unlatch */ - next_mode = DM_ASCII; - if (debug) printf("ASC "); - } else { - if(source[sp] == 13) { value = 0; } - if(source[sp] == '*') { value = 1; } - if(source[sp] == '>') { value = 2; } - if(source[sp] == ' ') { value = 3; } - if((source[sp] >= '0') && (source[sp] <= '9')) { value = (source[sp] - '0') + 4; } - if((source[sp] >= 'A') && (source[sp] <= 'Z')) { value = (source[sp] - 'A') + 14; } - - process_buffer[*process_p] = value; (*process_p)++; - - if(*process_p >= 3) { - int iv; - - iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; - target[tp] = iv / 256; tp++; - target[tp] = iv % 256; tp++; - concat(binary, " "); - if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); - - process_buffer[0] = process_buffer[3]; - process_buffer[1] = process_buffer[4]; - process_buffer[2] = process_buffer[5]; - process_buffer[3] = 0; - process_buffer[4] = 0; - process_buffer[5] = 0; - *process_p -= 3; - } - sp++; - } - } - - /* step (f) EDIFACT encodation */ - if(current_mode == DM_EDIFACT) { - int value = 0; - - next_mode = DM_EDIFACT; - if(*process_p == 3) { - next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); - } - - if(next_mode != DM_EDIFACT) { - process_buffer[*process_p] = 31; (*process_p)++; - next_mode = DM_ASCII; - } else { - if((source[sp] >= '@') && (source[sp] <= '^')) { value = source[sp] - '@'; } - if((source[sp] >= ' ') && (source[sp] <= '?')) { value = source[sp]; } - /* possibility put an assertion here for invalid character (none of the ifs trigger) */ - - process_buffer[*process_p] = value; (*process_p)++; - sp++; - } - - if(*process_p >= 4) { - target[tp] = (process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4); tp++; - target[tp] = ((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2); tp++; - target[tp] = ((process_buffer[2] & 0x03) << 6) + process_buffer[3]; tp++; - concat(binary, " "); - if (debug) printf("[%d %d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2], process_buffer[3]); - - process_buffer[0] = process_buffer[4]; - process_buffer[1] = process_buffer[5]; - process_buffer[2] = process_buffer[6]; - process_buffer[3] = process_buffer[7]; - process_buffer[4] = 0; - process_buffer[5] = 0; - process_buffer[6] = 0; - process_buffer[7] = 0; - *process_p -= 4; - } - } - - /* step (g) Base 256 encodation */ - if(current_mode == DM_BASE256) { - next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); - - if(next_mode == DM_BASE256) { - target[tp] = source[sp]; - if(debug) printf("B%02X ", target[tp]); - tp++; - sp++; - concat(binary, "b"); - } else { - next_mode = DM_ASCII; - if(debug) printf("ASC "); - } - } - - if(tp > 1558) { - return 0; - } - - } /* while */ - - /* Add length and randomising algorithm to b256 */ - i = 0; - while (i < tp) { - if(binary[i] == 'b') { - if((i == 0) || ((i != 0) && (binary[i - 1] != 'b'))) { - /* start of binary data */ - int binary_count; /* length of b256 data */ - - for(binary_count = 0; binary[binary_count + i] == 'b'; binary_count++); - - if(binary_count <= 249) { - dminsert(binary, i, 'b'); - insert_value(target, i, tp, binary_count); tp++; - } else { - dminsert(binary, i, 'b'); - dminsert(binary, i + 1, 'b'); - insert_value(target, i, tp, (binary_count / 250) + 249); tp++; - insert_value(target, i + 1, tp, binary_count % 250); tp++; - } - } - } - i++; - } - - for(i = 0; i < tp; i++) { - if(binary[i] == 'b') { - int prn, temp; - - prn = ((149 * (i + 1)) % 255) + 1; - temp = target[i] + prn; - if (temp <= 255) { target[i] = temp; } else { target[i] = temp - 256; } - } - } - - *(last_mode) = current_mode; - return tp; -} - -int dm200encode_remainder(unsigned char target[], int target_length, unsigned char source[], int inputlen, int last_mode, int process_buffer[], int process_p, int symbols_left) -{ - int debug = 0; - - switch (last_mode) - { - case DM_C40: - case DM_TEXT: - if (symbols_left == process_p) // No unlatch required! - { - if (process_p == 1) // 1 data character left to encode. - { - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 2) // 2 data characters left to encode. - { - // Pad with shift 1 value (0) and encode as double. - int intValue = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + 1; // ie (0 + 1). - target[target_length] = (unsigned char)(intValue / 256); target_length++; - target[target_length] = (unsigned char)(intValue % 256); target_length++; - } - } - - if (symbols_left > process_p) - { - target[target_length] = (254); target_length++; // Unlatch and encode remaining data in ascii. - if (process_p == 1 || (process_p == 2 && process_buffer[0] < 3)) // Check for a shift value. - { - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - else if (process_p == 2) - { - target[target_length] = source[inputlen - 2] + 1; target_length++; - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - } - break; - - case DM_X12: - if (symbols_left == process_p) // Unlatch not required! - { - if (process_p == 1) // 1 data character left to encode. - { - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 2) - { - // Encode last 2 bytes as ascii. - target[target_length] = source[inputlen - 2] + 1; target_length++; - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - } - - if (symbols_left > process_p) // Unlatch and encode remaining data in ascii. - { - target[target_length] = (254); target_length++; // Unlatch. - if (process_p == 1) - { - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 2) - { - target[target_length] = source[inputlen - 2] + 1; target_length++; - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - } - break; - - case DM_EDIFACT: - if (symbols_left == process_p) // Unlatch not required! - { - if (process_p == 1) - { - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 2) - { - target[target_length] = source[inputlen - 2] + 1; target_length++; - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 3) // Append edifact unlatch value (31) and encode as triple. - { - target[target_length] = (unsigned char)((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4)); target_length++; - target[target_length] = (unsigned char)(((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2)); target_length++; - target[target_length] = (unsigned char)(((process_buffer[2] & 0x03) << 6) + 31); target_length++; - } - } - - if (symbols_left > process_p) // Unlatch and encode remaining data in ascii. - { - // Edifact unlatch. - if (symbols_left < 3) - { - target[target_length] = 31; target_length++; - } - - else - target[target_length] = (31 << 2); target_length++; - - if (process_p == 1) - { - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 2) - { - target[target_length] = source[inputlen - 2] + 1; target_length++; - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - - if (process_p == 3) - { - target[target_length] = source[inputlen - 3] + 1; target_length++; - target[target_length] = source[inputlen - 2] + 1; target_length++; - target[target_length] = source[inputlen - 1] + 1; target_length++; - } - } - break; - } - - if(debug) - { - int i; - printf("\n\n"); - for(i = 0; i < target_length; i++) - printf("%03d ", target[i]); - - printf("\n"); - } - - return target_length; - } - -void add_tail(unsigned char target[], int tp, int tail_length) -{ - /* add pad bits */ - int i, prn, temp; - - for(i = tail_length; i > 0; i--) { - if(i == tail_length) { - target[tp] = 129; tp++; /* Pad */ - } else { - prn = ((149 * (tp + 1)) % 253) + 1; - temp = 129 + prn; - if(temp <= 254) { - target[tp] = temp; tp++; - } else { - target[tp] = temp - 254; tp++; - } - } - } -} - -int data_matrix_200(struct zint_symbol *symbol, unsigned char source[], int length) -{ - int inputlen, i, skew = 0; - unsigned char binary[2200]; - int binlen; - int process_buffer[8]; /* holds remaining data to finalised */ - int process_p; /* number of characters left to finalise */ - int symbolsize, optionsize, calcsize; - int taillength, error_number = 0; - int H, W, FH, FW, datablock, bytes, rsblock; - int last_mode; - unsigned char *grid = 0; - int symbols_left; - inputlen = length; - - /* inputlen may be decremented by 2 if macro character is used */ - binlen = dm200encode(symbol, source, binary, &last_mode, &inputlen, process_buffer, &process_p); - - if(binlen == 0) { - strcpy(symbol->errtxt, "Data too long to fit in symbol"); - return ZINT_ERROR_TOO_LONG; - } - - if((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) { - optionsize = intsymbol[symbol->option_2 - 1]; - } else { - optionsize = -1; - } - - calcsize = DMSIZESCOUNT-1; - for(i = DMSIZESCOUNT-1; i > -1; i--) { - if(matrixbytes[i] >= (binlen + process_p)) // Allow for the remaining data characters. - { - calcsize = i; - } - } - - /* Skip rectangular symbols in square only mode */ - while(symbol->option_3 == DM_SQUARE && matrixH[calcsize] != matrixW[calcsize]) { - calcsize++; - } - - symbolsize = optionsize; - if(calcsize > optionsize) { - symbolsize = calcsize; - if(optionsize != -1) { - /* flag an error */ - error_number = ZINT_WARN_INVALID_OPTION; - strcpy(symbol->errtxt, "Data does not fit in selected symbol size"); - } - } - - // Now we know the symbol size we can handle the remaining data in the process buffer. - symbols_left = matrixbytes[symbolsize] - binlen; - binlen = dm200encode_remainder(binary, binlen, source, inputlen, last_mode, process_buffer, process_p, symbols_left); - - H = matrixH[symbolsize]; - W = matrixW[symbolsize]; - FH = matrixFH[symbolsize]; - FW = matrixFW[symbolsize]; - bytes = matrixbytes[symbolsize]; - datablock = matrixdatablock[symbolsize]; - rsblock = matrixrsblock[symbolsize]; - - taillength = bytes - binlen; - - if(taillength != 0) { - add_tail(binary, binlen, taillength); - } - - // ecc code - if(symbolsize == INTSYMBOL144) { skew = 1; } - ecc200(binary, bytes, datablock, rsblock, skew); - // Print Codewords - #ifdef DEBUG - { - int CWCount; - if (skew) - CWCount = 1558+620; - else - CWCount = bytes + rsblock * (bytes / datablock); - printf("Codewords (%i):",CWCount); - for (int posCur = 0;posCur < CWCount;posCur++) - printf(" %3i",binary[posCur]); - puts("\n"); - } - #endif - { // placement - int x, y, NC, NR, *places; - NC = W - 2 * (W / FW); - NR = H - 2 * (H / FH); - places = (int*)malloc(NC * NR * sizeof(int)); - ecc200placement(places, NR, NC); - grid = (unsigned char*)malloc(W * H); - memset(grid, 0, W * H); - for (y = 0; y < H; y += FH) { - for (x = 0; x < W; x++) - grid[y * W + x] = 1; - for (x = 0; x < W; x += 2) - grid[(y + FH - 1) * W + x] = 1; - } - for (x = 0; x < W; x += FW) { - for (y = 0; y < H; y++) - grid[y * W + x] = 1; - for (y = 0; y < H; y += 2) - grid[y * W + x + FW - 1] = 1; - } - #ifdef DEBUG - // Print position matrix as in standard - for (y = NR-1; y >= 0; y--) { - for (x = 0; x < NC; x++) { - if (x != 0) - fprintf (stderr, "|"); - int v = places[(NR - y - 1) * NC + x]; - fprintf(stderr,"%3d.%2d",(v>>3),8-(v&7)); - } - fprintf (stderr, "\n"); - } - #endif - for (y = 0; y < NR; y++) { - for (x = 0; x < NC; x++) { - int v = places[(NR - y - 1) * NC + x]; - //fprintf (stderr, "%4d", v); - if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))) - grid[(1 + y + 2 * (y / (FH - 2))) * W + 1 + x + 2 * (x / (FW - 2))] = 1; - } - //fprintf (stderr, "\n"); - } - for(y = H - 1; y >= 0; y--) { - int x; - for(x = 0; x < W; x++) { - if(grid[W * y + x]) { - set_module(symbol, (H - y) - 1, x); - } - } - symbol->row_height[(H - y) - 1] = 1; - } - free(grid); - free(places); - } - - symbol->rows = H; - symbol->width = W; - - return error_number; -} - -int dmatrix(struct zint_symbol *symbol, unsigned char source[], int length) -{ - int error_number; - - if(symbol->option_1 <= 1) { - /* ECC 200 */ - error_number = data_matrix_200(symbol, source, length); - } else { - /* ECC 000 - 140 */ - strcpy(symbol->errtxt, "Older Data Matrix standards are no longer supported"); - error_number = ZINT_ERROR_INVALID_OPTION; - } - - return error_number; -} +/* dmatrix.c Handles Data Matrix ECC 200 symbols */ + +/* + libzint - the open source barcode library + Copyright (C) 2009 Robin Stuart + + developed from and including some functions from: + IEC16022 bar code generation + Adrian Kennard, Andrews & Arnold Ltd + with help from Cliff Hones on the RS coding + + (c) 2004 Adrian Kennard, Andrews & Arnold Ltd + (c) 2006 Stefan Schmidt + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include +#endif +#include "reedsol.h" +#include "common.h" +#include "dmatrix.h" + +// Annex M placement alorithm low level +static void ecc200placementbit(int *array, int NR, int NC, int r, int c, int p, char b) +{ + if (r < 0) { + r += NR; + c += 4 - ((NR + 4) % 8); + } + if (c < 0) { + c += NC; + r += 4 - ((NC + 4) % 8); + } + // Necessary for 26x32,26x40,26x48,36x120,36x144,72x120,72x144 + if (r >= NR) { + #ifdef DEBUG + fprintf(stderr,"r >= NR:%i,%i at r=%i->",p,b,r); + #endif + r -= NR; + #ifdef DEBUG + fprintf(stderr,"%i,c=%i\n",r,c); + #endif + } + #ifdef DEBUG + if(0 != array[r * NC + c] ){ + int a = array[r * NC + c]; + fprintf(stderr,"Double:%i,%i->%i,%i at r=%i,c=%i\n",a >> 3, a & 7, p,b,r,c); + return; + } + #endif + // Check index limits + assert( r < NR ); + assert( c < NC ); + // Check double-assignment + assert( 0 == array[r * NC + c] ); + array[r * NC + c] = (p << 3) + b; +} + +static void ecc200placementblock(int *array, int NR, int NC, int r, + int c, int p) +{ + ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7); + ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6); + ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5); + ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4); + ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3); + ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2); + ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1); + ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0); +} + +static void ecc200placementcornerA(int *array, int NR, int NC, int p) +{ + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6); + ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); + ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); + ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); +} + +static void ecc200placementcornerB(int *array, int NR, int NC, int p) +{ + ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); +} + +static void ecc200placementcornerC(int *array, int NR, int NC, int p) +{ + ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); + ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); + ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); +} + +static void ecc200placementcornerD(int *array, int NR, int NC, int p) +{ + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6); + ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); + ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2); + ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); +} + +// Annex M placement alorithm main function +static void ecc200placement(int *array, int NR, int NC) +{ + int r, c, p; + // invalidate + for (r = 0; r < NR; r++) + for (c = 0; c < NC; c++) + array[r * NC + c] = 0; + // start + p = 1; + r = 4; + c = 0; + do { + // check corner + if (r == NR && !c) + ecc200placementcornerA(array, NR, NC, p++); + if (r == NR - 2 && !c && NC % 4) + ecc200placementcornerB(array, NR, NC, p++); + if (r == NR - 2 && !c && (NC % 8) == 4) + ecc200placementcornerC(array, NR, NC, p++); + if (r == NR + 4 && c == 2 && !(NC % 8)) + ecc200placementcornerD(array, NR, NC, p++); + // up/right + do { + if (r < NR && c >= 0 && !array[r * NC + c]) + ecc200placementblock(array, NR, NC, r, c, p++); + r -= 2; + c += 2; + } + while (r >= 0 && c < NC); + r++; + c += 3; + // down/left + do { + if (r >= 0 && c < NC && !array[r * NC + c]) + ecc200placementblock(array, NR, NC, r, c, p++); + r += 2; + c -= 2; + } + while (r < NR && c >= 0); + r += 3; + c++; + } + while (r < NR || c < NC); + // unfilled corner + if (!array[NR * NC - 1]) + array[NR * NC - 1] = array[NR * NC - NC - 2] = 1; +} + +// calculate and append ecc code, and if necessary interleave +static void ecc200(unsigned char *binary, int bytes, int datablock, int rsblock, int skew) +{ + int blocks = (bytes + 2) / datablock, b; + int n, p; + rs_init_gf(0x12d); + rs_init_code(rsblock, 1); + for (b = 0; b < blocks; b++) { + unsigned char buf[256], ecc[256]; + p = 0; + for (n = b; n < bytes; n += blocks) + buf[p++] = binary[n]; + rs_encode(p, buf, ecc); + p = rsblock - 1; // comes back reversed + for (n = b; n < rsblock * blocks; n += blocks) { + if (skew) { + /* Rotate ecc data to make 144x144 size symbols acceptable */ + /* See http://groups.google.com/group/postscriptbarcode/msg/5ae8fda7757477da */ + if(b < 8) { + binary[bytes + n + 2] = ecc[p--]; + } else { + binary[bytes + n - 8] = ecc[p--]; + } + } else { + binary[bytes + n] = ecc[p--]; + } + } + } + rs_free(); +} + +int isX12(unsigned char source) +{ + if(source == 13) { return 1; } + if(source == 42) { return 1; } + if(source == 62) { return 1; } + if(source == 32) { return 1; } + if((source >= '0') && (source <= '9')) { return 1; } + if((source >= 'A') && (source <= 'Z')) { return 1; } + + return 0; +} + +void dminsert(char binary_string[], int posn, char newbit) +{ /* Insert a character into the middle of a string at position posn */ + int i, end; + + end = strlen(binary_string); + for(i = end; i > posn; i--) { + binary_string[i] = binary_string[i - 1]; + } + binary_string[posn] = newbit; +} + +void insert_value(unsigned char binary_stream[], int posn, int streamlen, char newbit) +{ + int i; + + for(i = streamlen; i > posn; i--) { + binary_stream[i] = binary_stream[i - 1]; + } + binary_stream[posn] = newbit; +} + +int p_r_6_2_1(unsigned char inputData[], int position, int sourcelen) { + /* Annex P section (r)(6)(ii)(I) + "If one of the three X12 terminator/separator characters first + occurs in the yet to be processed data before a non-X12 character..." + */ + + int i; + int nonX12Position = 0; + int specialX12Position = 0; + int retval = 0; + + for (i = position; i < sourcelen; i++) { + if (nonX12Position == 0) { + if (isX12(i) == 1) { + nonX12Position = i; + } + } + + if (specialX12Position == 0) { + if ((inputData[i] == (char) 13) || + (inputData[i] == '*') || + (inputData[i] == '>')) { + specialX12Position = i; + } + } + } + + if ((nonX12Position != 0) && (specialX12Position != 0)) { + if (specialX12Position < nonX12Position) { + retval = 1; + } + } + + return retval; +} + +int look_ahead_test(unsigned char inputData[], int sourcelen, int position, int current_mode, int gs1) +{ + /* 'look ahead test' from Annex P */ + + float ascii_count, c40_count, text_count, x12_count, edf_count, b256_count, best_count; + int sp, best_scheme; + + best_scheme = DM_NULL; + + /* step (j) */ + if(current_mode == DM_ASCII) { + ascii_count = 0.0; + c40_count = 1.0; + text_count = 1.0; + x12_count = 1.0; + edf_count = 1.0; + b256_count = 1.25; + } else { + ascii_count = 1.0; + c40_count = 2.0; + text_count = 2.0; + x12_count = 2.0; + edf_count = 2.0; + b256_count = 2.25; + } + + switch(current_mode) { + case DM_C40: c40_count = 0.0; break; + case DM_TEXT: text_count = 0.0; break; + case DM_X12: x12_count = 0.0; break; + case DM_EDIFACT: edf_count = 0.0; break; + case DM_BASE256: b256_count = 0.0; break; + } + + sp = position; + + do { + if(sp == (sourcelen - 1)) { + /* At the end of data ... step (k) */ + ascii_count = ceil(ascii_count); + b256_count = ceil(b256_count); + edf_count = ceil(edf_count); + text_count = ceil(text_count); + x12_count = ceil(x12_count); + c40_count = ceil(c40_count); + + best_count = c40_count; + best_scheme = DM_C40; // (k)(7) + + if (x12_count < best_count) { + best_count = x12_count; + best_scheme = DM_X12; // (k)(6) + } + + if (text_count < best_count) { + best_count = text_count; + best_scheme = DM_TEXT; // (k)(5) + } + + if (edf_count < best_count) { + best_count = edf_count; + best_scheme = DM_EDIFACT; // (k)(4) + } + + if (b256_count < best_count) { + best_count = b256_count; + best_scheme = DM_BASE256; // (k)(3) + } + + if (ascii_count <= best_count) { + best_scheme = DM_ASCII; // (k)(2) + } + } else { + + /* ascii ... step (l) */ + if ((inputData[sp] >= '0') && (inputData[sp] <= '9')) { + ascii_count += 0.5; // (l)(1) + } else { + if (inputData[sp] > 127) { + ascii_count = ceil(ascii_count) + 2.0; // (l)(2) + } else { + ascii_count = ceil(ascii_count) + 1.0; // (l)(3) + } + } + + /* c40 ... step (m) */ + if ((inputData[sp] == ' ') || + (((inputData[sp] >= '0') && (inputData[sp] <= '9')) || + ((inputData[sp] >= 'A') && (inputData[sp] <= 'Z')))) { + c40_count += (2.0 / 3.0); // (m)(1) + } else { + if (inputData[sp] > 127) { + c40_count += (8.0 / 3.0); // (m)(2) + } else { + c40_count += (4.0 / 3.0); // (m)(3) + } + } + + /* text ... step (n) */ + if ((inputData[sp] == ' ') || + (((inputData[sp] >= '0') && (inputData[sp] <= '9')) || + ((inputData[sp] >= 'a') && (inputData[sp] <= 'z')))) { + text_count += (2.0 / 3.0); // (n)(1) + } else { + if (inputData[sp] > 127) { + text_count += (8.0 / 3.0); // (n)(2) + } else { + text_count += (4.0 / 3.0); // (n)(3) + } + } + + /* x12 ... step (o) */ + if (isX12(inputData[sp])) { + x12_count += (2.0 / 3.0); // (o)(1) + } else { + if (inputData[sp] > 127) { + x12_count += (13.0 / 3.0); // (o)(2) + } else { + x12_count += (10.0 / 3.0); // (o)(3) + } + } + + /* edifact ... step (p) */ + if ((inputData[sp] >= ' ') && (inputData[sp] <= '^')) { + edf_count += (3.0 / 4.0); // (p)(1) + } else { + if (inputData[sp] > 127) { + edf_count += (17.0 / 4.0); // (p)(2) + } else { + edf_count += (13.0 / 4.0); // (p)(3) + } + } + if ((gs1 == 1) && (inputData[sp] == '[')) { + edf_count += 6.0; + } + + /* base 256 ... step (q) */ + if ((gs1 == 1) && (inputData[sp] == '[')) { + b256_count += 4.0; // (q)(1) + } else { + b256_count += 1.0; // (q)(2) + } + } + + + if (sp > (position + 3)) { + /* 4 data characters processed ... step (r) */ + + /* step (r)(6) */ + if (((c40_count + 1.0) < ascii_count) && + ((c40_count + 1.0) < b256_count) && + ((c40_count + 1.0) < edf_count) && + ((c40_count + 1.0) < text_count)) { + + if (c40_count < x12_count) { + best_scheme = DM_C40; + } + + if (c40_count == x12_count) { + if (p_r_6_2_1(inputData, sp, sourcelen) == 1) { + // Test (r)(6)(ii)(i) + best_scheme = DM_X12; + } else { + best_scheme = DM_C40; + } + } + } + + /* step (r)(5) */ + if (((x12_count + 1.0) < ascii_count) && + ((x12_count + 1.0) < b256_count) && + ((x12_count + 1.0) < edf_count) && + ((x12_count + 1.0) < text_count) && + ((x12_count + 1.0) < c40_count)) { + best_scheme = DM_X12; + } + + /* step (r)(4) */ + if (((text_count + 1.0) < ascii_count) && + ((text_count + 1.0) < b256_count) && + ((text_count + 1.0) < edf_count) && + ((text_count + 1.0) < x12_count) && + ((text_count + 1.0) < c40_count)) { + best_scheme = DM_TEXT; + } + + /* step (r)(3) */ + if (((edf_count + 1.0) < ascii_count) && + ((edf_count + 1.0) < b256_count) && + ((edf_count + 1.0) < text_count) && + ((edf_count + 1.0) < x12_count) && + ((edf_count + 1.0) < c40_count)) { + best_scheme = DM_EDIFACT; + } + + /* step (r)(2) */ + if (((b256_count + 1.0) <= ascii_count) || + (((b256_count + 1.0) < edf_count) && + ((b256_count + 1.0) < text_count) && + ((b256_count + 1.0) < x12_count) && + ((b256_count + 1.0) < c40_count))) { + best_scheme = DM_BASE256; + } + + /* step (r)(1) */ + if (((ascii_count + 1.0) <= b256_count) && + ((ascii_count + 1.0) <= edf_count) && + ((ascii_count + 1.0) <= text_count) && + ((ascii_count + 1.0) <= x12_count) && + ((ascii_count + 1.0) <= c40_count)) { + best_scheme = DM_ASCII; + } + } + + sp++; + } while (best_scheme == DM_NULL); // step (s) + + return best_scheme; +} + +int dm200encode(struct zint_symbol *symbol, unsigned char source[], unsigned char target[], int *last_mode, int *length_p, int process_buffer[], int *process_p) +{ + /* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate */ + /* Supports encoding FNC1 in supporting systems */ + + int sp, tp, i, gs1; + int current_mode, next_mode; + int inputlen = *length_p; + int debug = 0; +#ifndef _MSC_VER + char binary[2 * inputlen]; +#else + char* binary = (char*)_alloca(2 * inputlen); +#endif + + sp = 0; + tp = 0; + memset(process_buffer, 0, 8); + *process_p = 0; + strcpy(binary, ""); + + /* step (a) */ + current_mode = DM_ASCII; + next_mode = DM_ASCII; + + if(symbol->input_mode == GS1_MODE) { gs1 = 1; } else { gs1 = 0; } + + if(gs1) { + target[tp] = 232; tp++; + concat(binary, " "); + if(debug) printf("FN1 "); + } /* FNC1 */ + + if(symbol->output_options & READER_INIT) { + if(gs1) { + strcpy(symbol->errtxt, "Cannot encode in GS1 mode and Reader Initialisation at the same time"); + return ZINT_ERROR_INVALID_OPTION; + } else { + target[tp] = 234; tp++; /* Reader Programming */ + concat(binary, " "); + if(debug) printf("RP "); + } + } + + /* Check for Macro05/Macro06 */ + /* "[)>[RS]05[GS]...[RS][EOT]" -> CW 236 */ + /* "[)>[RS]06[GS]...[RS][EOT]" -> CW 237 */ + if (tp == 0 && sp == 0 && inputlen >= 9 + && source[0] == '[' && source[1] == ')' && source[2] == '>' + && source[3] == '\x1e' && source[4] == '0' + && (source[5] == '5' || source[5] == '6') + && source[6] == '\x1d' + && source[inputlen-2] == '\x1e' && source[inputlen-1] == '\x04' ) + { + /* Output macro Codeword */ + if (source[5] == '5') { + target[tp] = 236; + if(debug) printf("Macro05 "); + } else { + target[tp] = 237; + if(debug) printf("Macro06 "); + } + tp++; + concat(binary, " "); + /* Remove macro characters from input string */ + sp = 7; + inputlen -= 2; + *length_p -= 2; + } + + + while (sp < inputlen) { + + current_mode = next_mode; + + /* step (b) - ASCII encodation */ + if(current_mode == DM_ASCII) { + next_mode = DM_ASCII; + + if(istwodigits(source, sp) && ((sp + 1) != inputlen)) { + target[tp] = (10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130; + if(debug) printf("N%d ", target[tp] - 130); + tp++; concat(binary, " "); + sp += 2; + } else { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + + if(next_mode != DM_ASCII) { + switch(next_mode) { + case DM_C40: target[tp] = 230; tp++; concat(binary, " "); + if(debug) printf("C40 "); break; + case DM_TEXT: target[tp] = 239; tp++; concat(binary, " "); + if(debug) printf("TEX "); break; + case DM_X12: target[tp] = 238; tp++; concat(binary, " "); + if(debug) printf("X12 "); break; + case DM_EDIFACT: target[tp] = 240; tp++; concat(binary, " "); + if(debug) printf("EDI "); break; + case DM_BASE256: target[tp] = 231; tp++; concat(binary, " "); + if(debug) printf("BAS "); break; + } + } else { + if(source[sp] > 127) { + target[tp] = 235; /* FNC4 */ + if(debug) printf("FN4 "); + tp++; + target[tp] = (source[sp] - 128) + 1; + if(debug) printf("A%02X ", target[tp] - 1); + tp++; concat(binary, " "); + } else { + if(gs1 && (source[sp] == '[')) { + target[tp] = 232; /* FNC1 */ + if(debug) printf("FN1 "); + } else { + target[tp] = source[sp] + 1; + if(debug) printf("A%02X ", target[tp] - 1); + } + tp++; + concat(binary, " "); + } + sp++; + } + } + + } + + /* step (c) C40 encodation */ + if(current_mode == DM_C40) { + int shift_set, value; + + next_mode = DM_C40; + if(*process_p == 0) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if(next_mode != DM_C40) { + target[tp] = 254; tp++; concat(binary, " "); /* Unlatch */ + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } else { + if(source[sp] > 127) { + process_buffer[*process_p] = 1; (*process_p)++; + process_buffer[*process_p] = 30; (*process_p)++; /* Upper Shift */ + shift_set = c40_shift[source[sp] - 128]; + value = c40_value[source[sp] - 128]; + } else { + shift_set = c40_shift[source[sp]]; + value = c40_value[source[sp]]; + } + + if(gs1 && (source[sp] == '[')) { + shift_set = 2; + value = 27; /* FNC1 */ + } + + if(shift_set != 0) { + process_buffer[*process_p] = shift_set - 1; (*process_p)++; + } + process_buffer[*process_p] = value; (*process_p)++; + + if(*process_p >= 3) { + int iv; + + iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; + target[tp] = iv / 256; tp++; + target[tp] = iv % 256; tp++; + concat(binary, " "); + if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); + + process_buffer[0] = process_buffer[3]; + process_buffer[1] = process_buffer[4]; + process_buffer[2] = process_buffer[5]; + process_buffer[3] = 0; + process_buffer[4] = 0; + process_buffer[5] = 0; + *process_p -= 3; + } + sp++; + } + } + + /* step (d) Text encodation */ + if(current_mode == DM_TEXT) { + int shift_set, value; + + next_mode = DM_TEXT; + if(*process_p == 0) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if(next_mode != DM_TEXT) { + target[tp] = 254; tp++; concat(binary, " ");/* Unlatch */ + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } else { + if(source[sp] > 127) { + process_buffer[*process_p] = 1; (*process_p)++; + process_buffer[*process_p] = 30; (*process_p)++; /* Upper Shift */ + shift_set = text_shift[source[sp] - 128]; + value = text_value[source[sp] - 128]; + } else { + shift_set = text_shift[source[sp]]; + value = text_value[source[sp]]; + } + + if(gs1 && (source[sp] == '[')) { + shift_set = 2; + value = 27; /* FNC1 */ + } + + if(shift_set != 0) { + process_buffer[*process_p] = shift_set - 1; (*process_p)++; + } + process_buffer[*process_p] = value; (*process_p)++; + + if(*process_p >= 3) { + int iv; + + iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; + target[tp] = iv / 256; tp++; + target[tp] = iv % 256; tp++; + concat(binary, " "); + if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); + + process_buffer[0] = process_buffer[3]; + process_buffer[1] = process_buffer[4]; + process_buffer[2] = process_buffer[5]; + process_buffer[3] = 0; + process_buffer[4] = 0; + process_buffer[5] = 0; + *process_p -= 3; + } + sp++; + } + } + + /* step (e) X12 encodation */ + if(current_mode == DM_X12) { + int value = 0; + + next_mode = DM_X12; + if(*process_p == 0) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if(next_mode != DM_X12) { + target[tp] = 254; tp++; concat(binary, " ");/* Unlatch */ + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } else { + if(source[sp] == 13) { value = 0; } + if(source[sp] == '*') { value = 1; } + if(source[sp] == '>') { value = 2; } + if(source[sp] == ' ') { value = 3; } + if((source[sp] >= '0') && (source[sp] <= '9')) { value = (source[sp] - '0') + 4; } + if((source[sp] >= 'A') && (source[sp] <= 'Z')) { value = (source[sp] - 'A') + 14; } + + process_buffer[*process_p] = value; (*process_p)++; + + if(*process_p >= 3) { + int iv; + + iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; + target[tp] = iv / 256; tp++; + target[tp] = iv % 256; tp++; + concat(binary, " "); + if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); + + process_buffer[0] = process_buffer[3]; + process_buffer[1] = process_buffer[4]; + process_buffer[2] = process_buffer[5]; + process_buffer[3] = 0; + process_buffer[4] = 0; + process_buffer[5] = 0; + *process_p -= 3; + } + sp++; + } + } + + /* step (f) EDIFACT encodation */ + if(current_mode == DM_EDIFACT) { + int value = 0; + + next_mode = DM_EDIFACT; + if(*process_p == 3) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if(next_mode != DM_EDIFACT) { + process_buffer[*process_p] = 31; (*process_p)++; + next_mode = DM_ASCII; + } else { + if((source[sp] >= '@') && (source[sp] <= '^')) { value = source[sp] - '@'; } + if((source[sp] >= ' ') && (source[sp] <= '?')) { value = source[sp]; } + /* possibility put an assertion here for invalid character (none of the ifs trigger) */ + + process_buffer[*process_p] = value; (*process_p)++; + sp++; + } + + if(*process_p >= 4) { + target[tp] = (process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4); tp++; + target[tp] = ((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2); tp++; + target[tp] = ((process_buffer[2] & 0x03) << 6) + process_buffer[3]; tp++; + concat(binary, " "); + if (debug) printf("[%d %d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2], process_buffer[3]); + + process_buffer[0] = process_buffer[4]; + process_buffer[1] = process_buffer[5]; + process_buffer[2] = process_buffer[6]; + process_buffer[3] = process_buffer[7]; + process_buffer[4] = 0; + process_buffer[5] = 0; + process_buffer[6] = 0; + process_buffer[7] = 0; + *process_p -= 4; + } + } + + /* step (g) Base 256 encodation */ + if(current_mode == DM_BASE256) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + + if(next_mode == DM_BASE256) { + target[tp] = source[sp]; + if(debug) printf("B%02X ", target[tp]); + tp++; + sp++; + concat(binary, "b"); + } else { + next_mode = DM_ASCII; + if(debug) printf("ASC "); + } + } + + if(tp > 1558) { + return 0; + } + + } /* while */ + + /* Add length and randomising algorithm to b256 */ + i = 0; + while (i < tp) { + if(binary[i] == 'b') { + if((i == 0) || ((i != 0) && (binary[i - 1] != 'b'))) { + /* start of binary data */ + int binary_count; /* length of b256 data */ + + for(binary_count = 0; binary[binary_count + i] == 'b'; binary_count++); + + if(binary_count <= 249) { + dminsert(binary, i, 'b'); + insert_value(target, i, tp, binary_count); tp++; + } else { + dminsert(binary, i, 'b'); + dminsert(binary, i + 1, 'b'); + insert_value(target, i, tp, (binary_count / 250) + 249); tp++; + insert_value(target, i + 1, tp, binary_count % 250); tp++; + } + } + } + i++; + } + + for(i = 0; i < tp; i++) { + if(binary[i] == 'b') { + int prn, temp; + + prn = ((149 * (i + 1)) % 255) + 1; + temp = target[i] + prn; + if (temp <= 255) { target[i] = temp; } else { target[i] = temp - 256; } + } + } + + *(last_mode) = current_mode; + return tp; +} + +int dm200encode_remainder(unsigned char target[], int target_length, unsigned char source[], int inputlen, int last_mode, int process_buffer[], int process_p, int symbols_left) +{ + int debug = 0; + + switch (last_mode) + { + case DM_C40: + case DM_TEXT: + if (symbols_left == process_p) // No unlatch required! + { + if (process_p == 1) // 1 data character left to encode. + { + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 2) // 2 data characters left to encode. + { + // Pad with shift 1 value (0) and encode as double. + int intValue = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + 1; // ie (0 + 1). + target[target_length] = (unsigned char)(intValue / 256); target_length++; + target[target_length] = (unsigned char)(intValue % 256); target_length++; + } + } + + if (symbols_left > process_p) + { + target[target_length] = (254); target_length++; // Unlatch and encode remaining data in ascii. + if (process_p == 1 || (process_p == 2 && process_buffer[0] < 3)) // Check for a shift value. + { + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + else if (process_p == 2) + { + target[target_length] = source[inputlen - 2] + 1; target_length++; + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + } + break; + + case DM_X12: + if (symbols_left == process_p) // Unlatch not required! + { + if (process_p == 1) // 1 data character left to encode. + { + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 2) + { + // Encode last 2 bytes as ascii. + target[target_length] = source[inputlen - 2] + 1; target_length++; + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + } + + if (symbols_left > process_p) // Unlatch and encode remaining data in ascii. + { + target[target_length] = (254); target_length++; // Unlatch. + if (process_p == 1) + { + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 2) + { + target[target_length] = source[inputlen - 2] + 1; target_length++; + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + } + break; + + case DM_EDIFACT: + if (symbols_left == process_p) // Unlatch not required! + { + if (process_p == 1) + { + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 2) + { + target[target_length] = source[inputlen - 2] + 1; target_length++; + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 3) // Append edifact unlatch value (31) and encode as triple. + { + target[target_length] = (unsigned char)((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4)); target_length++; + target[target_length] = (unsigned char)(((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2)); target_length++; + target[target_length] = (unsigned char)(((process_buffer[2] & 0x03) << 6) + 31); target_length++; + } + } + + if (symbols_left > process_p) // Unlatch and encode remaining data in ascii. + { + // Edifact unlatch. + if (symbols_left < 3) + { + target[target_length] = 31; target_length++; + } + + else + target[target_length] = (31 << 2); target_length++; + + if (process_p == 1) + { + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 2) + { + target[target_length] = source[inputlen - 2] + 1; target_length++; + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + + if (process_p == 3) + { + target[target_length] = source[inputlen - 3] + 1; target_length++; + target[target_length] = source[inputlen - 2] + 1; target_length++; + target[target_length] = source[inputlen - 1] + 1; target_length++; + } + } + break; + } + + if(debug) + { + int i; + printf("\n\n"); + for(i = 0; i < target_length; i++) + printf("%03d ", target[i]); + + printf("\n"); + } + + return target_length; + } + +void add_tail(unsigned char target[], int tp, int tail_length) +{ + /* add pad bits */ + int i, prn, temp; + + for(i = tail_length; i > 0; i--) { + if(i == tail_length) { + target[tp] = 129; tp++; /* Pad */ + } else { + prn = ((149 * (tp + 1)) % 253) + 1; + temp = 129 + prn; + if(temp <= 254) { + target[tp] = temp; tp++; + } else { + target[tp] = temp - 254; tp++; + } + } + } +} + +int data_matrix_200(struct zint_symbol *symbol, unsigned char source[], int length) +{ + int inputlen, i, skew = 0; + unsigned char binary[2200]; + int binlen; + int process_buffer[8]; /* holds remaining data to finalised */ + int process_p; /* number of characters left to finalise */ + int symbolsize, optionsize, calcsize; + int taillength, error_number = 0; + int H, W, FH, FW, datablock, bytes, rsblock; + int last_mode; + unsigned char *grid = 0; + int symbols_left; + inputlen = length; + + /* inputlen may be decremented by 2 if macro character is used */ + binlen = dm200encode(symbol, source, binary, &last_mode, &inputlen, process_buffer, &process_p); + + if(binlen == 0) { + strcpy(symbol->errtxt, "Data too long to fit in symbol"); + return ZINT_ERROR_TOO_LONG; + } + + if((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) { + optionsize = intsymbol[symbol->option_2 - 1]; + } else { + optionsize = -1; + } + + calcsize = DMSIZESCOUNT-1; + for(i = DMSIZESCOUNT-1; i > -1; i--) { + if(matrixbytes[i] >= (binlen + process_p)) // Allow for the remaining data characters. + { + calcsize = i; + } + } + + /* Skip rectangular symbols in square only mode */ + while(symbol->option_3 == DM_SQUARE && matrixH[calcsize] != matrixW[calcsize]) { + calcsize++; + } + + symbolsize = optionsize; + if(calcsize > optionsize) { + symbolsize = calcsize; + if(optionsize != -1) { + /* flag an error */ + error_number = ZINT_WARN_INVALID_OPTION; + strcpy(symbol->errtxt, "Data does not fit in selected symbol size"); + } + } + + // Now we know the symbol size we can handle the remaining data in the process buffer. + symbols_left = matrixbytes[symbolsize] - binlen; + binlen = dm200encode_remainder(binary, binlen, source, inputlen, last_mode, process_buffer, process_p, symbols_left); + + H = matrixH[symbolsize]; + W = matrixW[symbolsize]; + FH = matrixFH[symbolsize]; + FW = matrixFW[symbolsize]; + bytes = matrixbytes[symbolsize]; + datablock = matrixdatablock[symbolsize]; + rsblock = matrixrsblock[symbolsize]; + + taillength = bytes - binlen; + + if(taillength != 0) { + add_tail(binary, binlen, taillength); + } + + // ecc code + if(symbolsize == INTSYMBOL144) { skew = 1; } + ecc200(binary, bytes, datablock, rsblock, skew); + // Print Codewords + #ifdef DEBUG + { + int CWCount; + if (skew) + CWCount = 1558+620; + else + CWCount = bytes + rsblock * (bytes / datablock); + printf("Codewords (%i):",CWCount); + for (int posCur = 0;posCur < CWCount;posCur++) + printf(" %3i",binary[posCur]); + puts("\n"); + } + #endif + { // placement + int x, y, NC, NR, *places; + NC = W - 2 * (W / FW); + NR = H - 2 * (H / FH); + places = (int*)malloc(NC * NR * sizeof(int)); + ecc200placement(places, NR, NC); + grid = (unsigned char*)malloc(W * H); + memset(grid, 0, W * H); + for (y = 0; y < H; y += FH) { + for (x = 0; x < W; x++) + grid[y * W + x] = 1; + for (x = 0; x < W; x += 2) + grid[(y + FH - 1) * W + x] = 1; + } + for (x = 0; x < W; x += FW) { + for (y = 0; y < H; y++) + grid[y * W + x] = 1; + for (y = 0; y < H; y += 2) + grid[y * W + x + FW - 1] = 1; + } + #ifdef DEBUG + // Print position matrix as in standard + for (y = NR-1; y >= 0; y--) { + for (x = 0; x < NC; x++) { + if (x != 0) + fprintf (stderr, "|"); + int v = places[(NR - y - 1) * NC + x]; + fprintf(stderr,"%3d.%2d",(v>>3),8-(v&7)); + } + fprintf (stderr, "\n"); + } + #endif + for (y = 0; y < NR; y++) { + for (x = 0; x < NC; x++) { + int v = places[(NR - y - 1) * NC + x]; + //fprintf (stderr, "%4d", v); + if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))) + grid[(1 + y + 2 * (y / (FH - 2))) * W + 1 + x + 2 * (x / (FW - 2))] = 1; + } + //fprintf (stderr, "\n"); + } + for(y = H - 1; y >= 0; y--) { + int x; + for(x = 0; x < W; x++) { + if(grid[W * y + x]) { + set_module(symbol, (H - y) - 1, x); + } + } + symbol->row_height[(H - y) - 1] = 1; + } + free(grid); + free(places); + } + + symbol->rows = H; + symbol->width = W; + + return error_number; +} + +int dmatrix(struct zint_symbol *symbol, unsigned char source[], int length) +{ + int error_number; + + if(symbol->option_1 <= 1) { + /* ECC 200 */ + error_number = data_matrix_200(symbol, source, length); + } else { + /* ECC 000 - 140 */ + strcpy(symbol->errtxt, "Older Data Matrix standards are no longer supported"); + error_number = ZINT_ERROR_INVALID_OPTION; + } + + return error_number; +} diff --git a/backend/png.c b/backend/png.c index 2ac2f5e7..cf2b7984 100644 --- a/backend/png.c +++ b/backend/png.c @@ -1,1165 +1,1165 @@ -/* png.c - Handles output to PNG file */ - -/* - libzint - the open source barcode library - Copyright (C) 2009 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. -*/ - -#include -#ifdef _MSC_VER -#include -#include -#endif -#include -#include -#include "common.h" - -#ifdef _MSC_VER -#include -#endif /* _MSC_VER */ - -#ifndef NO_PNG -#include -#include -#include -#endif /* NO_PNG */ -#include "maxipng.h" /* Maxicode shapes */ - -#include "font.h" /* Font for human readable text */ - -#define SSET "0123456789ABCDEF" - -#define PNG_DATA 100 -#define BMP_DATA 200 - -#ifndef NO_PNG -struct mainprog_info_type { - long width; - long height; - FILE *outfile; - jmp_buf jmpbuf; -}; - -static void writepng_error_handler(png_structp png_ptr, png_const_charp msg) -{ - struct mainprog_info_type *graphic; - - fprintf(stderr, "writepng libpng error: %s\n", msg); - fflush(stderr); - - graphic = (struct mainprog_info_type*)png_get_error_ptr(png_ptr); - if (graphic == NULL) { /* we are completely hosed now */ - fprintf(stderr, - "writepng severe error: jmpbuf not recoverable; terminating.\n"); - fflush(stderr); - return; - } - longjmp(graphic->jmpbuf, 1); -} - -int png_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle) -{ - struct mainprog_info_type wpng_info; - struct mainprog_info_type *graphic; - png_structp png_ptr; - png_infop info_ptr; - unsigned char *image_data; - int i, row, column, errno; - int fgred, fggrn, fgblu, bgred, bggrn, bgblu; - -#ifndef _MSC_VER - unsigned char outdata[image_width * 3]; -#else - unsigned char* outdata = (unsigned char*)_alloca(image_width * 3); -#endif - - graphic = &wpng_info; - - switch(rotate_angle) { - case 0: - case 180: - graphic->width = image_width; - graphic->height = image_height; - break; - case 90: - case 270: - graphic->width = image_height; - graphic->height = image_width; - break; - } - - /* sort out colour options */ - to_upper((unsigned char*)symbol->fgcolour); - to_upper((unsigned char*)symbol->bgcolour); - - if(strlen(symbol->fgcolour) != 6) { - strcpy(symbol->errtxt, "Malformed foreground colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - if(strlen(symbol->bgcolour) != 6) { - strcpy(symbol->errtxt, "Malformed background colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - errno = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour)); - if (errno == ZINT_ERROR_INVALID_DATA) { - strcpy(symbol->errtxt, "Malformed foreground colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - errno = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->bgcolour)); - if (errno == ZINT_ERROR_INVALID_DATA) { - strcpy(symbol->errtxt, "Malformed background colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - - fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); - fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); - fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); - bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); - bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); - bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); - - /* Open output file in binary mode */ - if((symbol->output_options & BARCODE_STDOUT) != 0) { -#ifdef _MSC_VER - if (-1 == _setmode(_fileno(stdout), _O_BINARY)) { - strcpy(symbol->errtxt, "Can't open output file"); - return ZINT_ERROR_FILE_ACCESS; - } -#endif - graphic->outfile = stdout; - } else { - if (!(graphic->outfile = fopen(symbol->outfile, "wb"))) { - strcpy(symbol->errtxt, "Can't open output file"); - return ZINT_ERROR_FILE_ACCESS; - } - } - - /* Set up error handling routine as proc() above */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, graphic, writepng_error_handler, NULL); - if (!png_ptr) { - strcpy(symbol->errtxt, "Out of memory"); - return ZINT_ERROR_MEMORY; - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, NULL); - strcpy(symbol->errtxt, "Out of memory"); - return ZINT_ERROR_MEMORY; - } - - /* catch jumping here */ - if (setjmp(graphic->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - strcpy(symbol->errtxt, "libpng error occurred"); - return ZINT_ERROR_MEMORY; - } - - /* open output file with libpng */ - png_init_io(png_ptr, graphic->outfile); - - /* set compression */ - png_set_compression_level(png_ptr,9); - - /* set Header block */ - png_set_IHDR(png_ptr, info_ptr, graphic->width, graphic->height, - 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - /* write all chunks up to (but not including) first IDAT */ - png_write_info(png_ptr, info_ptr); - - /* set up the transformations: for now, just pack low-bit-depth pixels - into bytes (one, two or four pixels per byte) */ - png_set_packing(png_ptr); - - /* Pixel Plotting */ - - switch(rotate_angle) { - case 0: /* Plot the right way up */ - for(row = 0; row < image_height; row++) { - for(column = 0; column < image_width; column++) { - i = column * 3; - switch(*(pixelbuf + (image_width * row) + column)) - { - case '1': - outdata[i] = fgred; - outdata[i + 1] = fggrn; - outdata[i + 2] = fgblu; - break; - default: - outdata[i] = bgred; - outdata[i + 1] = bggrn; - outdata[i + 2] = bgblu; - break; - - } - } - /* write row contents to file */ - image_data = outdata; - png_write_row(png_ptr, image_data); - } - break; - case 90: /* Plot 90 degrees clockwise */ - for(row = 0; row < image_width; row++) { - for(column = 0; column < image_height; column++) { - i = column * 3; - switch(*(pixelbuf + (image_width * (image_height - column - 1)) + row)) - { - case '1': - outdata[i] = fgred; - outdata[i + 1] = fggrn; - outdata[i + 2] = fgblu; - break; - default: - outdata[i] = bgred; - outdata[i + 1] = bggrn; - outdata[i + 2] = bgblu; - break; - - } - } - - /* write row contents to file */ - image_data = outdata; - png_write_row(png_ptr, image_data); - } - break; - case 180: /* Plot upside down */ - for(row = 0; row < image_height; row++) { - for(column = 0; column < image_width; column++) { - i = column * 3; - switch(*(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1))) - { - case '1': - outdata[i] = fgred; - outdata[i + 1] = fggrn; - outdata[i + 2] = fgblu; - break; - default: - outdata[i] = bgred; - outdata[i + 1] = bggrn; - outdata[i + 2] = bgblu; - break; - - } - } - - /* write row contents to file */ - image_data = outdata; - png_write_row(png_ptr, image_data); - } - break; - case 270: /* Plot 90 degrees anti-clockwise */ - for(row = 0; row < image_width; row++) { - for(column = 0; column < image_height; column++) { - i = column * 3; - switch(*(pixelbuf + (image_width * column) + (image_width - row - 1))) - { - case '1': - outdata[i] = fgred; - outdata[i + 1] = fggrn; - outdata[i + 2] = fgblu; - break; - default: - outdata[i] = bgred; - outdata[i + 1] = bggrn; - outdata[i + 2] = bgblu; - break; - - } - } - - /* write row contents to file */ - image_data = outdata; - png_write_row(png_ptr, image_data); - } - break; - } - - /* End the file */ - png_write_end(png_ptr, NULL); - - /* make sure we have disengaged */ - if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); - if(symbol->output_options & BARCODE_STDOUT) { - fflush(wpng_info.outfile); - } else { - fclose(wpng_info.outfile); - } - return 0; -} -#endif /* NO_PNG */ - -int bmp_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle) -{ - int i, row, column, errno; - int fgred, fggrn, fgblu, bgred, bggrn, bgblu; - - switch(rotate_angle) { - case 0: - case 180: - symbol->bitmap_width = image_width; - symbol->bitmap_height = image_height; - break; - case 90: - case 270: - symbol->bitmap_width = image_height; - symbol->bitmap_height = image_width; - break; - } - - if (symbol->bitmap != NULL) - free(symbol->bitmap); - - symbol->bitmap = (char *) malloc(image_width * image_height * 3); - - - /* sort out colour options */ - to_upper((unsigned char*)symbol->fgcolour); - to_upper((unsigned char*)symbol->bgcolour); - - if(strlen(symbol->fgcolour) != 6) { - strcpy(symbol->errtxt, "Malformed foreground colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - if(strlen(symbol->bgcolour) != 6) { - strcpy(symbol->errtxt, "Malformed background colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - errno = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour)); - if (errno == ZINT_ERROR_INVALID_DATA) { - strcpy(symbol->errtxt, "Malformed foreground colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - errno = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->fgcolour)); - if (errno == ZINT_ERROR_INVALID_DATA) { - strcpy(symbol->errtxt, "Malformed background colour target"); - return ZINT_ERROR_INVALID_OPTION; - } - - fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); - fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); - fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); - bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); - bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); - bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); - - /* Pixel Plotting */ - i = 0; - switch(rotate_angle) { - case 0: /* Plot the right way up */ - for(row = 0; row < image_height; row++) { - for(column = 0; column < image_width; column++) { - switch(*(pixelbuf + (image_width * row) + column)) - { - case '1': - symbol->bitmap[i++] = fgred; - symbol->bitmap[i++] = fggrn; - symbol->bitmap[i++] = fgblu; - break; - default: - symbol->bitmap[i++] = bgred; - symbol->bitmap[i++] = bggrn; - symbol->bitmap[i++] = bgblu; - break; - - } - } - } - break; - case 90: /* Plot 90 degrees clockwise */ - for(row = 0; row < image_width; row++) { - for(column = 0; column < image_height; column++) { - switch(*(pixelbuf + (image_width * (image_height - column - 1)) + row)) - { - case '1': - symbol->bitmap[i++] = fgred; - symbol->bitmap[i++] = fggrn; - symbol->bitmap[i++] = fgblu; - break; - default: - symbol->bitmap[i++] = bgred; - symbol->bitmap[i++] = bggrn; - symbol->bitmap[i++] = bgblu; - break; - - } - } - } - break; - case 180: /* Plot upside down */ - for(row = 0; row < image_height; row++) { - for(column = 0; column < image_width; column++) { - switch(*(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1))) - { - case '1': - symbol->bitmap[i++] = fgred; - symbol->bitmap[i++] = fggrn; - symbol->bitmap[i++] = fgblu; - break; - default: - symbol->bitmap[i++] = bgred; - symbol->bitmap[i++] = bggrn; - symbol->bitmap[i++] = bgblu; - break; - - } - } - } - break; - case 270: /* Plot 90 degrees anti-clockwise */ - for(row = 0; row < image_width; row++) { - for(column = 0; column < image_height; column++) { - switch(*(pixelbuf + (image_width * column) + (image_width - row - 1))) - { - case '1': - symbol->bitmap[i++] = fgred; - symbol->bitmap[i++] = fggrn; - symbol->bitmap[i++] = fgblu; - break; - default: - symbol->bitmap[i++] = bgred; - symbol->bitmap[i++] = bggrn; - symbol->bitmap[i++] = bgblu; - break; - - } - } - } - break; - } - - return 0; -} - -int png_to_file(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle, int image_type) -{ - int error_number; - float scaler = symbol->scale; - char *scaled_pixelbuf; - int horiz, vert, i; - int scale_width, scale_height; - - if(scaler == 0) { scaler = 0.5; } - scale_width = image_width * scaler; - scale_height = image_height * scaler; - - /* Apply scale options by creating another pixel buffer */ - if (!(scaled_pixelbuf = (char *) malloc(scale_width * scale_height))) { - printf("Insufficient memory for pixel buffer"); - return ZINT_ERROR_ENCODING_PROBLEM; - } else { - for(i = 0; i < (scale_width * scale_height); i++) { - *(scaled_pixelbuf + i) = '0'; - } - } - - for(vert = 0; vert < scale_height; vert++) { - for(horiz = 0; horiz < scale_width; horiz++) { - *(scaled_pixelbuf + (vert * scale_width) + horiz) = *(pixelbuf + ((int)(vert / scaler) * image_width) + (int)(horiz / scaler)); - } - } - - if(image_type == PNG_DATA) { -#ifndef NO_PNG - error_number = png_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); -#else - return ZINT_ERROR_INVALID_OPTION; -#endif - } else { - error_number = bmp_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); - } - - free(scaled_pixelbuf); - - return error_number; -} - -void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_width, int image_height) -{ - /* Draw a rectangle */ - int i, j, png_ypos; - - png_ypos = image_height - ypos - ylen; - /* This fudge is needed because EPS measures height from the bottom up but - PNG measures y position from the top down */ - - for(i = (xpos); i < (xpos + xlen); i++) { - for( j = (png_ypos); j < (png_ypos + ylen); j++) { - *(pixelbuf + (image_width * j) + i) = '1'; - } - } -} - -int bullseye_pixel(int row, int col) { - int block_val, block_pos, return_val; - - block_val = bullseye_compressed[(row * 12) + (col / 8)]; - return_val = 0; - block_pos = col % 8; - - switch(block_pos) { - case 0: if((block_val & 0x80) != 0) { return_val = 1; } break; - case 1: if((block_val & 0x40) != 0) { return_val = 1; } break; - case 2: if((block_val & 0x20) != 0) { return_val = 1; } break; - case 3: if((block_val & 0x10) != 0) { return_val = 1; } break; - case 4: if((block_val & 0x08) != 0) { return_val = 1; } break; - case 5: if((block_val & 0x04) != 0) { return_val = 1; } break; - case 6: if((block_val & 0x02) != 0) { return_val = 1; } break; - case 7: if((block_val & 0x01) != 0) { return_val = 1; } break; - } - - return return_val; -} - -void draw_bullseye(char *pixelbuf, int image_width, int xoffset, int yoffset) -{ - /* Central bullseye in Maxicode symbols */ - int i, j; - - for(j = 103; j < 196; j++) { - for(i = 0; i < 93; i++) { - if(bullseye_pixel(j - 103, i)) { - /* if(bullseye[(((j - 103) * 93) + i)] == 1) { */ - *(pixelbuf + (image_width * j) + (image_width * yoffset) + i + 99 + xoffset) = '1'; - } - } - } -} - -void draw_hexagon(char *pixelbuf, int image_width, int xposn, int yposn) -{ - /* Put a hexagon into the pixel buffer */ - int i, j; - - for(i = 0; i < 12; i++) { - for(j = 0; j < 10; j++) { - if(hexagon[(i * 10) + j] == 1) { - *(pixelbuf + (image_width * i) + (image_width * yposn) + xposn + j) = '1'; - } - } - } -} - -void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int smalltext, int image_width, int image_height) -{ - /* Put a letter into a position */ - int skip, i, j, glyph_no, alphabet; - - skip = 0; - alphabet = 0; - - if(letter < 33) { skip = 1; } - if((letter > 127) && (letter < 161)) { skip = 1; } - - if(skip == 0) { - if(letter > 128) { - alphabet = 1; - glyph_no = letter - 161; - } else { - glyph_no = letter - 33; - } - - if(smalltext) { - for(i = 0; i <= 8; i++) { - for(j = 0; j < 5; j++) { - if(alphabet == 0) { - if(small_font[(glyph_no * 5) + (i * 475) + j - 1] == 1) { - *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; - } - } else { - if(small_font_extended[(glyph_no * 5) + (i * 475) + j - 1] == 1) { - *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; - } - } - } - } - } else { - for(i = 0; i <= 13; i++) { - for(j = 0; j < 7 ; j++) { - if(alphabet == 0) { - if(ascii_font[(glyph_no * 7) + (i * 665) + j - 1] == 1) { - *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; - } - } else { - if(ascii_ext_font[(glyph_no * 7) + (i * 665) + j - 1] == 1) { - *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; - } - } - } - } - } - } -} - -void draw_string(char *pixbuf, char input_string[], int xposn, int yposn, int smalltext, int image_width, int image_height) -{ - /* Plot a string into the pixel buffer */ - int i, string_length, string_left_hand; - - string_length = strlen(input_string); - string_left_hand = xposn - ((7 * string_length) / 2); - - for(i = 0; i < string_length; i++) { - draw_letter(pixbuf, input_string[i], string_left_hand + (i * 7), yposn, smalltext, image_width, image_height); - } - -} - -int maxi_png_plot(struct zint_symbol *symbol, int rotate_angle, int data_type) -{ - int i, row, column, xposn, yposn; - int image_height, image_width; - char *pixelbuf; - int error_number; - int xoffset, yoffset; - - xoffset = symbol->border_width + symbol->whitespace_width; - yoffset = symbol->border_width; - image_width = 300 + (2 * xoffset * 2); - image_height = 300 + (2 * yoffset * 2); - - if (!(pixelbuf = (char *) malloc(image_width * image_height))) { - printf("Insifficient memory for pixel buffer"); - return ZINT_ERROR_ENCODING_PROBLEM; - } else { - for(i = 0; i < (image_width * image_height); i++) { - *(pixelbuf + i) = '0'; - } - } - - draw_bullseye(pixelbuf, image_width, (2 * xoffset), (2 * yoffset)); - - for(row = 0; row < symbol->rows; row++) { - yposn = row * 9; - for(column = 0; column < symbol->width; column++) { - xposn = column * 10; - if(module_is_set(symbol, row, column)) { - if(row & 1) { - /* Odd (reduced) row */ - xposn += 5; - draw_hexagon(pixelbuf, image_width, xposn + (2 * xoffset), yposn + (2 * yoffset)); - } else { - /* Even (full) row */ - draw_hexagon(pixelbuf, image_width, xposn + (2 * xoffset), yposn + (2 * yoffset)); - } - } - } - } - - if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) { - /* 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); - } - - if((symbol->output_options & BARCODE_BOX) != 0) { - /* 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); - } - - error_number=png_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type); - free(pixelbuf); - return error_number; -} - -/* Convert UTF-8 to Latin1 Codepage for the interpretation line */ -void to_latin1(unsigned char source[], unsigned char preprocessed[]) -{ - int j, i, input_length; - - input_length = ustrlen(source); - - j = 0; - i = 0; - while (i < input_length) { - switch (source[i]) { - case 0xC2: - /* UTF-8 C2xxh */ - /* Character range: C280h (latin: 80h) to C2BFh (latin: BFh) */ - i++; - preprocessed[j] = source[i]; - j++; - break; - case 0xC3: - /* UTF-8 C3xx */ - /* Character range: C380h (latin: C0h) to C3BFh (latin: FFh) */ - i++; - preprocessed[j] = source[i] + 64; - j++; - break; - default: - /* Process ASCII (< 80h), all other unicode points are ignored */ - if(source[i] < 128) { - preprocessed[j] = source[i]; - j++; - } - break; - } - i++; - } - preprocessed[j] = '\0'; - - return; -} - -int png_plot(struct zint_symbol *symbol, int rotate_angle, int data_type) -{ - int textdone, main_width, comp_offset, large_bar_count; - char textpart[10], addon[6]; - float addon_text_posn, preset_height, large_bar_height; - int i, r, textoffset, yoffset, xoffset, latch, image_width, image_height; - char *pixelbuf; - int addon_latch = 0, smalltext = 0; - int this_row, block_width, plot_height, plot_yposn, textpos; - float row_height, row_posn; - int error_number; - int default_text_posn; - int next_yposn; -#ifndef _MSC_VER - unsigned char local_text[ustrlen(symbol->text) + 1]; -#else - unsigned char* local_text = (unsigned char*)_alloca(ustrlen(symbol->text) + 1); -#endif - - if(symbol->show_hrt != 0) { - to_latin1(symbol->text, local_text); - } else { - local_text[0] = '\0'; - } - - textdone = 0; - main_width = symbol->width; - strcpy(addon, ""); - comp_offset = 0; - addon_text_posn = 0.0; - row_height = 0; - if(symbol->output_options & SMALL_TEXT) { - smalltext = 1; - } - - if (symbol->height == 0) { - symbol->height = 50; - } - - large_bar_count = 0; - preset_height = 0.0; - for(i = 0; i < symbol->rows; i++) { - preset_height += symbol->row_height[i]; - if(symbol->row_height[i] == 0) { - large_bar_count++; - } - } - - if (large_bar_count == 0) { - symbol->height = preset_height; - large_bar_height = 10; - } else { - large_bar_height = (symbol->height - preset_height) / large_bar_count; - } - - while(!(module_is_set(symbol, symbol->rows - 1, comp_offset))) { - comp_offset++; - } - - /* Certain symbols need whitespace otherwise characters get chopped off the sides */ - if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC)) - || (symbol->symbology == BARCODE_ISBNX)) { - switch(ustrlen(local_text)) { - case 13: /* EAN 13 */ - case 16: - case 19: - if(symbol->whitespace_width == 0) { - symbol->whitespace_width = 10; - } - main_width = 96 + comp_offset; - break; - default: - main_width = 68 + comp_offset; - } - } - - if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) { - if(symbol->whitespace_width == 0) { - symbol->whitespace_width = 10; - main_width = 96 + comp_offset; - } - } - - if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) { - if(symbol->whitespace_width == 0) { - symbol->whitespace_width = 10; - main_width = 51 + comp_offset; - } - } - - latch = 0; - r = 0; - /* Isolate add-on text */ - if(is_extendable(symbol->symbology)) { - for(i = 0; i < ustrlen(local_text); i++) { - if (latch == 1) { - addon[r] = local_text[i]; - r++; - } - if (symbol->text[i] == '+') { - latch = 1; - } - } - } - addon[r] = '\0'; - - if(ustrlen(local_text) != 0) { - textoffset = 9; - } else { - textoffset = 0; - } - xoffset = symbol->border_width + symbol->whitespace_width; - yoffset = symbol->border_width; - image_width = 2 * (symbol->width + xoffset + xoffset); - image_height = 2 * (symbol->height + textoffset + yoffset + yoffset); - - if (!(pixelbuf = (char *) malloc(image_width * image_height))) { - printf("Insufficient memory for pixel buffer"); - return ZINT_ERROR_ENCODING_PROBLEM; - } else { - for(i = 0; i < (image_width * image_height); i++) { - *(pixelbuf + i) = '0'; - } - } - - if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) { - default_text_posn = image_height - 17; - } else { - default_text_posn = image_height - 17 - symbol->border_width - symbol->border_width; - } - - row_posn = textoffset + yoffset; - next_yposn = textoffset + yoffset; - row_height = 0; - - /* Plot the body of the symbol to the pixel buffer */ - for(r = 0; r < symbol->rows; r++) { - this_row = symbol->rows - r - 1; /* invert r otherwise plots upside down */ - row_posn += row_height; - plot_yposn = next_yposn; - if(symbol->row_height[this_row] == 0) { - row_height = large_bar_height; - } else { - row_height = symbol->row_height[this_row]; - } - next_yposn = (int)(row_posn + row_height); - plot_height = next_yposn - plot_yposn; - - i = 0; - if(module_is_set(symbol, this_row, 0)) { - latch = 1; - } else { - latch = 0; - } - - do { - block_width = 0; - do { - block_width++; - } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i)); - 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) { - /* 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; - } - i += block_width; - - } while (i < symbol->width); - } - - xoffset += comp_offset; - - if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC)) || (symbol->symbology == BARCODE_ISBNX)) { - /* guard bar extensions and text formatting for EAN8 and EAN13 */ - switch(ustrlen(local_text)) { - 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); - for(i = 0; i < 4; i++) { - textpart[i] = symbol->text[i]; - } - textpart[4] = '\0'; - textpos = 2 * (17 + xoffset); - - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - for(i = 0; i < 4; i++) { - textpart[i] = symbol->text[i + 4]; - } - textpart[4] = '\0'; - textpos = 2 * (50 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - textdone = 1; - switch(strlen(addon)) { - case 2: - textpos = 2 * (xoffset + 86); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - case 5: - textpos = 2 * (xoffset + 100); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - } - - break; - 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); - - textpart[0] = symbol->text[0]; - textpart[1] = '\0'; - textpos = 2 * (-7 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - for(i = 0; i < 6; i++) { - textpart[i] = symbol->text[i + 1]; - } - textpart[6] = '\0'; - textpos = 2 * (24 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - for(i = 0; i < 6; i++) { - textpart[i] = symbol->text[i + 7]; - } - textpart[6] = '\0'; - textpos = 2 * (71 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - textdone = 1; - switch(strlen(addon)) { - case 2: - textpos = 2 * (xoffset + 114); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - case 5: - textpos = 2 * (xoffset + 128); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - } - break; - - } - } - - if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) { - /* guard bar extensions and text formatting for UPCA */ - latch = 1; - - i = 0 + comp_offset; - do { - block_width = 0; - do { - block_width++; - } 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); - latch = 0; - } else { - /* a space */ - latch = 1; - } - 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); - latch = 1; - i = 85 + comp_offset; - do { - block_width = 0; - do { - block_width++; - } 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); - latch = 0; - } else { - /* a space */ - latch = 1; - } - i += block_width; - } while (i < 96 + comp_offset); - textpart[0] = symbol->text[0]; - textpart[1] = '\0'; - textpos = 2 * (-5 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - for(i = 0; i < 5; i++) { - textpart[i] = symbol->text[i + 1]; - } - textpart[5] = '\0'; - textpos = 2 * (27 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - for(i = 0; i < 5; i++) { - textpart[i] = symbol->text[i + 6]; - } - textpart[6] = '\0'; - textpos = 2 * (68 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - textpart[0] = symbol->text[11]; - textpart[1] = '\0'; - textpos = 2 * (100 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - textdone = 1; - switch(strlen(addon)) { - case 2: - textpos = 2 * (xoffset + 116); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - case 5: - textpos = 2 * (xoffset + 130); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - } - - } - - if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (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); - - textpart[0] = symbol->text[0]; - textpart[1] = '\0'; - textpos = 2 * (-5 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - for(i = 0; i < 6; i++) { - textpart[i] = symbol->text[i + 1]; - } - textpart[6] = '\0'; - textpos = 2 * (24 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - textpart[0] = symbol->text[7]; - textpart[1] = '\0'; - textpos = 2 * (55 + xoffset); - draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); - textdone = 1; - switch(strlen(addon)) { - case 2: - textpos = 2 * (xoffset + 70); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - case 5: - textpos = 2 * (xoffset + 84); - draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); - break; - } - - } - - xoffset -= comp_offset; - - /* Put boundary bars or box around symbol */ - if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) { - /* boundary bars */ - 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); - if((symbol->output_options & BARCODE_BIND) != 0) { - if((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) { - /* row binding */ - 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); - } - } - } - } - - if((symbol->output_options & BARCODE_BOX) != 0) { - /* 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); - } - - /* Put the human readable text at the bottom */ - if((textdone == 0) && (ustrlen(local_text) != 0)) { - textpos = (image_width / 2); - draw_string(pixelbuf, (char*)local_text, textpos, default_text_posn, smalltext, image_width, image_height); - } - - error_number=png_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type); - free(pixelbuf); - return error_number; -} - -#ifndef NO_PNG -int png_handle(struct zint_symbol *symbol, int rotate_angle) -{ - int error; - - if(symbol->symbology == BARCODE_MAXICODE) { - error = maxi_png_plot(symbol, rotate_angle, PNG_DATA); - } else { - - error = png_plot(symbol, rotate_angle, PNG_DATA); - } - - return error; -} -#endif /* NO_PNG */ - -int bmp_handle(struct zint_symbol *symbol, int rotate_angle) -{ - int error; - - if(symbol->symbology == BARCODE_MAXICODE) { - error = maxi_png_plot(symbol, rotate_angle, BMP_DATA); - } else { - error = png_plot(symbol, rotate_angle, BMP_DATA); - } - - return error; -} - +/* png.c - Handles output to PNG file */ + +/* + libzint - the open source barcode library + Copyright (C) 2009 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. +*/ + +#include +#ifdef _MSC_VER +#include +#include +#endif +#include +#include +#include "common.h" + +#ifdef _MSC_VER +#include +#endif /* _MSC_VER */ + +#ifndef NO_PNG +#include +#include +#include +#endif /* NO_PNG */ +#include "maxipng.h" /* Maxicode shapes */ + +#include "font.h" /* Font for human readable text */ + +#define SSET "0123456789ABCDEF" + +#define PNG_DATA 100 +#define BMP_DATA 200 + +#ifndef NO_PNG +struct mainprog_info_type { + long width; + long height; + FILE *outfile; + jmp_buf jmpbuf; +}; + +static void writepng_error_handler(png_structp png_ptr, png_const_charp msg) +{ + struct mainprog_info_type *graphic; + + fprintf(stderr, "writepng libpng error: %s\n", msg); + fflush(stderr); + + graphic = (struct mainprog_info_type*)png_get_error_ptr(png_ptr); + if (graphic == NULL) { /* we are completely hosed now */ + fprintf(stderr, + "writepng severe error: jmpbuf not recoverable; terminating.\n"); + fflush(stderr); + return; + } + longjmp(graphic->jmpbuf, 1); +} + +int png_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle) +{ + struct mainprog_info_type wpng_info; + struct mainprog_info_type *graphic; + png_structp png_ptr; + png_infop info_ptr; + unsigned char *image_data; + int i, row, column, errno; + int fgred, fggrn, fgblu, bgred, bggrn, bgblu; + +#ifndef _MSC_VER + unsigned char outdata[image_width * 3]; +#else + unsigned char* outdata = (unsigned char*)_alloca(image_width * 3); +#endif + + graphic = &wpng_info; + + switch(rotate_angle) { + case 0: + case 180: + graphic->width = image_width; + graphic->height = image_height; + break; + case 90: + case 270: + graphic->width = image_height; + graphic->height = image_width; + break; + } + + /* sort out colour options */ + to_upper((unsigned char*)symbol->fgcolour); + to_upper((unsigned char*)symbol->bgcolour); + + if(strlen(symbol->fgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + if(strlen(symbol->bgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->bgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + + fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); + fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); + fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); + bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); + bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); + bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); + + /* Open output file in binary mode */ + if((symbol->output_options & BARCODE_STDOUT) != 0) { +#ifdef _MSC_VER + if (-1 == _setmode(_fileno(stdout), _O_BINARY)) { + strcpy(symbol->errtxt, "Can't open output file"); + return ZINT_ERROR_FILE_ACCESS; + } +#endif + graphic->outfile = stdout; + } else { + if (!(graphic->outfile = fopen(symbol->outfile, "wb"))) { + strcpy(symbol->errtxt, "Can't open output file"); + return ZINT_ERROR_FILE_ACCESS; + } + } + + /* Set up error handling routine as proc() above */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, graphic, writepng_error_handler, NULL); + if (!png_ptr) { + strcpy(symbol->errtxt, "Out of memory"); + return ZINT_ERROR_MEMORY; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + strcpy(symbol->errtxt, "Out of memory"); + return ZINT_ERROR_MEMORY; + } + + /* catch jumping here */ + if (setjmp(graphic->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + strcpy(symbol->errtxt, "libpng error occurred"); + return ZINT_ERROR_MEMORY; + } + + /* open output file with libpng */ + png_init_io(png_ptr, graphic->outfile); + + /* set compression */ + png_set_compression_level(png_ptr,9); + + /* set Header block */ + png_set_IHDR(png_ptr, info_ptr, graphic->width, graphic->height, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + /* write all chunks up to (but not including) first IDAT */ + png_write_info(png_ptr, info_ptr); + + /* set up the transformations: for now, just pack low-bit-depth pixels + into bytes (one, two or four pixels per byte) */ + png_set_packing(png_ptr); + + /* Pixel Plotting */ + + switch(rotate_angle) { + case 0: /* Plot the right way up */ + for(row = 0; row < image_height; row++) { + for(column = 0; column < image_width; column++) { + i = column * 3; + switch(*(pixelbuf + (image_width * row) + column)) + { + case '1': + outdata[i] = fgred; + outdata[i + 1] = fggrn; + outdata[i + 2] = fgblu; + break; + default: + outdata[i] = bgred; + outdata[i + 1] = bggrn; + outdata[i + 2] = bgblu; + break; + + } + } + /* write row contents to file */ + image_data = outdata; + png_write_row(png_ptr, image_data); + } + break; + case 90: /* Plot 90 degrees clockwise */ + for(row = 0; row < image_width; row++) { + for(column = 0; column < image_height; column++) { + i = column * 3; + switch(*(pixelbuf + (image_width * (image_height - column - 1)) + row)) + { + case '1': + outdata[i] = fgred; + outdata[i + 1] = fggrn; + outdata[i + 2] = fgblu; + break; + default: + outdata[i] = bgred; + outdata[i + 1] = bggrn; + outdata[i + 2] = bgblu; + break; + + } + } + + /* write row contents to file */ + image_data = outdata; + png_write_row(png_ptr, image_data); + } + break; + case 180: /* Plot upside down */ + for(row = 0; row < image_height; row++) { + for(column = 0; column < image_width; column++) { + i = column * 3; + switch(*(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1))) + { + case '1': + outdata[i] = fgred; + outdata[i + 1] = fggrn; + outdata[i + 2] = fgblu; + break; + default: + outdata[i] = bgred; + outdata[i + 1] = bggrn; + outdata[i + 2] = bgblu; + break; + + } + } + + /* write row contents to file */ + image_data = outdata; + png_write_row(png_ptr, image_data); + } + break; + case 270: /* Plot 90 degrees anti-clockwise */ + for(row = 0; row < image_width; row++) { + for(column = 0; column < image_height; column++) { + i = column * 3; + switch(*(pixelbuf + (image_width * column) + (image_width - row - 1))) + { + case '1': + outdata[i] = fgred; + outdata[i + 1] = fggrn; + outdata[i + 2] = fgblu; + break; + default: + outdata[i] = bgred; + outdata[i + 1] = bggrn; + outdata[i + 2] = bgblu; + break; + + } + } + + /* write row contents to file */ + image_data = outdata; + png_write_row(png_ptr, image_data); + } + break; + } + + /* End the file */ + png_write_end(png_ptr, NULL); + + /* make sure we have disengaged */ + if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); + if(symbol->output_options & BARCODE_STDOUT) { + fflush(wpng_info.outfile); + } else { + fclose(wpng_info.outfile); + } + return 0; +} +#endif /* NO_PNG */ + +int bmp_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle) +{ + int i, row, column, errno; + int fgred, fggrn, fgblu, bgred, bggrn, bgblu; + + switch(rotate_angle) { + case 0: + case 180: + symbol->bitmap_width = image_width; + symbol->bitmap_height = image_height; + break; + case 90: + case 270: + symbol->bitmap_width = image_height; + symbol->bitmap_height = image_width; + break; + } + + if (symbol->bitmap != NULL) + free(symbol->bitmap); + + symbol->bitmap = (char *) malloc(image_width * image_height * 3); + + + /* sort out colour options */ + to_upper((unsigned char*)symbol->fgcolour); + to_upper((unsigned char*)symbol->bgcolour); + + if(strlen(symbol->fgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + if(strlen(symbol->bgcolour) != 6) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed foreground colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + errno = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->fgcolour)); + if (errno == ZINT_ERROR_INVALID_DATA) { + strcpy(symbol->errtxt, "Malformed background colour target"); + return ZINT_ERROR_INVALID_OPTION; + } + + fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); + fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); + fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]); + bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]); + bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]); + bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]); + + /* Pixel Plotting */ + i = 0; + switch(rotate_angle) { + case 0: /* Plot the right way up */ + for(row = 0; row < image_height; row++) { + for(column = 0; column < image_width; column++) { + switch(*(pixelbuf + (image_width * row) + column)) + { + case '1': + symbol->bitmap[i++] = fgred; + symbol->bitmap[i++] = fggrn; + symbol->bitmap[i++] = fgblu; + break; + default: + symbol->bitmap[i++] = bgred; + symbol->bitmap[i++] = bggrn; + symbol->bitmap[i++] = bgblu; + break; + + } + } + } + break; + case 90: /* Plot 90 degrees clockwise */ + for(row = 0; row < image_width; row++) { + for(column = 0; column < image_height; column++) { + switch(*(pixelbuf + (image_width * (image_height - column - 1)) + row)) + { + case '1': + symbol->bitmap[i++] = fgred; + symbol->bitmap[i++] = fggrn; + symbol->bitmap[i++] = fgblu; + break; + default: + symbol->bitmap[i++] = bgred; + symbol->bitmap[i++] = bggrn; + symbol->bitmap[i++] = bgblu; + break; + + } + } + } + break; + case 180: /* Plot upside down */ + for(row = 0; row < image_height; row++) { + for(column = 0; column < image_width; column++) { + switch(*(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1))) + { + case '1': + symbol->bitmap[i++] = fgred; + symbol->bitmap[i++] = fggrn; + symbol->bitmap[i++] = fgblu; + break; + default: + symbol->bitmap[i++] = bgred; + symbol->bitmap[i++] = bggrn; + symbol->bitmap[i++] = bgblu; + break; + + } + } + } + break; + case 270: /* Plot 90 degrees anti-clockwise */ + for(row = 0; row < image_width; row++) { + for(column = 0; column < image_height; column++) { + switch(*(pixelbuf + (image_width * column) + (image_width - row - 1))) + { + case '1': + symbol->bitmap[i++] = fgred; + symbol->bitmap[i++] = fggrn; + symbol->bitmap[i++] = fgblu; + break; + default: + symbol->bitmap[i++] = bgred; + symbol->bitmap[i++] = bggrn; + symbol->bitmap[i++] = bgblu; + break; + + } + } + } + break; + } + + return 0; +} + +int png_to_file(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle, int image_type) +{ + int error_number; + float scaler = symbol->scale; + char *scaled_pixelbuf; + int horiz, vert, i; + int scale_width, scale_height; + + if(scaler == 0) { scaler = 0.5; } + scale_width = image_width * scaler; + scale_height = image_height * scaler; + + /* Apply scale options by creating another pixel buffer */ + if (!(scaled_pixelbuf = (char *) malloc(scale_width * scale_height))) { + printf("Insufficient memory for pixel buffer"); + return ZINT_ERROR_ENCODING_PROBLEM; + } else { + for(i = 0; i < (scale_width * scale_height); i++) { + *(scaled_pixelbuf + i) = '0'; + } + } + + for(vert = 0; vert < scale_height; vert++) { + for(horiz = 0; horiz < scale_width; horiz++) { + *(scaled_pixelbuf + (vert * scale_width) + horiz) = *(pixelbuf + ((int)(vert / scaler) * image_width) + (int)(horiz / scaler)); + } + } + + if(image_type == PNG_DATA) { +#ifndef NO_PNG + error_number = png_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); +#else + return ZINT_ERROR_INVALID_OPTION; +#endif + } else { + error_number = bmp_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle); + } + + free(scaled_pixelbuf); + + return error_number; +} + +void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_width, int image_height) +{ + /* Draw a rectangle */ + int i, j, png_ypos; + + png_ypos = image_height - ypos - ylen; + /* This fudge is needed because EPS measures height from the bottom up but + PNG measures y position from the top down */ + + for(i = (xpos); i < (xpos + xlen); i++) { + for( j = (png_ypos); j < (png_ypos + ylen); j++) { + *(pixelbuf + (image_width * j) + i) = '1'; + } + } +} + +int bullseye_pixel(int row, int col) { + int block_val, block_pos, return_val; + + block_val = bullseye_compressed[(row * 12) + (col / 8)]; + return_val = 0; + block_pos = col % 8; + + switch(block_pos) { + case 0: if((block_val & 0x80) != 0) { return_val = 1; } break; + case 1: if((block_val & 0x40) != 0) { return_val = 1; } break; + case 2: if((block_val & 0x20) != 0) { return_val = 1; } break; + case 3: if((block_val & 0x10) != 0) { return_val = 1; } break; + case 4: if((block_val & 0x08) != 0) { return_val = 1; } break; + case 5: if((block_val & 0x04) != 0) { return_val = 1; } break; + case 6: if((block_val & 0x02) != 0) { return_val = 1; } break; + case 7: if((block_val & 0x01) != 0) { return_val = 1; } break; + } + + return return_val; +} + +void draw_bullseye(char *pixelbuf, int image_width, int xoffset, int yoffset) +{ + /* Central bullseye in Maxicode symbols */ + int i, j; + + for(j = 103; j < 196; j++) { + for(i = 0; i < 93; i++) { + if(bullseye_pixel(j - 103, i)) { + /* if(bullseye[(((j - 103) * 93) + i)] == 1) { */ + *(pixelbuf + (image_width * j) + (image_width * yoffset) + i + 99 + xoffset) = '1'; + } + } + } +} + +void draw_hexagon(char *pixelbuf, int image_width, int xposn, int yposn) +{ + /* Put a hexagon into the pixel buffer */ + int i, j; + + for(i = 0; i < 12; i++) { + for(j = 0; j < 10; j++) { + if(hexagon[(i * 10) + j] == 1) { + *(pixelbuf + (image_width * i) + (image_width * yposn) + xposn + j) = '1'; + } + } + } +} + +void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int smalltext, int image_width, int image_height) +{ + /* Put a letter into a position */ + int skip, i, j, glyph_no, alphabet; + + skip = 0; + alphabet = 0; + + if(letter < 33) { skip = 1; } + if((letter > 127) && (letter < 161)) { skip = 1; } + + if(skip == 0) { + if(letter > 128) { + alphabet = 1; + glyph_no = letter - 161; + } else { + glyph_no = letter - 33; + } + + if(smalltext) { + for(i = 0; i <= 8; i++) { + for(j = 0; j < 5; j++) { + if(alphabet == 0) { + if(small_font[(glyph_no * 5) + (i * 475) + j - 1] == 1) { + *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; + } + } else { + if(small_font_extended[(glyph_no * 5) + (i * 475) + j - 1] == 1) { + *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; + } + } + } + } + } else { + for(i = 0; i <= 13; i++) { + for(j = 0; j < 7 ; j++) { + if(alphabet == 0) { + if(ascii_font[(glyph_no * 7) + (i * 665) + j - 1] == 1) { + *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; + } + } else { + if(ascii_ext_font[(glyph_no * 7) + (i * 665) + j - 1] == 1) { + *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1'; + } + } + } + } + } + } +} + +void draw_string(char *pixbuf, char input_string[], int xposn, int yposn, int smalltext, int image_width, int image_height) +{ + /* Plot a string into the pixel buffer */ + int i, string_length, string_left_hand; + + string_length = strlen(input_string); + string_left_hand = xposn - ((7 * string_length) / 2); + + for(i = 0; i < string_length; i++) { + draw_letter(pixbuf, input_string[i], string_left_hand + (i * 7), yposn, smalltext, image_width, image_height); + } + +} + +int maxi_png_plot(struct zint_symbol *symbol, int rotate_angle, int data_type) +{ + int i, row, column, xposn, yposn; + int image_height, image_width; + char *pixelbuf; + int error_number; + int xoffset, yoffset; + + xoffset = symbol->border_width + symbol->whitespace_width; + yoffset = symbol->border_width; + image_width = 300 + (2 * xoffset * 2); + image_height = 300 + (2 * yoffset * 2); + + if (!(pixelbuf = (char *) malloc(image_width * image_height))) { + printf("Insifficient memory for pixel buffer"); + return ZINT_ERROR_ENCODING_PROBLEM; + } else { + for(i = 0; i < (image_width * image_height); i++) { + *(pixelbuf + i) = '0'; + } + } + + draw_bullseye(pixelbuf, image_width, (2 * xoffset), (2 * yoffset)); + + for(row = 0; row < symbol->rows; row++) { + yposn = row * 9; + for(column = 0; column < symbol->width; column++) { + xposn = column * 10; + if(module_is_set(symbol, row, column)) { + if(row & 1) { + /* Odd (reduced) row */ + xposn += 5; + draw_hexagon(pixelbuf, image_width, xposn + (2 * xoffset), yposn + (2 * yoffset)); + } else { + /* Even (full) row */ + draw_hexagon(pixelbuf, image_width, xposn + (2 * xoffset), yposn + (2 * yoffset)); + } + } + } + } + + if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) { + /* 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); + } + + if((symbol->output_options & BARCODE_BOX) != 0) { + /* 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); + } + + error_number=png_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type); + free(pixelbuf); + return error_number; +} + +/* Convert UTF-8 to Latin1 Codepage for the interpretation line */ +void to_latin1(unsigned char source[], unsigned char preprocessed[]) +{ + int j, i, input_length; + + input_length = ustrlen(source); + + j = 0; + i = 0; + while (i < input_length) { + switch (source[i]) { + case 0xC2: + /* UTF-8 C2xxh */ + /* Character range: C280h (latin: 80h) to C2BFh (latin: BFh) */ + i++; + preprocessed[j] = source[i]; + j++; + break; + case 0xC3: + /* UTF-8 C3xx */ + /* Character range: C380h (latin: C0h) to C3BFh (latin: FFh) */ + i++; + preprocessed[j] = source[i] + 64; + j++; + break; + default: + /* Process ASCII (< 80h), all other unicode points are ignored */ + if(source[i] < 128) { + preprocessed[j] = source[i]; + j++; + } + break; + } + i++; + } + preprocessed[j] = '\0'; + + return; +} + +int png_plot(struct zint_symbol *symbol, int rotate_angle, int data_type) +{ + int textdone, main_width, comp_offset, large_bar_count; + char textpart[10], addon[6]; + float addon_text_posn, preset_height, large_bar_height; + int i, r, textoffset, yoffset, xoffset, latch, image_width, image_height; + char *pixelbuf; + int addon_latch = 0, smalltext = 0; + int this_row, block_width, plot_height, plot_yposn, textpos; + float row_height, row_posn; + int error_number; + int default_text_posn; + int next_yposn; +#ifndef _MSC_VER + unsigned char local_text[ustrlen(symbol->text) + 1]; +#else + unsigned char* local_text = (unsigned char*)_alloca(ustrlen(symbol->text) + 1); +#endif + + if(symbol->show_hrt != 0) { + to_latin1(symbol->text, local_text); + } else { + local_text[0] = '\0'; + } + + textdone = 0; + main_width = symbol->width; + strcpy(addon, ""); + comp_offset = 0; + addon_text_posn = 0.0; + row_height = 0; + if(symbol->output_options & SMALL_TEXT) { + smalltext = 1; + } + + if (symbol->height == 0) { + symbol->height = 50; + } + + large_bar_count = 0; + preset_height = 0.0; + for(i = 0; i < symbol->rows; i++) { + preset_height += symbol->row_height[i]; + if(symbol->row_height[i] == 0) { + large_bar_count++; + } + } + + if (large_bar_count == 0) { + symbol->height = preset_height; + large_bar_height = 10; + } else { + large_bar_height = (symbol->height - preset_height) / large_bar_count; + } + + while(!(module_is_set(symbol, symbol->rows - 1, comp_offset))) { + comp_offset++; + } + + /* Certain symbols need whitespace otherwise characters get chopped off the sides */ + if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC)) + || (symbol->symbology == BARCODE_ISBNX)) { + switch(ustrlen(local_text)) { + case 13: /* EAN 13 */ + case 16: + case 19: + if(symbol->whitespace_width == 0) { + symbol->whitespace_width = 10; + } + main_width = 96 + comp_offset; + break; + default: + main_width = 68 + comp_offset; + } + } + + if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) { + if(symbol->whitespace_width == 0) { + symbol->whitespace_width = 10; + main_width = 96 + comp_offset; + } + } + + if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) { + if(symbol->whitespace_width == 0) { + symbol->whitespace_width = 10; + main_width = 51 + comp_offset; + } + } + + latch = 0; + r = 0; + /* Isolate add-on text */ + if(is_extendable(symbol->symbology)) { + for(i = 0; i < ustrlen(local_text); i++) { + if (latch == 1) { + addon[r] = local_text[i]; + r++; + } + if (symbol->text[i] == '+') { + latch = 1; + } + } + } + addon[r] = '\0'; + + if(ustrlen(local_text) != 0) { + textoffset = 9; + } else { + textoffset = 0; + } + xoffset = symbol->border_width + symbol->whitespace_width; + yoffset = symbol->border_width; + image_width = 2 * (symbol->width + xoffset + xoffset); + image_height = 2 * (symbol->height + textoffset + yoffset + yoffset); + + if (!(pixelbuf = (char *) malloc(image_width * image_height))) { + printf("Insufficient memory for pixel buffer"); + return ZINT_ERROR_ENCODING_PROBLEM; + } else { + for(i = 0; i < (image_width * image_height); i++) { + *(pixelbuf + i) = '0'; + } + } + + if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) { + default_text_posn = image_height - 17; + } else { + default_text_posn = image_height - 17 - symbol->border_width - symbol->border_width; + } + + row_posn = textoffset + yoffset; + next_yposn = textoffset + yoffset; + row_height = 0; + + /* Plot the body of the symbol to the pixel buffer */ + for(r = 0; r < symbol->rows; r++) { + this_row = symbol->rows - r - 1; /* invert r otherwise plots upside down */ + row_posn += row_height; + plot_yposn = next_yposn; + if(symbol->row_height[this_row] == 0) { + row_height = large_bar_height; + } else { + row_height = symbol->row_height[this_row]; + } + next_yposn = (int)(row_posn + row_height); + plot_height = next_yposn - plot_yposn; + + i = 0; + if(module_is_set(symbol, this_row, 0)) { + latch = 1; + } else { + latch = 0; + } + + do { + block_width = 0; + do { + block_width++; + } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i)); + 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) { + /* 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; + } + i += block_width; + + } while (i < symbol->width); + } + + xoffset += comp_offset; + + if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC)) || (symbol->symbology == BARCODE_ISBNX)) { + /* guard bar extensions and text formatting for EAN8 and EAN13 */ + switch(ustrlen(local_text)) { + 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); + for(i = 0; i < 4; i++) { + textpart[i] = symbol->text[i]; + } + textpart[4] = '\0'; + textpos = 2 * (17 + xoffset); + + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + for(i = 0; i < 4; i++) { + textpart[i] = symbol->text[i + 4]; + } + textpart[4] = '\0'; + textpos = 2 * (50 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + textdone = 1; + switch(strlen(addon)) { + case 2: + textpos = 2 * (xoffset + 86); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + case 5: + textpos = 2 * (xoffset + 100); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + } + + break; + 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); + + textpart[0] = symbol->text[0]; + textpart[1] = '\0'; + textpos = 2 * (-7 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + for(i = 0; i < 6; i++) { + textpart[i] = symbol->text[i + 1]; + } + textpart[6] = '\0'; + textpos = 2 * (24 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + for(i = 0; i < 6; i++) { + textpart[i] = symbol->text[i + 7]; + } + textpart[6] = '\0'; + textpos = 2 * (71 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + textdone = 1; + switch(strlen(addon)) { + case 2: + textpos = 2 * (xoffset + 114); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + case 5: + textpos = 2 * (xoffset + 128); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + } + break; + + } + } + + if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) { + /* guard bar extensions and text formatting for UPCA */ + latch = 1; + + i = 0 + comp_offset; + do { + block_width = 0; + do { + block_width++; + } 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); + latch = 0; + } else { + /* a space */ + latch = 1; + } + 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); + latch = 1; + i = 85 + comp_offset; + do { + block_width = 0; + do { + block_width++; + } 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); + latch = 0; + } else { + /* a space */ + latch = 1; + } + i += block_width; + } while (i < 96 + comp_offset); + textpart[0] = symbol->text[0]; + textpart[1] = '\0'; + textpos = 2 * (-5 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + for(i = 0; i < 5; i++) { + textpart[i] = symbol->text[i + 1]; + } + textpart[5] = '\0'; + textpos = 2 * (27 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + for(i = 0; i < 5; i++) { + textpart[i] = symbol->text[i + 6]; + } + textpart[6] = '\0'; + textpos = 2 * (68 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + textpart[0] = symbol->text[11]; + textpart[1] = '\0'; + textpos = 2 * (100 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + textdone = 1; + switch(strlen(addon)) { + case 2: + textpos = 2 * (xoffset + 116); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + case 5: + textpos = 2 * (xoffset + 130); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + } + + } + + if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (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); + + textpart[0] = symbol->text[0]; + textpart[1] = '\0'; + textpos = 2 * (-5 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + for(i = 0; i < 6; i++) { + textpart[i] = symbol->text[i + 1]; + } + textpart[6] = '\0'; + textpos = 2 * (24 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + textpart[0] = symbol->text[7]; + textpart[1] = '\0'; + textpos = 2 * (55 + xoffset); + draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height); + textdone = 1; + switch(strlen(addon)) { + case 2: + textpos = 2 * (xoffset + 70); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + case 5: + textpos = 2 * (xoffset + 84); + draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height); + break; + } + + } + + xoffset -= comp_offset; + + /* Put boundary bars or box around symbol */ + if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) { + /* boundary bars */ + 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); + if((symbol->output_options & BARCODE_BIND) != 0) { + if((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) { + /* row binding */ + 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); + } + } + } + } + + if((symbol->output_options & BARCODE_BOX) != 0) { + /* 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); + } + + /* Put the human readable text at the bottom */ + if((textdone == 0) && (ustrlen(local_text) != 0)) { + textpos = (image_width / 2); + draw_string(pixelbuf, (char*)local_text, textpos, default_text_posn, smalltext, image_width, image_height); + } + + error_number=png_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type); + free(pixelbuf); + return error_number; +} + +#ifndef NO_PNG +int png_handle(struct zint_symbol *symbol, int rotate_angle) +{ + int error; + + if(symbol->symbology == BARCODE_MAXICODE) { + error = maxi_png_plot(symbol, rotate_angle, PNG_DATA); + } else { + + error = png_plot(symbol, rotate_angle, PNG_DATA); + } + + return error; +} +#endif /* NO_PNG */ + +int bmp_handle(struct zint_symbol *symbol, int rotate_angle) +{ + int error; + + if(symbol->symbology == BARCODE_MAXICODE) { + error = maxi_png_plot(symbol, rotate_angle, BMP_DATA); + } else { + error = png_plot(symbol, rotate_angle, BMP_DATA); + } + + return error; +} + diff --git a/backend/qr.c b/backend/qr.c index acebec5b..bd80803a 100644 --- a/backend/qr.c +++ b/backend/qr.c @@ -1,2464 +1,2464 @@ -/* qr.c Handles QR Code */ - -/* - libzint - the open source barcode library - Copyright (C) 2009 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. -*/ - -#include -#ifdef _MSC_VER -#include -#endif -#include "common.h" -#include -#include "sjis.h" -#include "qr.h" -#include "reedsol.h" -#include /* abs */ - -int in_alpha(int glyph) { - /* Returns true if input glyph is in the Alphanumeric set */ - int retval = 0; - char cglyph = (char) glyph; - - if((cglyph >= '0') && (cglyph <= '9')) { - retval = 1; - } - if((cglyph >= 'A') && (cglyph <= 'Z')) { - retval = 1; - } - switch (cglyph) { - case ' ': - case '$': - case '%': - case '*': - case '+': - case '-': - case '.': - case '/': - case ':': - retval = 1; - break; - } - - return retval; -} - -void define_mode(char mode[], int jisdata[], int length, int gs1) -{ - /* Values placed into mode[] are: K = Kanji, B = Binary, A = Alphanumeric, N = Numeric */ - int i, mlen, j; - - for(i = 0; i < length; i++) { - if(jisdata[i] > 0xff) { - mode[i] = 'K'; - } else { - mode[i] = 'B'; - if(in_alpha(jisdata[i])) { mode[i] = 'A'; } - if(gs1 && (jisdata[i] == '[')) { mode[i] = 'A'; } - if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { mode[i] = 'N'; } - } - } - - /* If less than 6 numeric digits together then don't use numeric mode */ - for(i = 0; i < length; i++) { - if(mode[i] == 'N') { - if(((i != 0) && (mode[i - 1] != 'N')) || (i == 0)) { - mlen = 0; - while (((mlen + i) < length) && (mode[mlen + i] == 'N')) { - mlen++; - }; - if(mlen < 6) { - for(j = 0; j < mlen; j++) { - mode[i + j] = 'A'; - } - } - } - } - } - - /* If less than 4 alphanumeric characters together then don't use alphanumeric mode */ - for(i = 0; i < length; i++) { - if(mode[i] == 'A') { - if(((i != 0) && (mode[i - 1] != 'A')) || (i == 0)) { - mlen = 0; - while (((mlen + i) < length) && (mode[mlen + i] == 'A')) { - mlen++; - }; - if(mlen < 6) { - for(j = 0; j < mlen; j++) { - mode[i + j] = 'B'; - } - } - } - } - } -} - -int estimate_binary_length(char mode[], int length, int gs1) -{ - /* Make an estimate (worst case scenario) of how long the binary string will be */ - int i, count = 0; - char current = 0; - int a_count = 0; - int n_count = 0; - - if(gs1) { count += 4; } - - for(i = 0; i < length; i++) { - if(mode[i] != current) { - switch(mode[i]) { - case 'K': count += 12 + 4; current = 'K'; break; - case 'B': count += 16 + 4; current = 'B'; break; - case 'A': count += 13 + 4; current = 'A'; a_count = 0; break; - case 'N': count += 14 + 4; current = 'N'; n_count = 0; break; - } - } - - switch(mode[i]) { - case 'K': count += 13; break; - case 'B': count += 8; break; - case 'A': - a_count++; - if((a_count & 1) == 0) { - count += 5; // 11 in total - a_count = 0; - } - else - count += 6; - break; - case 'N': - n_count++; - if((n_count % 3) == 0) { - count += 3; // 10 in total - n_count = 0; - } - else if ((n_count & 1) == 0) - count += 3; // 7 in total - else - count += 4; - break; - } - } - - return count; -} - -static void qr_bscan(char *binary, int data, int h) -{ - for (; h; h>>=1) { - concat(binary, data & h ? "1" : "0"); - } -} - -void qr_binary(int datastream[], int version, int target_binlen, char mode[], int jisdata[], int length, int gs1, int est_binlen) -{ - /* Convert input data to a binary stream and add padding */ - int position = 0, debug = 0; - int short_data_block_length, i, scheme = 1; - char data_block, padbits; - int current_binlen, current_bytes; - int toggle, percent; - -#ifndef _MSC_VER - char binary[est_binlen + 12]; -#else - char* binary = (char *)_alloca(est_binlen + 12); -#endif - strcpy(binary, ""); - - if(gs1) { - concat(binary, "0101"); /* FNC1 */ - } - - if(version <= 9) { - scheme = 1; - } else if((version >= 10) && (version <= 26)) { - scheme = 2; - } else if(version >= 27) { - scheme = 3; - } - - if(debug) { - for(i = 0; i < length; i++) { - printf("%c", mode[i]); - } - printf("\n"); - } - - percent = 0; - - do { - data_block = mode[position]; - short_data_block_length = 0; - do { - short_data_block_length++; - } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block)); - - switch(data_block) { - case 'K': - /* Kanji mode */ - /* Mode indicator */ - concat(binary, "1000"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, 0x20 << (scheme*2)); /* scheme = 1..3 */ - - if(debug) { printf("Kanji block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int jis = jisdata[position + i]; - int msb, lsb, prod; - - if(jis > 0x9fff) { jis -= 0xc140; } - msb = (jis & 0xff00) >> 4; - lsb = (jis & 0xff); - prod = (msb * 0xc0) + lsb; - - qr_bscan(binary, prod, 0x1000); - - if(debug) { printf("0x%4X ", prod); } - } - - if(debug) { printf("\n"); } - - break; - case 'B': - /* Byte mode */ - /* Mode indicator */ - concat(binary, "0100"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, scheme > 1 ? 0x8000 : 0x80); /* scheme = 1..3 */ - - if(debug) { printf("Byte block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int byte = jisdata[position + i]; - - if(gs1 && (byte == '[')) { - byte = 0x1d; /* FNC1 */ - } - - qr_bscan(binary, byte, 0x80); - - if(debug) { printf("0x%2X(%d) ", byte, byte); } - } - - if(debug) { printf("\n"); } - - break; - case 'A': - /* Alphanumeric mode */ - /* Mode indicator */ - concat(binary, "0010"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, 0x40 << (2 * scheme)); /* scheme = 1..3 */ - - if(debug) { printf("Alpha block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, prod; - - if(percent == 0) { - if(gs1 && (jisdata[position + i] == '%')) { - first = posn(RHODIUM, '%'); - second = posn(RHODIUM, '%'); - count = 2; - prod = (first * 45) + second; - i++; - } else { - if(gs1 && (jisdata[position + i] == '[')) { - first = posn(RHODIUM, '%'); /* FNC1 */ - } else { - first = posn(RHODIUM, (char) jisdata[position + i]); - } - count = 1; - i++; - prod = first; - - if(i < short_data_block_length && mode[position + i] == 'A') { - if(gs1 && (jisdata[position + i] == '%')) { - second = posn(RHODIUM, '%'); - count = 2; - prod = (first * 45) + second; - percent = 1; - } else { - if(gs1 && (jisdata[position + i] == '[')) { - second = posn(RHODIUM, '%'); /* FNC1 */ - } else { - second = posn(RHODIUM, (char) jisdata[position + i]); - } - count = 2; - i++; - prod = (first * 45) + second; - } - } - } - } else { - first = posn(RHODIUM, '%'); - count = 1; - i++; - prod = first; - percent = 0; - - if(i < short_data_block_length && mode[position + i] == 'A') { - if(gs1 && (jisdata[position + i] == '%')) { - second = posn(RHODIUM, '%'); - count = 2; - prod = (first * 45) + second; - percent = 1; - } else { - if(gs1 && (jisdata[position + i] == '[')) { - second = posn(RHODIUM, '%'); /* FNC1 */ - } else { - second = posn(RHODIUM, (char) jisdata[position + i]); - } - count = 2; - i++; - prod = (first * 45) + second; - } - } - } - - qr_bscan(binary, prod, count == 2 ? 0x400 : 0x20); /* count = 1..2 */ - - if(debug) { printf("0x%4X ", prod); } - }; - - if(debug) { printf("\n"); } - - break; - case 'N': - /* Numeric mode */ - /* Mode indicator */ - concat(binary, "0001"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, 0x80 << (2 * scheme)); /* scheme = 1..3 */ - - if(debug) { printf("Number block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, third = 0, prod; - - first = posn(NEON, (char) jisdata[position + i]); - count = 1; - prod = first; - - if(i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { - second = posn(NEON, (char) jisdata[position + i + 1]); - count = 2; - prod = (prod * 10) + second; - - if(i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { - third = posn(NEON, (char) jisdata[position + i + 2]); - count = 3; - prod = (prod * 10) + third; - } - } - - qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */ - - if(debug) { printf("0x%4X (%d)", prod, prod); } - - i += count; - }; - - if(debug) { printf("\n"); } - - break; - } - - position += short_data_block_length; - } while (position < length) ; - - printf("Actual binary: %d\n", (int) strlen(binary)); - - /* Terminator */ - concat(binary, "0000"); - - current_binlen = strlen(binary); - padbits = 8 - (current_binlen % 8); - if(padbits == 8) { padbits = 0; } - current_bytes = (current_binlen + padbits) / 8; - - /* Padding bits */ - for(i = 0; i < padbits; i++) { - concat(binary, "0"); - } - - /* Put data into 8-bit codewords */ - for(i = 0; i < current_bytes; i++) { - datastream[i] = 0x00; - if(binary[i * 8] == '1') { datastream[i] += 0x80; } - if(binary[i * 8 + 1] == '1') { datastream[i] += 0x40; } - if(binary[i * 8 + 2] == '1') { datastream[i] += 0x20; } - if(binary[i * 8 + 3] == '1') { datastream[i] += 0x10; } - if(binary[i * 8 + 4] == '1') { datastream[i] += 0x08; } - if(binary[i * 8 + 5] == '1') { datastream[i] += 0x04; } - if(binary[i * 8 + 6] == '1') { datastream[i] += 0x02; } - if(binary[i * 8 + 7] == '1') { datastream[i] += 0x01; } - } - - /* Add pad codewords */ - toggle = 0; - for(i = current_bytes; i < target_binlen; i++) { - if(toggle == 0) { - datastream[i] = 0xec; - toggle = 1; - } else { - datastream[i] = 0x11; - toggle = 0; - } - } - - if(debug) { - printf("Resulting codewords:\n\t"); - for(i = 0; i < target_binlen; i++) { - printf("0x%2X ", datastream[i]); - } - printf("\n"); - } -} - -void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int blocks) -{ - /* Split data into blocks, add error correction and then interleave the blocks and error correction data */ - int ecc_cw = qr_total_codewords[version - 1] - data_cw; - int short_data_block_length = data_cw / blocks; - int qty_long_blocks = data_cw % blocks; - int qty_short_blocks = blocks - qty_long_blocks; - int ecc_block_length = ecc_cw / blocks; - int i, j, length_this_block, posn, debug = 0; - - -#ifndef _MSC_VER - unsigned char data_block[short_data_block_length + 2]; - unsigned char ecc_block[ecc_block_length + 2]; - int interleaved_data[data_cw + 2]; - int interleaved_ecc[ecc_cw + 2]; -#else - unsigned char* data_block = (unsigned char *)_alloca(short_data_block_length + 2); - unsigned char* ecc_block = (unsigned char *)_alloca(ecc_block_length + 2); - int* interleaved_data = (int *)_alloca((data_cw + 2) * sizeof(int)); - int* interleaved_ecc = (int *)_alloca((ecc_cw + 2) * sizeof(int)); -#endif - - posn = 0; - - for(i = 0; i < blocks; i++) { - if(i < qty_short_blocks) { length_this_block = short_data_block_length; } else { length_this_block = short_data_block_length + 1; } - - for(j = 0; j < ecc_block_length; j++) { - ecc_block[j] = 0; - } - - for(j = 0; j < length_this_block; j++) { - data_block[j] = (unsigned char) datastream[posn + j]; - } - - rs_init_gf(0x11d); - rs_init_code(ecc_block_length, 0); - rs_encode(length_this_block, data_block, ecc_block); - rs_free(); - - if(debug) { - printf("Block %d: ", i + 1); - for(j = 0; j < length_this_block; j++) { - printf("%2X ", data_block[j]); - } - if(i < qty_short_blocks) { - printf(" "); - } - printf(" // "); - for(j = 0; j < ecc_block_length; j++) { - printf("%2X ", ecc_block[ecc_block_length - j - 1]); - } - printf("\n"); - } - - for(j = 0; j < short_data_block_length; j++) { - interleaved_data[(j * blocks) + i] = (int) data_block[j]; - } - - if(i >= qty_short_blocks){ - interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = (int) data_block[short_data_block_length]; - } - - for(j = 0; j < ecc_block_length; j++) { - interleaved_ecc[(j * blocks) + i] = (int) ecc_block[ecc_block_length - j - 1]; - } - - posn += length_this_block; - } - - for(j = 0; j < data_cw; j++) { - fullstream[j] = interleaved_data[j]; - } - for(j = 0; j < ecc_cw; j++) { - fullstream[j + data_cw] = interleaved_ecc[j]; - } - - if(debug) { - printf("\nData Stream: \n"); - for(j = 0; j < (data_cw + ecc_cw); j++) { - printf("%2X ", fullstream[j]); - } - printf("\n"); - } -} - -void place_finder(unsigned char grid[], int size, int x, int y) -{ - int xp, yp; - - int finder[] = { - 1, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 1, - 1, 0, 1, 1, 1, 0, 1, - 1, 0, 1, 1, 1, 0, 1, - 1, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1 - }; - - for(xp = 0; xp < 7; xp++) { - for(yp = 0; yp < 7; yp++) { - if (finder[xp + (7 * yp)] == 1) { - grid[((yp + y) * size) + (xp + x)] = 0x11; - } else { - grid[((yp + y) * size) + (xp + x)] = 0x10; - } - } - } -} - -void place_align(unsigned char grid[], int size, int x, int y) -{ - int xp, yp; - - int alignment[] = { - 1, 1, 1, 1, 1, - 1, 0, 0, 0, 1, - 1, 0, 1, 0, 1, - 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1 - }; - - x -= 2; - y -= 2; /* Input values represent centre of pattern */ - - for(xp = 0; xp < 5; xp++) { - for(yp = 0; yp < 5; yp++) { - if (alignment[xp + (5 * yp)] == 1) { - grid[((yp + y) * size) + (xp + x)] = 0x11; - } else { - grid[((yp + y) * size) + (xp + x)] = 0x10; - } - } - } -} - -void setup_grid(unsigned char* grid, int size, int version) -{ - int i, toggle = 1; - int loopsize, x, y, xcoord, ycoord; - - /* Add timing patterns */ - for(i = 0; i < size; i++) { - if(toggle == 1) { - grid[(6 * size) + i] = 0x21; - grid[(i * size) + 6] = 0x21; - toggle = 0; - } else { - grid[(6 * size) + i] = 0x20; - grid[(i * size) + 6] = 0x20; - toggle = 1; - } - } - - /* Add finder patterns */ - place_finder(grid, size, 0, 0); - place_finder(grid, size, 0, size - 7); - place_finder(grid, size, size - 7, 0); - - /* Add separators */ - for(i = 0; i < 7; i++) { - grid[(7 * size) + i] = 0x10; - grid[(i * size) + 7] = 0x10; - grid[(7 * size) + (size - 1 - i)] = 0x10; - grid[(i * size) + (size - 8)] = 0x10; - grid[((size - 8) * size) + i] = 0x10; - grid[((size - 1 - i) * size) + 7] = 0x10; - } - grid[(7 * size) + 7] = 0x10; - grid[(7 * size) + (size - 8)] = 0x10; - grid[((size - 8) * size) + 7] = 0x10; - - /* Add alignment patterns */ - if(version != 1) { - /* Version 1 does not have alignment patterns */ - - loopsize = qr_align_loopsize[version - 1]; - for(x = 0; x < loopsize; x++) { - for(y = 0; y < loopsize; y++) { - xcoord = qr_table_e1[((version - 2) * 7) + x]; - ycoord = qr_table_e1[((version - 2) * 7) + y]; - - if(!(grid[(ycoord * size) + xcoord] & 0x10)) { - place_align(grid, size, xcoord, ycoord); - } - } - } - } - - /* Reserve space for format information */ - for(i = 0; i < 8; i++) { - grid[(8 * size) + i] += 0x20; - grid[(i * size) + 8] += 0x20; - grid[(8 * size) + (size - 1 - i)] = 0x20; - grid[((size - 1 - i) * size) + 8] = 0x20; - } - grid[(8 * size) + 8] += 20; - grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */ - - /* Reserve space for version information */ - if(version >= 7) { - for(i = 0; i < 6; i++) { - grid[((size - 9) * size) + i] = 0x20; - grid[((size - 10) * size) + i] = 0x20; - grid[((size - 11) * size) + i] = 0x20; - grid[(i * size) + (size - 9)] = 0x20; - grid[(i * size) + (size - 10)] = 0x20; - grid[(i * size) + (size - 11)] = 0x20; - } - } -} - -int cwbit(int* datastream, int i) { - int word = i / 8; - int bit = i % 8; - int resultant = 0; - - switch(bit) { - case 0: if(datastream[word] & 0x80) { resultant = 1; } else { resultant = 0; } break; - case 1: if(datastream[word] & 0x40) { resultant = 1; } else { resultant = 0; } break; - case 2: if(datastream[word] & 0x20) { resultant = 1; } else { resultant = 0; } break; - case 3: if(datastream[word] & 0x10) { resultant = 1; } else { resultant = 0; } break; - case 4: if(datastream[word] & 0x08) { resultant = 1; } else { resultant = 0; } break; - case 5: if(datastream[word] & 0x04) { resultant = 1; } else { resultant = 0; } break; - case 6: if(datastream[word] & 0x02) { resultant = 1; } else { resultant = 0; } break; - case 7: if(datastream[word] & 0x01) { resultant = 1; } else { resultant = 0; } break; - } - - return resultant; -} - -void populate_grid(unsigned char* grid, int size, int* datastream, int cw) -{ - int direction = 1; /* up */ - int row = 0; /* right hand side */ - - int i, n, x, y; - - n = cw * 8; - y = size - 1; - i = 0; - do { - x = (size - 2) - (row * 2); - if(x < 6) - x--; /* skip over vertical timing pattern */ - - if(!(grid[(y * size) + (x + 1)] & 0xf0)) { - if (cwbit(datastream, i)) { - grid[(y * size) + (x + 1)] = 0x01; - } else { - grid[(y * size) + (x + 1)] = 0x00; - } - i++; - } - - if(i < n) { - if(!(grid[(y * size) + x] & 0xf0)) { - if (cwbit(datastream, i)) { - grid[(y * size) + x] = 0x01; - } else { - grid[(y * size) + x] = 0x00; - } - i++; - } - } - - if(direction) { y--; } else { y++; } - if(y == -1) { - /* reached the top */ - row++; - y = 0; - direction = 0; - } - if(y == size) { - /* reached the bottom */ - row++; - y = size - 1; - direction = 1; - } - } while (i < n); -} - -#ifdef ZINTLOG -int append_log(char log) -{ - FILE *file; - - file = fopen("zintlog.txt", "a+"); - fprintf(file, "%c", log); - fclose(file); - return 0; -} - -int write_log(char log[]) -{ - FILE *file; - - file = fopen("zintlog.txt", "a+"); - fprintf(file, log); /*writes*/ - fprintf(file, "\r\n"); /*writes*/ - fclose(file); - return 0; -} -#endif - -int evaluate(unsigned char *grid, int size, int pattern) -{ - int x, y, block; - int result = 0; - char state; - int p; - int dark_mods; - int percentage, k, k2; - int m; - int smallest; -#ifdef ZINTLOG - int result_b = 0; - char str[15]; -#endif - -#ifndef _MSC_VER - char local[size * size]; -#else - char* local = (char *)_alloca((size * size) * sizeof(char)); -#endif - - -#ifdef ZINTLOG - write_log(""); - sprintf(str, "%d", pattern); - write_log(str); -#endif - - // all eight bitmask variants have been encoded in the 8 bits of the bytes that make up the grid array. select them for evaluation according to the desired pattern. - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - switch(pattern) { - case 0: if (grid[(y * size) + x] & 0x01) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 1: if (grid[(y * size) + x] & 0x02) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 2: if (grid[(y * size) + x] & 0x04) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 3: if (grid[(y * size) + x] & 0x08) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 4: if (grid[(y * size) + x] & 0x10) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 5: if (grid[(y * size) + x] & 0x20) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 6: if (grid[(y * size) + x] & 0x40) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 7: if (grid[(y * size) + x] & 0x80) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - } - } - } - -#ifdef ZINTLOG - //bitmask output - for(y = 0; y < size; y++) { - strcpy (str, ""); - for(x = 0; x < size; x++) { - state =local[(y * size) + x]; - append_log(state); - } - write_log(""); - } - write_log(""); -#endif - - /* Test 1: Adjacent modules in row/column in same colour */ - /* Vertical */ - for(x = 0; x < size; x++) { - state = local[x]; - block = 0; - for(y = 0; y < size; y++) { - if(local[(y * size) + x] == state) { - block++; - if(block ==5) - result += 3; - - if(block>5) - result +=1; - } else { - block=0; - } - } - } - - /* Horizontal */ - for(y = 0; y < size; y++) { - state = local[y * size]; - block = 0; - for(x = 0; x < size; x++) { - if(local[(y * size) + x] == state) { - block++; - if(block ==5) - result += 3; - - if(block>5) - result +=1; - } else { - block=0; - } - } - } - -#ifdef ZINTLOG - /* output Test 1 */ - sprintf(str, "%d", result); - result_b=result; - write_log(str); -#endif - - /* Test 2 fd02131114 */ - for(x = 0; x < size-1; x++) { - for(y = 0; y < (size - 7) -1; y++) { - // y + 1??? - if((local[((y + 1) * size) + x] == '1') && - (local[((y + 1) * size) + x+1] == '1') && - (local[(((y + 1)+1) * size) + x] == '1') && - (local[(((y + 1)+1) * size) + x+1] == '1') - ) { result += 3; } - - if((local[((y + 1) * size) + x] == '0') && - (local[((y + 1) * size) + x+1] == '0') && - (local[(((y + 1)+1) * size) + x] == '0') && - (local[(((y + 1)+1) * size) + x+1] == '0') - ) { result += 3; } - } - } - -#ifdef ZINTLOG - /* output Test 2 */ - sprintf(str, "%d", result-result_b); - result_b=result; - write_log(str); -#endif - - /* Test 3: fd02131114 */ - /*pattern 10111010000 */ - /* Vertical */ - for(x = 0; x < size; x++) { - for(y = 0; y < (size - 11); y++) { - p = 0; - if(local[(y * size) + x] == '1') { p += 1; } - if(local[((y + 1) * size) + x] == '0') { p += 1; } - if(local[((y + 2) * size) + x] == '1') { p += 1; } - if(local[((y + 3) * size) + x] == '1') { p += 1; } - if(local[((y + 4) * size) + x] == '1') { p += 1; } - if(local[((y + 5) * size) + x] == '0') { p += 1; } - if(local[((y + 6) * size) + x] == '1') { p += 1; } - if(local[((y + 7) * size) + x] == '0') { p += 1; } - if(local[((y + 8) * size) + x] == '0') { p += 1; } - if(local[((y + 9) * size) + x] == '0') { p += 1; } - if(local[((y + 10) * size) + x] == '0') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /* Horizontal */ - for(y = 0; y < size; y++) { - for(x = 0; x < (size - 11); x++) { - p = 0; - if(local[(y * size) + x] == '1') { p += 1; } - if(local[(y * size) + x + 1] == '0') { p += 1; } - if(local[(y * size) + x + 2] == '1') { p += 1; } - if(local[(y * size) + x + 3] == '1') { p += 1; } - if(local[(y * size) + x + 4] == '1') { p += 1; } - if(local[(y * size) + x + 5] == '0') { p += 1; } - if(local[(y * size) + x + 6] == '1') { p += 1; } - if(local[(y * size) + x + 7] == '0') { p += 1; } - if(local[(y * size) + x + 8] == '0') { p += 1; } - if(local[(y * size) + x + 9] == '0') { p += 1; } - if(local[(y * size) + x + 10] == '0') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /*pattern 00001011101 */ - /* Vertical */ - for(x = 0; x < size; x++) { - for(y = 0; y < (size - 11); y++) { - p = 0; - if(local[(y * size) + x] == '0') { p += 1; } - if(local[((y + 1) * size) + x] == '0') { p += 1; } - if(local[((y + 2) * size) + x] == '0') { p += 1; } - if(local[((y + 3) * size) + x] == '0') { p += 1; } - if(local[((y + 4) * size) + x] == '1') { p += 1; } - if(local[((y + 5) * size) + x] == '0') { p += 1; } - if(local[((y + 6) * size) + x] == '1') { p += 1; } - if(local[((y + 7) * size) + x] == '1') { p += 1; } - if(local[((y + 8) * size) + x] == '1') { p += 1; } - if(local[((y + 9) * size) + x] == '0') { p += 1; } - if(local[((y + 10) * size) + x] == '1') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /* Horizontal */ - for(y = 0; y < size; y++) { - for(x = 0; x < (size - 11); x++) { - p = 0; - if(local[(y * size) + x] == '0') { p += 1; } - if(local[(y * size) + x + 1] == '0') { p += 1; } - if(local[(y * size) + x + 2] == '0') { p += 1; } - if(local[(y * size) + x + 3] == '0') { p += 1; } - if(local[(y * size) + x + 4] == '1') { p += 1; } - if(local[(y * size) + x + 5] == '0') { p += 1; } - if(local[(y * size) + x + 6] == '1') { p += 1; } - if(local[(y * size) + x + 7] == '1') { p += 1; } - if(local[(y * size) + x + 8] == '1') { p += 1; } - if(local[(y * size) + x + 9] == '0') { p += 1; } - if(local[(y * size) + x + 10] == '1') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - -#ifdef ZINTLOG - /* output Test 3 */ - sprintf(str, "%d", result-result_b); - result_b=result; - write_log(str); -#endif - - /* Test 4: Proportion of dark modules in entire symbol */ - dark_mods = 0; - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - if(local[(y * size) + x] == '1') { - dark_mods++; - } - } - } - percentage = 100 * (dark_mods / (size * size)); - m=0; - for(x = 0; x < 100; x+=5) { - if(x> i) & 0x01 ? (0x01 >> pattern) : 0x00; - } - - for(i = 0; i < 8; i++) { - eval[(8 * size) + (size - i - 1)] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00; - } - - for(i = 0; i < 6; i++) { - eval[(8 * size) + (5 - i)] = (seq >> (i + 9)) & 0x01 ? (0x01 >> pattern) : 0x00; - } - - for(i = 0; i < 7; i++) { - eval[(((size - 7) + i) * size) + 8] = (seq >> (i + 8)) & 0x01 ? (0x01 >> pattern) : 0x00; - } - - eval[(7 * size) + 8] = (seq >> 6) & 0x01 ? (0x01 >> pattern) : 0x00; - eval[(8 * size) + 8] = (seq >> 7) & 0x01 ? (0x01 >> pattern) : 0x00; - eval[(8 * size) + 7] = (seq >> 8) & 0x01 ? (0x01 >> pattern) : 0x00; -} - -int apply_bitmask(unsigned char *grid, int size, int ecc_level) -{ - int x, y; - unsigned char p; - int pattern, penalty[8]; - int best_val, best_pattern; - int bit; - -#ifndef _MSC_VER - unsigned char mask[size * size]; - unsigned char eval[size * size]; -#else - unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); - unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); -#endif - - /* Perform data masking */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - mask[(y * size) + x] = 0x00; - - // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. - if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked. - if(((y + x) & 1) == 0) { mask[(y * size) + x] += 0x01; } - if((y & 1) == 0) { mask[(y * size) + x] += 0x02; } - if((x % 3) == 0) { mask[(y * size) + x] += 0x04; } - if(((y + x) % 3) == 0) { mask[(y * size) + x] += 0x08; } - if((((y / 2) + (x / 3)) & 1) == 0) { mask[(y * size) + x] += 0x10; } - if((((y * x) & 1) + ((y * x) % 3)) == 0) { mask[(y * size) + x] += 0x20; } - if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x40; } - if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x80; } - } - } - } - - // apply data masks to grid, result in eval - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - if(grid[(y * size) + x] & 0x01) - { p = 0xff; } - else { p = 0x00; } - - eval[(y * size) + x] = mask[(y * size) + x] ^ p; - } - } - - - /* Evaluate result */ - for(pattern = 0; pattern < 8; pattern++) { - - add_format_info_eval(eval, size, ecc_level, pattern); - - penalty[pattern] = evaluate(eval, size, pattern); - } - - best_pattern = 0; - best_val = penalty[0]; - for(pattern = 1; pattern < 8; pattern++) { - if(penalty[pattern] < best_val) { - best_pattern = pattern; - best_val = penalty[pattern]; - } - } - -#ifdef ZINTLOG - char str[15]; - sprintf(str, "%d", best_val); - write_log("choosed pattern:"); - write_log(str); -#endif - - /* Apply mask */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - bit = 0; - switch(best_pattern) { - case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; - case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; - case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; - case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; - case 4: if(mask[(y * size) + x] & 0x10) { bit = 1; } break; - case 5: if(mask[(y * size) + x] & 0x20) { bit = 1; } break; - case 6: if(mask[(y * size) + x] & 0x40) { bit = 1; } break; - case 7: if(mask[(y * size) + x] & 0x80) { bit = 1; } break; - } - if(bit == 1) { - if(grid[(y * size) + x] & 0x01) { - grid[(y * size) + x] = 0x00; - } else { - grid[(y * size) + x] = 0x01; - } - } - } - } - - return best_pattern; -} - -void add_format_info(unsigned char *grid, int size, int ecc_level, int pattern) -{ - /* Add format information to grid */ - - int format = pattern; - unsigned int seq; - int i; - - switch(ecc_level) { - case LEVEL_L: format += 0x08; break; - case LEVEL_Q: format += 0x18; break; - case LEVEL_H: format += 0x10; break; - } - - seq = qr_annex_c[format]; - - for(i = 0; i < 6; i++) { - grid[(i * size) + 8] += (seq >> i) & 0x01; - } - - for(i = 0; i < 8; i++) { - grid[(8 * size) + (size - i - 1)] += (seq >> i) & 0x01; - } - - for(i = 0; i < 6; i++) { - grid[(8 * size) + (5 - i)] += (seq >> (i + 9)) & 0x01; - } - - for(i = 0; i < 7; i++) { - grid[(((size - 7) + i) * size) + 8] += (seq >> (i + 8)) & 0x01; - } - - grid[(7 * size) + 8] += (seq >> 6) & 0x01; - grid[(8 * size) + 8] += (seq >> 7) & 0x01; - grid[(8 * size) + 7] += (seq >> 8) & 0x01; -} - -void add_version_info(unsigned char *grid, int size, int version) -{ - /* Add version information */ - int i; - - long int version_data = qr_annex_d[version - 7]; - for(i = 0; i < 6; i++) { - grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41; - grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41; - grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41; - grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41; - grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41; - grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41; - } -} - -int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) -{ - int error_number, i, j, glyph, est_binlen; - int ecc_level, autosize, version, max_cw, target_binlen, blocks, size; - int bitmask, gs1; - -#ifndef _MSC_VER - int utfdata[length + 1]; - int jisdata[length + 1]; - char mode[length + 1]; -#else - int* datastream; - int* fullstream; - unsigned char* grid; - int* utfdata = (int *)_alloca((length + 1) * sizeof(int)); - int* jisdata = (int *)_alloca((length + 1) * sizeof(int)); - char* mode = (char *)_alloca(length + 1); -#endif - - gs1 = (symbol->input_mode == GS1_MODE); - - switch(symbol->input_mode) { - case DATA_MODE: - for(i = 0; i < length; i++) { - jisdata[i] = (int)source[i]; - } - break; - default: - /* Convert Unicode input to Shift-JIS */ - error_number = utf8toutf16(symbol, source, utfdata, &length); - if(error_number != 0) { return error_number; } - - for(i = 0; i < length; i++) { - if(utfdata[i] <= 0xff) { - jisdata[i] = utfdata[i]; - } else { - j = 0; - glyph = 0; - do { - if(sjis_lookup[j * 2] == utfdata[i]) { - glyph = sjis_lookup[(j * 2) + 1]; - } - j++; - } while ((j < 6843) && (glyph == 0)); - if(glyph == 0) { - strcpy(symbol->errtxt, "Invalid character in input data"); - return ZINT_ERROR_INVALID_DATA; - } - jisdata[i] = glyph; - } - } - break; - } - - define_mode(mode, jisdata, length, gs1); - est_binlen = estimate_binary_length(mode, length, gs1); - - ecc_level = LEVEL_L; - max_cw = 2956; - if((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) { - switch (symbol->option_1) { - case 1: ecc_level = LEVEL_L; max_cw = 2956; break; - case 2: ecc_level = LEVEL_M; max_cw = 2334; break; - case 3: ecc_level = LEVEL_Q; max_cw = 1666; break; - case 4: ecc_level = LEVEL_H; max_cw = 1276; break; - } - } - - if(est_binlen > (8 * max_cw)) { - strcpy(symbol->errtxt, "Input too long for selected error correction level"); - return ZINT_ERROR_TOO_LONG; - } - - autosize = 40; - for(i = 39; i >= 0; i--) { - switch(ecc_level) { - case LEVEL_L: - if ((8 * qr_data_codewords_L[i]) >= est_binlen) { - autosize = i + 1; - } - break; - case LEVEL_M: - if ((8 * qr_data_codewords_M[i]) >= est_binlen) { - autosize = i + 1; - } - break; - case LEVEL_Q: - if ((8 * qr_data_codewords_Q[i]) >= est_binlen) { - autosize = i + 1; - } - break; - case LEVEL_H: - if ((8 * qr_data_codewords_H[i]) >= est_binlen) { - autosize = i + 1; - } - break; - } - } - - if((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) { - if (symbol->option_2 > autosize) { - version = symbol->option_2; - } else { - version = autosize; - } - } else { - version = autosize; - } - - /* Ensure maxium error correction capacity */ - if(est_binlen <= qr_data_codewords_M[version - 1]) { ecc_level = LEVEL_M; } - if(est_binlen <= qr_data_codewords_Q[version - 1]) { ecc_level = LEVEL_Q; } - if(est_binlen <= qr_data_codewords_H[version - 1]) { ecc_level = LEVEL_H; } - - target_binlen = qr_data_codewords_L[version - 1]; blocks = qr_blocks_L[version - 1]; - switch(ecc_level) { - case LEVEL_M: target_binlen = qr_data_codewords_M[version - 1]; blocks = qr_blocks_M[version - 1]; break; - case LEVEL_Q: target_binlen = qr_data_codewords_Q[version - 1]; blocks = qr_blocks_Q[version - 1]; break; - case LEVEL_H: target_binlen = qr_data_codewords_H[version - 1]; blocks = qr_blocks_H[version - 1]; break; - } - -#ifndef _MSC_VER - int datastream[target_binlen + 1]; - int fullstream[qr_total_codewords[version - 1] + 1]; -#else - datastream = (int *)_alloca((target_binlen + 1) * sizeof(int)); - fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int)); -#endif - - qr_binary(datastream, version, target_binlen, mode, jisdata, length, gs1, est_binlen); - add_ecc(fullstream, datastream, version, target_binlen, blocks); - - size = qr_sizes[version - 1]; -#ifndef _MSC_VER - unsigned char grid[size * size]; -#else - grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); -#endif - - for(i = 0; i < size; i++) { - for(j = 0; j < size; j++) { - grid[(i * size) + j] = 0; - } - } - - setup_grid(grid, size, version); - populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]); - - if(version >= 7) { - add_version_info(grid, size, version); - } - - bitmask = apply_bitmask(grid, size, ecc_level); - - add_format_info(grid, size, ecc_level, bitmask); - - - - symbol->width = size; - symbol->rows = size; - - for(i = 0; i < size; i++) { - for(j = 0; j < size; j++) { - if(grid[(i * size) + j] & 0x01) { - set_module(symbol, i, j); - } - } - symbol->row_height[i] = 1; - } - - return 0; -} - -/* NOTE: From this point forward concerns Micro QR Code only */ - -int micro_qr_intermediate(char binary[], int jisdata[], char mode[], int length, int *kanji_used, int *alphanum_used, int *byte_used) -{ - /* Convert input data to an "intermediate stage" where data is binary encoded but - control information is not */ - int position = 0, debug = 0; - int short_data_block_length, i; - char data_block; - char buffer[2]; - - strcpy(binary, ""); - - if(debug) { - for(i = 0; i < length; i++) { - printf("%c", mode[i]); - } - printf("\n"); - } - - do { - if(strlen(binary) > 128) { - return ZINT_ERROR_TOO_LONG; - } - - data_block = mode[position]; - short_data_block_length = 0; - do { - short_data_block_length++; - } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block)); - - switch(data_block) { - case 'K': - /* Kanji mode */ - /* Mode indicator */ - concat(binary, "K"); - *kanji_used = 1; - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); - - if(debug) { printf("Kanji block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int jis = jisdata[position + i]; - int msb, lsb, prod; - - if(jis > 0x9fff) { jis -= 0xc140; } - msb = (jis & 0xff00) >> 4; - lsb = (jis & 0xff); - prod = (msb * 0xc0) + lsb; - - qr_bscan(binary, prod, 0x1000); - - if(debug) { printf("0x%4X ", prod); } - - if(strlen(binary) > 128) { - return ZINT_ERROR_TOO_LONG; - } - } - - if(debug) { printf("\n"); } - - break; - case 'B': - /* Byte mode */ - /* Mode indicator */ - concat(binary, "B"); - *byte_used = 1; - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); - - if(debug) { printf("Byte block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int byte = jisdata[position + i]; - - qr_bscan(binary, byte, 0x80); - - if(debug) { printf("0x%4X ", byte); } - - if(strlen(binary) > 128) { - return ZINT_ERROR_TOO_LONG; - } - } - - if(debug) { printf("\n"); } - - break; - case 'A': - /* Alphanumeric mode */ - /* Mode indicator */ - concat(binary, "A"); - *alphanum_used = 1; - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); - - if(debug) { printf("Alpha block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, prod; - - first = posn(RHODIUM, (char) jisdata[position + i]); - count = 1; - prod = first; - - if(i + 1 < short_data_block_length && mode[position + i + 1] == 'A') { - second = posn(RHODIUM, (char) jisdata[position + i + 1]); - count = 2; - prod = (first * 45) + second; - } - - qr_bscan(binary, prod, 1 << (5 * count)); /* count = 1..2 */ - - if(debug) { printf("0x%4X ", prod); } - - if(strlen(binary) > 128) { - return ZINT_ERROR_TOO_LONG; - } - - i += 2; - }; - - if(debug) { printf("\n"); } - - break; - case 'N': - /* Numeric mode */ - /* Mode indicator */ - concat(binary, "N"); - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); - - if(debug) { printf("Number block (length %d)\n\t", short_data_block_length); } - - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, third = 0, prod; - - first = posn(NEON, (char) jisdata[position + i]); - count = 1; - prod = first; - - if(i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { - second = posn(NEON, (char) jisdata[position + i + 1]); - count = 2; - prod = (prod * 10) + second; - } - - if(i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { - third = posn(NEON, (char) jisdata[position + i + 2]); - count = 3; - prod = (prod * 10) + third; - } - - qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */ - - if(debug) { printf("0x%4X (%d)", prod, prod); } - - if(strlen(binary) > 128) { - return ZINT_ERROR_TOO_LONG; - } - - i += 3; - }; - - if(debug) { printf("\n"); } - - break; - } - - position += short_data_block_length; - } while (position < length - 1) ; - - return 0; -} - -void get_bitlength(int count[], char stream[]) { - int length, i; - - length = strlen(stream); - - for(i = 0; i < 4; i++) { - count[i] = 0; - } - - i = 0; - do { - if((stream[i] == '0') || (stream[i] == '1')) { - count[0]++; - count[1]++; - count[2]++; - count[3]++; - i++; - } else { - switch(stream[i]) { - case 'K': - count[2] += 5; - count[3] += 7; - i += 2; - break; - case 'B': - count[2] += 6; - count[3] += 8; - i += 2; - break; - case 'A': - count[1] += 4; - count[2] += 6; - count[3] += 8; - i += 2; - break; - case 'N': - count[0] += 3; - count[1] += 5; - count[2] += 7; - count[3] += 9; - i += 2; - break; - } - } - } while (i < length); -} - -void microqr_expand_binary(char binary_stream[], char full_stream[], int version) -{ - int i, length; - - length = strlen(binary_stream); - - i = 0; - do { - switch(binary_stream[i]) { - case '1': concat(full_stream, "1"); i++; break; - case '0': concat(full_stream, "0"); i++; break; - case 'N': - /* Numeric Mode */ - /* Mode indicator */ - switch(version) { - case 1: concat(full_stream, "0"); break; - case 2: concat(full_stream, "00"); break; - case 3: concat(full_stream, "000"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 4 << version); /* version = 0..3 */ - - i += 2; - break; - case 'A': - /* Alphanumeric Mode */ - /* Mode indicator */ - switch(version) { - case 1: concat(full_stream, "1"); break; - case 2: concat(full_stream, "01"); break; - case 3: concat(full_stream, "001"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 1..3 */ - - i += 2; - break; - case 'B': - /* Byte Mode */ - /* Mode indicator */ - switch(version) { - case 2: concat(full_stream, "10"); break; - case 3: concat(full_stream, "010"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 2..3 */ - - i += 2; - break; - case 'K': - /* Kanji Mode */ - /* Mode indicator */ - switch(version) { - case 2: concat(full_stream, "11"); break; - case 3: concat(full_stream, "011"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 1 << version); /* version = 2..3 */ - - i += 2; - break; - } - - } while (i < length); -} - -void micro_qr_m1(char binary_data[]) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[4], ecc_blocks[3]; - - bits_total = 20; - latch = 0; - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 3) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "000"); - } - - if(latch == 0) { - /* Manage last (4-bit) block */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 4) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - if(bits_left > 4) { - remainder = (bits_left - 4) / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - concat(binary_data, "0000"); - } - - data_codewords = 3; - ecc_codewords = 2; - - /* Copy data into codewords */ - for(i = 0; i < (data_codewords - 1); i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - data_blocks[2] = 0; - if(binary_data[16] == '1') { data_blocks[2] += 0x08; } - if(binary_data[17] == '1') { data_blocks[2] += 0x04; } - if(binary_data[18] == '1') { data_blocks[2] += 0x02; } - if(binary_data[19] == '1') { data_blocks[2] += 0x01; } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } -} - -void micro_qr_m2(char binary_data[], int ecc_mode) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[6], ecc_blocks[7]; - - latch = 0; - - if(ecc_mode == LEVEL_L) { bits_total = 40; } - if(ecc_mode == LEVEL_M) { bits_total = 32; } - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 5) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "00000"); - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - remainder = bits_left / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - - if(ecc_mode == LEVEL_L) { data_codewords = 5; ecc_codewords = 5; } - if(ecc_mode == LEVEL_M) { data_codewords = 4; ecc_codewords = 6; } - - /* Copy data into codewords */ - for(i = 0; i < data_codewords; i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } - - return; -} - -void micro_qr_m3(char binary_data[], int ecc_mode) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[12], ecc_blocks[9]; - - latch = 0; - - if(ecc_mode == LEVEL_L) { bits_total = 84; } - if(ecc_mode == LEVEL_M) { bits_total = 68; } - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 7) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "0000000"); - } - - if(latch == 0) { - /* Manage last (4-bit) block */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 4) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - if(bits_left > 4) { - remainder = (bits_left - 4) / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - concat(binary_data, "0000"); - } - - if(ecc_mode == LEVEL_L) { data_codewords = 11; ecc_codewords = 6; } - if(ecc_mode == LEVEL_M) { data_codewords = 9; ecc_codewords = 8; } - - /* Copy data into codewords */ - for(i = 0; i < (data_codewords - 1); i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - - if(ecc_mode == LEVEL_L) { - data_blocks[10] = 0; - if(binary_data[80] == '1') { data_blocks[10] += 0x08; } - if(binary_data[81] == '1') { data_blocks[10] += 0x04; } - if(binary_data[82] == '1') { data_blocks[10] += 0x02; } - if(binary_data[83] == '1') { data_blocks[10] += 0x01; } - } - - if(ecc_mode == LEVEL_M) { - data_blocks[8] = 0; - if(binary_data[64] == '1') { data_blocks[8] += 0x08; } - if(binary_data[65] == '1') { data_blocks[8] += 0x04; } - if(binary_data[66] == '1') { data_blocks[8] += 0x02; } - if(binary_data[67] == '1') { data_blocks[8] += 0x01; } - } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } - - return; -} - -void micro_qr_m4(char binary_data[], int ecc_mode) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[17], ecc_blocks[15]; - - latch = 0; - - if(ecc_mode == LEVEL_L) { bits_total = 128; } - if(ecc_mode == LEVEL_M) { bits_total = 112; } - if(ecc_mode == LEVEL_Q) { bits_total = 80; } - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 9) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "000000000"); - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - remainder = bits_left / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - - if(ecc_mode == LEVEL_L) { data_codewords = 16; ecc_codewords = 8; } - if(ecc_mode == LEVEL_M) { data_codewords = 14; ecc_codewords = 10; } - if(ecc_mode == LEVEL_Q) { data_codewords = 10; ecc_codewords = 14; } - - /* Copy data into codewords */ - for(i = 0; i < data_codewords; i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } -} - -void micro_setup_grid(unsigned char* grid, int size) -{ - int i, toggle = 1; - - /* Add timing patterns */ - for(i = 0; i < size; i++) { - if(toggle == 1) { - grid[i] = 0x21; - grid[(i * size)] = 0x21; - toggle = 0; - } else { - grid[i] = 0x20; - grid[(i * size)] = 0x20; - toggle = 1; - } - } - - /* Add finder patterns */ - place_finder(grid, size, 0, 0); - - /* Add separators */ - for(i = 0; i < 7; i++) { - grid[(7 * size) + i] = 0x10; - grid[(i * size) + 7] = 0x10; - } - grid[(7 * size) + 7] = 0x10; - - - /* Reserve space for format information */ - for(i = 0; i < 8; i++) { - grid[(8 * size) + i] += 0x20; - grid[(i * size) + 8] += 0x20; - } - grid[(8 * size) + 8] += 20; -} - -void micro_populate_grid(unsigned char* grid, int size, char full_stream[]) -{ - int direction = 1; /* up */ - int row = 0; /* right hand side */ - - int i, n, x, y; - - n = strlen(full_stream); - y = size - 1; - i = 0; - do { - x = (size - 2) - (row * 2); - - if(!(grid[(y * size) + (x + 1)] & 0xf0)) { - if (full_stream[i] == '1') { - grid[(y * size) + (x + 1)] = 0x01; - } else { - grid[(y * size) + (x + 1)] = 0x00; - } - i++; - } - - if(i < n) { - if(!(grid[(y * size) + x] & 0xf0)) { - if (full_stream[i] == '1') { - grid[(y * size) + x] = 0x01; - } else { - grid[(y * size) + x] = 0x00; - } - i++; - } - } - - if(direction) { y--; } else { y++; } - if(y == 0) { - /* reached the top */ - row++; - y = 1; - direction = 0; - } - if(y == size) { - /* reached the bottom */ - row++; - y = size - 1; - direction = 1; - } - } while (i < n); -} - -int micro_evaluate(unsigned char *grid, int size, int pattern) -{ - int sum1, sum2, i, filter = 0, retval; - - switch(pattern) { - case 0: filter = 0x01; break; - case 1: filter = 0x02; break; - case 2: filter = 0x04; break; - case 3: filter = 0x08; break; - } - - sum1 = 0; - sum2 = 0; - for(i = 1; i < size; i++) { - if(grid[(i * size) + size - 1] & filter) { sum1++; } - if(grid[((size - 1) * size) + i] & filter) { sum2++; } - } - - if(sum1 <= sum2) { retval = (sum1 * 16) + sum2; } else { retval = (sum2 * 16) + sum1; } - - return retval; -} - -int micro_apply_bitmask(unsigned char *grid, int size) -{ - int x, y; - unsigned char p; - int pattern, value[8]; - int best_val, best_pattern; - int bit; - -#ifndef _MSC_VER - unsigned char mask[size * size]; - unsigned char eval[size * size]; -#else - unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); - unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); -#endif - - /* Perform data masking */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - mask[(y * size) + x] = 0x00; - - if (!(grid[(y * size) + x] & 0xf0)) { - if((y & 1) == 0) { - mask[(y * size) + x] += 0x01; - } - - if((((y / 2) + (x / 3)) & 1) == 0) { - mask[(y * size) + x] += 0x02; - } - - if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { - mask[(y * size) + x] += 0x04; - } - - if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { - mask[(y * size) + x] += 0x08; - } - } - } - } - - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; } - - eval[(y * size) + x] = mask[(y * size) + x] ^ p; - } - } - - - /* Evaluate result */ - for(pattern = 0; pattern < 8; pattern++) { - value[pattern] = micro_evaluate(eval, size, pattern); - } - - best_pattern = 0; - best_val = value[0]; - for(pattern = 1; pattern < 4; pattern++) { - if(value[pattern] > best_val) { - best_pattern = pattern; - best_val = value[pattern]; - } - } - - /* Apply mask */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - bit = 0; - switch(best_pattern) { - case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; - case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; - case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; - case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; - } - if(bit == 1) { - if(grid[(y * size) + x] & 0x01) { - grid[(y * size) + x] = 0x00; - } else { - grid[(y * size) + x] = 0x01; - } - } - } - } - - return best_pattern; -} - -int microqr(struct zint_symbol *symbol, unsigned char source[], int length) -{ - int i, j, glyph, size; - char binary_stream[200]; - char full_stream[200]; - int utfdata[40]; - int jisdata[40]; - char mode[40]; - int error_number, kanji_used = 0, alphanum_used = 0, byte_used = 0; - int version_valid[4]; - int binary_count[4]; - int ecc_level, autoversion, version; - int n_count, a_count, bitmask, format, format_full; -#ifdef _MSC_VER - unsigned char* grid; -#endif - - if(length > 35) { - strcpy(symbol->errtxt, "Input data too long"); - return ZINT_ERROR_TOO_LONG; - } - - for(i = 0; i < 4; i++) { - version_valid[i] = 1; - } - - switch(symbol->input_mode) { - case DATA_MODE: - for(i = 0; i < length; i++) { - jisdata[i] = (int)source[i]; - } - break; - default: - /* Convert Unicode input to Shift-JIS */ - error_number = utf8toutf16(symbol, source, utfdata, &length); - if(error_number != 0) { return error_number; } - - for(i = 0; i < length; i++) { - if(utfdata[i] <= 0xff) { - jisdata[i] = utfdata[i]; - } else { - j = 0; - glyph = 0; - do { - if(sjis_lookup[j * 2] == utfdata[i]) { - glyph = sjis_lookup[(j * 2) + 1]; - } - j++; - } while ((j < 6843) && (glyph == 0)); - if(glyph == 0) { - strcpy(symbol->errtxt, "Invalid character in input data"); - return ZINT_ERROR_INVALID_DATA; - } - jisdata[i] = glyph; - } - } - break; - } - - define_mode(mode, jisdata, length, 0); - - n_count = 0; - a_count = 0; - for(i = 0; i < length; i++) { - if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { n_count++; } - if(in_alpha(jisdata[i])) { a_count++; } - } - - if(a_count == length) { - /* All data can be encoded in Alphanumeric mode */ - for(i = 0; i < length; i++) { - mode[i] = 'A'; - } - } - - if(n_count == length) { - /* All data can be encoded in Numeric mode */ - for(i = 0; i < length; i++) { - mode[i] = 'N'; - } - } - - error_number = micro_qr_intermediate(binary_stream, jisdata, mode, length, &kanji_used, &alphanum_used, &byte_used); - if(error_number != 0) { - strcpy(symbol->errtxt, "Input data too long"); - return error_number; - } - - get_bitlength(binary_count, binary_stream); - - /* Eliminate possivle versions depending on type of content */ - if(byte_used) { - version_valid[0] = 0; - version_valid[1] = 0; - } - - if(alphanum_used) { - version_valid[0] = 0; - } - - if(kanji_used) { - version_valid[0] = 0; - version_valid[1] = 0; - } - - /* Eliminate possible versions depending on length of binary data */ - if(binary_count[0] > 20) { version_valid[0] = 0; } - if(binary_count[1] > 40) { version_valid[1] = 0; } - if(binary_count[2] > 84) { version_valid[2] = 0; } - if(binary_count[3] > 128) { - strcpy(symbol->errtxt, "Input data too long"); - return ZINT_ERROR_TOO_LONG; - } - - /* Eliminate possible versions depending on error correction level specified */ - ecc_level = LEVEL_L; - if((symbol->option_1 >= 1) && (symbol->option_2 <= 4)) { - ecc_level = symbol->option_1; - } - - if(ecc_level == LEVEL_H) { - strcpy(symbol->errtxt, "Error correction level H not available"); - return ZINT_ERROR_INVALID_OPTION; - } - - if(ecc_level == LEVEL_Q) { - version_valid[0] = 0; - version_valid[1] = 0; - version_valid[2] = 0; - if(binary_count[3] > 80) { - strcpy(symbol->errtxt, "Input data too long"); - return ZINT_ERROR_TOO_LONG; - } - } - - if(ecc_level == LEVEL_M) { - version_valid[0] = 0; - if(binary_count[1] > 32) { version_valid[1] = 0; } - if(binary_count[2] > 68) { version_valid[2] = 0; } - if(binary_count[3] > 112) { - strcpy(symbol->errtxt, "Input data too long"); - return ZINT_ERROR_TOO_LONG; - } - } - - autoversion = 3; - if(version_valid[2]) { autoversion = 2; } - if(version_valid[1]) { autoversion = 1; } - if(version_valid[0]) { autoversion = 0; } - - version = autoversion; - /* Get version from user */ - if((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) { - if(symbol->option_2 >= autoversion) { - version = symbol->option_2; - } - } - - /* If there is enough unused space then increase the error correction level */ - if(version == 3) { - if(binary_count[3] <= 112) { ecc_level = LEVEL_M; } - if(binary_count[3] <= 80) { ecc_level = LEVEL_Q; } - } - - if(version == 2) { - if(binary_count[2] <= 68) { ecc_level = LEVEL_M; } - } - - if(version == 1) { - if(binary_count[1] <= 32) { ecc_level = LEVEL_M; } - } - - strcpy(full_stream, ""); - microqr_expand_binary(binary_stream, full_stream, version); - - switch(version) { - case 0: micro_qr_m1(full_stream); break; - case 1: micro_qr_m2(full_stream, ecc_level); break; - case 2: micro_qr_m3(full_stream, ecc_level); break; - case 3: micro_qr_m4(full_stream, ecc_level); break; - } - - size = micro_qr_sizes[version]; -#ifndef _MSC_VER - unsigned char grid[size * size]; -#else - grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); -#endif - - for(i = 0; i < size; i++) { - for(j = 0; j < size; j++) { - grid[(i * size) + j] = 0; - } - } - - micro_setup_grid(grid, size); - micro_populate_grid(grid, size, full_stream); - bitmask = micro_apply_bitmask(grid, size); - - /* Add format data */ - format = 0; - switch(version) { - case 1: switch(ecc_level) { - case 1: format = 1; break; - case 2: format = 2; break; - } - break; - case 2: switch(ecc_level) { - case 1: format = 3; break; - case 2: format = 4; break; - } - break; - case 3: switch(ecc_level) { - case 1: format = 5; break; - case 2: format = 6; break; - case 3: format = 7; break; - } - break; - } - - format_full = qr_annex_c1[(format << 2) + bitmask]; - - if(format_full & 0x4000) { grid[(8 * size) + 1] += 0x01; } - if(format_full & 0x2000) { grid[(8 * size) + 2] += 0x01; } - if(format_full & 0x1000) { grid[(8 * size) + 3] += 0x01; } - if(format_full & 0x800) { grid[(8 * size) + 4] += 0x01; } - if(format_full & 0x400) { grid[(8 * size) + 5] += 0x01; } - if(format_full & 0x200) { grid[(8 * size) + 6] += 0x01; } - if(format_full & 0x100) { grid[(8 * size) + 7] += 0x01; } - if(format_full & 0x80) { grid[(8 * size) + 8] += 0x01; } - if(format_full & 0x40) { grid[(7 * size) + 8] += 0x01; } - if(format_full & 0x20) { grid[(6 * size) + 8] += 0x01; } - if(format_full & 0x10) { grid[(5 * size) + 8] += 0x01; } - if(format_full & 0x08) { grid[(4 * size) + 8] += 0x01; } - if(format_full & 0x04) { grid[(3 * size) + 8] += 0x01; } - if(format_full & 0x02) { grid[(2 * size) + 8] += 0x01; } - if(format_full & 0x01) { grid[(1 * size) + 8] += 0x01; } - - symbol->width = size; - symbol->rows = size; - - for(i = 0; i < size; i++) { - for(j = 0; j < size; j++) { - if(grid[(i * size) + j] & 0x01) { - set_module(symbol, i, j); - } - } - symbol->row_height[i] = 1; - } - - return 0; -} +/* qr.c Handles QR Code */ + +/* + libzint - the open source barcode library + Copyright (C) 2009 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. +*/ + +#include +#ifdef _MSC_VER +#include +#endif +#include "common.h" +#include +#include "sjis.h" +#include "qr.h" +#include "reedsol.h" +#include /* abs */ + +int in_alpha(int glyph) { + /* Returns true if input glyph is in the Alphanumeric set */ + int retval = 0; + char cglyph = (char) glyph; + + if((cglyph >= '0') && (cglyph <= '9')) { + retval = 1; + } + if((cglyph >= 'A') && (cglyph <= 'Z')) { + retval = 1; + } + switch (cglyph) { + case ' ': + case '$': + case '%': + case '*': + case '+': + case '-': + case '.': + case '/': + case ':': + retval = 1; + break; + } + + return retval; +} + +void define_mode(char mode[], int jisdata[], int length, int gs1) +{ + /* Values placed into mode[] are: K = Kanji, B = Binary, A = Alphanumeric, N = Numeric */ + int i, mlen, j; + + for(i = 0; i < length; i++) { + if(jisdata[i] > 0xff) { + mode[i] = 'K'; + } else { + mode[i] = 'B'; + if(in_alpha(jisdata[i])) { mode[i] = 'A'; } + if(gs1 && (jisdata[i] == '[')) { mode[i] = 'A'; } + if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { mode[i] = 'N'; } + } + } + + /* If less than 6 numeric digits together then don't use numeric mode */ + for(i = 0; i < length; i++) { + if(mode[i] == 'N') { + if(((i != 0) && (mode[i - 1] != 'N')) || (i == 0)) { + mlen = 0; + while (((mlen + i) < length) && (mode[mlen + i] == 'N')) { + mlen++; + }; + if(mlen < 6) { + for(j = 0; j < mlen; j++) { + mode[i + j] = 'A'; + } + } + } + } + } + + /* If less than 4 alphanumeric characters together then don't use alphanumeric mode */ + for(i = 0; i < length; i++) { + if(mode[i] == 'A') { + if(((i != 0) && (mode[i - 1] != 'A')) || (i == 0)) { + mlen = 0; + while (((mlen + i) < length) && (mode[mlen + i] == 'A')) { + mlen++; + }; + if(mlen < 6) { + for(j = 0; j < mlen; j++) { + mode[i + j] = 'B'; + } + } + } + } + } +} + +int estimate_binary_length(char mode[], int length, int gs1) +{ + /* Make an estimate (worst case scenario) of how long the binary string will be */ + int i, count = 0; + char current = 0; + int a_count = 0; + int n_count = 0; + + if(gs1) { count += 4; } + + for(i = 0; i < length; i++) { + if(mode[i] != current) { + switch(mode[i]) { + case 'K': count += 12 + 4; current = 'K'; break; + case 'B': count += 16 + 4; current = 'B'; break; + case 'A': count += 13 + 4; current = 'A'; a_count = 0; break; + case 'N': count += 14 + 4; current = 'N'; n_count = 0; break; + } + } + + switch(mode[i]) { + case 'K': count += 13; break; + case 'B': count += 8; break; + case 'A': + a_count++; + if((a_count & 1) == 0) { + count += 5; // 11 in total + a_count = 0; + } + else + count += 6; + break; + case 'N': + n_count++; + if((n_count % 3) == 0) { + count += 3; // 10 in total + n_count = 0; + } + else if ((n_count & 1) == 0) + count += 3; // 7 in total + else + count += 4; + break; + } + } + + return count; +} + +static void qr_bscan(char *binary, int data, int h) +{ + for (; h; h>>=1) { + concat(binary, data & h ? "1" : "0"); + } +} + +void qr_binary(int datastream[], int version, int target_binlen, char mode[], int jisdata[], int length, int gs1, int est_binlen) +{ + /* Convert input data to a binary stream and add padding */ + int position = 0, debug = 0; + int short_data_block_length, i, scheme = 1; + char data_block, padbits; + int current_binlen, current_bytes; + int toggle, percent; + +#ifndef _MSC_VER + char binary[est_binlen + 12]; +#else + char* binary = (char *)_alloca(est_binlen + 12); +#endif + strcpy(binary, ""); + + if(gs1) { + concat(binary, "0101"); /* FNC1 */ + } + + if(version <= 9) { + scheme = 1; + } else if((version >= 10) && (version <= 26)) { + scheme = 2; + } else if(version >= 27) { + scheme = 3; + } + + if(debug) { + for(i = 0; i < length; i++) { + printf("%c", mode[i]); + } + printf("\n"); + } + + percent = 0; + + do { + data_block = mode[position]; + short_data_block_length = 0; + do { + short_data_block_length++; + } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block)); + + switch(data_block) { + case 'K': + /* Kanji mode */ + /* Mode indicator */ + concat(binary, "1000"); + + /* Character count indicator */ + qr_bscan(binary, short_data_block_length, 0x20 << (scheme*2)); /* scheme = 1..3 */ + + if(debug) { printf("Kanji block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + for(i = 0; i < short_data_block_length; i++) { + int jis = jisdata[position + i]; + int msb, lsb, prod; + + if(jis > 0x9fff) { jis -= 0xc140; } + msb = (jis & 0xff00) >> 4; + lsb = (jis & 0xff); + prod = (msb * 0xc0) + lsb; + + qr_bscan(binary, prod, 0x1000); + + if(debug) { printf("0x%4X ", prod); } + } + + if(debug) { printf("\n"); } + + break; + case 'B': + /* Byte mode */ + /* Mode indicator */ + concat(binary, "0100"); + + /* Character count indicator */ + qr_bscan(binary, short_data_block_length, scheme > 1 ? 0x8000 : 0x80); /* scheme = 1..3 */ + + if(debug) { printf("Byte block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + for(i = 0; i < short_data_block_length; i++) { + int byte = jisdata[position + i]; + + if(gs1 && (byte == '[')) { + byte = 0x1d; /* FNC1 */ + } + + qr_bscan(binary, byte, 0x80); + + if(debug) { printf("0x%2X(%d) ", byte, byte); } + } + + if(debug) { printf("\n"); } + + break; + case 'A': + /* Alphanumeric mode */ + /* Mode indicator */ + concat(binary, "0010"); + + /* Character count indicator */ + qr_bscan(binary, short_data_block_length, 0x40 << (2 * scheme)); /* scheme = 1..3 */ + + if(debug) { printf("Alpha block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + i = 0; + while ( i < short_data_block_length ) { + int count; + int first = 0, second = 0, prod; + + if(percent == 0) { + if(gs1 && (jisdata[position + i] == '%')) { + first = posn(RHODIUM, '%'); + second = posn(RHODIUM, '%'); + count = 2; + prod = (first * 45) + second; + i++; + } else { + if(gs1 && (jisdata[position + i] == '[')) { + first = posn(RHODIUM, '%'); /* FNC1 */ + } else { + first = posn(RHODIUM, (char) jisdata[position + i]); + } + count = 1; + i++; + prod = first; + + if(i < short_data_block_length && mode[position + i] == 'A') { + if(gs1 && (jisdata[position + i] == '%')) { + second = posn(RHODIUM, '%'); + count = 2; + prod = (first * 45) + second; + percent = 1; + } else { + if(gs1 && (jisdata[position + i] == '[')) { + second = posn(RHODIUM, '%'); /* FNC1 */ + } else { + second = posn(RHODIUM, (char) jisdata[position + i]); + } + count = 2; + i++; + prod = (first * 45) + second; + } + } + } + } else { + first = posn(RHODIUM, '%'); + count = 1; + i++; + prod = first; + percent = 0; + + if(i < short_data_block_length && mode[position + i] == 'A') { + if(gs1 && (jisdata[position + i] == '%')) { + second = posn(RHODIUM, '%'); + count = 2; + prod = (first * 45) + second; + percent = 1; + } else { + if(gs1 && (jisdata[position + i] == '[')) { + second = posn(RHODIUM, '%'); /* FNC1 */ + } else { + second = posn(RHODIUM, (char) jisdata[position + i]); + } + count = 2; + i++; + prod = (first * 45) + second; + } + } + } + + qr_bscan(binary, prod, count == 2 ? 0x400 : 0x20); /* count = 1..2 */ + + if(debug) { printf("0x%4X ", prod); } + }; + + if(debug) { printf("\n"); } + + break; + case 'N': + /* Numeric mode */ + /* Mode indicator */ + concat(binary, "0001"); + + /* Character count indicator */ + qr_bscan(binary, short_data_block_length, 0x80 << (2 * scheme)); /* scheme = 1..3 */ + + if(debug) { printf("Number block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + i = 0; + while ( i < short_data_block_length ) { + int count; + int first = 0, second = 0, third = 0, prod; + + first = posn(NEON, (char) jisdata[position + i]); + count = 1; + prod = first; + + if(i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { + second = posn(NEON, (char) jisdata[position + i + 1]); + count = 2; + prod = (prod * 10) + second; + + if(i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { + third = posn(NEON, (char) jisdata[position + i + 2]); + count = 3; + prod = (prod * 10) + third; + } + } + + qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */ + + if(debug) { printf("0x%4X (%d)", prod, prod); } + + i += count; + }; + + if(debug) { printf("\n"); } + + break; + } + + position += short_data_block_length; + } while (position < length) ; + + printf("Actual binary: %d\n", (int) strlen(binary)); + + /* Terminator */ + concat(binary, "0000"); + + current_binlen = strlen(binary); + padbits = 8 - (current_binlen % 8); + if(padbits == 8) { padbits = 0; } + current_bytes = (current_binlen + padbits) / 8; + + /* Padding bits */ + for(i = 0; i < padbits; i++) { + concat(binary, "0"); + } + + /* Put data into 8-bit codewords */ + for(i = 0; i < current_bytes; i++) { + datastream[i] = 0x00; + if(binary[i * 8] == '1') { datastream[i] += 0x80; } + if(binary[i * 8 + 1] == '1') { datastream[i] += 0x40; } + if(binary[i * 8 + 2] == '1') { datastream[i] += 0x20; } + if(binary[i * 8 + 3] == '1') { datastream[i] += 0x10; } + if(binary[i * 8 + 4] == '1') { datastream[i] += 0x08; } + if(binary[i * 8 + 5] == '1') { datastream[i] += 0x04; } + if(binary[i * 8 + 6] == '1') { datastream[i] += 0x02; } + if(binary[i * 8 + 7] == '1') { datastream[i] += 0x01; } + } + + /* Add pad codewords */ + toggle = 0; + for(i = current_bytes; i < target_binlen; i++) { + if(toggle == 0) { + datastream[i] = 0xec; + toggle = 1; + } else { + datastream[i] = 0x11; + toggle = 0; + } + } + + if(debug) { + printf("Resulting codewords:\n\t"); + for(i = 0; i < target_binlen; i++) { + printf("0x%2X ", datastream[i]); + } + printf("\n"); + } +} + +void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int blocks) +{ + /* Split data into blocks, add error correction and then interleave the blocks and error correction data */ + int ecc_cw = qr_total_codewords[version - 1] - data_cw; + int short_data_block_length = data_cw / blocks; + int qty_long_blocks = data_cw % blocks; + int qty_short_blocks = blocks - qty_long_blocks; + int ecc_block_length = ecc_cw / blocks; + int i, j, length_this_block, posn, debug = 0; + + +#ifndef _MSC_VER + unsigned char data_block[short_data_block_length + 2]; + unsigned char ecc_block[ecc_block_length + 2]; + int interleaved_data[data_cw + 2]; + int interleaved_ecc[ecc_cw + 2]; +#else + unsigned char* data_block = (unsigned char *)_alloca(short_data_block_length + 2); + unsigned char* ecc_block = (unsigned char *)_alloca(ecc_block_length + 2); + int* interleaved_data = (int *)_alloca((data_cw + 2) * sizeof(int)); + int* interleaved_ecc = (int *)_alloca((ecc_cw + 2) * sizeof(int)); +#endif + + posn = 0; + + for(i = 0; i < blocks; i++) { + if(i < qty_short_blocks) { length_this_block = short_data_block_length; } else { length_this_block = short_data_block_length + 1; } + + for(j = 0; j < ecc_block_length; j++) { + ecc_block[j] = 0; + } + + for(j = 0; j < length_this_block; j++) { + data_block[j] = (unsigned char) datastream[posn + j]; + } + + rs_init_gf(0x11d); + rs_init_code(ecc_block_length, 0); + rs_encode(length_this_block, data_block, ecc_block); + rs_free(); + + if(debug) { + printf("Block %d: ", i + 1); + for(j = 0; j < length_this_block; j++) { + printf("%2X ", data_block[j]); + } + if(i < qty_short_blocks) { + printf(" "); + } + printf(" // "); + for(j = 0; j < ecc_block_length; j++) { + printf("%2X ", ecc_block[ecc_block_length - j - 1]); + } + printf("\n"); + } + + for(j = 0; j < short_data_block_length; j++) { + interleaved_data[(j * blocks) + i] = (int) data_block[j]; + } + + if(i >= qty_short_blocks){ + interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = (int) data_block[short_data_block_length]; + } + + for(j = 0; j < ecc_block_length; j++) { + interleaved_ecc[(j * blocks) + i] = (int) ecc_block[ecc_block_length - j - 1]; + } + + posn += length_this_block; + } + + for(j = 0; j < data_cw; j++) { + fullstream[j] = interleaved_data[j]; + } + for(j = 0; j < ecc_cw; j++) { + fullstream[j + data_cw] = interleaved_ecc[j]; + } + + if(debug) { + printf("\nData Stream: \n"); + for(j = 0; j < (data_cw + ecc_cw); j++) { + printf("%2X ", fullstream[j]); + } + printf("\n"); + } +} + +void place_finder(unsigned char grid[], int size, int x, int y) +{ + int xp, yp; + + int finder[] = { + 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 1, + 1, 0, 1, 1, 1, 0, 1, + 1, 0, 1, 1, 1, 0, 1, + 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1 + }; + + for(xp = 0; xp < 7; xp++) { + for(yp = 0; yp < 7; yp++) { + if (finder[xp + (7 * yp)] == 1) { + grid[((yp + y) * size) + (xp + x)] = 0x11; + } else { + grid[((yp + y) * size) + (xp + x)] = 0x10; + } + } + } +} + +void place_align(unsigned char grid[], int size, int x, int y) +{ + int xp, yp; + + int alignment[] = { + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + }; + + x -= 2; + y -= 2; /* Input values represent centre of pattern */ + + for(xp = 0; xp < 5; xp++) { + for(yp = 0; yp < 5; yp++) { + if (alignment[xp + (5 * yp)] == 1) { + grid[((yp + y) * size) + (xp + x)] = 0x11; + } else { + grid[((yp + y) * size) + (xp + x)] = 0x10; + } + } + } +} + +void setup_grid(unsigned char* grid, int size, int version) +{ + int i, toggle = 1; + int loopsize, x, y, xcoord, ycoord; + + /* Add timing patterns */ + for(i = 0; i < size; i++) { + if(toggle == 1) { + grid[(6 * size) + i] = 0x21; + grid[(i * size) + 6] = 0x21; + toggle = 0; + } else { + grid[(6 * size) + i] = 0x20; + grid[(i * size) + 6] = 0x20; + toggle = 1; + } + } + + /* Add finder patterns */ + place_finder(grid, size, 0, 0); + place_finder(grid, size, 0, size - 7); + place_finder(grid, size, size - 7, 0); + + /* Add separators */ + for(i = 0; i < 7; i++) { + grid[(7 * size) + i] = 0x10; + grid[(i * size) + 7] = 0x10; + grid[(7 * size) + (size - 1 - i)] = 0x10; + grid[(i * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + i] = 0x10; + grid[((size - 1 - i) * size) + 7] = 0x10; + } + grid[(7 * size) + 7] = 0x10; + grid[(7 * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + 7] = 0x10; + + /* Add alignment patterns */ + if(version != 1) { + /* Version 1 does not have alignment patterns */ + + loopsize = qr_align_loopsize[version - 1]; + for(x = 0; x < loopsize; x++) { + for(y = 0; y < loopsize; y++) { + xcoord = qr_table_e1[((version - 2) * 7) + x]; + ycoord = qr_table_e1[((version - 2) * 7) + y]; + + if(!(grid[(ycoord * size) + xcoord] & 0x10)) { + place_align(grid, size, xcoord, ycoord); + } + } + } + } + + /* Reserve space for format information */ + for(i = 0; i < 8; i++) { + grid[(8 * size) + i] += 0x20; + grid[(i * size) + 8] += 0x20; + grid[(8 * size) + (size - 1 - i)] = 0x20; + grid[((size - 1 - i) * size) + 8] = 0x20; + } + grid[(8 * size) + 8] += 20; + grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */ + + /* Reserve space for version information */ + if(version >= 7) { + for(i = 0; i < 6; i++) { + grid[((size - 9) * size) + i] = 0x20; + grid[((size - 10) * size) + i] = 0x20; + grid[((size - 11) * size) + i] = 0x20; + grid[(i * size) + (size - 9)] = 0x20; + grid[(i * size) + (size - 10)] = 0x20; + grid[(i * size) + (size - 11)] = 0x20; + } + } +} + +int cwbit(int* datastream, int i) { + int word = i / 8; + int bit = i % 8; + int resultant = 0; + + switch(bit) { + case 0: if(datastream[word] & 0x80) { resultant = 1; } else { resultant = 0; } break; + case 1: if(datastream[word] & 0x40) { resultant = 1; } else { resultant = 0; } break; + case 2: if(datastream[word] & 0x20) { resultant = 1; } else { resultant = 0; } break; + case 3: if(datastream[word] & 0x10) { resultant = 1; } else { resultant = 0; } break; + case 4: if(datastream[word] & 0x08) { resultant = 1; } else { resultant = 0; } break; + case 5: if(datastream[word] & 0x04) { resultant = 1; } else { resultant = 0; } break; + case 6: if(datastream[word] & 0x02) { resultant = 1; } else { resultant = 0; } break; + case 7: if(datastream[word] & 0x01) { resultant = 1; } else { resultant = 0; } break; + } + + return resultant; +} + +void populate_grid(unsigned char* grid, int size, int* datastream, int cw) +{ + int direction = 1; /* up */ + int row = 0; /* right hand side */ + + int i, n, x, y; + + n = cw * 8; + y = size - 1; + i = 0; + do { + x = (size - 2) - (row * 2); + if(x < 6) + x--; /* skip over vertical timing pattern */ + + if(!(grid[(y * size) + (x + 1)] & 0xf0)) { + if (cwbit(datastream, i)) { + grid[(y * size) + (x + 1)] = 0x01; + } else { + grid[(y * size) + (x + 1)] = 0x00; + } + i++; + } + + if(i < n) { + if(!(grid[(y * size) + x] & 0xf0)) { + if (cwbit(datastream, i)) { + grid[(y * size) + x] = 0x01; + } else { + grid[(y * size) + x] = 0x00; + } + i++; + } + } + + if(direction) { y--; } else { y++; } + if(y == -1) { + /* reached the top */ + row++; + y = 0; + direction = 0; + } + if(y == size) { + /* reached the bottom */ + row++; + y = size - 1; + direction = 1; + } + } while (i < n); +} + +#ifdef ZINTLOG +int append_log(char log) +{ + FILE *file; + + file = fopen("zintlog.txt", "a+"); + fprintf(file, "%c", log); + fclose(file); + return 0; +} + +int write_log(char log[]) +{ + FILE *file; + + file = fopen("zintlog.txt", "a+"); + fprintf(file, log); /*writes*/ + fprintf(file, "\r\n"); /*writes*/ + fclose(file); + return 0; +} +#endif + +int evaluate(unsigned char *grid, int size, int pattern) +{ + int x, y, block; + int result = 0; + char state; + int p; + int dark_mods; + int percentage, k, k2; + int m; + int smallest; +#ifdef ZINTLOG + int result_b = 0; + char str[15]; +#endif + +#ifndef _MSC_VER + char local[size * size]; +#else + char* local = (char *)_alloca((size * size) * sizeof(char)); +#endif + + +#ifdef ZINTLOG + write_log(""); + sprintf(str, "%d", pattern); + write_log(str); +#endif + + // all eight bitmask variants have been encoded in the 8 bits of the bytes that make up the grid array. select them for evaluation according to the desired pattern. + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + switch(pattern) { + case 0: if (grid[(y * size) + x] & 0x01) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 1: if (grid[(y * size) + x] & 0x02) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 2: if (grid[(y * size) + x] & 0x04) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 3: if (grid[(y * size) + x] & 0x08) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 4: if (grid[(y * size) + x] & 0x10) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 5: if (grid[(y * size) + x] & 0x20) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 6: if (grid[(y * size) + x] & 0x40) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + case 7: if (grid[(y * size) + x] & 0x80) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; + } + } + } + +#ifdef ZINTLOG + //bitmask output + for(y = 0; y < size; y++) { + strcpy (str, ""); + for(x = 0; x < size; x++) { + state =local[(y * size) + x]; + append_log(state); + } + write_log(""); + } + write_log(""); +#endif + + /* Test 1: Adjacent modules in row/column in same colour */ + /* Vertical */ + for(x = 0; x < size; x++) { + state = local[x]; + block = 0; + for(y = 0; y < size; y++) { + if(local[(y * size) + x] == state) { + block++; + if(block ==5) + result += 3; + + if(block>5) + result +=1; + } else { + block=0; + } + } + } + + /* Horizontal */ + for(y = 0; y < size; y++) { + state = local[y * size]; + block = 0; + for(x = 0; x < size; x++) { + if(local[(y * size) + x] == state) { + block++; + if(block ==5) + result += 3; + + if(block>5) + result +=1; + } else { + block=0; + } + } + } + +#ifdef ZINTLOG + /* output Test 1 */ + sprintf(str, "%d", result); + result_b=result; + write_log(str); +#endif + + /* Test 2 fd02131114 */ + for(x = 0; x < size-1; x++) { + for(y = 0; y < (size - 7) -1; y++) { + // y + 1??? + if((local[((y + 1) * size) + x] == '1') && + (local[((y + 1) * size) + x+1] == '1') && + (local[(((y + 1)+1) * size) + x] == '1') && + (local[(((y + 1)+1) * size) + x+1] == '1') + ) { result += 3; } + + if((local[((y + 1) * size) + x] == '0') && + (local[((y + 1) * size) + x+1] == '0') && + (local[(((y + 1)+1) * size) + x] == '0') && + (local[(((y + 1)+1) * size) + x+1] == '0') + ) { result += 3; } + } + } + +#ifdef ZINTLOG + /* output Test 2 */ + sprintf(str, "%d", result-result_b); + result_b=result; + write_log(str); +#endif + + /* Test 3: fd02131114 */ + /*pattern 10111010000 */ + /* Vertical */ + for(x = 0; x < size; x++) { + for(y = 0; y < (size - 11); y++) { + p = 0; + if(local[(y * size) + x] == '1') { p += 1; } + if(local[((y + 1) * size) + x] == '0') { p += 1; } + if(local[((y + 2) * size) + x] == '1') { p += 1; } + if(local[((y + 3) * size) + x] == '1') { p += 1; } + if(local[((y + 4) * size) + x] == '1') { p += 1; } + if(local[((y + 5) * size) + x] == '0') { p += 1; } + if(local[((y + 6) * size) + x] == '1') { p += 1; } + if(local[((y + 7) * size) + x] == '0') { p += 1; } + if(local[((y + 8) * size) + x] == '0') { p += 1; } + if(local[((y + 9) * size) + x] == '0') { p += 1; } + if(local[((y + 10) * size) + x] == '0') { p += 1; } + if(p == 11) { + result += 40; + } + } + } + + /* Horizontal */ + for(y = 0; y < size; y++) { + for(x = 0; x < (size - 11); x++) { + p = 0; + if(local[(y * size) + x] == '1') { p += 1; } + if(local[(y * size) + x + 1] == '0') { p += 1; } + if(local[(y * size) + x + 2] == '1') { p += 1; } + if(local[(y * size) + x + 3] == '1') { p += 1; } + if(local[(y * size) + x + 4] == '1') { p += 1; } + if(local[(y * size) + x + 5] == '0') { p += 1; } + if(local[(y * size) + x + 6] == '1') { p += 1; } + if(local[(y * size) + x + 7] == '0') { p += 1; } + if(local[(y * size) + x + 8] == '0') { p += 1; } + if(local[(y * size) + x + 9] == '0') { p += 1; } + if(local[(y * size) + x + 10] == '0') { p += 1; } + if(p == 11) { + result += 40; + } + } + } + + /*pattern 00001011101 */ + /* Vertical */ + for(x = 0; x < size; x++) { + for(y = 0; y < (size - 11); y++) { + p = 0; + if(local[(y * size) + x] == '0') { p += 1; } + if(local[((y + 1) * size) + x] == '0') { p += 1; } + if(local[((y + 2) * size) + x] == '0') { p += 1; } + if(local[((y + 3) * size) + x] == '0') { p += 1; } + if(local[((y + 4) * size) + x] == '1') { p += 1; } + if(local[((y + 5) * size) + x] == '0') { p += 1; } + if(local[((y + 6) * size) + x] == '1') { p += 1; } + if(local[((y + 7) * size) + x] == '1') { p += 1; } + if(local[((y + 8) * size) + x] == '1') { p += 1; } + if(local[((y + 9) * size) + x] == '0') { p += 1; } + if(local[((y + 10) * size) + x] == '1') { p += 1; } + if(p == 11) { + result += 40; + } + } + } + + /* Horizontal */ + for(y = 0; y < size; y++) { + for(x = 0; x < (size - 11); x++) { + p = 0; + if(local[(y * size) + x] == '0') { p += 1; } + if(local[(y * size) + x + 1] == '0') { p += 1; } + if(local[(y * size) + x + 2] == '0') { p += 1; } + if(local[(y * size) + x + 3] == '0') { p += 1; } + if(local[(y * size) + x + 4] == '1') { p += 1; } + if(local[(y * size) + x + 5] == '0') { p += 1; } + if(local[(y * size) + x + 6] == '1') { p += 1; } + if(local[(y * size) + x + 7] == '1') { p += 1; } + if(local[(y * size) + x + 8] == '1') { p += 1; } + if(local[(y * size) + x + 9] == '0') { p += 1; } + if(local[(y * size) + x + 10] == '1') { p += 1; } + if(p == 11) { + result += 40; + } + } + } + +#ifdef ZINTLOG + /* output Test 3 */ + sprintf(str, "%d", result-result_b); + result_b=result; + write_log(str); +#endif + + /* Test 4: Proportion of dark modules in entire symbol */ + dark_mods = 0; + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + if(local[(y * size) + x] == '1') { + dark_mods++; + } + } + } + percentage = 100 * (dark_mods / (size * size)); + m=0; + for(x = 0; x < 100; x+=5) { + if(x> i) & 0x01 ? (0x01 >> pattern) : 0x00; + } + + for(i = 0; i < 8; i++) { + eval[(8 * size) + (size - i - 1)] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00; + } + + for(i = 0; i < 6; i++) { + eval[(8 * size) + (5 - i)] = (seq >> (i + 9)) & 0x01 ? (0x01 >> pattern) : 0x00; + } + + for(i = 0; i < 7; i++) { + eval[(((size - 7) + i) * size) + 8] = (seq >> (i + 8)) & 0x01 ? (0x01 >> pattern) : 0x00; + } + + eval[(7 * size) + 8] = (seq >> 6) & 0x01 ? (0x01 >> pattern) : 0x00; + eval[(8 * size) + 8] = (seq >> 7) & 0x01 ? (0x01 >> pattern) : 0x00; + eval[(8 * size) + 7] = (seq >> 8) & 0x01 ? (0x01 >> pattern) : 0x00; +} + +int apply_bitmask(unsigned char *grid, int size, int ecc_level) +{ + int x, y; + unsigned char p; + int pattern, penalty[8]; + int best_val, best_pattern; + int bit; + +#ifndef _MSC_VER + unsigned char mask[size * size]; + unsigned char eval[size * size]; +#else + unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); +#endif + + /* Perform data masking */ + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + mask[(y * size) + x] = 0x00; + + // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. + if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked. + if(((y + x) & 1) == 0) { mask[(y * size) + x] += 0x01; } + if((y & 1) == 0) { mask[(y * size) + x] += 0x02; } + if((x % 3) == 0) { mask[(y * size) + x] += 0x04; } + if(((y + x) % 3) == 0) { mask[(y * size) + x] += 0x08; } + if((((y / 2) + (x / 3)) & 1) == 0) { mask[(y * size) + x] += 0x10; } + if((((y * x) & 1) + ((y * x) % 3)) == 0) { mask[(y * size) + x] += 0x20; } + if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x40; } + if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x80; } + } + } + } + + // apply data masks to grid, result in eval + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + if(grid[(y * size) + x] & 0x01) + { p = 0xff; } + else { p = 0x00; } + + eval[(y * size) + x] = mask[(y * size) + x] ^ p; + } + } + + + /* Evaluate result */ + for(pattern = 0; pattern < 8; pattern++) { + + add_format_info_eval(eval, size, ecc_level, pattern); + + penalty[pattern] = evaluate(eval, size, pattern); + } + + best_pattern = 0; + best_val = penalty[0]; + for(pattern = 1; pattern < 8; pattern++) { + if(penalty[pattern] < best_val) { + best_pattern = pattern; + best_val = penalty[pattern]; + } + } + +#ifdef ZINTLOG + char str[15]; + sprintf(str, "%d", best_val); + write_log("choosed pattern:"); + write_log(str); +#endif + + /* Apply mask */ + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + bit = 0; + switch(best_pattern) { + case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; + case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; + case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; + case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; + case 4: if(mask[(y * size) + x] & 0x10) { bit = 1; } break; + case 5: if(mask[(y * size) + x] & 0x20) { bit = 1; } break; + case 6: if(mask[(y * size) + x] & 0x40) { bit = 1; } break; + case 7: if(mask[(y * size) + x] & 0x80) { bit = 1; } break; + } + if(bit == 1) { + if(grid[(y * size) + x] & 0x01) { + grid[(y * size) + x] = 0x00; + } else { + grid[(y * size) + x] = 0x01; + } + } + } + } + + return best_pattern; +} + +void add_format_info(unsigned char *grid, int size, int ecc_level, int pattern) +{ + /* Add format information to grid */ + + int format = pattern; + unsigned int seq; + int i; + + switch(ecc_level) { + case LEVEL_L: format += 0x08; break; + case LEVEL_Q: format += 0x18; break; + case LEVEL_H: format += 0x10; break; + } + + seq = qr_annex_c[format]; + + for(i = 0; i < 6; i++) { + grid[(i * size) + 8] += (seq >> i) & 0x01; + } + + for(i = 0; i < 8; i++) { + grid[(8 * size) + (size - i - 1)] += (seq >> i) & 0x01; + } + + for(i = 0; i < 6; i++) { + grid[(8 * size) + (5 - i)] += (seq >> (i + 9)) & 0x01; + } + + for(i = 0; i < 7; i++) { + grid[(((size - 7) + i) * size) + 8] += (seq >> (i + 8)) & 0x01; + } + + grid[(7 * size) + 8] += (seq >> 6) & 0x01; + grid[(8 * size) + 8] += (seq >> 7) & 0x01; + grid[(8 * size) + 7] += (seq >> 8) & 0x01; +} + +void add_version_info(unsigned char *grid, int size, int version) +{ + /* Add version information */ + int i; + + long int version_data = qr_annex_d[version - 7]; + for(i = 0; i < 6; i++) { + grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41; + grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41; + grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41; + grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41; + grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41; + grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41; + } +} + +int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) +{ + int error_number, i, j, glyph, est_binlen; + int ecc_level, autosize, version, max_cw, target_binlen, blocks, size; + int bitmask, gs1; + +#ifndef _MSC_VER + int utfdata[length + 1]; + int jisdata[length + 1]; + char mode[length + 1]; +#else + int* datastream; + int* fullstream; + unsigned char* grid; + int* utfdata = (int *)_alloca((length + 1) * sizeof(int)); + int* jisdata = (int *)_alloca((length + 1) * sizeof(int)); + char* mode = (char *)_alloca(length + 1); +#endif + + gs1 = (symbol->input_mode == GS1_MODE); + + switch(symbol->input_mode) { + case DATA_MODE: + for(i = 0; i < length; i++) { + jisdata[i] = (int)source[i]; + } + break; + default: + /* Convert Unicode input to Shift-JIS */ + error_number = utf8toutf16(symbol, source, utfdata, &length); + if(error_number != 0) { return error_number; } + + for(i = 0; i < length; i++) { + if(utfdata[i] <= 0xff) { + jisdata[i] = utfdata[i]; + } else { + j = 0; + glyph = 0; + do { + if(sjis_lookup[j * 2] == utfdata[i]) { + glyph = sjis_lookup[(j * 2) + 1]; + } + j++; + } while ((j < 6843) && (glyph == 0)); + if(glyph == 0) { + strcpy(symbol->errtxt, "Invalid character in input data"); + return ZINT_ERROR_INVALID_DATA; + } + jisdata[i] = glyph; + } + } + break; + } + + define_mode(mode, jisdata, length, gs1); + est_binlen = estimate_binary_length(mode, length, gs1); + + ecc_level = LEVEL_L; + max_cw = 2956; + if((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) { + switch (symbol->option_1) { + case 1: ecc_level = LEVEL_L; max_cw = 2956; break; + case 2: ecc_level = LEVEL_M; max_cw = 2334; break; + case 3: ecc_level = LEVEL_Q; max_cw = 1666; break; + case 4: ecc_level = LEVEL_H; max_cw = 1276; break; + } + } + + if(est_binlen > (8 * max_cw)) { + strcpy(symbol->errtxt, "Input too long for selected error correction level"); + return ZINT_ERROR_TOO_LONG; + } + + autosize = 40; + for(i = 39; i >= 0; i--) { + switch(ecc_level) { + case LEVEL_L: + if ((8 * qr_data_codewords_L[i]) >= est_binlen) { + autosize = i + 1; + } + break; + case LEVEL_M: + if ((8 * qr_data_codewords_M[i]) >= est_binlen) { + autosize = i + 1; + } + break; + case LEVEL_Q: + if ((8 * qr_data_codewords_Q[i]) >= est_binlen) { + autosize = i + 1; + } + break; + case LEVEL_H: + if ((8 * qr_data_codewords_H[i]) >= est_binlen) { + autosize = i + 1; + } + break; + } + } + + if((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) { + if (symbol->option_2 > autosize) { + version = symbol->option_2; + } else { + version = autosize; + } + } else { + version = autosize; + } + + /* Ensure maxium error correction capacity */ + if(est_binlen <= qr_data_codewords_M[version - 1]) { ecc_level = LEVEL_M; } + if(est_binlen <= qr_data_codewords_Q[version - 1]) { ecc_level = LEVEL_Q; } + if(est_binlen <= qr_data_codewords_H[version - 1]) { ecc_level = LEVEL_H; } + + target_binlen = qr_data_codewords_L[version - 1]; blocks = qr_blocks_L[version - 1]; + switch(ecc_level) { + case LEVEL_M: target_binlen = qr_data_codewords_M[version - 1]; blocks = qr_blocks_M[version - 1]; break; + case LEVEL_Q: target_binlen = qr_data_codewords_Q[version - 1]; blocks = qr_blocks_Q[version - 1]; break; + case LEVEL_H: target_binlen = qr_data_codewords_H[version - 1]; blocks = qr_blocks_H[version - 1]; break; + } + +#ifndef _MSC_VER + int datastream[target_binlen + 1]; + int fullstream[qr_total_codewords[version - 1] + 1]; +#else + datastream = (int *)_alloca((target_binlen + 1) * sizeof(int)); + fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int)); +#endif + + qr_binary(datastream, version, target_binlen, mode, jisdata, length, gs1, est_binlen); + add_ecc(fullstream, datastream, version, target_binlen, blocks); + + size = qr_sizes[version - 1]; +#ifndef _MSC_VER + unsigned char grid[size * size]; +#else + grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); +#endif + + for(i = 0; i < size; i++) { + for(j = 0; j < size; j++) { + grid[(i * size) + j] = 0; + } + } + + setup_grid(grid, size, version); + populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]); + + if(version >= 7) { + add_version_info(grid, size, version); + } + + bitmask = apply_bitmask(grid, size, ecc_level); + + add_format_info(grid, size, ecc_level, bitmask); + + + + symbol->width = size; + symbol->rows = size; + + for(i = 0; i < size; i++) { + for(j = 0; j < size; j++) { + if(grid[(i * size) + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + + return 0; +} + +/* NOTE: From this point forward concerns Micro QR Code only */ + +int micro_qr_intermediate(char binary[], int jisdata[], char mode[], int length, int *kanji_used, int *alphanum_used, int *byte_used) +{ + /* Convert input data to an "intermediate stage" where data is binary encoded but + control information is not */ + int position = 0, debug = 0; + int short_data_block_length, i; + char data_block; + char buffer[2]; + + strcpy(binary, ""); + + if(debug) { + for(i = 0; i < length; i++) { + printf("%c", mode[i]); + } + printf("\n"); + } + + do { + if(strlen(binary) > 128) { + return ZINT_ERROR_TOO_LONG; + } + + data_block = mode[position]; + short_data_block_length = 0; + do { + short_data_block_length++; + } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block)); + + switch(data_block) { + case 'K': + /* Kanji mode */ + /* Mode indicator */ + concat(binary, "K"); + *kanji_used = 1; + + /* Character count indicator */ + buffer[0] = short_data_block_length; + buffer[1] = '\0'; + concat(binary, buffer); + + if(debug) { printf("Kanji block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + for(i = 0; i < short_data_block_length; i++) { + int jis = jisdata[position + i]; + int msb, lsb, prod; + + if(jis > 0x9fff) { jis -= 0xc140; } + msb = (jis & 0xff00) >> 4; + lsb = (jis & 0xff); + prod = (msb * 0xc0) + lsb; + + qr_bscan(binary, prod, 0x1000); + + if(debug) { printf("0x%4X ", prod); } + + if(strlen(binary) > 128) { + return ZINT_ERROR_TOO_LONG; + } + } + + if(debug) { printf("\n"); } + + break; + case 'B': + /* Byte mode */ + /* Mode indicator */ + concat(binary, "B"); + *byte_used = 1; + + /* Character count indicator */ + buffer[0] = short_data_block_length; + buffer[1] = '\0'; + concat(binary, buffer); + + if(debug) { printf("Byte block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + for(i = 0; i < short_data_block_length; i++) { + int byte = jisdata[position + i]; + + qr_bscan(binary, byte, 0x80); + + if(debug) { printf("0x%4X ", byte); } + + if(strlen(binary) > 128) { + return ZINT_ERROR_TOO_LONG; + } + } + + if(debug) { printf("\n"); } + + break; + case 'A': + /* Alphanumeric mode */ + /* Mode indicator */ + concat(binary, "A"); + *alphanum_used = 1; + + /* Character count indicator */ + buffer[0] = short_data_block_length; + buffer[1] = '\0'; + concat(binary, buffer); + + if(debug) { printf("Alpha block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + i = 0; + while ( i < short_data_block_length ) { + int count; + int first = 0, second = 0, prod; + + first = posn(RHODIUM, (char) jisdata[position + i]); + count = 1; + prod = first; + + if(i + 1 < short_data_block_length && mode[position + i + 1] == 'A') { + second = posn(RHODIUM, (char) jisdata[position + i + 1]); + count = 2; + prod = (first * 45) + second; + } + + qr_bscan(binary, prod, 1 << (5 * count)); /* count = 1..2 */ + + if(debug) { printf("0x%4X ", prod); } + + if(strlen(binary) > 128) { + return ZINT_ERROR_TOO_LONG; + } + + i += 2; + }; + + if(debug) { printf("\n"); } + + break; + case 'N': + /* Numeric mode */ + /* Mode indicator */ + concat(binary, "N"); + + /* Character count indicator */ + buffer[0] = short_data_block_length; + buffer[1] = '\0'; + concat(binary, buffer); + + if(debug) { printf("Number block (length %d)\n\t", short_data_block_length); } + + /* Character representation */ + i = 0; + while ( i < short_data_block_length ) { + int count; + int first = 0, second = 0, third = 0, prod; + + first = posn(NEON, (char) jisdata[position + i]); + count = 1; + prod = first; + + if(i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { + second = posn(NEON, (char) jisdata[position + i + 1]); + count = 2; + prod = (prod * 10) + second; + } + + if(i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { + third = posn(NEON, (char) jisdata[position + i + 2]); + count = 3; + prod = (prod * 10) + third; + } + + qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */ + + if(debug) { printf("0x%4X (%d)", prod, prod); } + + if(strlen(binary) > 128) { + return ZINT_ERROR_TOO_LONG; + } + + i += 3; + }; + + if(debug) { printf("\n"); } + + break; + } + + position += short_data_block_length; + } while (position < length - 1) ; + + return 0; +} + +void get_bitlength(int count[], char stream[]) { + int length, i; + + length = strlen(stream); + + for(i = 0; i < 4; i++) { + count[i] = 0; + } + + i = 0; + do { + if((stream[i] == '0') || (stream[i] == '1')) { + count[0]++; + count[1]++; + count[2]++; + count[3]++; + i++; + } else { + switch(stream[i]) { + case 'K': + count[2] += 5; + count[3] += 7; + i += 2; + break; + case 'B': + count[2] += 6; + count[3] += 8; + i += 2; + break; + case 'A': + count[1] += 4; + count[2] += 6; + count[3] += 8; + i += 2; + break; + case 'N': + count[0] += 3; + count[1] += 5; + count[2] += 7; + count[3] += 9; + i += 2; + break; + } + } + } while (i < length); +} + +void microqr_expand_binary(char binary_stream[], char full_stream[], int version) +{ + int i, length; + + length = strlen(binary_stream); + + i = 0; + do { + switch(binary_stream[i]) { + case '1': concat(full_stream, "1"); i++; break; + case '0': concat(full_stream, "0"); i++; break; + case 'N': + /* Numeric Mode */ + /* Mode indicator */ + switch(version) { + case 1: concat(full_stream, "0"); break; + case 2: concat(full_stream, "00"); break; + case 3: concat(full_stream, "000"); break; + } + + /* Character count indicator */ + qr_bscan(full_stream, binary_stream[i + 1], 4 << version); /* version = 0..3 */ + + i += 2; + break; + case 'A': + /* Alphanumeric Mode */ + /* Mode indicator */ + switch(version) { + case 1: concat(full_stream, "1"); break; + case 2: concat(full_stream, "01"); break; + case 3: concat(full_stream, "001"); break; + } + + /* Character count indicator */ + qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 1..3 */ + + i += 2; + break; + case 'B': + /* Byte Mode */ + /* Mode indicator */ + switch(version) { + case 2: concat(full_stream, "10"); break; + case 3: concat(full_stream, "010"); break; + } + + /* Character count indicator */ + qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 2..3 */ + + i += 2; + break; + case 'K': + /* Kanji Mode */ + /* Mode indicator */ + switch(version) { + case 2: concat(full_stream, "11"); break; + case 3: concat(full_stream, "011"); break; + } + + /* Character count indicator */ + qr_bscan(full_stream, binary_stream[i + 1], 1 << version); /* version = 2..3 */ + + i += 2; + break; + } + + } while (i < length); +} + +void micro_qr_m1(char binary_data[]) +{ + int i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[4], ecc_blocks[3]; + + bits_total = 20; + latch = 0; + + /* Add terminator */ + bits_left = bits_total - strlen(binary_data); + if(bits_left <= 3) { + for(i = 0; i < bits_left; i++) { + concat(binary_data, "0"); + } + latch = 1; + } else { + concat(binary_data, "000"); + } + + if(latch == 0) { + /* Manage last (4-bit) block */ + bits_left = bits_total - strlen(binary_data); + if(bits_left <= 4) { + for(i = 0; i < bits_left; i++) { + concat(binary_data, "0"); + } + latch = 1; + } + } + + if(latch == 0) { + /* Complete current byte */ + remainder = 8 - (strlen(binary_data) % 8); + if(remainder == 8) { remainder = 0; } + for(i = 0; i < remainder; i++) { + concat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - strlen(binary_data); + if(bits_left > 4) { + remainder = (bits_left - 4) / 8; + for(i = 0; i < remainder; i++) { + concat(binary_data, i & 1 ? "00010001" : "11101100"); + } + } + concat(binary_data, "0000"); + } + + data_codewords = 3; + ecc_codewords = 2; + + /* Copy data into codewords */ + for(i = 0; i < (data_codewords - 1); i++) { + data_blocks[i] = 0; + if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } + if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } + if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } + if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } + if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } + if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } + if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } + if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } + } + data_blocks[2] = 0; + if(binary_data[16] == '1') { data_blocks[2] += 0x08; } + if(binary_data[17] == '1') { data_blocks[2] += 0x04; } + if(binary_data[18] == '1') { data_blocks[2] += 0x02; } + if(binary_data[19] == '1') { data_blocks[2] += 0x01; } + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); + } +} + +void micro_qr_m2(char binary_data[], int ecc_mode) +{ + int i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[6], ecc_blocks[7]; + + latch = 0; + + if(ecc_mode == LEVEL_L) { bits_total = 40; } + if(ecc_mode == LEVEL_M) { bits_total = 32; } + + /* Add terminator */ + bits_left = bits_total - strlen(binary_data); + if(bits_left <= 5) { + for(i = 0; i < bits_left; i++) { + concat(binary_data, "0"); + } + latch = 1; + } else { + concat(binary_data, "00000"); + } + + if(latch == 0) { + /* Complete current byte */ + remainder = 8 - (strlen(binary_data) % 8); + if(remainder == 8) { remainder = 0; } + for(i = 0; i < remainder; i++) { + concat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - strlen(binary_data); + remainder = bits_left / 8; + for(i = 0; i < remainder; i++) { + concat(binary_data, i & 1 ? "00010001" : "11101100"); + } + } + + if(ecc_mode == LEVEL_L) { data_codewords = 5; ecc_codewords = 5; } + if(ecc_mode == LEVEL_M) { data_codewords = 4; ecc_codewords = 6; } + + /* Copy data into codewords */ + for(i = 0; i < data_codewords; i++) { + data_blocks[i] = 0; + if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } + if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } + if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } + if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } + if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } + if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } + if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } + if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } + } + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); + } + + return; +} + +void micro_qr_m3(char binary_data[], int ecc_mode) +{ + int i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[12], ecc_blocks[9]; + + latch = 0; + + if(ecc_mode == LEVEL_L) { bits_total = 84; } + if(ecc_mode == LEVEL_M) { bits_total = 68; } + + /* Add terminator */ + bits_left = bits_total - strlen(binary_data); + if(bits_left <= 7) { + for(i = 0; i < bits_left; i++) { + concat(binary_data, "0"); + } + latch = 1; + } else { + concat(binary_data, "0000000"); + } + + if(latch == 0) { + /* Manage last (4-bit) block */ + bits_left = bits_total - strlen(binary_data); + if(bits_left <= 4) { + for(i = 0; i < bits_left; i++) { + concat(binary_data, "0"); + } + latch = 1; + } + } + + if(latch == 0) { + /* Complete current byte */ + remainder = 8 - (strlen(binary_data) % 8); + if(remainder == 8) { remainder = 0; } + for(i = 0; i < remainder; i++) { + concat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - strlen(binary_data); + if(bits_left > 4) { + remainder = (bits_left - 4) / 8; + for(i = 0; i < remainder; i++) { + concat(binary_data, i & 1 ? "00010001" : "11101100"); + } + } + concat(binary_data, "0000"); + } + + if(ecc_mode == LEVEL_L) { data_codewords = 11; ecc_codewords = 6; } + if(ecc_mode == LEVEL_M) { data_codewords = 9; ecc_codewords = 8; } + + /* Copy data into codewords */ + for(i = 0; i < (data_codewords - 1); i++) { + data_blocks[i] = 0; + if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } + if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } + if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } + if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } + if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } + if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } + if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } + if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } + } + + if(ecc_mode == LEVEL_L) { + data_blocks[10] = 0; + if(binary_data[80] == '1') { data_blocks[10] += 0x08; } + if(binary_data[81] == '1') { data_blocks[10] += 0x04; } + if(binary_data[82] == '1') { data_blocks[10] += 0x02; } + if(binary_data[83] == '1') { data_blocks[10] += 0x01; } + } + + if(ecc_mode == LEVEL_M) { + data_blocks[8] = 0; + if(binary_data[64] == '1') { data_blocks[8] += 0x08; } + if(binary_data[65] == '1') { data_blocks[8] += 0x04; } + if(binary_data[66] == '1') { data_blocks[8] += 0x02; } + if(binary_data[67] == '1') { data_blocks[8] += 0x01; } + } + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); + } + + return; +} + +void micro_qr_m4(char binary_data[], int ecc_mode) +{ + int i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[17], ecc_blocks[15]; + + latch = 0; + + if(ecc_mode == LEVEL_L) { bits_total = 128; } + if(ecc_mode == LEVEL_M) { bits_total = 112; } + if(ecc_mode == LEVEL_Q) { bits_total = 80; } + + /* Add terminator */ + bits_left = bits_total - strlen(binary_data); + if(bits_left <= 9) { + for(i = 0; i < bits_left; i++) { + concat(binary_data, "0"); + } + latch = 1; + } else { + concat(binary_data, "000000000"); + } + + if(latch == 0) { + /* Complete current byte */ + remainder = 8 - (strlen(binary_data) % 8); + if(remainder == 8) { remainder = 0; } + for(i = 0; i < remainder; i++) { + concat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - strlen(binary_data); + remainder = bits_left / 8; + for(i = 0; i < remainder; i++) { + concat(binary_data, i & 1 ? "00010001" : "11101100"); + } + } + + if(ecc_mode == LEVEL_L) { data_codewords = 16; ecc_codewords = 8; } + if(ecc_mode == LEVEL_M) { data_codewords = 14; ecc_codewords = 10; } + if(ecc_mode == LEVEL_Q) { data_codewords = 10; ecc_codewords = 14; } + + /* Copy data into codewords */ + for(i = 0; i < data_codewords; i++) { + data_blocks[i] = 0; + if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } + if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } + if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } + if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } + if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } + if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } + if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } + if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } + } + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); + } +} + +void micro_setup_grid(unsigned char* grid, int size) +{ + int i, toggle = 1; + + /* Add timing patterns */ + for(i = 0; i < size; i++) { + if(toggle == 1) { + grid[i] = 0x21; + grid[(i * size)] = 0x21; + toggle = 0; + } else { + grid[i] = 0x20; + grid[(i * size)] = 0x20; + toggle = 1; + } + } + + /* Add finder patterns */ + place_finder(grid, size, 0, 0); + + /* Add separators */ + for(i = 0; i < 7; i++) { + grid[(7 * size) + i] = 0x10; + grid[(i * size) + 7] = 0x10; + } + grid[(7 * size) + 7] = 0x10; + + + /* Reserve space for format information */ + for(i = 0; i < 8; i++) { + grid[(8 * size) + i] += 0x20; + grid[(i * size) + 8] += 0x20; + } + grid[(8 * size) + 8] += 20; +} + +void micro_populate_grid(unsigned char* grid, int size, char full_stream[]) +{ + int direction = 1; /* up */ + int row = 0; /* right hand side */ + + int i, n, x, y; + + n = strlen(full_stream); + y = size - 1; + i = 0; + do { + x = (size - 2) - (row * 2); + + if(!(grid[(y * size) + (x + 1)] & 0xf0)) { + if (full_stream[i] == '1') { + grid[(y * size) + (x + 1)] = 0x01; + } else { + grid[(y * size) + (x + 1)] = 0x00; + } + i++; + } + + if(i < n) { + if(!(grid[(y * size) + x] & 0xf0)) { + if (full_stream[i] == '1') { + grid[(y * size) + x] = 0x01; + } else { + grid[(y * size) + x] = 0x00; + } + i++; + } + } + + if(direction) { y--; } else { y++; } + if(y == 0) { + /* reached the top */ + row++; + y = 1; + direction = 0; + } + if(y == size) { + /* reached the bottom */ + row++; + y = size - 1; + direction = 1; + } + } while (i < n); +} + +int micro_evaluate(unsigned char *grid, int size, int pattern) +{ + int sum1, sum2, i, filter = 0, retval; + + switch(pattern) { + case 0: filter = 0x01; break; + case 1: filter = 0x02; break; + case 2: filter = 0x04; break; + case 3: filter = 0x08; break; + } + + sum1 = 0; + sum2 = 0; + for(i = 1; i < size; i++) { + if(grid[(i * size) + size - 1] & filter) { sum1++; } + if(grid[((size - 1) * size) + i] & filter) { sum2++; } + } + + if(sum1 <= sum2) { retval = (sum1 * 16) + sum2; } else { retval = (sum2 * 16) + sum1; } + + return retval; +} + +int micro_apply_bitmask(unsigned char *grid, int size) +{ + int x, y; + unsigned char p; + int pattern, value[8]; + int best_val, best_pattern; + int bit; + +#ifndef _MSC_VER + unsigned char mask[size * size]; + unsigned char eval[size * size]; +#else + unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); +#endif + + /* Perform data masking */ + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + mask[(y * size) + x] = 0x00; + + if (!(grid[(y * size) + x] & 0xf0)) { + if((y & 1) == 0) { + mask[(y * size) + x] += 0x01; + } + + if((((y / 2) + (x / 3)) & 1) == 0) { + mask[(y * size) + x] += 0x02; + } + + if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[(y * size) + x] += 0x04; + } + + if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[(y * size) + x] += 0x08; + } + } + } + } + + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; } + + eval[(y * size) + x] = mask[(y * size) + x] ^ p; + } + } + + + /* Evaluate result */ + for(pattern = 0; pattern < 8; pattern++) { + value[pattern] = micro_evaluate(eval, size, pattern); + } + + best_pattern = 0; + best_val = value[0]; + for(pattern = 1; pattern < 4; pattern++) { + if(value[pattern] > best_val) { + best_pattern = pattern; + best_val = value[pattern]; + } + } + + /* Apply mask */ + for(x = 0; x < size; x++) { + for(y = 0; y < size; y++) { + bit = 0; + switch(best_pattern) { + case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; + case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; + case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; + case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; + } + if(bit == 1) { + if(grid[(y * size) + x] & 0x01) { + grid[(y * size) + x] = 0x00; + } else { + grid[(y * size) + x] = 0x01; + } + } + } + } + + return best_pattern; +} + +int microqr(struct zint_symbol *symbol, unsigned char source[], int length) +{ + int i, j, glyph, size; + char binary_stream[200]; + char full_stream[200]; + int utfdata[40]; + int jisdata[40]; + char mode[40]; + int error_number, kanji_used = 0, alphanum_used = 0, byte_used = 0; + int version_valid[4]; + int binary_count[4]; + int ecc_level, autoversion, version; + int n_count, a_count, bitmask, format, format_full; +#ifdef _MSC_VER + unsigned char* grid; +#endif + + if(length > 35) { + strcpy(symbol->errtxt, "Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + + for(i = 0; i < 4; i++) { + version_valid[i] = 1; + } + + switch(symbol->input_mode) { + case DATA_MODE: + for(i = 0; i < length; i++) { + jisdata[i] = (int)source[i]; + } + break; + default: + /* Convert Unicode input to Shift-JIS */ + error_number = utf8toutf16(symbol, source, utfdata, &length); + if(error_number != 0) { return error_number; } + + for(i = 0; i < length; i++) { + if(utfdata[i] <= 0xff) { + jisdata[i] = utfdata[i]; + } else { + j = 0; + glyph = 0; + do { + if(sjis_lookup[j * 2] == utfdata[i]) { + glyph = sjis_lookup[(j * 2) + 1]; + } + j++; + } while ((j < 6843) && (glyph == 0)); + if(glyph == 0) { + strcpy(symbol->errtxt, "Invalid character in input data"); + return ZINT_ERROR_INVALID_DATA; + } + jisdata[i] = glyph; + } + } + break; + } + + define_mode(mode, jisdata, length, 0); + + n_count = 0; + a_count = 0; + for(i = 0; i < length; i++) { + if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { n_count++; } + if(in_alpha(jisdata[i])) { a_count++; } + } + + if(a_count == length) { + /* All data can be encoded in Alphanumeric mode */ + for(i = 0; i < length; i++) { + mode[i] = 'A'; + } + } + + if(n_count == length) { + /* All data can be encoded in Numeric mode */ + for(i = 0; i < length; i++) { + mode[i] = 'N'; + } + } + + error_number = micro_qr_intermediate(binary_stream, jisdata, mode, length, &kanji_used, &alphanum_used, &byte_used); + if(error_number != 0) { + strcpy(symbol->errtxt, "Input data too long"); + return error_number; + } + + get_bitlength(binary_count, binary_stream); + + /* Eliminate possivle versions depending on type of content */ + if(byte_used) { + version_valid[0] = 0; + version_valid[1] = 0; + } + + if(alphanum_used) { + version_valid[0] = 0; + } + + if(kanji_used) { + version_valid[0] = 0; + version_valid[1] = 0; + } + + /* Eliminate possible versions depending on length of binary data */ + if(binary_count[0] > 20) { version_valid[0] = 0; } + if(binary_count[1] > 40) { version_valid[1] = 0; } + if(binary_count[2] > 84) { version_valid[2] = 0; } + if(binary_count[3] > 128) { + strcpy(symbol->errtxt, "Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + + /* Eliminate possible versions depending on error correction level specified */ + ecc_level = LEVEL_L; + if((symbol->option_1 >= 1) && (symbol->option_2 <= 4)) { + ecc_level = symbol->option_1; + } + + if(ecc_level == LEVEL_H) { + strcpy(symbol->errtxt, "Error correction level H not available"); + return ZINT_ERROR_INVALID_OPTION; + } + + if(ecc_level == LEVEL_Q) { + version_valid[0] = 0; + version_valid[1] = 0; + version_valid[2] = 0; + if(binary_count[3] > 80) { + strcpy(symbol->errtxt, "Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + } + + if(ecc_level == LEVEL_M) { + version_valid[0] = 0; + if(binary_count[1] > 32) { version_valid[1] = 0; } + if(binary_count[2] > 68) { version_valid[2] = 0; } + if(binary_count[3] > 112) { + strcpy(symbol->errtxt, "Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + } + + autoversion = 3; + if(version_valid[2]) { autoversion = 2; } + if(version_valid[1]) { autoversion = 1; } + if(version_valid[0]) { autoversion = 0; } + + version = autoversion; + /* Get version from user */ + if((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) { + if(symbol->option_2 >= autoversion) { + version = symbol->option_2; + } + } + + /* If there is enough unused space then increase the error correction level */ + if(version == 3) { + if(binary_count[3] <= 112) { ecc_level = LEVEL_M; } + if(binary_count[3] <= 80) { ecc_level = LEVEL_Q; } + } + + if(version == 2) { + if(binary_count[2] <= 68) { ecc_level = LEVEL_M; } + } + + if(version == 1) { + if(binary_count[1] <= 32) { ecc_level = LEVEL_M; } + } + + strcpy(full_stream, ""); + microqr_expand_binary(binary_stream, full_stream, version); + + switch(version) { + case 0: micro_qr_m1(full_stream); break; + case 1: micro_qr_m2(full_stream, ecc_level); break; + case 2: micro_qr_m3(full_stream, ecc_level); break; + case 3: micro_qr_m4(full_stream, ecc_level); break; + } + + size = micro_qr_sizes[version]; +#ifndef _MSC_VER + unsigned char grid[size * size]; +#else + grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); +#endif + + for(i = 0; i < size; i++) { + for(j = 0; j < size; j++) { + grid[(i * size) + j] = 0; + } + } + + micro_setup_grid(grid, size); + micro_populate_grid(grid, size, full_stream); + bitmask = micro_apply_bitmask(grid, size); + + /* Add format data */ + format = 0; + switch(version) { + case 1: switch(ecc_level) { + case 1: format = 1; break; + case 2: format = 2; break; + } + break; + case 2: switch(ecc_level) { + case 1: format = 3; break; + case 2: format = 4; break; + } + break; + case 3: switch(ecc_level) { + case 1: format = 5; break; + case 2: format = 6; break; + case 3: format = 7; break; + } + break; + } + + format_full = qr_annex_c1[(format << 2) + bitmask]; + + if(format_full & 0x4000) { grid[(8 * size) + 1] += 0x01; } + if(format_full & 0x2000) { grid[(8 * size) + 2] += 0x01; } + if(format_full & 0x1000) { grid[(8 * size) + 3] += 0x01; } + if(format_full & 0x800) { grid[(8 * size) + 4] += 0x01; } + if(format_full & 0x400) { grid[(8 * size) + 5] += 0x01; } + if(format_full & 0x200) { grid[(8 * size) + 6] += 0x01; } + if(format_full & 0x100) { grid[(8 * size) + 7] += 0x01; } + if(format_full & 0x80) { grid[(8 * size) + 8] += 0x01; } + if(format_full & 0x40) { grid[(7 * size) + 8] += 0x01; } + if(format_full & 0x20) { grid[(6 * size) + 8] += 0x01; } + if(format_full & 0x10) { grid[(5 * size) + 8] += 0x01; } + if(format_full & 0x08) { grid[(4 * size) + 8] += 0x01; } + if(format_full & 0x04) { grid[(3 * size) + 8] += 0x01; } + if(format_full & 0x02) { grid[(2 * size) + 8] += 0x01; } + if(format_full & 0x01) { grid[(1 * size) + 8] += 0x01; } + + symbol->width = size; + symbol->rows = size; + + for(i = 0; i < size; i++) { + for(j = 0; j < size; j++) { + if(grid[(i * size) + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + + return 0; +}