Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/hanxin.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* hanxin.c - Han Xin Code */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com> | |
| 5 | |
| 6 Redistribution and use in source and binary forms, with or without | |
| 7 modification, are permitted provided that the following conditions | |
| 8 are met: | |
| 9 | |
| 10 1. Redistributions of source code must retain the above copyright | |
| 11 notice, this list of conditions and the following disclaimer. | |
| 12 2. Redistributions in binary form must reproduce the above copyright | |
| 13 notice, this list of conditions and the following disclaimer in the | |
| 14 documentation and/or other materials provided with the distribution. | |
| 15 3. Neither the name of the project nor the names of its contributors | |
| 16 may be used to endorse or promote products derived from this software | |
| 17 without specific prior written permission. | |
| 18 | |
| 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 29 SUCH DAMAGE. | |
| 30 */ | |
| 31 /* SPDX-License-Identifier: BSD-3-Clause */ | |
| 32 | |
| 33 /* This code attempts to implement Han Xin Code according to ISO/IEC 20830:2021 | |
| 34 * (previously ISO/IEC 20830 (draft 2019-10-10) and AIMD-015:2010 (Rev 0.8)) */ | |
| 35 | |
| 36 #include <assert.h> | |
| 37 #include <stdio.h> | |
| 38 #include "common.h" | |
| 39 #include "reedsol.h" | |
| 40 #include "hanxin.h" | |
| 41 #include "eci.h" | |
| 42 | |
| 43 /* Find which submode to use for a text character */ | |
| 44 static int hx_getsubmode(const unsigned int input) { | |
| 45 | |
| 46 if (z_isdigit(input)) { | |
| 47 return 1; | |
| 48 } | |
| 49 | |
| 50 if (z_isupper(input)) { | |
| 51 return 1; | |
| 52 } | |
| 53 | |
| 54 if (z_islower(input)) { | |
| 55 return 1; | |
| 56 } | |
| 57 | |
| 58 return 2; | |
| 59 } | |
| 60 | |
| 61 /* Return length of terminator for encoding mode */ | |
| 62 static int hx_terminator_length(const char mode) { | |
| 63 int result = 0; | |
| 64 | |
| 65 switch (mode) { | |
| 66 case 'n': | |
| 67 result = 10; | |
| 68 break; | |
| 69 case 't': | |
| 70 result = 6; | |
| 71 break; | |
| 72 case '1': | |
| 73 case '2': | |
| 74 result = 12; | |
| 75 break; | |
| 76 case 'd': | |
| 77 result = 15; | |
| 78 break; | |
| 79 } | |
| 80 | |
| 81 return result; | |
| 82 } | |
| 83 | |
| 84 /* Calculate the length of the binary string */ | |
| 85 static int hx_calc_binlen(const char mode[], const unsigned int ddata[], const int length, const int eci) { | |
| 86 int i; | |
| 87 char lastmode = '\0'; | |
| 88 int est_binlen = 0; | |
| 89 int submode = 1; | |
| 90 int numeric_run = 0; | |
| 91 | |
| 92 if (eci != 0) { | |
| 93 est_binlen += 4; | |
| 94 if (eci <= 127) { | |
| 95 est_binlen += 8; | |
| 96 } else if (eci <= 16383) { | |
| 97 est_binlen += 16; | |
| 98 } else { | |
| 99 est_binlen += 24; | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 i = 0; | |
| 104 do { | |
| 105 if (mode[i] != lastmode) { | |
| 106 if (i > 0) { | |
| 107 est_binlen += hx_terminator_length(lastmode); | |
| 108 } | |
| 109 /* GB 4-byte has indicator for each character (and no terminator) so not included here */ | |
| 110 /* Region1/Region2 have special terminator to go directly into each other's mode so not included here */ | |
| 111 if (mode[i] != 'f' || ((mode[i] == '1' && lastmode == '2') || (mode[i] == '2' && lastmode == '1'))) { | |
| 112 est_binlen += 4; | |
| 113 } | |
| 114 if (mode[i] == 'b') { /* Byte mode has byte count (and no terminator) */ | |
| 115 est_binlen += 13; | |
| 116 } | |
| 117 lastmode = mode[i]; | |
| 118 submode = 1; | |
| 119 numeric_run = 0; | |
| 120 } | |
| 121 switch (mode[i]) { | |
| 122 case 'n': | |
| 123 if (numeric_run % 3 == 0) { | |
| 124 est_binlen += 10; | |
| 125 } | |
| 126 numeric_run++; | |
| 127 break; | |
| 128 case 't': | |
| 129 if (hx_getsubmode(ddata[i]) != submode) { | |
| 130 est_binlen += 6; | |
| 131 submode = hx_getsubmode(ddata[i]); | |
| 132 } | |
| 133 est_binlen += 6; | |
| 134 break; | |
| 135 case 'b': | |
| 136 est_binlen += ddata[i] > 0xFF ? 16 : 8; | |
| 137 break; | |
| 138 case '1': | |
| 139 case '2': | |
| 140 est_binlen += 12; | |
| 141 break; | |
| 142 case 'd': | |
| 143 est_binlen += 15; | |
| 144 break; | |
| 145 case 'f': | |
| 146 est_binlen += 25; | |
| 147 i++; | |
| 148 break; | |
| 149 } | |
| 150 i++; | |
| 151 } while (i < length); | |
| 152 | |
| 153 est_binlen += hx_terminator_length(lastmode); | |
| 154 | |
| 155 return est_binlen; | |
| 156 } | |
| 157 | |
| 158 /* Call `hx_calc_binlen()` for each segment */ | |
| 159 static int hx_calc_binlen_segs(const char mode[], const unsigned int ddata[], const struct zint_seg segs[], | |
| 160 const int seg_count) { | |
| 161 int i; | |
| 162 int count = 0; | |
| 163 const unsigned int *dd = ddata; | |
| 164 const char *m = mode; | |
| 165 | |
| 166 for (i = 0; i < seg_count; i++) { | |
| 167 count += hx_calc_binlen(m, dd, segs[i].length, segs[i].eci); | |
| 168 m += segs[i].length; | |
| 169 dd += segs[i].length; | |
| 170 } | |
| 171 | |
| 172 return count; | |
| 173 } | |
| 174 | |
| 175 static int hx_isRegion1(const unsigned int glyph) { | |
| 176 unsigned int byte; | |
| 177 | |
| 178 byte = glyph >> 8; | |
| 179 | |
| 180 if ((byte >= 0xb0) && (byte <= 0xd7)) { | |
| 181 byte = glyph & 0xff; | |
| 182 if ((byte >= 0xa1) && (byte <= 0xfe)) { | |
| 183 return 1; | |
| 184 } | |
| 185 } else if ((byte >= 0xa1) && (byte <= 0xa3)) { | |
| 186 byte = glyph & 0xff; | |
| 187 if ((byte >= 0xa1) && (byte <= 0xfe)) { | |
| 188 return 1; | |
| 189 } | |
| 190 } else if ((glyph >= 0xa8a1) && (glyph <= 0xa8c0)) { | |
| 191 return 1; | |
| 192 } | |
| 193 | |
| 194 return 0; | |
| 195 } | |
| 196 | |
| 197 static int hx_isRegion2(const unsigned int glyph) { | |
| 198 unsigned int byte; | |
| 199 | |
| 200 byte = glyph >> 8; | |
| 201 | |
| 202 if ((byte >= 0xd8) && (byte <= 0xf7)) { | |
| 203 byte = glyph & 0xff; | |
| 204 if ((byte >= 0xa1) && (byte <= 0xfe)) { | |
| 205 return 1; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 return 0; | |
| 210 } | |
| 211 | |
| 212 static int hx_isDoubleByte(const unsigned int glyph) { | |
| 213 unsigned int byte; | |
| 214 | |
| 215 byte = glyph >> 8; | |
| 216 | |
| 217 if ((byte >= 0x81) && (byte <= 0xfe)) { | |
| 218 byte = glyph & 0xff; | |
| 219 if ((byte >= 0x40) && (byte <= 0x7e)) { | |
| 220 return 1; | |
| 221 } | |
| 222 if ((byte >= 0x80) && (byte <= 0xfe)) { | |
| 223 return 1; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 return 0; | |
| 228 } | |
| 229 | |
| 230 static int hx_isFourByte(const unsigned int glyph, const unsigned int glyph2) { | |
| 231 unsigned int byte; | |
| 232 | |
| 233 byte = glyph >> 8; | |
| 234 | |
| 235 if ((byte >= 0x81) && (byte <= 0xfe)) { | |
| 236 byte = glyph & 0xff; | |
| 237 if ((byte >= 0x30) && (byte <= 0x39)) { | |
| 238 byte = glyph2 >> 8; | |
| 239 if ((byte >= 0x81) && (byte <= 0xfe)) { | |
| 240 byte = glyph2 & 0xff; | |
| 241 if ((byte >= 0x30) && (byte <= 0x39)) { | |
| 242 return 1; | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 return 0; | |
| 249 } | |
| 250 | |
| 251 /* Convert Text 1 sub-mode character to encoding value, as given in table 3 */ | |
| 252 static int hx_lookup_text1(const unsigned int input) { | |
| 253 | |
| 254 if (z_isdigit(input)) { | |
| 255 return input - '0'; | |
| 256 } | |
| 257 | |
| 258 if (z_isupper(input)) { | |
| 259 return input - 'A' + 10; | |
| 260 } | |
| 261 | |
| 262 if (z_islower(input)) { | |
| 263 return input - 'a' + 36; | |
| 264 } | |
| 265 | |
| 266 return -1; | |
| 267 } | |
| 268 | |
| 269 /* Convert Text 2 sub-mode character to encoding value, as given in table 4 */ | |
| 270 static int hx_lookup_text2(const unsigned int input) { | |
| 271 | |
| 272 if (input <= 27) { | |
| 273 return input; | |
| 274 } | |
| 275 | |
| 276 if ((input >= ' ') && (input <= '/')) { | |
| 277 return input - ' ' + 28; | |
| 278 } | |
| 279 | |
| 280 if ((input >= ':') && (input <= '@')) { | |
| 281 return input - ':' + 44; | |
| 282 } | |
| 283 | |
| 284 if ((input >= '[') && (input <= 96)) { | |
| 285 return input - '[' + 51; | |
| 286 } | |
| 287 | |
| 288 if ((input >= '{') && (input <= 127)) { | |
| 289 return input - '{' + 57; | |
| 290 } | |
| 291 | |
| 292 return -1; | |
| 293 } | |
| 294 | |
| 295 /* hx_define_mode() stuff */ | |
| 296 | |
| 297 /* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */ | |
| 298 #define HX_MULT 6 | |
| 299 | |
| 300 /* Whether in numeric or not. If in numeric, *p_end is set to position after numeric, | |
| 301 * and *p_cost is set to per-numeric cost */ | |
| 302 static int hx_in_numeric(const unsigned int ddata[], const int length, const int in_posn, | |
| 303 unsigned int *p_end, unsigned int *p_cost) { | |
| 304 int i, digit_cnt; | |
| 305 | |
| 306 if (in_posn < (int) *p_end) { | |
| 307 return 1; | |
| 308 } | |
| 309 | |
| 310 /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times HX_MULT) */ | |
| 311 for (i = in_posn; i < length && i < in_posn + 3 && z_isdigit(ddata[i]); i++); | |
| 312 | |
| 313 digit_cnt = i - in_posn; | |
| 314 | |
| 315 if (digit_cnt == 0) { | |
| 316 *p_end = 0; | |
| 317 return 0; | |
| 318 } | |
| 319 *p_end = i; | |
| 320 *p_cost = digit_cnt == 1 | |
| 321 ? 60 /* 10 * HX_MULT */ : digit_cnt == 2 ? 30 /* (10 / 2) * HX_MULT */ : 20 /* (10 / 3) * HX_MULT */; | |
| 322 return 1; | |
| 323 } | |
| 324 | |
| 325 /* Whether in four-byte or not. If in four-byte, *p_fourbyte is set to position after four-byte, | |
| 326 * and *p_fourbyte_cost is set to per-position cost */ | |
| 327 static int hx_in_fourbyte(const unsigned int ddata[], const int length, const int in_posn, | |
| 328 unsigned int *p_end, unsigned int *p_cost) { | |
| 329 if (in_posn < (int) *p_end) { | |
| 330 return 1; | |
| 331 } | |
| 332 | |
| 333 if (in_posn == length - 1 || !hx_isFourByte(ddata[in_posn], ddata[in_posn + 1])) { | |
| 334 *p_end = 0; | |
| 335 return 0; | |
| 336 } | |
| 337 *p_end = in_posn + 2; | |
| 338 *p_cost = 75; /* ((4 + 21) / 2) * HX_MULT */ | |
| 339 return 1; | |
| 340 } | |
| 341 | |
| 342 /* Indexes into mode_types array */ | |
| 343 #define HX_N 0 /* Numeric */ | |
| 344 #define HX_T 1 /* Text */ | |
| 345 #define HX_B 2 /* Binary */ | |
| 346 #define HX_1 3 /* Common Chinese Region One */ | |
| 347 #define HX_2 4 /* Common Chinese Region Two */ | |
| 348 #define HX_D 5 /* GB 18030 2-byte Region */ | |
| 349 #define HX_F 6 /* GB 18030 4-byte Region */ | |
| 350 /* Note Unicode, GS1 and URI modes not implemented */ | |
| 351 | |
| 352 #define HX_NUM_MODES 7 | |
| 353 | |
| 354 /* Calculate optimized encoding modes. Adapted from Project Nayuki */ | |
| 355 /* Copyright (c) Project Nayuki. (MIT License) See qr.c for detailed notice */ | |
| 356 static void hx_define_mode(char *mode, const unsigned int ddata[], const int length, const int debug_print) { | |
| 357 /* Must be in same order as HX_N etc */ | |
| 358 static const char mode_types[] = { 'n', 't', 'b', '1', '2', 'd', 'f', '\0' }; | |
| 359 | |
| 360 /* Initial mode costs */ | |
| 361 static const unsigned int head_costs[HX_NUM_MODES] = { | |
| 362 /* N T B 1 2 D F */ | |
| 363 4 * HX_MULT, 4 * HX_MULT, (4 + 13) * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0 | |
| 364 }; | |
| 365 | |
| 366 /* Cost of switching modes from k to j */ | |
| 367 static const unsigned char switch_costs[HX_NUM_MODES][HX_NUM_MODES] = { | |
| 368 /* N T B 1 2 D F */ | |
| 369 /*N*/ { 0, (10 + 4) * HX_MULT, (10 + 4 + 13) * HX_MULT, (10 + 4) * HX_MULT, (10 + 4) * HX_MULT, (10 + 4) * HX_MULT, 10 * HX_MULT }, | |
| 370 /*T*/ { (6 + 4) * HX_MULT, 0, (6 + 4 + 13) * HX_MULT, (6 + 4) * HX_MULT, (6 + 4) * HX_MULT, (6 + 4) * HX_MULT, 6 * HX_MULT }, | |
| 371 /*B*/ { 4 * HX_MULT, 4 * HX_MULT, 0, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0 }, | |
| 372 /*1*/ { (12 + 4) * HX_MULT, (12 + 4) * HX_MULT, (12 + 4 + 13) * HX_MULT, 0, 12 * HX_MULT, (12 + 4) * HX_MULT, 12 * HX_MULT }, | |
| 373 /*2*/ { (12 + 4) * HX_MULT, (12 + 4) * HX_MULT, (12 + 4 + 13) * HX_MULT, 12 * HX_MULT, 0, (12 + 4) * HX_MULT, 12 * HX_MULT }, | |
| 374 /*D*/ { (15 + 4) * HX_MULT, (15 + 4) * HX_MULT, (15 + 4 + 13) * HX_MULT, (15 + 4) * HX_MULT, (15 + 4) * HX_MULT, 0, 15 * HX_MULT }, | |
| 375 /*F*/ { 4 * HX_MULT, 4 * HX_MULT, (4 + 13) * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0 }, | |
| 376 }; | |
| 377 | |
| 378 /* Final end-of-data costs */ | |
| 379 static const unsigned char eod_costs[HX_NUM_MODES] = { | |
| 380 /* N T B 1 2 D F */ | |
| 381 10 * HX_MULT, 6 * HX_MULT, 0, 12 * HX_MULT, 12 * HX_MULT, 15 * HX_MULT, 0 | |
| 382 }; | |
| 383 | |
| 384 unsigned int numeric_end = 0, numeric_cost = 0, text_submode = 1, fourbyte_end = 0, fourbyte_cost = 0; /* State */ | |
| 385 int text1, text2; | |
| 386 | |
| 387 int i, j, k; | |
| 388 unsigned int min_cost; | |
| 389 char cur_mode; | |
| 390 unsigned int prev_costs[HX_NUM_MODES]; | |
| 391 unsigned int cur_costs[HX_NUM_MODES]; | |
| 392 char (*char_modes)[HX_NUM_MODES] = (char (*)[HX_NUM_MODES]) z_alloca(HX_NUM_MODES * length); | |
| 393 | |
| 394 /* char_modes[i][j] represents the mode to encode the code point at index i such that the final segment | |
| 395 ends in mode_types[j] and the total number of bits is minimized over all possible choices */ | |
| 396 memset(char_modes, 0, HX_NUM_MODES * length); | |
| 397 | |
| 398 /* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/XX_MULT) | |
| 399 * bits needed to encode the entire string prefix of length i, and end in mode_types[j] */ | |
| 400 memcpy(prev_costs, head_costs, HX_NUM_MODES * sizeof(unsigned int)); | |
| 401 | |
| 402 /* Calculate costs using dynamic programming */ | |
| 403 for (i = 0; i < length; i++) { | |
| 404 memset(cur_costs, 0, HX_NUM_MODES * sizeof(unsigned int)); | |
| 405 | |
| 406 if (hx_in_numeric(ddata, length, i, &numeric_end, &numeric_cost)) { | |
| 407 cur_costs[HX_N] = prev_costs[HX_N] + numeric_cost; | |
| 408 char_modes[i][HX_N] = 'n'; | |
| 409 text1 = 1; | |
| 410 text2 = 0; | |
| 411 } else { | |
| 412 text1 = hx_lookup_text1(ddata[i]) != -1; | |
| 413 text2 = hx_lookup_text2(ddata[i]) != -1; | |
| 414 } | |
| 415 | |
| 416 if (text1 || text2) { | |
| 417 if ((text_submode == 1 && text2) || (text_submode == 2 && text1)) { | |
| 418 cur_costs[HX_T] = prev_costs[HX_T] + 72; /* (6 + 6) * HX_MULT */ | |
| 419 text_submode = text2 ? 2 : 1; | |
| 420 } else { | |
| 421 cur_costs[HX_T] = prev_costs[HX_T] + 36; /* 6 * HX_MULT */ | |
| 422 } | |
| 423 char_modes[i][HX_T] = 't'; | |
| 424 } else { | |
| 425 text_submode = 1; | |
| 426 } | |
| 427 | |
| 428 /* Binary mode can encode anything */ | |
| 429 cur_costs[HX_B] = prev_costs[HX_B] + (ddata[i] > 0xFF ? 96 : 48); /* (16 : 8) * HX_MULT */ | |
| 430 char_modes[i][HX_B] = 'b'; | |
| 431 | |
| 432 if (hx_in_fourbyte(ddata, length, i, &fourbyte_end, &fourbyte_cost)) { | |
| 433 cur_costs[HX_F] = prev_costs[HX_F] + fourbyte_cost; | |
| 434 char_modes[i][HX_F] = 'f'; | |
| 435 } else { | |
| 436 if (hx_isDoubleByte(ddata[i])) { | |
| 437 cur_costs[HX_D] = prev_costs[HX_D] + 90; /* 15 * HX_MULT */ | |
| 438 char_modes[i][HX_D] = 'd'; | |
| 439 if (hx_isRegion1(ddata[i])) { /* Subset */ | |
| 440 cur_costs[HX_1] = prev_costs[HX_1] + 72; /* 12 * HX_MULT */ | |
| 441 char_modes[i][HX_1] = '1'; | |
| 442 } else if (hx_isRegion2(ddata[i])) { /* Subset */ | |
| 443 cur_costs[HX_2] = prev_costs[HX_2] + 72; /* 12 * HX_MULT */ | |
| 444 char_modes[i][HX_2] = '2'; | |
| 445 } | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 if (i == length - 1) { /* Add end of data costs if last character */ | |
| 450 for (j = 0; j < HX_NUM_MODES; j++) { | |
| 451 if (char_modes[i][j]) { | |
| 452 cur_costs[j] += eod_costs[j]; | |
| 453 } | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 /* Start new segment at the end to switch modes */ | |
| 458 for (j = 0; j < HX_NUM_MODES; j++) { /* To mode */ | |
| 459 for (k = 0; k < HX_NUM_MODES; k++) { /* From mode */ | |
| 460 if (j != k && char_modes[i][k]) { | |
| 461 const unsigned int new_cost = cur_costs[k] + switch_costs[k][j]; | |
| 462 if (!char_modes[i][j] || new_cost < cur_costs[j]) { | |
| 463 cur_costs[j] = new_cost; | |
| 464 char_modes[i][j] = mode_types[k]; | |
| 465 } | |
| 466 } | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 memcpy(prev_costs, cur_costs, HX_NUM_MODES * sizeof(unsigned int)); | |
| 471 } | |
| 472 | |
| 473 /* Find optimal ending mode */ | |
| 474 min_cost = prev_costs[0]; | |
| 475 cur_mode = mode_types[0]; | |
| 476 for (i = 1; i < HX_NUM_MODES; i++) { | |
| 477 if (prev_costs[i] < min_cost) { | |
| 478 min_cost = prev_costs[i]; | |
| 479 cur_mode = mode_types[i]; | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 /* Get optimal mode for each code point by tracing backwards */ | |
| 484 for (i = length - 1; i >= 0; i--) { | |
| 485 j = posn(mode_types, cur_mode); | |
| 486 cur_mode = char_modes[i][j]; | |
| 487 mode[i] = cur_mode; | |
| 488 } | |
| 489 | |
| 490 if (debug_print) { | |
| 491 printf(" Mode: %.*s\n", length, mode); | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 /* Call `hx_define_mode()` for each segment */ | |
| 496 static void hx_define_mode_segs(char mode[], const unsigned int ddata[], const struct zint_seg segs[], | |
| 497 const int seg_count, const int debug_print) { | |
| 498 int i; | |
| 499 const unsigned int *dd = ddata; | |
| 500 char *m = mode; | |
| 501 | |
| 502 for (i = 0; i < seg_count; i++) { | |
| 503 hx_define_mode(m, dd, segs[i].length, debug_print); | |
| 504 m += segs[i].length; | |
| 505 dd += segs[i].length; | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 /* Convert input data to binary stream */ | |
| 510 static void hx_calculate_binary(char binary[], const char mode[], const unsigned int ddata[], const int length, | |
| 511 const int eci, int *p_bp, const int debug_print) { | |
| 512 int position = 0; | |
| 513 int i, count, encoding_value; | |
| 514 int first_byte, second_byte; | |
| 515 int third_byte, fourth_byte; | |
| 516 int glyph; | |
| 517 int submode; | |
| 518 int bp = *p_bp; | |
| 519 | |
| 520 if (eci != 0) { | |
| 521 /* Encoding ECI assignment number, according to Table 5 */ | |
| 522 bp = bin_append_posn(8, 4, binary, bp); /* ECI */ | |
| 523 if (eci <= 127) { | |
| 524 bp = bin_append_posn(eci, 8, binary, bp); | |
| 525 } else if (eci <= 16383) { | |
| 526 bp = bin_append_posn(2, 2, binary, bp); | |
| 527 bp = bin_append_posn(eci, 14, binary, bp); | |
| 528 } else { | |
| 529 bp = bin_append_posn(6, 3, binary, bp); | |
| 530 bp = bin_append_posn(eci, 21, binary, bp); | |
| 531 } | |
| 532 } | |
| 533 | |
| 534 do { | |
| 535 int block_length = 0; | |
| 536 int double_byte = 0; | |
| 537 do { | |
| 538 if (mode[position] == 'b' && ddata[position + block_length] > 0xFF) { | |
| 539 double_byte++; | |
| 540 } | |
| 541 block_length++; | |
| 542 } while (position + block_length < length && mode[position + block_length] == mode[position]); | |
| 543 | |
| 544 switch (mode[position]) { | |
| 545 case 'n': | |
| 546 /* Numeric mode */ | |
| 547 /* Mode indicator */ | |
| 548 bp = bin_append_posn(1, 4, binary, bp); | |
| 549 | |
| 550 if (debug_print) { | |
| 551 printf("Numeric (N%d): ", block_length); | |
| 552 } | |
| 553 | |
| 554 count = 0; /* Suppress gcc -Wmaybe-uninitialized */ | |
| 555 i = 0; | |
| 556 | |
| 557 while (i < block_length) { | |
| 558 const int first = ctoi((const char) ddata[position + i]); | |
| 559 count = 1; | |
| 560 encoding_value = first; | |
| 561 | |
| 562 if (i + 1 < block_length && mode[position + i + 1] == 'n') { | |
| 563 const int second = ctoi((const char) ddata[position + i + 1]); | |
| 564 count = 2; | |
| 565 encoding_value = (encoding_value * 10) + second; | |
| 566 | |
| 567 if (i + 2 < block_length && mode[position + i + 2] == 'n') { | |
| 568 const int third = ctoi((const char) ddata[position + i + 2]); | |
| 569 count = 3; | |
| 570 encoding_value = (encoding_value * 10) + third; | |
| 571 } | |
| 572 } | |
| 573 | |
| 574 bp = bin_append_posn(encoding_value, 10, binary, bp); | |
| 575 | |
| 576 if (debug_print) { | |
| 577 printf(" 0x%3x(%d)", encoding_value, encoding_value); | |
| 578 } | |
| 579 | |
| 580 i += count; | |
| 581 } | |
| 582 | |
| 583 /* Mode terminator depends on number of characters in last group (Table 2) */ | |
| 584 switch (count) { | |
| 585 case 1: | |
| 586 bp = bin_append_posn(1021, 10, binary, bp); | |
| 587 break; | |
| 588 case 2: | |
| 589 bp = bin_append_posn(1022, 10, binary, bp); | |
| 590 break; | |
| 591 case 3: | |
| 592 bp = bin_append_posn(1023, 10, binary, bp); | |
| 593 break; | |
| 594 } | |
| 595 | |
| 596 if (debug_print) { | |
| 597 printf(" (TERM %d)\n", count); | |
| 598 } | |
| 599 | |
| 600 break; | |
| 601 case 't': | |
| 602 /* Text mode */ | |
| 603 /* Mode indicator */ | |
| 604 bp = bin_append_posn(2, 4, binary, bp); | |
| 605 | |
| 606 if (debug_print) { | |
| 607 printf("Text (T%d):", block_length); | |
| 608 } | |
| 609 | |
| 610 submode = 1; | |
| 611 | |
| 612 i = 0; | |
| 613 | |
| 614 while (i < block_length) { | |
| 615 | |
| 616 if (hx_getsubmode(ddata[i + position]) != submode) { | |
| 617 /* Change submode */ | |
| 618 bp = bin_append_posn(62, 6, binary, bp); | |
| 619 submode = hx_getsubmode(ddata[i + position]); | |
| 620 if (debug_print) { | |
| 621 fputs(" SWITCH", stdout); | |
| 622 } | |
| 623 } | |
| 624 | |
| 625 if (submode == 1) { | |
| 626 encoding_value = hx_lookup_text1(ddata[i + position]); | |
| 627 } else { | |
| 628 encoding_value = hx_lookup_text2(ddata[i + position]); | |
| 629 } | |
| 630 | |
| 631 bp = bin_append_posn(encoding_value, 6, binary, bp); | |
| 632 | |
| 633 if (debug_print) { | |
| 634 printf(" %.2x[ASC %.2x]", encoding_value, ddata[i + position]); | |
| 635 } | |
| 636 i++; | |
| 637 } | |
| 638 | |
| 639 /* Terminator */ | |
| 640 bp = bin_append_posn(63, 6, binary, bp); | |
| 641 | |
| 642 if (debug_print) { | |
| 643 fputs("\n", stdout); | |
| 644 } | |
| 645 break; | |
| 646 case 'b': | |
| 647 /* Binary Mode */ | |
| 648 /* Mode indicator */ | |
| 649 bp = bin_append_posn(3, 4, binary, bp); | |
| 650 | |
| 651 /* Count indicator */ | |
| 652 bp = bin_append_posn(block_length + double_byte, 13, binary, bp); | |
| 653 | |
| 654 if (debug_print) { | |
| 655 printf("Binary Mode (B%d):", block_length + double_byte); | |
| 656 } | |
| 657 | |
| 658 i = 0; | |
| 659 | |
| 660 while (i < block_length) { | |
| 661 | |
| 662 /* 8-bit bytes with no conversion */ | |
| 663 bp = bin_append_posn(ddata[i + position], ddata[i + position] > 0xFF ? 16 : 8, binary, bp); | |
| 664 | |
| 665 if (debug_print) { | |
| 666 printf(" %02x", (int) ddata[i + position]); | |
| 667 } | |
| 668 | |
| 669 i++; | |
| 670 } | |
| 671 | |
| 672 if (debug_print) { | |
| 673 fputs("\n", stdout); | |
| 674 } | |
| 675 break; | |
| 676 case '1': | |
| 677 /* Region One encoding */ | |
| 678 /* Mode indicator */ | |
| 679 if (position == 0 || mode[position - 1] != '2') { /* Unless previous mode Region Two */ | |
| 680 bp = bin_append_posn(4, 4, binary, bp); | |
| 681 } | |
| 682 | |
| 683 if (debug_print) { | |
| 684 printf("Region One%s H(1)%d:", | |
| 685 position == 0 || mode[position - 1] != '2' ? "" : " (NO indicator)", block_length); | |
| 686 } | |
| 687 | |
| 688 i = 0; | |
| 689 | |
| 690 while (i < block_length) { | |
| 691 first_byte = (ddata[i + position] & 0xff00) >> 8; | |
| 692 second_byte = ddata[i + position] & 0xff; | |
| 693 | |
| 694 /* Subset 1 */ | |
| 695 glyph = (0x5e * (first_byte - 0xb0)) + (second_byte - 0xa1); | |
| 696 | |
| 697 /* Subset 2 */ | |
| 698 if ((first_byte >= 0xa1) && (first_byte <= 0xa3)) { | |
| 699 if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) { | |
| 700 glyph = (0x5e * (first_byte - 0xa1)) + (second_byte - 0xa1) + 0xeb0; | |
| 701 } | |
| 702 } | |
| 703 | |
| 704 /* Subset 3 */ | |
| 705 if ((ddata[i + position] >= 0xa8a1) && (ddata[i + position] <= 0xa8c0)) { | |
| 706 glyph = (second_byte - 0xa1) + 0xfca; | |
| 707 } | |
| 708 | |
| 709 if (debug_print) { | |
| 710 printf(" %.3x[GB %.4x]", glyph, ddata[i + position]); | |
| 711 } | |
| 712 | |
| 713 bp = bin_append_posn(glyph, 12, binary, bp); | |
| 714 i++; | |
| 715 } | |
| 716 | |
| 717 /* Terminator */ | |
| 718 bp = bin_append_posn(position + block_length == length || mode[position + block_length] != '2' | |
| 719 ? 4095 : 4094, 12, binary, bp); | |
| 720 | |
| 721 if (debug_print) { | |
| 722 printf(" (TERM %x)\n", position + block_length == length || mode[position + block_length] != '2' | |
| 723 ? 4095 : 4094); | |
| 724 } | |
| 725 | |
| 726 break; | |
| 727 case '2': | |
| 728 /* Region Two encoding */ | |
| 729 /* Mode indicator */ | |
| 730 if (position == 0 || mode[position - 1] != '1') { /* Unless previous mode Region One */ | |
| 731 bp = bin_append_posn(5, 4, binary, bp); | |
| 732 } | |
| 733 | |
| 734 if (debug_print) { | |
| 735 printf("Region Two%s H(2)%d:", | |
| 736 position == 0 || mode[position - 1] != '1' ? "" : " (NO indicator)", block_length); | |
| 737 } | |
| 738 | |
| 739 i = 0; | |
| 740 | |
| 741 while (i < block_length) { | |
| 742 first_byte = (ddata[i + position] & 0xff00) >> 8; | |
| 743 second_byte = ddata[i + position] & 0xff; | |
| 744 | |
| 745 glyph = (0x5e * (first_byte - 0xd8)) + (second_byte - 0xa1); | |
| 746 | |
| 747 if (debug_print) { | |
| 748 printf(" %.3x[GB %.4x]", glyph, ddata[i + position]); | |
| 749 } | |
| 750 | |
| 751 bp = bin_append_posn(glyph, 12, binary, bp); | |
| 752 i++; | |
| 753 } | |
| 754 | |
| 755 /* Terminator */ | |
| 756 bp = bin_append_posn(position + block_length == length || mode[position + block_length] != '1' | |
| 757 ? 4095 : 4094, 12, binary, bp); | |
| 758 | |
| 759 if (debug_print) { | |
| 760 printf(" (TERM %x)\n", position + block_length == length || mode[position + block_length] != '1' | |
| 761 ? 4095 : 4094); | |
| 762 } | |
| 763 | |
| 764 break; | |
| 765 case 'd': | |
| 766 /* Double byte encoding */ | |
| 767 /* Mode indicator */ | |
| 768 bp = bin_append_posn(6, 4, binary, bp); | |
| 769 | |
| 770 if (debug_print) { | |
| 771 printf("Double byte (H(d)%d):", block_length); | |
| 772 } | |
| 773 | |
| 774 i = 0; | |
| 775 | |
| 776 while (i < block_length) { | |
| 777 first_byte = (ddata[i + position] & 0xff00) >> 8; | |
| 778 second_byte = ddata[i + position] & 0xff; | |
| 779 | |
| 780 if (second_byte <= 0x7e) { | |
| 781 glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x40); | |
| 782 } else { | |
| 783 glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x41); | |
| 784 } | |
| 785 | |
| 786 if (debug_print) { | |
| 787 printf("%.4x ", glyph); | |
| 788 } | |
| 789 | |
| 790 bp = bin_append_posn(glyph, 15, binary, bp); | |
| 791 i++; | |
| 792 } | |
| 793 | |
| 794 /* Terminator */ | |
| 795 bp = bin_append_posn(32767, 15, binary, bp); | |
| 796 /* Terminator sequence of length 12 is a mistake | |
| 797 - confirmed by Wang Yi */ | |
| 798 | |
| 799 if (debug_print) { | |
| 800 fputc('\n', stdout); | |
| 801 } | |
| 802 break; | |
| 803 case 'f': | |
| 804 /* Four-byte encoding */ | |
| 805 if (debug_print) { | |
| 806 printf("Four byte (H(f)%d):", block_length); | |
| 807 } | |
| 808 | |
| 809 i = 0; | |
| 810 | |
| 811 while (i < block_length) { | |
| 812 | |
| 813 /* Mode indicator */ | |
| 814 bp = bin_append_posn(7, 4, binary, bp); | |
| 815 | |
| 816 first_byte = (ddata[i + position] & 0xff00) >> 8; | |
| 817 second_byte = ddata[i + position] & 0xff; | |
| 818 third_byte = (ddata[i + position + 1] & 0xff00) >> 8; | |
| 819 fourth_byte = ddata[i + position + 1] & 0xff; | |
| 820 | |
| 821 glyph = (0x3138 * (first_byte - 0x81)) + (0x04ec * (second_byte - 0x30)) + | |
| 822 (0x0a * (third_byte - 0x81)) + (fourth_byte - 0x30); | |
| 823 | |
| 824 if (debug_print) { | |
| 825 printf(" %d", glyph); | |
| 826 } | |
| 827 | |
| 828 bp = bin_append_posn(glyph, 21, binary, bp); | |
| 829 i += 2; | |
| 830 } | |
| 831 | |
| 832 /* No terminator */ | |
| 833 | |
| 834 if (debug_print) { | |
| 835 fputc('\n', stdout); | |
| 836 } | |
| 837 break; | |
| 838 } | |
| 839 | |
| 840 position += block_length; | |
| 841 | |
| 842 } while (position < length); | |
| 843 | |
| 844 if (debug_print) printf("Binary (%d): %.*s\n", bp, bp, binary); | |
| 845 | |
| 846 *p_bp = bp; | |
| 847 } | |
| 848 | |
| 849 /* Call `hx_calculate_binary()` for each segment */ | |
| 850 static void hx_calculate_binary_segs(char binary[], const char mode[], const unsigned int ddata[], | |
| 851 const struct zint_seg segs[], const int seg_count, int *p_bin_len, const int debug_print) { | |
| 852 int i; | |
| 853 const unsigned int *dd = ddata; | |
| 854 const char *m = mode; | |
| 855 int bp = 0; | |
| 856 | |
| 857 for (i = 0; i < seg_count; i++) { | |
| 858 hx_calculate_binary(binary, m, dd, segs[i].length, segs[i].eci, &bp, debug_print); | |
| 859 m += segs[i].length; | |
| 860 dd += segs[i].length; | |
| 861 } | |
| 862 | |
| 863 *p_bin_len = bp; | |
| 864 } | |
| 865 | |
| 866 /* Finder pattern for top left of symbol */ | |
| 867 static void hx_place_finder_top_left(unsigned char *grid, const int size) { | |
| 868 int xp, yp; | |
| 869 int x = 0, y = 0; | |
| 870 char finder[] = {0x7F, 0x40, 0x5F, 0x50, 0x57, 0x57, 0x57}; | |
| 871 | |
| 872 for (xp = 0; xp < 7; xp++) { | |
| 873 for (yp = 0; yp < 7; yp++) { | |
| 874 if (finder[yp] & 0x40 >> xp) { | |
| 875 grid[((yp + y) * size) + (xp + x)] = 0x11; | |
| 876 } else { | |
| 877 grid[((yp + y) * size) + (xp + x)] = 0x10; | |
| 878 } | |
| 879 } | |
| 880 } | |
| 881 } | |
| 882 | |
| 883 /* Finder pattern for top right and bottom left of symbol */ | |
| 884 static void hx_place_finder(unsigned char *grid, const int size, const int x, const int y) { | |
| 885 int xp, yp; | |
| 886 static const char finder[] = {0x7F, 0x01, 0x7D, 0x05, 0x75, 0x75, 0x75}; | |
| 887 | |
| 888 for (xp = 0; xp < 7; xp++) { | |
| 889 for (yp = 0; yp < 7; yp++) { | |
| 890 if (finder[yp] & 0x40 >> xp) { | |
| 891 grid[((yp + y) * size) + (xp + x)] = 0x11; | |
| 892 } else { | |
| 893 grid[((yp + y) * size) + (xp + x)] = 0x10; | |
| 894 } | |
| 895 } | |
| 896 } | |
| 897 } | |
| 898 | |
| 899 /* Finder pattern for bottom right of symbol */ | |
| 900 static void hx_place_finder_bottom_right(unsigned char *grid, const int size) { | |
| 901 int xp, yp; | |
| 902 const int x = size - 7; | |
| 903 const int y = x; | |
| 904 static const char finder[] = {0x75, 0x75, 0x75, 0x05, 0x7D, 0x01, 0x7F}; | |
| 905 | |
| 906 for (xp = 0; xp < 7; xp++) { | |
| 907 for (yp = 0; yp < 7; yp++) { | |
| 908 if (finder[yp] & 0x40 >> xp) { | |
| 909 grid[((yp + y) * size) + (xp + x)] = 0x11; | |
| 910 } else { | |
| 911 grid[((yp + y) * size) + (xp + x)] = 0x10; | |
| 912 } | |
| 913 } | |
| 914 } | |
| 915 } | |
| 916 | |
| 917 /* Avoid plotting outside symbol or over finder patterns */ | |
| 918 static void hx_safe_plot(unsigned char *grid, const int size, const int x, const int y, const int value) { | |
| 919 if ((x >= 0) && (x < size)) { | |
| 920 if ((y >= 0) && (y < size)) { | |
| 921 if (grid[(y * size) + x] == 0) { | |
| 922 grid[(y * size) + x] = value; | |
| 923 } | |
| 924 } | |
| 925 } | |
| 926 } | |
| 927 | |
| 928 /* Plot an alignment pattern around top and right of a module */ | |
| 929 static void hx_plot_alignment(unsigned char *grid, const int size, const int x, const int y, const int w, | |
| 930 const int h) { | |
| 931 int i; | |
| 932 hx_safe_plot(grid, size, x, y, 0x11); | |
| 933 hx_safe_plot(grid, size, x - 1, y + 1, 0x10); | |
| 934 | |
| 935 for (i = 1; i <= w; i++) { | |
| 936 /* Top */ | |
| 937 hx_safe_plot(grid, size, x - i, y, 0x11); | |
| 938 hx_safe_plot(grid, size, x - i - 1, y + 1, 0x10); | |
| 939 } | |
| 940 | |
| 941 for (i = 1; i < h; i++) { | |
| 942 /* Right */ | |
| 943 hx_safe_plot(grid, size, x, y + i, 0x11); | |
| 944 hx_safe_plot(grid, size, x - 1, y + i + 1, 0x10); | |
| 945 } | |
| 946 } | |
| 947 | |
| 948 /* Plot assistant alignment patterns */ | |
| 949 static void hx_plot_assistant(unsigned char *grid, const int size, const int x, const int y) { | |
| 950 hx_safe_plot(grid, size, x - 1, y - 1, 0x10); | |
| 951 hx_safe_plot(grid, size, x, y - 1, 0x10); | |
| 952 hx_safe_plot(grid, size, x + 1, y - 1, 0x10); | |
| 953 hx_safe_plot(grid, size, x - 1, y, 0x10); | |
| 954 hx_safe_plot(grid, size, x, y, 0x11); | |
| 955 hx_safe_plot(grid, size, x + 1, y, 0x10); | |
| 956 hx_safe_plot(grid, size, x - 1, y + 1, 0x10); | |
| 957 hx_safe_plot(grid, size, x, y + 1, 0x10); | |
| 958 hx_safe_plot(grid, size, x + 1, y + 1, 0x10); | |
| 959 } | |
| 960 | |
| 961 /* Put static elements in the grid */ | |
| 962 static void hx_setup_grid(unsigned char *grid, const int size, const int version) { | |
| 963 int i; | |
| 964 | |
| 965 memset(grid, 0, (size_t) size * size); | |
| 966 | |
| 967 /* Add finder patterns */ | |
| 968 hx_place_finder_top_left(grid, size); | |
| 969 hx_place_finder(grid, size, 0, size - 7); | |
| 970 hx_place_finder(grid, size, size - 7, 0); | |
| 971 hx_place_finder_bottom_right(grid, size); | |
| 972 | |
| 973 /* Add finder pattern separator region */ | |
| 974 for (i = 0; i < 8; i++) { | |
| 975 /* Top left */ | |
| 976 grid[(7 * size) + i] = 0x10; | |
| 977 grid[(i * size) + 7] = 0x10; | |
| 978 | |
| 979 /* Top right */ | |
| 980 grid[(7 * size) + (size - i - 1)] = 0x10; | |
| 981 grid[((size - i - 1) * size) + 7] = 0x10; | |
| 982 | |
| 983 /* Bottom left */ | |
| 984 grid[(i * size) + (size - 8)] = 0x10; | |
| 985 grid[((size - 8) * size) + i] = 0x10; | |
| 986 | |
| 987 /* Bottom right */ | |
| 988 grid[((size - 8) * size) + (size - i - 1)] = 0x10; | |
| 989 grid[((size - i - 1) * size) + (size - 8)] = 0x10; | |
| 990 } | |
| 991 | |
| 992 /* Reserve function information region */ | |
| 993 for (i = 0; i < 9; i++) { | |
| 994 /* Top left */ | |
| 995 grid[(8 * size) + i] = 0x10; | |
| 996 grid[(i * size) + 8] = 0x10; | |
| 997 | |
| 998 /* Top right */ | |
| 999 grid[(8 * size) + (size - i - 1)] = 0x10; | |
| 1000 grid[((size - i - 1) * size) + 8] = 0x10; | |
| 1001 | |
| 1002 /* Bottom left */ | |
| 1003 grid[(i * size) + (size - 9)] = 0x10; | |
| 1004 grid[((size - 9) * size) + i] = 0x10; | |
| 1005 | |
| 1006 /* Bottom right */ | |
| 1007 grid[((size - 9) * size) + (size - i - 1)] = 0x10; | |
| 1008 grid[((size - i - 1) * size) + (size - 9)] = 0x10; | |
| 1009 } | |
| 1010 | |
| 1011 if (version > 3) { | |
| 1012 const int k = hx_module_k[version - 1]; | |
| 1013 const int r = hx_module_r[version - 1]; | |
| 1014 const int m = hx_module_m[version - 1]; | |
| 1015 int x, y, row_switch, column_switch; | |
| 1016 int module_height, module_width; | |
| 1017 int mod_x, mod_y; | |
| 1018 | |
| 1019 /* Add assistant alignment patterns to left and right */ | |
| 1020 y = 0; | |
| 1021 mod_y = 0; | |
| 1022 do { | |
| 1023 if (mod_y < m) { | |
| 1024 module_height = k; | |
| 1025 } else { | |
| 1026 module_height = r - 1; | |
| 1027 } | |
| 1028 | |
| 1029 if ((mod_y & 1) == 0) { | |
| 1030 if ((m & 1) == 1) { | |
| 1031 hx_plot_assistant(grid, size, 0, y); | |
| 1032 } | |
| 1033 } else { | |
| 1034 if ((m & 1) == 0) { | |
| 1035 hx_plot_assistant(grid, size, 0, y); | |
| 1036 } | |
| 1037 hx_plot_assistant(grid, size, size - 1, y); | |
| 1038 } | |
| 1039 | |
| 1040 mod_y++; | |
| 1041 y += module_height; | |
| 1042 } while (y < size); | |
| 1043 | |
| 1044 /* Add assistant alignment patterns to top and bottom */ | |
| 1045 x = (size - 1); | |
| 1046 mod_x = 0; | |
| 1047 do { | |
| 1048 if (mod_x < m) { | |
| 1049 module_width = k; | |
| 1050 } else { | |
| 1051 module_width = r - 1; | |
| 1052 } | |
| 1053 | |
| 1054 if ((mod_x & 1) == 0) { | |
| 1055 if ((m & 1) == 1) { | |
| 1056 hx_plot_assistant(grid, size, x, (size - 1)); | |
| 1057 } | |
| 1058 } else { | |
| 1059 if ((m & 1) == 0) { | |
| 1060 hx_plot_assistant(grid, size, x, (size - 1)); | |
| 1061 } | |
| 1062 hx_plot_assistant(grid, size, x, 0); | |
| 1063 } | |
| 1064 | |
| 1065 mod_x++; | |
| 1066 x -= module_width; | |
| 1067 } while (x >= 0); | |
| 1068 | |
| 1069 /* Add alignment pattern */ | |
| 1070 column_switch = 1; | |
| 1071 y = 0; | |
| 1072 mod_y = 0; | |
| 1073 do { | |
| 1074 if (mod_y < m) { | |
| 1075 module_height = k; | |
| 1076 } else { | |
| 1077 module_height = r - 1; | |
| 1078 } | |
| 1079 | |
| 1080 if (column_switch == 1) { | |
| 1081 row_switch = 1; | |
| 1082 column_switch = 0; | |
| 1083 } else { | |
| 1084 row_switch = 0; | |
| 1085 column_switch = 1; | |
| 1086 } | |
| 1087 | |
| 1088 x = (size - 1); | |
| 1089 mod_x = 0; | |
| 1090 do { | |
| 1091 if (mod_x < m) { | |
| 1092 module_width = k; | |
| 1093 } else { | |
| 1094 module_width = r - 1; | |
| 1095 } | |
| 1096 | |
| 1097 if (row_switch == 1) { | |
| 1098 if (!(y == 0 && x == (size - 1))) { | |
| 1099 hx_plot_alignment(grid, size, x, y, module_width, module_height); | |
| 1100 } | |
| 1101 row_switch = 0; | |
| 1102 } else { | |
| 1103 row_switch = 1; | |
| 1104 } | |
| 1105 mod_x++; | |
| 1106 x -= module_width; | |
| 1107 } while (x >= 0); | |
| 1108 | |
| 1109 mod_y++; | |
| 1110 y += module_height; | |
| 1111 } while (y < size); | |
| 1112 } | |
| 1113 } | |
| 1114 | |
| 1115 /* Calculate error correction codes */ | |
| 1116 static void hx_add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int data_codewords, | |
| 1117 const int version, const int ecc_level) { | |
| 1118 unsigned char data_block[180]; | |
| 1119 unsigned char ecc_block[36]; | |
| 1120 int i, j, block; | |
| 1121 int input_position = 0; | |
| 1122 int output_position = 0; | |
| 1123 const int table_d1_pos = ((version - 1) * 36) + ((ecc_level - 1) * 9); | |
| 1124 rs_t rs; | |
| 1125 | |
| 1126 rs_init_gf(&rs, 0x163); /* x^8 + x^6 + x^5 + x + 1 = 0 */ | |
| 1127 | |
| 1128 for (i = 0; i < 3; i++) { | |
| 1129 const int batch_size = hx_table_d1[table_d1_pos + (3 * i)]; | |
| 1130 const int data_length = hx_table_d1[table_d1_pos + (3 * i) + 1]; | |
| 1131 const int ecc_length = hx_table_d1[table_d1_pos + (3 * i) + 2]; | |
| 1132 | |
| 1133 rs_init_code(&rs, ecc_length, 1); | |
| 1134 | |
| 1135 for (block = 0; block < batch_size; block++) { | |
| 1136 for (j = 0; j < data_length; j++) { | |
| 1137 data_block[j] = input_position < data_codewords ? datastream[input_position] : 0; | |
| 1138 fullstream[output_position++] = data_block[j]; | |
| 1139 input_position++; | |
| 1140 } | |
| 1141 | |
| 1142 rs_encode(&rs, data_length, data_block, ecc_block); | |
| 1143 | |
| 1144 for (j = 0; j < ecc_length; j++) { | |
| 1145 fullstream[output_position++] = ecc_block[j]; | |
| 1146 } | |
| 1147 } | |
| 1148 } | |
| 1149 } | |
| 1150 | |
| 1151 static void hx_set_function_info(unsigned char *grid, const int size, const int version, const int ecc_level, | |
| 1152 const int bitmask, const int debug_print) { | |
| 1153 int i, j; | |
| 1154 char function_information[34]; | |
| 1155 unsigned char fi_cw[3] = {0}; | |
| 1156 unsigned char fi_ecc[4]; | |
| 1157 int bp = 0; | |
| 1158 rs_t rs; | |
| 1159 | |
| 1160 /* Form function information string */ | |
| 1161 | |
| 1162 bp = bin_append_posn(version + 20, 8, function_information, bp); | |
| 1163 bp = bin_append_posn(ecc_level - 1, 2, function_information, bp); | |
| 1164 bp = bin_append_posn(bitmask, 2, function_information, bp); | |
| 1165 | |
| 1166 for (i = 0; i < 3; i++) { | |
| 1167 for (j = 0; j < 4; j++) { | |
| 1168 if (function_information[(i * 4) + j] == '1') { | |
| 1169 fi_cw[i] += (0x08 >> j); | |
| 1170 } | |
| 1171 } | |
| 1172 } | |
| 1173 | |
| 1174 rs_init_gf(&rs, 0x13); | |
| 1175 rs_init_code(&rs, 4, 1); | |
| 1176 rs_encode(&rs, 3, fi_cw, fi_ecc); | |
| 1177 | |
| 1178 for (i = 0; i < 4; i++) { | |
| 1179 bp = bin_append_posn(fi_ecc[i], 4, function_information, bp); | |
| 1180 } | |
| 1181 | |
| 1182 /* Previously added alternating filler pattern here (as does BWIPP) but not mentioned in ISO/IEC 20830:2021 and | |
| 1183 does not appear in Figure 1 nor in the figures in Annex K (although does appear in Figure 2 and Figures 4-9) | |
| 1184 nor in the AIM ITS/04-023:2022 examples: so just clear */ | |
| 1185 for (i = 28; i < 34; i++) { | |
| 1186 function_information[i] = '0'; | |
| 1187 } | |
| 1188 | |
| 1189 if (debug_print) { | |
| 1190 printf("Version: %d, ECC: %d, Mask: %d, Structural Info: %.34s\n", version, ecc_level, bitmask, | |
| 1191 function_information); | |
| 1192 } | |
| 1193 | |
| 1194 /* Add function information to symbol */ | |
| 1195 for (i = 0; i < 9; i++) { | |
| 1196 if (function_information[i] == '1') { | |
| 1197 grid[(8 * size) + i] = 0x01; | |
| 1198 grid[((size - 8 - 1) * size) + (size - i - 1)] = 0x01; | |
| 1199 } | |
| 1200 if (function_information[i + 8] == '1') { | |
| 1201 grid[((8 - i) * size) + 8] = 0x01; | |
| 1202 grid[((size - 8 - 1 + i) * size) + (size - 8 - 1)] = 0x01; | |
| 1203 } | |
| 1204 if (function_information[i + 17] == '1') { | |
| 1205 grid[(i * size) + (size - 1 - 8)] = 0x01; | |
| 1206 grid[((size - 1 - i) * size) + 8] = 0x01; | |
| 1207 } | |
| 1208 if (function_information[i + 25] == '1') { | |
| 1209 grid[(8 * size) + (size - 1 - 8 + i)] = 0x01; | |
| 1210 grid[((size - 1 - 8) * size) + (8 - i)] = 0x01; | |
| 1211 } | |
| 1212 } | |
| 1213 } | |
| 1214 | |
| 1215 /* Rearrange data in batches of 13 codewords (section 5.8.2) */ | |
| 1216 static void hx_make_picket_fence(const unsigned char fullstream[], unsigned char picket_fence[], | |
| 1217 const int streamsize) { | |
| 1218 int i, start; | |
| 1219 int output_position = 0; | |
| 1220 | |
| 1221 for (start = 0; start < 13; start++) { | |
| 1222 for (i = start; i < streamsize; i += 13) { | |
| 1223 picket_fence[output_position] = fullstream[i]; | |
| 1224 output_position++; | |
| 1225 } | |
| 1226 } | |
| 1227 } | |
| 1228 | |
| 1229 /* Evaluate a bitmask according to table 9 */ | |
| 1230 static int hx_evaluate(const unsigned char *local, const int size) { | |
| 1231 static const unsigned char h1010111[7] = { 1, 0, 1, 0, 1, 1, 1 }; | |
| 1232 static const unsigned char h1110101[7] = { 1, 1, 1, 0, 1, 0, 1 }; | |
| 1233 | |
| 1234 int x, y, r, block; | |
| 1235 int result = 0; | |
| 1236 int state; | |
| 1237 int a, b, afterCount, beforeCount; | |
| 1238 | |
| 1239 /* Test 1: 1:1:1:1:3 or 3:1:1:1:1 ratio pattern in row/column */ | |
| 1240 /* Vertical */ | |
| 1241 for (x = 0; x < size; x++) { | |
| 1242 for (y = 0; y <= (size - 7); y++) { | |
| 1243 if (local[y * size + x] && local[(y + 1) * size + x] != local[(y + 5) * size + x] && | |
| 1244 local[(y + 2) * size + x] && !local[(y + 3) * size + x] && | |
| 1245 local[(y + 4) * size + x] && local[(y + 6) * size + x]) { | |
| 1246 /* Pattern found, check before and after */ | |
| 1247 beforeCount = 0; | |
| 1248 for (b = (y - 1); b >= (y - 3); b--) { | |
| 1249 if (b < 0) { /* Count < edge as whitespace */ | |
| 1250 beforeCount = 3; | |
| 1251 break; | |
| 1252 } | |
| 1253 if (local[(b * size) + x]) { | |
| 1254 break; | |
| 1255 } | |
| 1256 beforeCount++; | |
| 1257 } | |
| 1258 if (beforeCount == 3) { | |
| 1259 /* Pattern is preceded by light area 3 modules wide */ | |
| 1260 result += 50; | |
| 1261 } else { | |
| 1262 afterCount = 0; | |
| 1263 for (a = (y + 7); a <= (y + 9); a++) { | |
| 1264 if (a >= size) { /* Count > edge as whitespace */ | |
| 1265 afterCount = 3; | |
| 1266 break; | |
| 1267 } | |
| 1268 if (local[(a * size) + x]) { | |
| 1269 break; | |
| 1270 } | |
| 1271 afterCount++; | |
| 1272 } | |
| 1273 if (afterCount == 3) { | |
| 1274 /* Pattern is followed by light area 3 modules wide */ | |
| 1275 result += 50; | |
| 1276 } | |
| 1277 } | |
| 1278 y++; /* Skip to next possible match */ | |
| 1279 } | |
| 1280 } | |
| 1281 } | |
| 1282 | |
| 1283 /* Horizontal */ | |
| 1284 for (y = 0; y < size; y++) { | |
| 1285 r = y * size; | |
| 1286 for (x = 0; x <= (size - 7); x++) { | |
| 1287 if (memcmp(local + r + x, h1010111, 7) == 0 || memcmp(local + r + x, h1110101, 7) == 0) { | |
| 1288 /* Pattern found, check before and after */ | |
| 1289 beforeCount = 0; | |
| 1290 for (b = (x - 1); b >= (x - 3); b--) { | |
| 1291 if (b < 0) { /* Count < edge as whitespace */ | |
| 1292 beforeCount = 3; | |
| 1293 break; | |
| 1294 } | |
| 1295 if (local[r + b]) { | |
| 1296 break; | |
| 1297 } | |
| 1298 beforeCount++; | |
| 1299 } | |
| 1300 | |
| 1301 if (beforeCount == 3) { | |
| 1302 /* Pattern is preceded by light area 3 modules wide */ | |
| 1303 result += 50; | |
| 1304 } else { | |
| 1305 afterCount = 0; | |
| 1306 for (a = (x + 7); a <= (x + 9); a++) { | |
| 1307 if (a >= size) { /* Count > edge as whitespace */ | |
| 1308 afterCount = 3; | |
| 1309 break; | |
| 1310 } | |
| 1311 if (local[r + a]) { | |
| 1312 break; | |
| 1313 } | |
| 1314 afterCount++; | |
| 1315 } | |
| 1316 if (afterCount == 3) { | |
| 1317 /* Pattern is followed by light area 3 modules wide */ | |
| 1318 result += 50; | |
| 1319 } | |
| 1320 } | |
| 1321 x++; /* Skip to next possible match */ | |
| 1322 } | |
| 1323 } | |
| 1324 } | |
| 1325 | |
| 1326 /* Test 2: Adjacent modules in row/column in same colour */ | |
| 1327 /* In AIMD-15 section 5.8.3.2 it is stated... “In Table 9 below, i refers to the row | |
| 1328 * position of the module.” - however i being the length of the run of the | |
| 1329 * same colour (i.e. "block" below) in the same fashion as ISO/IEC 18004 | |
| 1330 * makes more sense. -- Confirmed by Wang Yi */ | |
| 1331 /* Fixed in ISO/IEC 20830 section 5.8.4.3 "In Table, i refers to the modules with | |
| 1332 same color." */ | |
| 1333 | |
| 1334 /* Vertical */ | |
| 1335 for (x = 0; x < size; x++) { | |
| 1336 block = 0; | |
| 1337 state = 0; | |
| 1338 for (y = 0; y < size; y++) { | |
| 1339 if (local[(y * size) + x] == state) { | |
| 1340 block++; | |
| 1341 } else { | |
| 1342 if (block >= 3) { | |
| 1343 result += block * 4; | |
| 1344 } | |
| 1345 block = 1; | |
| 1346 state = local[(y * size) + x]; | |
| 1347 } | |
| 1348 } | |
| 1349 if (block >= 3) { | |
| 1350 result += block * 4; | |
| 1351 } | |
| 1352 } | |
| 1353 | |
| 1354 /* Horizontal */ | |
| 1355 for (y = 0; y < size; y++) { | |
| 1356 r = y * size; | |
| 1357 block = 0; | |
| 1358 state = 0; | |
| 1359 for (x = 0; x < size; x++) { | |
| 1360 if (local[r + x] == state) { | |
| 1361 block++; | |
| 1362 } else { | |
| 1363 if (block >= 3) { | |
| 1364 result += block * 4; | |
| 1365 } | |
| 1366 block = 1; | |
| 1367 state = local[r + x]; | |
| 1368 } | |
| 1369 } | |
| 1370 if (block >= 3) { | |
| 1371 result += block * 4; | |
| 1372 } | |
| 1373 } | |
| 1374 | |
| 1375 return result; | |
| 1376 } | |
| 1377 | |
| 1378 /* Apply the four possible bitmasks for evaluation */ | |
| 1379 /* TODO: Haven't been able to replicate (or even get close to) the penalty scores in ISO/IEC 20830:2021 | |
| 1380 * Annex K examples */ | |
| 1381 static void hx_apply_bitmask(unsigned char *grid, const int size, const int version, const int ecc_level, | |
| 1382 const int user_mask, const int debug_print) { | |
| 1383 int x, y; | |
| 1384 int i, j, r, k; | |
| 1385 int pattern, penalty[4] = {0}; | |
| 1386 int best_pattern; | |
| 1387 int bit; | |
| 1388 const int size_squared = size * size; | |
| 1389 unsigned char *mask = (unsigned char *) z_alloca(size_squared); | |
| 1390 unsigned char *local = (unsigned char *) z_alloca(size_squared); | |
| 1391 | |
| 1392 /* Perform data masking */ | |
| 1393 memset(mask, 0, size_squared); | |
| 1394 for (y = 0; y < size; y++) { | |
| 1395 r = y * size; | |
| 1396 for (x = 0; x < size; x++) { | |
| 1397 k = r + x; | |
| 1398 | |
| 1399 if (!(grid[k] & 0xf0)) { | |
| 1400 j = x + 1; | |
| 1401 i = y + 1; | |
| 1402 if (((i + j) & 1) == 0) { | |
| 1403 mask[k] |= 0x02; | |
| 1404 } | |
| 1405 if (((((i + j) % 3) + (j % 3)) & 1) == 0) { | |
| 1406 mask[k] |= 0x04; | |
| 1407 } | |
| 1408 if ((((i % j) + (j % i) + (i % 3) + (j % 3)) & 1) == 0) { | |
| 1409 mask[k] |= 0x08; | |
| 1410 } | |
| 1411 } | |
| 1412 } | |
| 1413 } | |
| 1414 | |
| 1415 if (user_mask) { | |
| 1416 best_pattern = user_mask - 1; | |
| 1417 } else { | |
| 1418 /* apply data masks to grid, result in local */ | |
| 1419 | |
| 1420 /* Do null pattern 00 separately first */ | |
| 1421 pattern = 0; | |
| 1422 for (k = 0; k < size_squared; k++) { | |
| 1423 local[k] = grid[k] & 0x0f; | |
| 1424 } | |
| 1425 /* Set the Structural Info */ | |
| 1426 hx_set_function_info(local, size, version, ecc_level, pattern, 0 /*debug_print*/); | |
| 1427 | |
| 1428 /* Evaluate result */ | |
| 1429 penalty[pattern] = hx_evaluate(local, size); | |
| 1430 | |
| 1431 best_pattern = 0; | |
| 1432 for (pattern = 1; pattern < 4; pattern++) { | |
| 1433 bit = 1 << pattern; | |
| 1434 for (k = 0; k < size_squared; k++) { | |
| 1435 if (mask[k] & bit) { | |
| 1436 local[k] = grid[k] ^ 0x01; | |
| 1437 } else { | |
| 1438 local[k] = grid[k] & 0x0f; | |
| 1439 } | |
| 1440 } | |
| 1441 /* Set the Structural Info */ | |
| 1442 hx_set_function_info(local, size, version, ecc_level, pattern, 0 /*debug_print*/); | |
| 1443 | |
| 1444 /* Evaluate result */ | |
| 1445 penalty[pattern] = hx_evaluate(local, size); | |
| 1446 if (penalty[pattern] < penalty[best_pattern]) { | |
| 1447 best_pattern = pattern; | |
| 1448 } | |
| 1449 } | |
| 1450 } | |
| 1451 | |
| 1452 if (debug_print) { | |
| 1453 printf("Mask: %d (%s)", best_pattern, user_mask ? "specified" : "automatic"); | |
| 1454 if (!user_mask) { | |
| 1455 for (pattern = 0; pattern < 4; pattern++) printf(" %d:%d", pattern, penalty[pattern]); | |
| 1456 } | |
| 1457 fputc('\n', stdout); | |
| 1458 } | |
| 1459 | |
| 1460 /* Apply mask */ | |
| 1461 if (best_pattern) { /* If not null mask */ | |
| 1462 if (!user_mask && best_pattern == 3) { /* Reuse last */ | |
| 1463 memcpy(grid, local, size_squared); | |
| 1464 } else { | |
| 1465 bit = 1 << best_pattern; | |
| 1466 for (k = 0; k < size_squared; k++) { | |
| 1467 if (mask[k] & bit) { | |
| 1468 grid[k] ^= 0x01; | |
| 1469 } | |
| 1470 } | |
| 1471 } | |
| 1472 } | |
| 1473 /* Set the Structural Info */ | |
| 1474 hx_set_function_info(grid, size, version, ecc_level, best_pattern, debug_print); | |
| 1475 } | |
| 1476 | |
| 1477 /* Han Xin Code - main */ | |
| 1478 INTERNAL int hanxin(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { | |
| 1479 int warn_number = 0; | |
| 1480 int est_binlen; | |
| 1481 int ecc_level = symbol->option_1; | |
| 1482 int i, j, j_max, version; | |
| 1483 int full_multibyte; | |
| 1484 int user_mask; | |
| 1485 int data_codewords = 0, size; | |
| 1486 int size_squared; | |
| 1487 int codewords; | |
| 1488 int bin_len; | |
| 1489 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 1490 const int eci_length_segs = get_eci_length_segs(segs, seg_count); | |
| 1491 struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count); | |
| 1492 unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * eci_length_segs); | |
| 1493 char *mode = (char *) z_alloca(eci_length_segs); | |
| 1494 char *binary; | |
| 1495 unsigned char *datastream; | |
| 1496 unsigned char *fullstream; | |
| 1497 unsigned char *picket_fence; | |
| 1498 unsigned char *grid; | |
| 1499 | |
| 1500 segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECI & protect lengths) */ | |
| 1501 | |
| 1502 /* If ZINT_FULL_MULTIBYTE set use Hanzi mode in DATA_MODE or for non-GB 18030 in UNICODE_MODE */ | |
| 1503 full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE; | |
| 1504 user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 4 */ | |
| 1505 if (user_mask > 4) { | |
| 1506 user_mask = 0; /* Ignore */ | |
| 1507 } | |
| 1508 | |
| 1509 if ((symbol->input_mode & 0x07) == DATA_MODE) { | |
| 1510 gb18030_cpy_segs(local_segs, seg_count, ddata, full_multibyte); | |
| 1511 } else { | |
| 1512 unsigned int *dd = ddata; | |
| 1513 for (i = 0; i < seg_count; i++) { | |
| 1514 int done = 0; | |
| 1515 if (local_segs[i].eci != 32 || seg_count > 1) { /* Unless ECI 32 (GB 18030) or have multiple segments */ | |
| 1516 /* Try other conversions (ECI 0 defaults to ISO/IEC 8859-1) */ | |
| 1517 int error_number = gb18030_utf8_to_eci(local_segs[i].eci, local_segs[i].source, &local_segs[i].length, | |
| 1518 dd, full_multibyte); | |
| 1519 if (error_number == 0) { | |
| 1520 done = 1; | |
| 1521 } else if (local_segs[i].eci || seg_count > 1) { | |
| 1522 return errtxtf(error_number, symbol, 545, "Invalid character in input for ECI '%d'", | |
| 1523 local_segs[i].eci); | |
| 1524 } | |
| 1525 } | |
| 1526 if (!done) { | |
| 1527 /* Try GB 18030 */ | |
| 1528 int error_number = gb18030_utf8(symbol, local_segs[i].source, &local_segs[i].length, dd); | |
| 1529 if (error_number != 0) { | |
| 1530 return error_number; | |
| 1531 } | |
| 1532 if (local_segs[i].eci != 32) { | |
| 1533 warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 543, | |
| 1534 "Converted to GB 18030 but no ECI specified"); | |
| 1535 } | |
| 1536 } | |
| 1537 dd += local_segs[i].length; | |
| 1538 } | |
| 1539 } | |
| 1540 | |
| 1541 hx_define_mode_segs(mode, ddata, local_segs, seg_count, debug_print); | |
| 1542 | |
| 1543 est_binlen = hx_calc_binlen_segs(mode, ddata, local_segs, seg_count); | |
| 1544 if (debug_print) { | |
| 1545 printf("Estimated binary length: %d\n", est_binlen); | |
| 1546 } | |
| 1547 | |
| 1548 binary = (char *) malloc(est_binlen + 1); | |
| 1549 | |
| 1550 if ((ecc_level <= 0) || (ecc_level >= 5)) { | |
| 1551 ecc_level = 1; | |
| 1552 } | |
| 1553 | |
| 1554 hx_calculate_binary_segs(binary, mode, ddata, local_segs, seg_count, &bin_len, debug_print); | |
| 1555 codewords = bin_len >> 3; | |
| 1556 if (bin_len & 0x07) { | |
| 1557 codewords++; | |
| 1558 } | |
| 1559 if (debug_print) { | |
| 1560 printf("Num. of codewords: %d (%d padbits)\n", codewords, bin_len & 0x07); | |
| 1561 } | |
| 1562 | |
| 1563 version = 85; | |
| 1564 for (i = 84; i > 0; i--) { | |
| 1565 if (hx_data_codewords[ecc_level - 1][i - 1] >= codewords) { | |
| 1566 version = i; | |
| 1567 data_codewords = hx_data_codewords[ecc_level - 1][i - 1]; | |
| 1568 } | |
| 1569 } | |
| 1570 | |
| 1571 if (version == 85) { | |
| 1572 free(binary); | |
| 1573 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 541, "Input too long, requires %d codewords (maximum 3264)", | |
| 1574 codewords); | |
| 1575 } | |
| 1576 | |
| 1577 if ((symbol->option_2 < 0) || (symbol->option_2 > 84)) { | |
| 1578 symbol->option_2 = 0; | |
| 1579 } | |
| 1580 | |
| 1581 if (symbol->option_2 > version) { | |
| 1582 version = symbol->option_2; | |
| 1583 } | |
| 1584 | |
| 1585 if ((symbol->option_2 != 0) && (symbol->option_2 < version)) { | |
| 1586 free(binary); | |
| 1587 if (ecc_level == 1) { | |
| 1588 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 542, | |
| 1589 "Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)", | |
| 1590 symbol->option_2, codewords, hx_data_codewords[ecc_level - 1][symbol->option_2 - 1]); | |
| 1591 } | |
| 1592 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 542, | |
| 1593 "Input too long for Version %1$d, ECC %2$d, requires %3$d codewords (maximum %4$d)", | |
| 1594 symbol->option_2, ecc_level, codewords, | |
| 1595 hx_data_codewords[ecc_level - 1][symbol->option_2 - 1]); | |
| 1596 } | |
| 1597 | |
| 1598 /* If there is spare capacity, increase the level of ECC */ | |
| 1599 | |
| 1600 /* Unless explicitly specified (within min/max bounds) by user */ | |
| 1601 if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) { | |
| 1602 if (ecc_level == 1 && codewords <= hx_data_codewords[1][version - 1]) { | |
| 1603 ecc_level = 2; | |
| 1604 data_codewords = hx_data_codewords[1][version - 1]; | |
| 1605 } | |
| 1606 | |
| 1607 if (ecc_level == 2 && codewords <= hx_data_codewords[2][version - 1]) { | |
| 1608 ecc_level = 3; | |
| 1609 data_codewords = hx_data_codewords[2][version - 1]; | |
| 1610 } | |
| 1611 | |
| 1612 if (ecc_level == 3 && codewords <= hx_data_codewords[3][version - 1]) { | |
| 1613 ecc_level = 4; | |
| 1614 data_codewords = hx_data_codewords[3][version - 1]; | |
| 1615 } | |
| 1616 } | |
| 1617 | |
| 1618 size = (version * 2) + 21; | |
| 1619 size_squared = size * size; | |
| 1620 | |
| 1621 datastream = (unsigned char *) z_alloca(data_codewords); | |
| 1622 fullstream = (unsigned char *) z_alloca(hx_total_codewords[version - 1]); | |
| 1623 picket_fence = (unsigned char *) z_alloca(hx_total_codewords[version - 1]); | |
| 1624 grid = (unsigned char *) z_alloca(size_squared); | |
| 1625 | |
| 1626 memset(datastream, 0, data_codewords); | |
| 1627 | |
| 1628 for (i = 0; i < bin_len; i++) { | |
| 1629 if (binary[i] == '1') { | |
| 1630 datastream[i >> 3] |= 0x80 >> (i & 0x07); | |
| 1631 } | |
| 1632 } | |
| 1633 free(binary); | |
| 1634 | |
| 1635 if (debug_print) { | |
| 1636 printf("Datastream (%d):", data_codewords); | |
| 1637 for (i = 0; i < data_codewords; i++) { | |
| 1638 printf(" %.2x", datastream[i]); | |
| 1639 } | |
| 1640 fputc('\n', stdout); | |
| 1641 } | |
| 1642 #ifdef ZINT_TEST | |
| 1643 if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, data_codewords); | |
| 1644 #endif | |
| 1645 | |
| 1646 hx_setup_grid(grid, size, version); | |
| 1647 | |
| 1648 hx_add_ecc(fullstream, datastream, data_codewords, version, ecc_level); | |
| 1649 | |
| 1650 if (debug_print) { | |
| 1651 printf("Fullstream (%d):", hx_total_codewords[version - 1]); | |
| 1652 for (i = 0; i < hx_total_codewords[version - 1]; i++) { | |
| 1653 printf(" %.2x", fullstream[i]); | |
| 1654 } | |
| 1655 fputc('\n', stdout); | |
| 1656 } | |
| 1657 | |
| 1658 hx_make_picket_fence(fullstream, picket_fence, hx_total_codewords[version - 1]); | |
| 1659 | |
| 1660 /* Populate grid */ | |
| 1661 j = 0; | |
| 1662 j_max = hx_total_codewords[version - 1] * 8; | |
| 1663 for (i = 0; i < size_squared; i++) { | |
| 1664 if (grid[i] == 0x00) { | |
| 1665 if (j < j_max) { | |
| 1666 if (picket_fence[(j >> 3)] & (0x80 >> (j & 0x07))) { | |
| 1667 grid[i] = 0x01; | |
| 1668 } | |
| 1669 j++; | |
| 1670 } else { | |
| 1671 break; | |
| 1672 } | |
| 1673 } | |
| 1674 } | |
| 1675 | |
| 1676 hx_apply_bitmask(grid, size, version, ecc_level, user_mask, debug_print); | |
| 1677 | |
| 1678 symbol->width = size; | |
| 1679 symbol->rows = size; | |
| 1680 | |
| 1681 for (i = 0; i < size; i++) { | |
| 1682 const int r = i * size; | |
| 1683 for (j = 0; j < size; j++) { | |
| 1684 if (grid[r + j] & 0x01) { | |
| 1685 set_module(symbol, i, j); | |
| 1686 } | |
| 1687 } | |
| 1688 symbol->row_height[i] = 1; | |
| 1689 } | |
| 1690 symbol->height = size; | |
| 1691 | |
| 1692 return warn_number; | |
| 1693 } | |
| 1694 | |
| 1695 /* vim: set ts=4 sw=4 et : */ |
