Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/postal.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 /* postal.c - Handles POSTNET, PLANET, CEPNet, FIM. RM4SCC and Flattermarken */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com> | |
| 5 Including bug fixes by Bryan Hatton | |
| 6 | |
| 7 Redistribution and use in source and binary forms, with or without | |
| 8 modification, are permitted provided that the following conditions | |
| 9 are met: | |
| 10 | |
| 11 1. Redistributions of source code must retain the above copyright | |
| 12 notice, this list of conditions and the following disclaimer. | |
| 13 2. Redistributions in binary form must reproduce the above copyright | |
| 14 notice, this list of conditions and the following disclaimer in the | |
| 15 documentation and/or other materials provided with the distribution. | |
| 16 3. Neither the name of the project nor the names of its contributors | |
| 17 may be used to endorse or promote products derived from this software | |
| 18 without specific prior written permission. | |
| 19 | |
| 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 30 SUCH DAMAGE. | |
| 31 */ | |
| 32 /* SPDX-License-Identifier: BSD-3-Clause */ | |
| 33 | |
| 34 #include <stdio.h> | |
| 35 #include "common.h" | |
| 36 | |
| 37 static const char DAFTSET[] = "FADT"; | |
| 38 static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
| 39 static const char KASUTSET[] = "1234567890-abcdefgh"; | |
| 40 static const char CHKASUTSET[] = "0123456789-abcdefgh"; | |
| 41 #define SHKASUTSET_F (IS_NUM_F | IS_MNS_F | IS_UPR_F) /* SHKASUTSET "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ" */ | |
| 42 | |
| 43 /* PostNet number encoding table - In this table L is long as S is short */ | |
| 44 static const char PNTable[10][5] = { | |
| 45 {'L','L','S','S','S'}, {'S','S','S','L','L'}, {'S','S','L','S','L'}, {'S','S','L','L','S'}, {'S','L','S','S','L'}, | |
| 46 {'S','L','S','L','S'}, {'S','L','L','S','S'}, {'L','S','S','S','L'}, {'L','S','S','L','S'}, {'L','S','L','S','S'} | |
| 47 }; | |
| 48 | |
| 49 static const char PLTable[10][5] = { | |
| 50 {'S','S','L','L','L'}, {'L','L','L','S','S'}, {'L','L','S','L','S'}, {'L','L','S','S','L'}, {'L','S','L','L','S'}, | |
| 51 {'L','S','L','S','L'}, {'L','S','S','L','L'}, {'S','L','L','L','S'}, {'S','L','L','S','L'}, {'S','L','S','L','L'} | |
| 52 }; | |
| 53 | |
| 54 static const char RoyalValues[36][2] = { | |
| 55 { 1, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 1, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 4 }, | |
| 56 { 2, 5 }, { 2, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }, { 3, 4 }, { 3, 5 }, { 3, 0 }, { 4, 1 }, { 4, 2 }, | |
| 57 { 4, 3 }, { 4, 4 }, { 4, 5 }, { 4, 0 }, { 5, 1 }, { 5, 2 }, { 5, 3 }, { 5, 4 }, { 5, 5 }, { 5, 0 }, | |
| 58 { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 0, 5 }, { 0, 0 } | |
| 59 }; | |
| 60 | |
| 61 /* 0 = Full, 1 = Ascender, 2 = Descender, 3 = Tracker */ | |
| 62 static const char RoyalTable[36][4] = { | |
| 63 {'3','3','0','0'}, {'3','2','1','0'}, {'3','2','0','1'}, {'2','3','1','0'}, {'2','3','0','1'}, {'2','2','1','1'}, | |
| 64 {'3','1','2','0'}, {'3','0','3','0'}, {'3','0','2','1'}, {'2','1','3','0'}, {'2','1','2','1'}, {'2','0','3','1'}, | |
| 65 {'3','1','0','2'}, {'3','0','1','2'}, {'3','0','0','3'}, {'2','1','1','2'}, {'2','1','0','3'}, {'2','0','1','3'}, | |
| 66 {'1','3','2','0'}, {'1','2','3','0'}, {'1','2','2','1'}, {'0','3','3','0'}, {'0','3','2','1'}, {'0','2','3','1'}, | |
| 67 {'1','3','0','2'}, {'1','2','1','2'}, {'1','2','0','3'}, {'0','3','1','2'}, {'0','3','0','3'}, {'0','2','1','3'}, | |
| 68 {'1','1','2','2'}, {'1','0','3','2'}, {'1','0','2','3'}, {'0','1','3','2'}, {'0','1','2','3'}, {'0','0','3','3'} | |
| 69 }; | |
| 70 | |
| 71 static const char FlatTable[10][4] = { | |
| 72 {'0','5','0','4'}, { "18" }, {'0','1','1','7'}, {'0','2','1','6'}, {'0','3','1','5'}, | |
| 73 {'0','4','1','4'}, {'0','5','1','3'}, {'0','6','1','2'}, {'0','7','1','1'}, {'0','8','1','0'} | |
| 74 }; | |
| 75 | |
| 76 static const char KoreaTable[10][10] = { | |
| 77 {'1','3','1','3','1','5','0','6','1','3'}, {'0','7','1','3','1','3','1','3','1','3'}, | |
| 78 {'0','4','1','7','1','3','1','3','1','3'}, {'1','5','0','6','1','3','1','3','1','3'}, | |
| 79 {'0','4','1','3','1','7','1','3','1','3'}, { "17171313" }, | |
| 80 {'1','3','1','5','0','6','1','3','1','3'}, {'0','4','1','3','1','3','1','7','1','3'}, | |
| 81 { "17131713" }, { "13171713" } | |
| 82 }; | |
| 83 | |
| 84 static const char JapanTable[19][3] = { | |
| 85 {'1','1','4'}, {'1','3','2'}, {'3','1','2'}, {'1','2','3'}, {'1','4','1'}, | |
| 86 {'3','2','1'}, {'2','1','3'}, {'2','3','1'}, {'4','1','1'}, {'1','4','4'}, | |
| 87 {'4','1','4'}, {'3','2','4'}, {'3','4','2'}, {'2','3','4'}, {'4','3','2'}, | |
| 88 {'2','4','3'}, {'4','2','3'}, {'4','4','1'}, {'1','1','1'} | |
| 89 }; | |
| 90 | |
| 91 /* Set height for POSTNET/PLANET/CEPNet codes, maintaining ratio */ | |
| 92 static int usps_set_height(struct zint_symbol *symbol, const int no_errtxt) { | |
| 93 /* USPS Domestic Mail Manual (USPS DMM 300) Jan 8, 2006 (updated 2011) 708.4.2.5 POSTNET Barcode Dimensions and | |
| 94 Spacing | |
| 95 http://web.archive.org/web/20061113174253/http://pe.usps.com/cpim/ftp/manuals/dmm300/full/mailingStandards.pdf | |
| 96 Using bar pitch as X (1" / 43) ~ 0.023" based on 22 bars + 21 spaces per inch (bar width 0.015" - 0.025") | |
| 97 Half bar height 0.05" +- 0.01; 0.040" (min) / 0.025" (X max) = 1.6 min, 0.060" (max) / 0.015" (X min) = 4 max | |
| 98 Full bar height 0.125" +- 0.01; 0.115" (min) / 0.025" (X max) = 4.6 min, 0.135" (max) / 0.015" (X min) = 9 max | |
| 99 */ | |
| 100 /* CEPNet e Código Bidimensional Datamatrix 2D (26/05/2021) 3.3.2 Arquitetura das barras - same as POSTNET */ | |
| 101 int error_number = 0; | |
| 102 | |
| 103 /* No legacy for CEPNet as new */ | |
| 104 if ((symbol->output_options & COMPLIANT_HEIGHT) || symbol->symbology == BARCODE_CEPNET) { | |
| 105 symbol->row_height[0] = 3.2249999f; /* 0.075 * 43 */ | |
| 106 symbol->row_height[1] = 2.1500001f; /* 0.05 * 43 */ | |
| 107 } else { | |
| 108 symbol->row_height[0] = 6.0f; | |
| 109 symbol->row_height[1] = 6.0f; | |
| 110 } | |
| 111 if (symbol->height) { | |
| 112 /* Half ratio */ | |
| 113 const float h_ratio = symbol->row_height[1] / (symbol->row_height[0] + symbol->row_height[1]); /* 0.4 */ | |
| 114 symbol->row_height[1] = stripf(symbol->height * h_ratio); | |
| 115 if (symbol->row_height[1] < 0.5f) { /* Absolute minimum */ | |
| 116 symbol->row_height[1] = 0.5f; | |
| 117 symbol->row_height[0] = stripf(0.5f / h_ratio - 0.5f); /* 0.75 */ | |
| 118 } else { | |
| 119 symbol->row_height[0] = stripf(symbol->height - symbol->row_height[1]); | |
| 120 } | |
| 121 } | |
| 122 symbol->height = stripf(symbol->row_height[0] + symbol->row_height[1]); | |
| 123 | |
| 124 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 125 if (symbol->height < 4.6f || symbol->height > 9.0f) { | |
| 126 error_number = ZINT_WARN_NONCOMPLIANT; | |
| 127 if (!no_errtxt) { | |
| 128 errtxt(0, symbol, 498, "Height not compliant with standards"); | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 return error_number; | |
| 134 } | |
| 135 | |
| 136 /* Handles the POSTNET system used for Zip codes in the US */ | |
| 137 /* Also handles Brazilian CEPNet - more information CEPNet e Código Bidimensional Datamatrix 2D (26/05/2021) at | |
| 138 https://www.correios.com.br/enviar/correspondencia/arquivos/nacional/ | |
| 139 guia-tecnico-cepnet-e-2d-triagem-enderecamento-27-04-2021.pdf/view | |
| 140 */ | |
| 141 static int postnet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) { | |
| 142 int i, sum, check_digit; | |
| 143 int error_number = 0; | |
| 144 | |
| 145 if (length > 38) { | |
| 146 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 480, "Input length %d too long (maximum 38)", length); | |
| 147 } | |
| 148 | |
| 149 if (symbol->symbology == BARCODE_CEPNET) { | |
| 150 if (length != 8) { | |
| 151 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 780, "Input length %d wrong (should be 8 digits)", | |
| 152 length); | |
| 153 } | |
| 154 } else { | |
| 155 if (length != 5 && length != 9 && length != 11) { | |
| 156 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 479, | |
| 157 "Input length %d is not standard (5, 9 or 11)", length); | |
| 158 } | |
| 159 } | |
| 160 if ((i = not_sane(NEON_F, source, length))) { | |
| 161 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 481, | |
| 162 "Invalid character at position %d in input (digits only)", i); | |
| 163 } | |
| 164 sum = 0; | |
| 165 | |
| 166 /* start character */ | |
| 167 *d++ = 'L'; | |
| 168 | |
| 169 for (i = 0; i < length; i++, d += 5) { | |
| 170 const int val = source[i] - '0'; | |
| 171 memcpy(d, PNTable[val], 5); | |
| 172 sum += val; | |
| 173 } | |
| 174 | |
| 175 check_digit = (10 - (sum % 10)) % 10; | |
| 176 memcpy(d, PNTable[check_digit], 5); | |
| 177 d += 5; | |
| 178 | |
| 179 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); | |
| 180 | |
| 181 /* stop character */ | |
| 182 strcpy(d, "L"); | |
| 183 | |
| 184 return error_number; | |
| 185 } | |
| 186 | |
| 187 /* Puts POSTNET barcodes into the pattern matrix */ | |
| 188 INTERNAL int postnet(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 189 /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */ | |
| 190 char height_pattern[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */ | |
| 191 unsigned int loopey, h; | |
| 192 int writer; | |
| 193 int error_number, warn_number; | |
| 194 | |
| 195 error_number = postnet_enc(symbol, source, height_pattern, length); | |
| 196 if (error_number >= ZINT_ERROR) { | |
| 197 return error_number; | |
| 198 } | |
| 199 | |
| 200 writer = 0; | |
| 201 h = (int) strlen(height_pattern); | |
| 202 for (loopey = 0; loopey < h; loopey++) { | |
| 203 if (height_pattern[loopey] == 'L') { | |
| 204 set_module(symbol, 0, writer); | |
| 205 } | |
| 206 set_module(symbol, 1, writer); | |
| 207 writer += 2; | |
| 208 } | |
| 209 warn_number = usps_set_height(symbol, error_number /*no_errtxt*/); | |
| 210 symbol->rows = 2; | |
| 211 symbol->width = writer - 1; | |
| 212 | |
| 213 return error_number ? error_number : warn_number; | |
| 214 } | |
| 215 | |
| 216 /* Handles the PLANET system used for item tracking in the US */ | |
| 217 static int planet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) { | |
| 218 int i, sum, check_digit; | |
| 219 int error_number = 0; | |
| 220 | |
| 221 if (length > 38) { | |
| 222 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 482, "Input length %d too long (maximum 38)", length); | |
| 223 } | |
| 224 if (length != 11 && length != 13) { | |
| 225 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 478, "Input length %d is not standard (11 or 13)", | |
| 226 length); | |
| 227 } | |
| 228 if ((i = not_sane(NEON_F, source, length))) { | |
| 229 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 483, | |
| 230 "Invalid character at position %d in input (digits only)", i); | |
| 231 } | |
| 232 sum = 0; | |
| 233 | |
| 234 /* start character */ | |
| 235 *d++ = 'L'; | |
| 236 | |
| 237 for (i = 0; i < length; i++, d += 5) { | |
| 238 const int val = source[i] - '0'; | |
| 239 memcpy(d, PLTable[val], 5); | |
| 240 sum += val; | |
| 241 } | |
| 242 | |
| 243 check_digit = (10 - (sum % 10)) % 10; | |
| 244 memcpy(d, PLTable[check_digit], 5); | |
| 245 d += 5; | |
| 246 | |
| 247 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); | |
| 248 | |
| 249 /* stop character */ | |
| 250 strcpy(d, "L"); | |
| 251 | |
| 252 return error_number; | |
| 253 } | |
| 254 | |
| 255 /* Puts PLANET barcodes into the pattern matrix */ | |
| 256 INTERNAL int planet(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 257 /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */ | |
| 258 char height_pattern[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */ | |
| 259 unsigned int loopey, h; | |
| 260 int writer; | |
| 261 int error_number, warn_number; | |
| 262 | |
| 263 error_number = planet_enc(symbol, source, height_pattern, length); | |
| 264 if (error_number >= ZINT_ERROR) { | |
| 265 return error_number; | |
| 266 } | |
| 267 | |
| 268 writer = 0; | |
| 269 h = (int) strlen(height_pattern); | |
| 270 for (loopey = 0; loopey < h; loopey++) { | |
| 271 if (height_pattern[loopey] == 'L') { | |
| 272 set_module(symbol, 0, writer); | |
| 273 } | |
| 274 set_module(symbol, 1, writer); | |
| 275 writer += 2; | |
| 276 } | |
| 277 warn_number = usps_set_height(symbol, error_number /*no_errtxt*/); | |
| 278 symbol->rows = 2; | |
| 279 symbol->width = writer - 1; | |
| 280 | |
| 281 return error_number ? error_number : warn_number; | |
| 282 } | |
| 283 | |
| 284 /* Korean Postal Authority */ | |
| 285 INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 286 int total, i, check, zeroes, error_number = 0; | |
| 287 char localstr[8], dest[80]; | |
| 288 char *d = dest; | |
| 289 int posns[6]; | |
| 290 | |
| 291 if (length > 6) { | |
| 292 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 484, "Input length %d too long (maximum 6)", length); | |
| 293 } | |
| 294 if ((i = not_sane(NEON_F, source, length))) { | |
| 295 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 485, | |
| 296 "Invalid character at position %d in input (digits only)", i); | |
| 297 } | |
| 298 zeroes = 6 - length; | |
| 299 memset(localstr, '0', zeroes); | |
| 300 ustrcpy(localstr + zeroes, source); | |
| 301 | |
| 302 total = 0; | |
| 303 for (i = 0; i < 6; i++) { | |
| 304 posns[i] = ctoi(localstr[i]); | |
| 305 total += posns[i]; | |
| 306 } | |
| 307 check = 10 - (total % 10); | |
| 308 if (check == 10) { | |
| 309 check = 0; | |
| 310 } | |
| 311 localstr[6] = itoc(check); | |
| 312 localstr[7] = '\0'; | |
| 313 | |
| 314 for (i = 5; i >= 0; i--) { | |
| 315 const char *const entry = KoreaTable[posns[i]]; | |
| 316 memcpy(d, entry, 10); | |
| 317 d += entry[8] ? 10 : 8; | |
| 318 } | |
| 319 memcpy(d, KoreaTable[check], 10); | |
| 320 d += KoreaTable[check][8] ? 10 : 8; | |
| 321 | |
| 322 expand(symbol, dest, d - dest); | |
| 323 | |
| 324 ustrcpy(symbol->text, localstr); | |
| 325 | |
| 326 /* TODO: Find documentation on BARCODE_KOREAPOST dimensions/height */ | |
| 327 | |
| 328 return error_number; | |
| 329 } | |
| 330 | |
| 331 /* The simplest barcode symbology ever! Supported by MS Word, so here it is! | |
| 332 glyphs from http://en.wikipedia.org/wiki/Facing_Identification_Mark */ | |
| 333 INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 334 int error_number = 0; | |
| 335 | |
| 336 if (length > 1) { | |
| 337 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 486, "Input length %d too long (maximum 1)", length); | |
| 338 } | |
| 339 | |
| 340 switch ((char) source[0]) { | |
| 341 case 'a': | |
| 342 case 'A': | |
| 343 expand(symbol, "111515111", 9); | |
| 344 break; | |
| 345 case 'b': | |
| 346 case 'B': | |
| 347 expand(symbol, "13111311131", 11); | |
| 348 break; | |
| 349 case 'c': | |
| 350 case 'C': | |
| 351 expand(symbol, "11131313111", 11); | |
| 352 break; | |
| 353 case 'd': | |
| 354 case 'D': | |
| 355 expand(symbol, "1111131311111", 13); | |
| 356 break; | |
| 357 case 'e': | |
| 358 case 'E': | |
| 359 expand(symbol, "1317131", 7); | |
| 360 break; | |
| 361 default: | |
| 362 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 487, | |
| 363 "Invalid character in input (\"A\", \"B\", \"C\", \"D\" or \"E\" only)"); | |
| 364 break; | |
| 365 } | |
| 366 | |
| 367 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 368 /* USPS Domestic Mail Manual (USPS DMM 300) Jan 8, 2006 (updated 2011) 708.9.3 | |
| 369 X 0.03125" (1/32) +- 0.008" so X max 0.03925", height 0.625" (5/8) +- 0.125" (1/8) */ | |
| 370 const float min_height = 12.7388535f; /* 0.5 / 0.03925 */ | |
| 371 const float default_height = 20.0f; /* 0.625 / 0.03125 */ | |
| 372 const float max_height = 31.0559006f; /* 0.75 / 0.02415 */ | |
| 373 error_number = set_height(symbol, min_height, default_height, max_height, 0 /*no_errtxt*/); | |
| 374 } else { | |
| 375 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 376 } | |
| 377 | |
| 378 return error_number; | |
| 379 } | |
| 380 | |
| 381 /* Set height for DAFT-type codes, maintaining ratio. Expects row_height[0] & row_height[1] to be set */ | |
| 382 /* Used by auspost.c also */ | |
| 383 INTERNAL int daft_set_height(struct zint_symbol *symbol, const float min_height, const float max_height) { | |
| 384 int error_number = 0; | |
| 385 | |
| 386 if (symbol->height) { | |
| 387 /* Tracker ratio */ | |
| 388 const float t_ratio = stripf(symbol->row_height[1] / stripf(symbol->row_height[0] * 2 | |
| 389 + symbol->row_height[1])); | |
| 390 symbol->row_height[1] = stripf(symbol->height * t_ratio); | |
| 391 if (symbol->row_height[1] < 0.5f) { /* Absolute minimum */ | |
| 392 symbol->row_height[1] = 0.5f; | |
| 393 symbol->row_height[0] = stripf(0.25f / t_ratio - 0.25f); | |
| 394 } else { | |
| 395 symbol->row_height[0] = stripf(stripf(symbol->height - symbol->row_height[1]) / 2.0f); | |
| 396 } | |
| 397 if (symbol->row_height[0] < 0.5f) { | |
| 398 symbol->row_height[0] = 0.5f; | |
| 399 symbol->row_height[1] = stripf(t_ratio / (1.0f - t_ratio)); | |
| 400 } | |
| 401 } | |
| 402 symbol->row_height[2] = symbol->row_height[0]; | |
| 403 symbol->height = stripf(stripf(symbol->row_height[0] + symbol->row_height[1]) + symbol->row_height[2]); | |
| 404 | |
| 405 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 406 if ((min_height && symbol->height < min_height) || (max_height && symbol->height > max_height)) { | |
| 407 error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 499, "Height not compliant with standards"); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 return error_number; | |
| 412 } | |
| 413 | |
| 414 /* Handles the 4 State barcodes used in the UK by Royal Mail */ | |
| 415 static void rm4scc_enc(const struct zint_symbol *symbol, const int *posns, char *d, const int length) { | |
| 416 int i; | |
| 417 int top, bottom, row, column, check_digit; | |
| 418 | |
| 419 top = 0; | |
| 420 bottom = 0; | |
| 421 | |
| 422 /* start character */ | |
| 423 *d++ = '1'; | |
| 424 | |
| 425 for (i = 0; i < length; i++, d += 4) { | |
| 426 const int p = posns[i]; | |
| 427 memcpy(d, RoyalTable[p], 4); | |
| 428 top += RoyalValues[p][0]; | |
| 429 bottom += RoyalValues[p][1]; | |
| 430 } | |
| 431 | |
| 432 /* Calculate the check digit */ | |
| 433 row = (top % 6) - 1; | |
| 434 column = (bottom % 6) - 1; | |
| 435 if (row == -1) { | |
| 436 row = 5; | |
| 437 } | |
| 438 if (column == -1) { | |
| 439 column = 5; | |
| 440 } | |
| 441 check_digit = (6 * row) + column; | |
| 442 memcpy(d, RoyalTable[check_digit], 4); | |
| 443 d += 4; | |
| 444 | |
| 445 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); | |
| 446 | |
| 447 /* stop character */ | |
| 448 strcpy(d, "0"); | |
| 449 } | |
| 450 | |
| 451 /* Puts RM4SCC into the data matrix */ | |
| 452 INTERNAL int rm4scc(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 453 int i; | |
| 454 char height_pattern[210]; | |
| 455 int posns[50]; | |
| 456 int loopey, h; | |
| 457 int writer; | |
| 458 int error_number = 0; | |
| 459 | |
| 460 if (length > 50) { | |
| 461 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 488, "Input length %d too long (maximum 50)", length); | |
| 462 } | |
| 463 to_upper(source, length); | |
| 464 if ((i = not_sane_lookup(KRSET, 36, source, length, posns))) { | |
| 465 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 489, | |
| 466 "Invalid character at position %d in input (alphanumerics only)", i); | |
| 467 } | |
| 468 rm4scc_enc(symbol, posns, height_pattern, length); | |
| 469 | |
| 470 writer = 0; | |
| 471 h = (int) strlen(height_pattern); | |
| 472 for (loopey = 0; loopey < h; loopey++) { | |
| 473 if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) { | |
| 474 set_module(symbol, 0, writer); | |
| 475 } | |
| 476 set_module(symbol, 1, writer); | |
| 477 if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '0')) { | |
| 478 set_module(symbol, 2, writer); | |
| 479 } | |
| 480 writer += 2; | |
| 481 } | |
| 482 | |
| 483 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 484 /* Royal Mail Know How User's Manual Appendix C: using CBC | |
| 485 (https://web.archive.org/web/20120120060743/ | |
| 486 http://www.royalmail.com/sites/default/files/docs/pdf/Know How 2006 PIP vs 1.6a Accepted Changes.pdf) | |
| 487 Bar pitch and min/maxes same as Mailmark, so using recommendations from | |
| 488 Royal Mail Mailmark Barcode Definition Document (15 Sept 2015) Section 3.5.1 | |
| 489 */ | |
| 490 const float min_height = 6.47952747f; /* (4.22 * 39) / 25.4 */ | |
| 491 const float max_height = 10.8062992f; /* (5.84 * 47) / 25.4 */ | |
| 492 symbol->row_height[0] = 3.16417313f; /* (1.9 * 42.3) / 25.4 */ | |
| 493 symbol->row_height[1] = 2.16496062f; /* (1.3 * 42.3) / 25.4 */ | |
| 494 /* Note using max X for minimum and min X for maximum */ | |
| 495 error_number = daft_set_height(symbol, min_height, max_height); | |
| 496 } else { | |
| 497 symbol->row_height[0] = 3.0f; | |
| 498 symbol->row_height[1] = 2.0f; | |
| 499 (void) daft_set_height(symbol, 0.0f, 0.0f); | |
| 500 } | |
| 501 symbol->rows = 3; | |
| 502 symbol->width = writer - 1; | |
| 503 | |
| 504 return error_number; | |
| 505 } | |
| 506 | |
| 507 /* Handles Dutch Post TNT KIX symbols | |
| 508 The same as RM4SCC but without check digit or stop/start chars | |
| 509 Specification at http://www.tntpost.nl/zakelijk/klantenservice/downloads/kIX_code/download.aspx */ | |
| 510 INTERNAL int kix(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 511 char height_pattern[75]; | |
| 512 char *d = height_pattern; | |
| 513 int posns[18]; | |
| 514 int loopey; | |
| 515 int writer, i, h; | |
| 516 int error_number = 0; | |
| 517 | |
| 518 if (length > 18) { | |
| 519 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 490, "Input length %d too long (maximum 18)", length); | |
| 520 } | |
| 521 to_upper(source, length); | |
| 522 if ((i = not_sane_lookup(KRSET, 36, source, length, posns))) { | |
| 523 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 491, | |
| 524 "Invalid character at position %d in input (alphanumerics only)", i); | |
| 525 } | |
| 526 | |
| 527 /* Encode data */ | |
| 528 for (i = 0; i < length; i++, d += 4) { | |
| 529 memcpy(d, RoyalTable[posns[i]], 4); | |
| 530 } | |
| 531 | |
| 532 writer = 0; | |
| 533 h = d - height_pattern; | |
| 534 for (loopey = 0; loopey < h; loopey++) { | |
| 535 if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) { | |
| 536 set_module(symbol, 0, writer); | |
| 537 } | |
| 538 set_module(symbol, 1, writer); | |
| 539 if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '0')) { | |
| 540 set_module(symbol, 2, writer); | |
| 541 } | |
| 542 writer += 2; | |
| 543 } | |
| 544 | |
| 545 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 546 /* Dimensions same as RM4SCC */ | |
| 547 const float min_height = 6.47952747f; /* (4.22 * 39) / 25.4 */ | |
| 548 const float max_height = 10.8062992f; /* (5.84 * 47) / 25.4 */ | |
| 549 symbol->row_height[0] = 3.16417313f; /* (1.9 * 42.3) / 25.4 */ | |
| 550 symbol->row_height[1] = 2.16496062f; /* (1.3 * 42.3) / 25.4 */ | |
| 551 /* Note using max X for minimum and min X for maximum */ | |
| 552 error_number = daft_set_height(symbol, min_height, max_height); | |
| 553 } else { | |
| 554 symbol->row_height[0] = 3.0f; | |
| 555 symbol->row_height[1] = 2.0f; | |
| 556 (void) daft_set_height(symbol, 0.0f, 0.0f); | |
| 557 } | |
| 558 symbol->rows = 3; | |
| 559 symbol->width = writer - 1; | |
| 560 | |
| 561 return error_number; | |
| 562 } | |
| 563 | |
| 564 /* Handles DAFT Code symbols */ | |
| 565 INTERNAL int daft(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 566 int i; | |
| 567 int posns[576]; | |
| 568 int loopey; | |
| 569 int writer; | |
| 570 | |
| 571 if (length > 576) { /* 576 * 2 = 1152 */ | |
| 572 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 492, "Input length %d too long (maximum 576)", length); | |
| 573 } | |
| 574 to_upper(source, length); | |
| 575 | |
| 576 if ((i = not_sane_lookup(DAFTSET, 4, source, length, posns))) { | |
| 577 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 493, | |
| 578 "Invalid character at position %d in input (\"D\", \"A\", \"F\" and \"T\" only)", i); | |
| 579 } | |
| 580 | |
| 581 writer = 0; | |
| 582 for (loopey = 0; loopey < length; loopey++) { | |
| 583 if ((posns[loopey] == 1) || (posns[loopey] == 0)) { | |
| 584 set_module(symbol, 0, writer); | |
| 585 } | |
| 586 set_module(symbol, 1, writer); | |
| 587 if ((posns[loopey] == 2) || (posns[loopey] == 0)) { | |
| 588 set_module(symbol, 2, writer); | |
| 589 } | |
| 590 writer += 2; | |
| 591 } | |
| 592 | |
| 593 /* Allow ratio of tracker to be specified in thousandths */ | |
| 594 if (symbol->option_2 >= 50 && symbol->option_2 <= 900) { | |
| 595 const float t_ratio = symbol->option_2 / 1000.0f; | |
| 596 if (symbol->height < 0.5f) { | |
| 597 symbol->height = 8.0f; | |
| 598 } | |
| 599 symbol->row_height[1] = stripf(symbol->height * t_ratio); | |
| 600 symbol->row_height[0] = stripf((symbol->height - symbol->row_height[1]) / 2.0f); | |
| 601 } else { | |
| 602 symbol->row_height[0] = 3.0f; | |
| 603 symbol->row_height[1] = 2.0f; | |
| 604 } | |
| 605 | |
| 606 /* DAFT generic barcode so no dimensions/height specification */ | |
| 607 (void) daft_set_height(symbol, 0.0f, 0.0f); | |
| 608 symbol->rows = 3; | |
| 609 symbol->width = writer - 1; | |
| 610 | |
| 611 return 0; | |
| 612 } | |
| 613 | |
| 614 /* Flattermarken - Not really a barcode symbology! */ | |
| 615 INTERNAL int flat(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 616 int i, error_number = 0; | |
| 617 char dest[512]; /* 128 * 4 = 512 */ | |
| 618 char *d = dest; | |
| 619 | |
| 620 if (length > 128) { /* 128 * 9 = 1152 */ | |
| 621 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 494, "Input length %d too long (maximum 128)", length); | |
| 622 } | |
| 623 if ((i = not_sane(NEON_F, source, length))) { | |
| 624 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 495, | |
| 625 "Invalid character at position %d in input (digits only)", i); | |
| 626 } | |
| 627 | |
| 628 for (i = 0; i < length; i++) { | |
| 629 const char *const entry = FlatTable[source[i] - '0']; | |
| 630 memcpy(d, entry, 4); | |
| 631 d += entry[2] ? 4 : 2; | |
| 632 } | |
| 633 | |
| 634 expand(symbol, dest, d - dest); | |
| 635 | |
| 636 /* TODO: Find documentation on BARCODE_FLAT dimensions/height */ | |
| 637 | |
| 638 return error_number; | |
| 639 } | |
| 640 | |
| 641 /* Japanese Postal Code (Kasutama Barcode) */ | |
| 642 INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 643 int error_number = 0, h; | |
| 644 char pattern[69]; | |
| 645 char *d = pattern; | |
| 646 int writer, loopey, inter_posn, i, sum, check; | |
| 647 char check_char; | |
| 648 char inter[20 + 1]; | |
| 649 | |
| 650 if (length > 20) { | |
| 651 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 496, "Input length %d too long (maximum 20)", length); | |
| 652 } | |
| 653 | |
| 654 to_upper(source, length); | |
| 655 | |
| 656 if ((i = not_sane(SHKASUTSET_F, source, length))) { | |
| 657 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 497, | |
| 658 "Invalid character at position %d in input (alphanumerics and \"-\" only)", i); | |
| 659 } | |
| 660 memset(inter, 'd', 20); /* Pad character CC4 */ | |
| 661 inter[20] = '\0'; | |
| 662 | |
| 663 i = 0; | |
| 664 inter_posn = 0; | |
| 665 do { | |
| 666 if (z_isdigit(source[i]) || (source[i] == '-')) { | |
| 667 inter[inter_posn] = source[i]; | |
| 668 inter_posn++; | |
| 669 } else { | |
| 670 if (source[i] <= 'J') { | |
| 671 inter[inter_posn] = 'a'; | |
| 672 inter[inter_posn + 1] = source[i] - 'A' + '0'; | |
| 673 } else if (source[i] <= 'T') { | |
| 674 inter[inter_posn] = 'b'; | |
| 675 inter[inter_posn + 1] = source[i] - 'K' + '0'; | |
| 676 } else { /* (source[i] >= 'U') && (source[i] <= 'Z') */ | |
| 677 inter[inter_posn] = 'c'; | |
| 678 inter[inter_posn + 1] = source[i] - 'U' + '0'; | |
| 679 } | |
| 680 inter_posn += 2; | |
| 681 } | |
| 682 i++; | |
| 683 } while ((i < length) && (inter_posn < 20)); | |
| 684 | |
| 685 if (i != length || inter[20] != '\0') { | |
| 686 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 477, | |
| 687 "Input too long, requires too many symbol characters (maximum 20)"); | |
| 688 } | |
| 689 | |
| 690 memcpy(d, "13", 2); /* Start */ | |
| 691 d += 2; | |
| 692 | |
| 693 sum = 0; | |
| 694 for (i = 0; i < 20; i++, d += 3) { | |
| 695 memcpy(d, JapanTable[posn(KASUTSET, inter[i])], 3); | |
| 696 sum += posn(CHKASUTSET, inter[i]); | |
| 697 } | |
| 698 | |
| 699 /* Calculate check digit */ | |
| 700 check = 19 - (sum % 19); | |
| 701 if (check == 19) { | |
| 702 check = 0; | |
| 703 } | |
| 704 if (check <= 9) { | |
| 705 check_char = check + '0'; | |
| 706 } else if (check == 10) { | |
| 707 check_char = '-'; | |
| 708 } else { | |
| 709 check_char = (check - 11) + 'a'; | |
| 710 } | |
| 711 memcpy(d, JapanTable[posn(KASUTSET, check_char)], 3); | |
| 712 d += 3; | |
| 713 | |
| 714 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check: %d, char: %c\n", check, check_char); | |
| 715 | |
| 716 memcpy(d, "31", 2); /* Stop */ | |
| 717 d += 2; | |
| 718 | |
| 719 /* Resolve pattern to 4-state symbols */ | |
| 720 writer = 0; | |
| 721 h = d - pattern; | |
| 722 for (loopey = 0; loopey < h; loopey++) { | |
| 723 if ((pattern[loopey] == '2') || (pattern[loopey] == '1')) { | |
| 724 set_module(symbol, 0, writer); | |
| 725 } | |
| 726 set_module(symbol, 1, writer); | |
| 727 if ((pattern[loopey] == '3') || (pattern[loopey] == '1')) { | |
| 728 set_module(symbol, 2, writer); | |
| 729 } | |
| 730 writer += 2; | |
| 731 } | |
| 732 | |
| 733 symbol->rows = 3; | |
| 734 symbol->width = writer - 1; | |
| 735 | |
| 736 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 737 /* Japan Post Zip/Barcode Manual pp.11-12 https://www.post.japanpost.jp/zipcode/zipmanual/p11.html | |
| 738 X 0.6mm (0.5mm - 0.7mm) | |
| 739 Tracker height 1.2mm (1.05mm - 1.35mm) / 0.6mm = 2, | |
| 740 Ascender/descender = 1.2mm (Full 3.6mm (3.4mm - 3.6mm, max preferred) less T divided by 2) / 0.6mm = 2 */ | |
| 741 const float min_height = 4.85714293f; /* 3.4 / 0.7 */ | |
| 742 const float max_height = 7.19999981f; /* 3.6 / 0.5 */ | |
| 743 symbol->row_height[0] = 2.0f; | |
| 744 symbol->row_height[1] = 2.0f; | |
| 745 error_number = daft_set_height(symbol, min_height, max_height); | |
| 746 } else { | |
| 747 symbol->row_height[0] = 3.0f; | |
| 748 symbol->row_height[1] = 2.0f; | |
| 749 (void) daft_set_height(symbol, 0.0f, 0.0f); | |
| 750 } | |
| 751 | |
| 752 return error_number; | |
| 753 } | |
| 754 | |
| 755 /* vim: set ts=4 sw=4 et : */ |
