diff --git a/backend/hanxin.c b/backend/hanxin.c index fc0267e5..e2a858b9 100644 --- a/backend/hanxin.c +++ b/backend/hanxin.c @@ -41,11 +41,31 @@ #include "reedsol.h" #include "hanxin.h" +/* Find which submode to use for a text character */ +int getsubmode(char input) { + int submode = 2; + + if ((input >= '0') && (input <= '9')) { + submode = 1; + } + + if ((input >= 'A') && (input <= 'Z')) { + submode = 1; + } + + if ((input >= 'a') && (input <= 'z')) { + submode = 1; + } + + return submode; +} + /* Calculate the approximate length of the binary string */ -int calculate_binlength(char mode[], int length) { +int calculate_binlength(char mode[], const unsigned char source[], int length) { int i; char lastmode = ' '; int est_binlen = 0; + int submode = 1; for (i = 0; i < length; i++) { switch (mode[i]) { @@ -60,6 +80,11 @@ int calculate_binlength(char mode[], int length) { if (lastmode != 't') { est_binlen += 10; lastmode = 't'; + submode = 1; + } + if (getsubmode((char) source[i]) != submode) { + est_binlen += 6; + submode = getsubmode((char) source[i]); } est_binlen += 6; case 'b': @@ -101,25 +126,6 @@ void hx_define_mode(char mode[], const unsigned char source[], int length) { mode[length] = '\0'; } -/* Find which submode to use for a text character */ -int getsubmode(char input) { - int submode = 2; - - if ((input >= '0') && (input <= '9')) { - submode = 1; - } - - if ((input >= 'A') && (input <= 'Z')) { - submode = 1; - } - - if ((input >= 'a') && (input <= 'z')) { - submode = 1; - } - - return submode; -} - /* Convert Text 1 sub-mode character to encoding value, as given in table 3 */ int lookup_text1(char input) { int encoding_value = 0; @@ -341,22 +347,363 @@ void calculate_binary(char binary[], char mode[], const unsigned char source[], } while (position < length); } +/* Finder pattern for top left of symbol */ +void hx_place_finder_top_left(unsigned char* grid, int size) { + int xp, yp; + int x = 0, y = 0; + + int finder[] = { + 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 0, 0, 0, 0, + 1, 0, 1, 0, 1, 1, 1, + 1, 0, 1, 0, 1, 1, 1, + 1, 0, 1, 0, 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; + } + } + } +} + +/* Finder pattern for top right and bottom left of symbol */ +void hx_place_finder(unsigned char* grid, int size, int x, int y) { + int xp, yp; + + int finder[] = { + 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 0, 1, + 0, 0, 0, 0, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 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; + } + } + } +} + +/* Finder pattern for bottom right of symbol */ +void hx_place_finder_bottom_right(unsigned char* grid, int size) { + int xp, yp; + int x = size - 7, y = size - 7; + + int finder[] = { + 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 1, + 0, 0, 0, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 0, 1, + 0, 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; + } + } + } +} + +/* Avoid plotting outside symbol or over finder patterns */ +void hx_safe_plot(unsigned char *grid, int size, int x, int y, int value) { + if ((x >= 0) && (x < size)) { + if ((y >= 0) && (y < size)) { + if (grid[(y * size) + x] == 0) { + grid[(y * size) + x] = value; + } + } + } +} + +/* Plot an alignment pattern around top and right of a module */ +void hx_plot_alignment(unsigned char *grid, int size, int x, int y, int w, int h) { + int i; + hx_safe_plot(grid, size, x, y, 0x11); + hx_safe_plot(grid, size, x - 1, y + 1, 0x10); + + for (i = 1; i <= w; i++) { + /* Top */ + hx_safe_plot(grid, size, x - i, y, 0x11); + hx_safe_plot(grid, size, x - i - 1, y + 1, 0x10); + } + + for (i = 1; i < h; i++) { + /* Right */ + hx_safe_plot(grid, size, x, y + i, 0x11); + hx_safe_plot(grid, size, x - 1, y + i + 1, 0x10); + } +} + +/* Plot assistany alignment patterns */ +void hx_plot_assistant(unsigned char *grid, int size, int x, int y) { + hx_safe_plot(grid, size, x - 1, y - 1, 0x10); + hx_safe_plot(grid, size, x, y - 1, 0x10); + hx_safe_plot(grid, size, x + 1, y - 1, 0x10); + hx_safe_plot(grid, size, x - 1, y, 0x10); + hx_safe_plot(grid, size, x, y, 0x11); + hx_safe_plot(grid, size, x + 1, y, 0x10); + hx_safe_plot(grid, size, x - 1, y + 1, 0x10); + hx_safe_plot(grid, size, x, y + 1, 0x10); + hx_safe_plot(grid, size, x + 1, y + 1, 0x10); +} + +/* Put static elements in the grid */ +void hx_setup_grid(unsigned char* grid, int size, int version) { + int i, j; + + for (i = 0; i < size; i++) { + for (j = 0; j < size; j++) { + grid[(i * size) + j] = 0; + } + } + + /* Add finder patterns */ + hx_place_finder_top_left(grid, size); + hx_place_finder(grid, size, 0, size - 7); + hx_place_finder(grid, size, size - 7, 0); + hx_place_finder_bottom_right(grid, size); + + /* Add finder pattern separator region */ + for (i = 0; i < 8; i++) { + /* Top left */ + grid[(7 * size) + i] = 0x10; + grid[(i * size) + 7] = 0x10; + + /* Top right */ + grid[(7 * size) + (size - i - 1)] = 0x10; + grid[((size - i - 1) * size) + 7] = 0x10; + + /* Bottom left */ + grid[(i * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + i] = 0x10; + + /* Bottom right */ + grid[((size - 8) * size) + (size - i - 1)] = 0x10; + grid[((size - i - 1) * size) + (size - 8)] = 0x10; + } + + /* Reserve function information region */ + for (i = 0; i < 9; i++) { + /* Top left */ + grid[(8 * size) + i] = 0x10; + grid[(i * size) + 8] = 0x10; + + /* Top right */ + grid[(8 * size) + (size - i - 1)] = 0x10; + grid[((size - i - 1) * size) + 8] = 0x10; + + /* Bottom left */ + grid[(i * size) + (size - 9)] = 0x10; + grid[((size - 9) * size) + i] = 0x10; + + /* Bottom right */ + grid[((size - 9) * size) + (size - i - 1)] = 0x10; + grid[((size - i - 1) * size) + (size - 9)] = 0x10; + } + + if (version > 3) { + int k = hx_module_k[version - 1]; + int r = hx_module_r[version - 1]; + int m = hx_module_m[version - 1]; + int x, y, row_switch, column_switch; + int module_height, module_width; + int mod_x, mod_y; + + /* Add assistant alignment patterns to left and right */ + y = 0; + mod_y = 0; + do { + if (mod_y < m) { + module_height = k; + } else { + module_height = r - 1; + } + + if ((mod_y % 2) == 0) { + if ((m % 2) == 1) { + hx_plot_assistant(grid, size, 0, y); + } + } else { + if ((m % 2) == 0) { + hx_plot_assistant(grid, size, 0, y); + } + hx_plot_assistant(grid, size, size - 1, y); + } + + mod_y++; + y += module_height; + } while (y < size); + + /* Add assistant alignment patterns to top and bottom */ + x = (size - 1); + mod_x = 0; + do { + if (mod_x < m) { + module_width = k; + } else { + module_width = r - 1; + } + + if ((mod_x % 2) == 0) { + if ((m % 2) == 1) { + hx_plot_assistant(grid, size, x, (size - 1)); + } + } else { + if ((m % 2) == 0) { + hx_plot_assistant(grid, size, x, (size - 1)); + } + hx_plot_assistant(grid, size, x, 0); + } + + mod_x++; + x -= module_width; + } while (x >= 0); + + /* Add alignment pattern */ + column_switch = 1; + y = 0; + mod_y = 0; + do { + if (mod_y < m) { + module_height = k; + } else { + module_height = r - 1; + } + + if (column_switch == 1) { + row_switch = 1; + column_switch = 0; + } else { + row_switch = 0; + column_switch = 1; + } + + x = (size - 1); + mod_x = 0; + do { + if (mod_x < m) { + module_width = k; + } else { + module_width = r - 1; + } + + if (row_switch == 1) { + if (!(y == 0 && x == (size - 1))) { + hx_plot_alignment(grid, size, x, y, module_width, module_height); + } + row_switch = 0; + } else { + row_switch = 1; + } + mod_x++; + x -= module_width; + } while (x >= 0); + + mod_y++; + y += module_height; + } while (y < size); + } +} + /* Han Xin Code - main */ int han_xin(struct zint_symbol *symbol, const unsigned char source[], int length) { char mode[length + 1]; int est_binlen; + int ecc_level = 1; + int i, j, version; + int target_binlen, size; hx_define_mode(mode, source, length); - est_binlen = calculate_binlength(mode, length); + est_binlen = calculate_binlength(mode, source, length); char binary[est_binlen + 10]; binary[0] = '\0'; calculate_binary(binary, mode, source, length); + version = 85; + for (i = 84; i > 0; i--) { + switch (ecc_level) { + case 1: + if ((hx_data_codewords_L1[i - 1] * 8) > est_binlen) { + version = i; + target_binlen = hx_data_codewords_L1[i - 1] * 8; + } + break; + case 2: + if ((hx_data_codewords_L2[i - 1] * 8) > est_binlen) { + version = i; + target_binlen = hx_data_codewords_L2[i - 1] * 8; + } + break; + case 3: + if ((hx_data_codewords_L3[i - 1] * 8) > est_binlen) { + version = i; + target_binlen = hx_data_codewords_L3[i - 1] * 8; + } + break; + case 4: + if ((hx_data_codewords_L4[i - 1] * 8) > est_binlen) { + version = i; + target_binlen = hx_data_codewords_L4[i - 1] * 8; + } + break; + } + } + + if (version == 85) { + strcpy(symbol->errtxt, "Input too long for selected error correction level"); + return ZINT_ERROR_TOO_LONG; + } + + size = (version * 2) + 21; + +#ifndef _MSC_VER + int datastream[target_binlen + 1]; + int fullstream[hx_total_codewords[version - 1] + 1]; + unsigned char grid[size * size]; +#else + datastream = (int *) _alloca((target_binlen + 1) * sizeof (int)); + fullstream = (int *) _alloca((hx_total_codewords[version - 1] + 1) * sizeof (int)); + grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); +#endif + + hx_setup_grid(grid, size, version); + printf("Binary: %s\n", binary); - strcpy(symbol->errtxt, "Under Construction!"); - return ZINT_ERROR_INVALID_OPTION; + 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; } \ No newline at end of file diff --git a/backend/hanxin.h b/backend/hanxin.h index 1b5a7d53..f4d4289d 100644 --- a/backend/hanxin.h +++ b/backend/hanxin.h @@ -29,21 +29,90 @@ SUCH DAMAGE. */ -#ifndef HANXIN_H -#define HANXIN_H +/* Data from table B1: Data capacity of Han Xin Code */ +static int hx_total_codewords[] = { + 25, 37, 50, 54, 69, 84, 100, 117, 136, 155, 161, 181, 203, 225, 249, + 273, 299, 325, 353, 381, 411, 422, 453, 485, 518, 552, 587, 623, 660, + 698, 737, 754, 794, 836, 878, 922, 966, 1011, 1058, 1105, 1126, 1175, + 1224, 1275, 1327, 1380, 1434, 1489, 1513, 1569, 1628, 1686, 1745, 1805, + 1867, 1929, 1992, 2021, 2086, 2151, 2218, 2286, 2355, 2425, 2496, 2528, + 2600, 2673, 2749, 2824, 2900, 2977, 3056, 3135, 3171, 3252, 3334, 3416, + 3500, 3585, 3671, 3758, 3798, 3886 +}; -#ifdef __cplusplus -extern "C" { -#endif +static int hx_data_codewords_L1[] = { + 21, 31, 42, 46, 57, 70, 84, 99, 114, 131, 135, 153, 171, 189, 209, 229, + 251, 273, 297, 321, 345, 354, 381, 407, 436, 464, 493, 523, 554, 586, 619, + 634, 666, 702, 738, 774, 812, 849, 888, 929, 946, 987, 1028, 1071, 1115, + 1160, 1204, 1251, 1271, 1317, 1368, 1416, 1465, 1517, 1569, 1621, 1674, + 1697, 1752, 1807, 1864, 1920, 1979, 2037, 2096, 2124, 2184, 2245, 2309, + 2372, 2436, 2501, 2568, 2140, 2633, 2663, 2732, 2800, 2870, 2940, 3011, + 3083, 3156, 3190, 3264 +}; +static int hx_data_codewords_L2[] = { + 17, 25, 34, 38, 49, 58, 70, 81, 96, 109, 113, 127, 143, 157, 175,191, 209, + 227, 247, 267, 287, 296, 317, 339, 362, 386, 411, 437, 462, 488, 515, 528, + 556, 586, 614, 646, 676, 707, 740, 773, 788, 823, 856, 893, 929, 966, 1004, + 1043, 1059, 1099, 1140, 1180, 1221, 1263, 1307, 1351, 1394, 1415, 1460, + 1505, 1552, 1600, 1649, 1697, 1748, 1770, 1820, 1871, 1925, 1976, 2030, + 2083, 2140, 2195, 2219, 2276, 2334, 2392, 2450, 2509, 2569, 2630, 2658, + 2720 +}; +static int hx_data_codewords_L3[] = { + 13, 19, 26, 30, 37, 46, 54, 63, 74, 83, 87, 97, 109, 121, 135, 147, 161, + 175, 191, 205, 221, 228, 245, 261, 280, 298, 317, 337, 358, 376, 397, 408, + 428, 452, 474, 498, 522, 545, 572, 597, 608, 635, 660, 689, 717, 746, 774, + 805, 817, 847, 880, 910, 943, 975, 1009, 1041, 1076, 1091, 1126, 1161, 1198, + 1600, 1271, 1309, 1348, 1366, 1404, 1443, 1485, 1524, 1566, 1607,1650, 1693, + 1713, 1756, 1800, 1844, 1890, 1935, 1983, 2030, 2050, 2098 +}; +static int hx_data_codewords_L4[] = { + 9, 15, 20, 22, 27, 34, 40, 47, 54, 61, 65, 73, 81, 89, 99, 109, 119, 129, + 141, 153, 165, 168, 181, 195, 208, 220, 235, 251, 264, 280, 295, 302, 318, + 334, 352, 368, 386, 405, 424, 441, 450, 490, 509, 531, 552, 574, 595, 605, + 627, 652, 674, 697, 721, 747, 771, 796, 809, 834, 861, 892, 914, 969, 998, + 1012, 1040, 1069, 1099, 1130, 1160, 1191, 1222, 1253, 1269, 1300, 1334, + 1366, 1433, 1469, 1504, 1520, 1554 +}; -#ifdef __cplusplus -} -#endif - -#endif /* NEWFILE_H */ - +/* Value 'k' from Annex A */ +static int hx_module_k[] = { + 0, 0, 0, 14, 16, 16, 17, 18, 19, 20, + 14, 15, 16, 16, 17, 17, 18, 19, 20, 20, + 21, 16, 17, 17, 18, 18, 19, 19, 20, 20, + 21, 17, 17, 18, 18, 19, 19, 19, 20, 20, + 17, 17, 18, 18, 18, 19, 19, 19, 17, 17, + 18, 18, 18, 18, 19, 19, 19, 17, 17, 18, + 18, 18, 18, 19, 19, 17, 17, 17, 18, 18, + 18, 18, 19, 19, 17, 17, 17, 18, 18, 18, + 18, 18, 17, 17 +}; +/* Value 'r' from Annex A */ +static int hx_module_r[] = { + 0, 0, 0, 15, 15, 17, 18, 19, 20, 21, + 15, 15, 15, 17, 17, 19, 19, 19, 19, 21, + 21, 17, 16, 18, 17, 19, 18, 20, 19, 21, + 20, 17, 19, 17, 19, 17, 19, 21, 19, 21, + 18, 20, 17, 19, 21, 18, 20, 22, 17, 19, + 15, 17, 19, 21, 17, 19, 21, 18, 20, 15, + 17, 19, 21, 16, 18, 17, 19, 21, 15, 17, + 19, 21, 15, 17, 18, 20, 22, 15, 17, 19, + 21, 23, 17, 19 +}; +/* Value of 'm' from Annex A */ +static int hx_module_m[] = { + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 10, 10 +}; \ No newline at end of file