Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/vector.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 /* vector.c - Creates vector image objects */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2018-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 #include "common.h" | |
| 34 #include "output.h" | |
| 35 #include "zfiletypes.h" | |
| 36 | |
| 37 INTERNAL int ps_plot(struct zint_symbol *symbol); | |
| 38 INTERNAL int svg_plot(struct zint_symbol *symbol); | |
| 39 INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle); | |
| 40 | |
| 41 static int vector_add_rect(struct zint_symbol *symbol, const float x, const float y, const float width, | |
| 42 const float height, struct zint_vector_rect **last_rect) { | |
| 43 struct zint_vector_rect *rect; | |
| 44 | |
| 45 if (!(rect = (struct zint_vector_rect *) malloc(sizeof(struct zint_vector_rect)))) { | |
| 46 /* NOTE: clang-tidy-20 gets confused about return value of function returning a function unfortunately, | |
| 47 so put on 2 lines (see also "postal.c" `postnet_enc()` & `planet_enc()`, same issue) */ | |
| 48 errtxt(0, symbol, 691, "Insufficient memory for vector rectangle"); | |
| 49 return 0; | |
| 50 } | |
| 51 | |
| 52 rect->next = NULL; | |
| 53 rect->x = x; | |
| 54 rect->y = y; | |
| 55 rect->width = width; | |
| 56 rect->height = height; | |
| 57 rect->colour = -1; /* Default colour */ | |
| 58 | |
| 59 if (*last_rect) | |
| 60 (*last_rect)->next = rect; | |
| 61 else | |
| 62 symbol->vector->rectangles = rect; /* first rectangle */ | |
| 63 | |
| 64 *last_rect = rect; | |
| 65 | |
| 66 return 1; | |
| 67 } | |
| 68 | |
| 69 static int vector_add_hexagon(struct zint_symbol *symbol, const float x, const float y, | |
| 70 const float diameter, struct zint_vector_hexagon **last_hexagon) { | |
| 71 struct zint_vector_hexagon *hexagon; | |
| 72 | |
| 73 if (!(hexagon = (struct zint_vector_hexagon *) malloc(sizeof(struct zint_vector_hexagon)))) { | |
| 74 return errtxt(0, symbol, 692, "Insufficient memory for vector hexagon"); | |
| 75 } | |
| 76 hexagon->next = NULL; | |
| 77 hexagon->x = x; | |
| 78 hexagon->y = y; | |
| 79 hexagon->diameter = diameter; | |
| 80 hexagon->rotation = 0; | |
| 81 | |
| 82 if (*last_hexagon) | |
| 83 (*last_hexagon)->next = hexagon; | |
| 84 else | |
| 85 symbol->vector->hexagons = hexagon; /* first hexagon */ | |
| 86 | |
| 87 *last_hexagon = hexagon; | |
| 88 | |
| 89 return 1; | |
| 90 } | |
| 91 | |
| 92 static int vector_add_circle(struct zint_symbol *symbol, const float x, const float y, const float diameter, | |
| 93 const float width, const int colour, struct zint_vector_circle **last_circle) { | |
| 94 struct zint_vector_circle *circle; | |
| 95 | |
| 96 if (!(circle = (struct zint_vector_circle *) malloc(sizeof(struct zint_vector_circle)))) { | |
| 97 return errtxt(0, symbol, 693, "Insufficient memory for vector circle"); | |
| 98 } | |
| 99 circle->next = NULL; | |
| 100 circle->x = x; | |
| 101 circle->y = y; | |
| 102 circle->diameter = diameter; | |
| 103 circle->width = width; | |
| 104 circle->colour = colour; | |
| 105 | |
| 106 if (*last_circle) | |
| 107 (*last_circle)->next = circle; | |
| 108 else | |
| 109 symbol->vector->circles = circle; /* first circle */ | |
| 110 | |
| 111 *last_circle = circle; | |
| 112 | |
| 113 return 1; | |
| 114 } | |
| 115 | |
| 116 static int vector_add_string(struct zint_symbol *symbol, const unsigned char *text, const int length, | |
| 117 const float x, const float y, const float fsize, const float width, const int halign, | |
| 118 struct zint_vector_string **last_string) { | |
| 119 struct zint_vector_string *string; | |
| 120 | |
| 121 if (!(string = (struct zint_vector_string *) malloc(sizeof(struct zint_vector_string)))) { | |
| 122 return errtxt(0, symbol, 694, "Insufficient memory for vector string"); | |
| 123 } | |
| 124 string->next = NULL; | |
| 125 string->x = x; | |
| 126 string->y = y; | |
| 127 string->width = width; | |
| 128 string->fsize = fsize; | |
| 129 string->length = length == -1 ? (int) ustrlen(text) : length; | |
| 130 string->rotation = 0; | |
| 131 string->halign = halign; | |
| 132 if (!(string->text = (unsigned char *) malloc(string->length + 1))) { | |
| 133 free(string); | |
| 134 return errtxt(0, symbol, 695, "Insufficient memory for vector string text"); | |
| 135 } | |
| 136 memcpy(string->text, text, string->length); | |
| 137 string->text[string->length] = '\0'; | |
| 138 | |
| 139 if (*last_string) | |
| 140 (*last_string)->next = string; | |
| 141 else | |
| 142 symbol->vector->strings = string; /* First text portion */ | |
| 143 | |
| 144 *last_string = string; | |
| 145 | |
| 146 return 1; | |
| 147 } | |
| 148 | |
| 149 INTERNAL void vector_free(struct zint_symbol *symbol) { | |
| 150 if (symbol->vector != NULL) { | |
| 151 struct zint_vector_rect *rect; | |
| 152 struct zint_vector_hexagon *hex; | |
| 153 struct zint_vector_circle *circle; | |
| 154 struct zint_vector_string *string; | |
| 155 | |
| 156 /* Free Rectangles */ | |
| 157 rect = symbol->vector->rectangles; | |
| 158 while (rect) { | |
| 159 struct zint_vector_rect *r = rect; | |
| 160 rect = rect->next; | |
| 161 free(r); | |
| 162 } | |
| 163 | |
| 164 /* Free Hexagons */ | |
| 165 hex = symbol->vector->hexagons; | |
| 166 while (hex) { | |
| 167 struct zint_vector_hexagon *h = hex; | |
| 168 hex = hex->next; | |
| 169 free(h); | |
| 170 } | |
| 171 | |
| 172 /* Free Circles */ | |
| 173 circle = symbol->vector->circles; | |
| 174 while (circle) { | |
| 175 struct zint_vector_circle *c = circle; | |
| 176 circle = circle->next; | |
| 177 free(c); | |
| 178 } | |
| 179 | |
| 180 /* Free Strings */ | |
| 181 string = symbol->vector->strings; | |
| 182 while (string) { | |
| 183 struct zint_vector_string *s = string; | |
| 184 string = string->next; | |
| 185 free(s->text); | |
| 186 free(s); | |
| 187 } | |
| 188 | |
| 189 /* Free vector */ | |
| 190 free(symbol->vector); | |
| 191 symbol->vector = NULL; | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 static void vector_scale(struct zint_symbol *symbol, const int file_type) { | |
| 196 struct zint_vector_rect *rect; | |
| 197 struct zint_vector_hexagon *hex; | |
| 198 struct zint_vector_circle *circle; | |
| 199 struct zint_vector_string *string; | |
| 200 float scale = symbol->scale * 2.0f; | |
| 201 | |
| 202 if (scale < 0.2f) { /* Minimum vector scale 0.1 */ | |
| 203 scale = 0.2f; | |
| 204 } | |
| 205 | |
| 206 if ((file_type == OUT_EMF_FILE) && (symbol->symbology == BARCODE_MAXICODE)) { | |
| 207 /* Increase size to overcome limitations in EMF file format */ | |
| 208 scale *= 20; | |
| 209 } | |
| 210 | |
| 211 symbol->vector->width = stripf(symbol->vector->width * scale); | |
| 212 symbol->vector->height = stripf(symbol->vector->height * scale); | |
| 213 | |
| 214 rect = symbol->vector->rectangles; | |
| 215 while (rect) { | |
| 216 rect->x = stripf(rect->x * scale); | |
| 217 rect->y = stripf(rect->y * scale); | |
| 218 rect->height = stripf(rect->height * scale); | |
| 219 rect->width = stripf(rect->width * scale); | |
| 220 rect = rect->next; | |
| 221 } | |
| 222 | |
| 223 hex = symbol->vector->hexagons; | |
| 224 while (hex) { | |
| 225 hex->x = stripf(hex->x * scale); | |
| 226 hex->y = stripf(hex->y * scale); | |
| 227 hex->diameter = stripf(hex->diameter * scale); | |
| 228 hex = hex->next; | |
| 229 } | |
| 230 | |
| 231 circle = symbol->vector->circles; | |
| 232 while (circle) { | |
| 233 circle->x = stripf(circle->x * scale); | |
| 234 circle->y = stripf(circle->y * scale); | |
| 235 circle->diameter = stripf(circle->diameter * scale); | |
| 236 circle->width = stripf(circle->width * scale); | |
| 237 circle = circle->next; | |
| 238 } | |
| 239 | |
| 240 string = symbol->vector->strings; | |
| 241 while (string) { | |
| 242 string->x = stripf(string->x * scale); | |
| 243 string->y = stripf(string->y * scale); | |
| 244 string->width = stripf(string->width * scale); | |
| 245 string->fsize = stripf(string->fsize * scale); | |
| 246 string = string->next; | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 static void vector_rotate(struct zint_symbol *symbol, const int rotate_angle) { | |
| 251 /* Rotates the image */ | |
| 252 struct zint_vector_rect *rect; | |
| 253 struct zint_vector_hexagon *hex; | |
| 254 struct zint_vector_circle *circle; | |
| 255 struct zint_vector_string *string; | |
| 256 float temp; | |
| 257 | |
| 258 if (rotate_angle == 0) { | |
| 259 /* No rotation needed */ | |
| 260 return; | |
| 261 } | |
| 262 | |
| 263 rect = symbol->vector->rectangles; | |
| 264 while (rect) { | |
| 265 if (rotate_angle == 90) { | |
| 266 temp = rect->x; | |
| 267 rect->x = stripf(symbol->vector->height - (rect->y + rect->height)); | |
| 268 rect->y = temp; | |
| 269 temp = rect->width; | |
| 270 rect->width = rect->height; | |
| 271 rect->height = temp; | |
| 272 } else if (rotate_angle == 180) { | |
| 273 rect->x = stripf(symbol->vector->width - (rect->x + rect->width)); | |
| 274 rect->y = stripf(symbol->vector->height - (rect->y + rect->height)); | |
| 275 } else if (rotate_angle == 270) { | |
| 276 temp = rect->x; | |
| 277 rect->x = rect->y; | |
| 278 rect->y = stripf(symbol->vector->width - (temp + rect->width)); | |
| 279 temp = rect->width; | |
| 280 rect->width = rect->height; | |
| 281 rect->height = temp; | |
| 282 } | |
| 283 rect = rect->next; | |
| 284 } | |
| 285 | |
| 286 hex = symbol->vector->hexagons; | |
| 287 while (hex) { | |
| 288 if (rotate_angle == 90) { | |
| 289 temp = hex->x; | |
| 290 hex->x = stripf(symbol->vector->height - hex->y); | |
| 291 hex->y = temp; | |
| 292 hex->rotation = 90; | |
| 293 } else if (rotate_angle == 180) { | |
| 294 hex->x = stripf(symbol->vector->width - hex->x); | |
| 295 hex->y = stripf(symbol->vector->height - hex->y); | |
| 296 hex->rotation = 180; | |
| 297 } else if (rotate_angle == 270) { | |
| 298 temp = hex->x; | |
| 299 hex->x = hex->y; | |
| 300 hex->y = stripf(symbol->vector->width - temp); | |
| 301 hex->rotation = 270; | |
| 302 } | |
| 303 hex = hex->next; | |
| 304 } | |
| 305 | |
| 306 circle = symbol->vector->circles; | |
| 307 while (circle) { | |
| 308 if (rotate_angle == 90) { | |
| 309 temp = circle->x; | |
| 310 circle->x = stripf(symbol->vector->height - circle->y); | |
| 311 circle->y = temp; | |
| 312 } else if (rotate_angle == 180) { | |
| 313 circle->x = stripf(symbol->vector->width - circle->x); | |
| 314 circle->y = stripf(symbol->vector->height - circle->y); | |
| 315 } else if (rotate_angle == 270) { | |
| 316 temp = circle->x; | |
| 317 circle->x = circle->y; | |
| 318 circle->y = stripf(symbol->vector->width - temp); | |
| 319 } | |
| 320 circle = circle->next; | |
| 321 } | |
| 322 | |
| 323 string = symbol->vector->strings; | |
| 324 while (string) { | |
| 325 if (rotate_angle == 90) { | |
| 326 temp = string->x; | |
| 327 string->x = stripf(symbol->vector->height - string->y); | |
| 328 string->y = temp; | |
| 329 string->rotation = 90; | |
| 330 } else if (rotate_angle == 180) { | |
| 331 string->x = stripf(symbol->vector->width - string->x); | |
| 332 string->y = stripf(symbol->vector->height - string->y); | |
| 333 string->rotation = 180; | |
| 334 } else if (rotate_angle == 270) { | |
| 335 temp = string->x; | |
| 336 string->x = string->y; | |
| 337 string->y = stripf(symbol->vector->width - temp); | |
| 338 string->rotation = 270; | |
| 339 } | |
| 340 string = string->next; | |
| 341 } | |
| 342 | |
| 343 if ((rotate_angle == 90) || (rotate_angle == 270)) { | |
| 344 temp = symbol->vector->height; | |
| 345 symbol->vector->height = symbol->vector->width; | |
| 346 symbol->vector->width = temp; | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 static void vector_reduce_rectangles(struct zint_symbol *symbol) { | |
| 351 /* Looks for vertically aligned rectangles and merges them together */ | |
| 352 struct zint_vector_rect *rect, *target, *prev; | |
| 353 | |
| 354 rect = symbol->vector->rectangles; | |
| 355 while (rect) { | |
| 356 prev = rect; | |
| 357 target = prev->next; | |
| 358 | |
| 359 while (target) { | |
| 360 if ((rect->x == target->x) && (rect->width == target->width) | |
| 361 && (stripf(rect->y + rect->height) == target->y) && (rect->colour == target->colour)) { | |
| 362 rect->height += target->height; | |
| 363 prev->next = target->next; | |
| 364 free(target); | |
| 365 } else { | |
| 366 prev = target; | |
| 367 } | |
| 368 target = prev->next; | |
| 369 } | |
| 370 | |
| 371 rect = rect->next; | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { | |
| 376 int error_number; | |
| 377 int main_width; | |
| 378 int comp_xoffset = 0; | |
| 379 int comp_roffset = 0; | |
| 380 unsigned char addon[6]; | |
| 381 int addon_len = 0; | |
| 382 int addon_gap = 0; | |
| 383 float addon_text_yposn = 0.0f; | |
| 384 float xoffset, yoffset, roffset, boffset, qz_right; | |
| 385 float textoffset; | |
| 386 int upceanflag = 0; | |
| 387 int addon_latch = 0; | |
| 388 int hide_text; | |
| 389 int i, r; | |
| 390 int block_width = 0; | |
| 391 int font_height; /* Font pixel size (so whole integers) */ | |
| 392 float text_gap; /* Gap between barcode and text */ | |
| 393 float guard_descent; | |
| 394 const int upcean_guard_whitespace = !(symbol->output_options & BARCODE_NO_QUIET_ZONES) | |
| 395 && (symbol->output_options & EANUPC_GUARD_WHITESPACE); | |
| 396 const int is_codablockf = symbol->symbology == BARCODE_CODABLOCKF || symbol->symbology == BARCODE_HIBC_BLOCKF; | |
| 397 const int no_extend = is_codablockf || symbol->symbology == BARCODE_DPD; | |
| 398 | |
| 399 float large_bar_height; | |
| 400 int xoffset_comp; | |
| 401 const float descent = 1.32779717f; /* Arimo value for normal text (font height 7) */ | |
| 402 const float descent_small = 0.948426545f; /* Arimo value for SMALL_TEXT (font height 5) */ | |
| 403 | |
| 404 /* For UPC/EAN only */ | |
| 405 float addon_row_yposn = 0.0f; /* Suppress gcc -Wmaybe-uninitialized false positive */ | |
| 406 float addon_row_height = 0.0f; /* Ditto */ | |
| 407 int upcae_outside_font_height = 0; /* UPC-A/E outside digits font size */ | |
| 408 const float gws_left_fudge = 0.5f; /* These make the guard whitespaces appear closer to the edge for SVG/qzint */ | |
| 409 const float gws_right_fudge = 0.5f; /* (undone by EMF/EPS) */ | |
| 410 /* Note using "ascender" to mean height above digits as "ascent" usually measured from baseline */ | |
| 411 const float digit_ascender_factor = 0.22f; /* Assuming digit ascender height roughly 22% of font size */ | |
| 412 float digit_ascender = 0.0f; /* Avoid gcc -Wmaybe-uninitialized */ | |
| 413 const float antialias_fudge_factor = 0.02f; | |
| 414 float antialias_fudge = 0.0f; /* Avoid gcc -Wmaybe-uninitialized */ | |
| 415 int rect_count = 0, last_row_start = 0; /* For UPC/EAN guard bars */ | |
| 416 | |
| 417 float dot_overspill = 0.0f; | |
| 418 float dot_offset = 0.0f; | |
| 419 float yposn; | |
| 420 | |
| 421 struct zint_vector *vector; | |
| 422 struct zint_vector_rect *rect, *last_rect = NULL; | |
| 423 struct zint_vector_hexagon *last_hexagon = NULL; | |
| 424 struct zint_vector_string *last_string = NULL; | |
| 425 struct zint_vector_circle *last_circle = NULL; | |
| 426 struct zint_vector_rect **first_row_rects | |
| 427 = (struct zint_vector_rect **) z_alloca(sizeof(struct zint_vector_rect *) * (symbol->rows + 1)); | |
| 428 | |
| 429 memset(first_row_rects, 0, sizeof(struct zint_vector_rect *) * (symbol->rows + 1)); | |
| 430 | |
| 431 /* Free any previous rendering structures */ | |
| 432 vector_free(symbol); | |
| 433 | |
| 434 /* Sanity check colours */ | |
| 435 error_number = out_check_colour_options(symbol); | |
| 436 if (error_number != 0) { | |
| 437 return error_number; | |
| 438 } | |
| 439 if (symbol->rows <= 0) { | |
| 440 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 697, "No rows"); | |
| 441 } | |
| 442 | |
| 443 /* Allocate memory */ | |
| 444 if (!(vector = symbol->vector = (struct zint_vector *) malloc(sizeof(struct zint_vector)))) { | |
| 445 return errtxt(ZINT_ERROR_MEMORY, symbol, 696, "Insufficient memory for vector header"); | |
| 446 } | |
| 447 vector->rectangles = NULL; | |
| 448 vector->hexagons = NULL; | |
| 449 vector->circles = NULL; | |
| 450 vector->strings = NULL; | |
| 451 | |
| 452 large_bar_height = out_large_bar_height(symbol, 0 /*si (scale and round)*/, NULL /*row_heights_si*/, | |
| 453 NULL /*symbol_height_si*/); | |
| 454 | |
| 455 main_width = symbol->width; | |
| 456 | |
| 457 if (is_composite(symbol->symbology)) { | |
| 458 while (!module_is_set(symbol, symbol->rows - 1, comp_xoffset)) { | |
| 459 comp_xoffset++; | |
| 460 } | |
| 461 } | |
| 462 if (is_upcean(symbol->symbology)) { | |
| 463 upceanflag = out_process_upcean(symbol, comp_xoffset, &main_width, addon, &addon_len, &addon_gap); | |
| 464 } else if (is_composite(symbol->symbology)) { | |
| 465 int x; | |
| 466 for (x = symbol->width - 1; x && !module_is_set(symbol, symbol->rows - 1, x); comp_roffset++, x--); | |
| 467 main_width -= comp_xoffset + comp_roffset; | |
| 468 } | |
| 469 | |
| 470 hide_text = ((!symbol->show_hrt) || (ustrlen(symbol->text) == 0)); | |
| 471 | |
| 472 out_set_whitespace_offsets(symbol, hide_text, comp_xoffset, &xoffset, &yoffset, &roffset, &boffset, &qz_right, | |
| 473 0 /*scaler*/, NULL, NULL, NULL, NULL, NULL); | |
| 474 | |
| 475 xoffset_comp = xoffset + comp_xoffset; | |
| 476 | |
| 477 if ((symbol->symbology != BARCODE_MAXICODE) && (symbol->output_options & BARCODE_DOTTY_MODE)) { | |
| 478 if (symbol->dot_size < 1.0f) { | |
| 479 dot_overspill = 0.0f; | |
| 480 /* Offset (1 - dot_size) / 2 + dot_radius == (1 - dot_size + dot_size) / 2 == 1 / 2 */ | |
| 481 dot_offset = 0.5f; | |
| 482 } else { /* Allow for exceeding 1X */ | |
| 483 dot_overspill = symbol->dot_size - 1.0f + 0.1f; /* Fudge for anti-aliasing */ | |
| 484 dot_offset = symbol->dot_size / 2.0f + 0.05f; /* Fudge for anti-aliasing */ | |
| 485 } | |
| 486 } | |
| 487 | |
| 488 vector->width = symbol->width + dot_overspill + (xoffset + roffset); | |
| 489 | |
| 490 /* Note font sizes scaled by 2 so really twice these values */ | |
| 491 if (upceanflag) { | |
| 492 /* Note BOLD_TEXT ignored for UPCEAN by svg/emf/ps/qzint */ | |
| 493 font_height = symbol->output_options & SMALL_TEXT ? 7 : 10; | |
| 494 digit_ascender = font_height * digit_ascender_factor; | |
| 495 antialias_fudge = font_height * antialias_fudge_factor; | |
| 496 /* Although font size 7 (for normal) seems small it meets GS1 General Spec (GGS) Section 5.2.5: | |
| 497 "the size of the first and last digits should be reduced to a maximum width equivalent to four modules" */ | |
| 498 upcae_outside_font_height = symbol->output_options & SMALL_TEXT ? 6 : 7; | |
| 499 /* Note default now 1.0 (GGS 5.2.5 "Normally the minimum is one module") but was 0.5 (absolute minimum) */ | |
| 500 text_gap = symbol->text_gap - digit_ascender; | |
| 501 /* Guard bar height (none for EAN-2 and EAN-5) */ | |
| 502 guard_descent = upceanflag >= 6 ? symbol->guard_descent : 0.0f; | |
| 503 } else { | |
| 504 font_height = symbol->output_options & SMALL_TEXT ? 5 : 7; | |
| 505 antialias_fudge = font_height * antialias_fudge_factor; | |
| 506 text_gap = symbol->text_gap; | |
| 507 guard_descent = 0.0f; | |
| 508 } | |
| 509 | |
| 510 if (hide_text) { | |
| 511 textoffset = guard_descent; | |
| 512 } else { | |
| 513 textoffset = font_height + stripf(text_gap + antialias_fudge); | |
| 514 if (upceanflag) { | |
| 515 if (textoffset < guard_descent) { | |
| 516 textoffset = guard_descent; | |
| 517 } | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 vector->height = symbol->height + textoffset + dot_overspill + (yoffset + boffset); | |
| 522 | |
| 523 /* Plot Maxicode symbols */ | |
| 524 if (symbol->symbology == BARCODE_MAXICODE) { | |
| 525 float bull_x, bull_y, bull_d_incr, bull_width; | |
| 526 const float two_div_sqrt3 = 1.1547f; /* 2 / √3 */ | |
| 527 const float sqrt3_div_two = 0.866f; /* √3 / 2 == 1.5 / √3 */ | |
| 528 | |
| 529 /* `hex_diameter` is short diameter, X in ISO/IEC 16023:2000 Figure 8 (same as W) */ | |
| 530 const float hex_diameter = 1.0f; | |
| 531 const float hex_radius = hex_diameter / 2.0f; | |
| 532 const float hex_ydiameter = two_div_sqrt3 * hex_diameter; /* Long diameter, V in Figure 8 */ | |
| 533 const float hex_yradius = hex_ydiameter / 2.0f; | |
| 534 const float yposn_offset = sqrt3_div_two * hex_diameter; /* Vertical distance between rows, Y in Figure 8 */ | |
| 535 | |
| 536 vector->width = 30 * hex_diameter + (xoffset + roffset); | |
| 537 /* 32 rows drawn yposn_offset apart + final hexagon */ | |
| 538 vector->height = 32 * yposn_offset + hex_ydiameter + (yoffset + boffset); | |
| 539 | |
| 540 /* Bullseye (ISO/IEC 16023:2000 4.2.1.1 and 4.11.4) */ | |
| 541 bull_x = 14.5f * hex_diameter + xoffset; /* 14W right from leftmost centre = 14.5X */ | |
| 542 bull_y = vector->height / 2.0f; /* 16Y above bottom-most centre = halfway */ | |
| 543 /* Total finder diameter is 9X, so diametric increment for 5 diameters d2 to d6 is (9X - d1) / 5 */ | |
| 544 bull_d_incr = (hex_diameter * 9 - hex_ydiameter) / 5.0f; | |
| 545 bull_width = bull_d_incr / 2.0f; | |
| 546 | |
| 547 if (!vector_add_circle(symbol, bull_x, bull_y, hex_ydiameter + bull_d_incr * 5 - bull_width, bull_width, 0, | |
| 548 &last_circle)) return ZINT_ERROR_MEMORY; | |
| 549 if (!vector_add_circle(symbol, bull_x, bull_y, hex_ydiameter + bull_d_incr * 3 - bull_width, bull_width, 0, | |
| 550 &last_circle)) return ZINT_ERROR_MEMORY; | |
| 551 if (!vector_add_circle(symbol, bull_x, bull_y, hex_ydiameter + bull_d_incr - bull_width, bull_width, 0, | |
| 552 &last_circle)) return ZINT_ERROR_MEMORY; | |
| 553 | |
| 554 /* Hexagons */ | |
| 555 for (r = 0; r < symbol->rows; r++) { | |
| 556 const int odd_row = r & 1; /* Odd (reduced) row, even (full) row */ | |
| 557 const float hex_yposn = r * yposn_offset + hex_yradius + yoffset; | |
| 558 const float xposn_offset = (odd_row ? hex_diameter : hex_radius) + xoffset; | |
| 559 for (i = 0; i < symbol->width - odd_row; i++) { | |
| 560 if (module_is_set(symbol, r, i)) { | |
| 561 const float hex_xposn = i * hex_diameter + xposn_offset; | |
| 562 if (!vector_add_hexagon(symbol, hex_xposn, hex_yposn, hex_diameter, &last_hexagon)) | |
| 563 return ZINT_ERROR_MEMORY; | |
| 564 } | |
| 565 } | |
| 566 } | |
| 567 /* Dotty mode */ | |
| 568 } else if (symbol->output_options & BARCODE_DOTTY_MODE) { | |
| 569 for (r = 0; r < symbol->rows; r++) { | |
| 570 for (i = 0; i < symbol->width; i++) { | |
| 571 if (module_is_set(symbol, r, i)) { | |
| 572 if (!vector_add_circle(symbol, i + dot_offset + xoffset, r + dot_offset + yoffset, | |
| 573 symbol->dot_size, 0, 0, &last_circle)) return ZINT_ERROR_MEMORY; | |
| 574 } | |
| 575 } | |
| 576 } | |
| 577 /* Plot rectangles - most symbols created here */ | |
| 578 } else if (symbol->symbology == BARCODE_ULTRA) { | |
| 579 yposn = yoffset; | |
| 580 for (r = 0; r < symbol->rows; r++) { | |
| 581 const float row_height = symbol->row_height[r]; | |
| 582 | |
| 583 for (i = 0; i < symbol->width; i += block_width) { | |
| 584 const int fill = module_colour_is_set(symbol, r, i); | |
| 585 for (block_width = 1; (i + block_width < symbol->width) | |
| 586 && module_colour_is_set(symbol, r, i + block_width) == fill; block_width++); | |
| 587 if (fill) { | |
| 588 /* a colour block */ | |
| 589 if (!vector_add_rect(symbol, i + xoffset, yposn, block_width, row_height, &last_rect)) | |
| 590 return ZINT_ERROR_MEMORY; | |
| 591 last_rect->colour = module_colour_is_set(symbol, r, i); | |
| 592 } | |
| 593 } | |
| 594 yposn += row_height; | |
| 595 } | |
| 596 | |
| 597 } else if (upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ | |
| 598 yposn = yoffset; | |
| 599 for (r = 0; r < symbol->rows; r++) { | |
| 600 const float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; | |
| 601 last_row_start = rect_count; | |
| 602 | |
| 603 for (i = 0; i < symbol->width; i += block_width) { | |
| 604 const int fill = module_is_set(symbol, r, i); | |
| 605 for (block_width = 1; (i + block_width < symbol->width) | |
| 606 && module_is_set(symbol, r, i + block_width) == fill; block_width++); | |
| 607 | |
| 608 if ((r == (symbol->rows - 1)) && (i > main_width) && (addon_latch == 0)) { | |
| 609 addon_text_yposn = yposn + font_height - digit_ascender; | |
| 610 if (addon_text_yposn < 0.0f) { | |
| 611 addon_text_yposn = 0.0f; | |
| 612 } | |
| 613 addon_row_yposn = yposn + font_height + text_gap + antialias_fudge; | |
| 614 addon_row_height = row_height - (addon_row_yposn - yposn); | |
| 615 /* Following ISO/IEC 15420:2009 Figure 5 — UPC-A bar code symbol with 2-digit add-on (contrary to | |
| 616 GS1 General Specs v24.0 Figure 5.2.6.6-5) descends for all including UPC-A/E */ | |
| 617 addon_row_height += guard_descent; | |
| 618 if (addon_row_height < 0.5f) { | |
| 619 addon_row_height = 0.5f; | |
| 620 } | |
| 621 addon_latch = 1; | |
| 622 } | |
| 623 if (fill) { | |
| 624 /* a bar */ | |
| 625 if (addon_latch) { | |
| 626 if (!vector_add_rect(symbol, i + xoffset, addon_row_yposn, block_width, addon_row_height, | |
| 627 &last_rect)) return ZINT_ERROR_MEMORY; | |
| 628 } else { | |
| 629 if (!vector_add_rect(symbol, i + xoffset, yposn, block_width, row_height, &last_rect)) | |
| 630 return ZINT_ERROR_MEMORY; | |
| 631 } | |
| 632 rect_count++; | |
| 633 } | |
| 634 } | |
| 635 yposn += row_height; | |
| 636 } | |
| 637 | |
| 638 } else { | |
| 639 yposn = yoffset; | |
| 640 if (upceanflag && !hide_text) { /* EAN-2, EAN-5 (standalone add-ons) */ | |
| 641 yposn += font_height + text_gap + antialias_fudge; | |
| 642 } | |
| 643 for (r = 0; r < symbol->rows; r++) { | |
| 644 const float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; | |
| 645 | |
| 646 for (i = 0; i < symbol->width; i += block_width) { | |
| 647 const int fill = module_is_set(symbol, r, i); | |
| 648 for (block_width = 1; (i + block_width < symbol->width) | |
| 649 && module_is_set(symbol, r, i + block_width) == fill; block_width++); | |
| 650 if (fill) { | |
| 651 /* a bar */ | |
| 652 if (!vector_add_rect(symbol, i + xoffset, yposn, block_width, row_height, &last_rect)) | |
| 653 return ZINT_ERROR_MEMORY; | |
| 654 if (i == 0) { | |
| 655 first_row_rects[r] = last_rect; | |
| 656 } | |
| 657 } | |
| 658 } | |
| 659 yposn += row_height; | |
| 660 } | |
| 661 } | |
| 662 | |
| 663 if (guard_descent && upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ | |
| 664 /* Guard bar extension */ | |
| 665 if (upceanflag == 6) { /* UPC-E */ | |
| 666 i = 0; | |
| 667 for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { | |
| 668 switch (i - last_row_start) { | |
| 669 case 0: | |
| 670 case 1: | |
| 671 case 14: | |
| 672 case 15: | |
| 673 case 16: | |
| 674 rect->height += guard_descent; | |
| 675 break; | |
| 676 } | |
| 677 i++; | |
| 678 } | |
| 679 } else if (upceanflag == 8) { /* EAN-8 */ | |
| 680 i = 0; | |
| 681 for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { | |
| 682 switch (i - last_row_start) { | |
| 683 case 0: | |
| 684 case 1: | |
| 685 case 10: | |
| 686 case 11: | |
| 687 case 20: | |
| 688 case 21: | |
| 689 rect->height += guard_descent; | |
| 690 break; | |
| 691 } | |
| 692 i++; | |
| 693 } | |
| 694 } else if (upceanflag == 12) { /* UPC-A */ | |
| 695 i = 0; | |
| 696 for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { | |
| 697 switch (i - last_row_start) { | |
| 698 case 0: | |
| 699 case 1: | |
| 700 case 2: | |
| 701 case 3: | |
| 702 case 14: | |
| 703 case 15: | |
| 704 case 26: | |
| 705 case 27: | |
| 706 case 28: | |
| 707 case 29: | |
| 708 rect->height += guard_descent; | |
| 709 break; | |
| 710 } | |
| 711 i++; | |
| 712 } | |
| 713 } else { /* EAN-13 */ | |
| 714 i = 0; | |
| 715 for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { | |
| 716 switch (i - last_row_start) { | |
| 717 case 0: | |
| 718 case 1: | |
| 719 case 14: | |
| 720 case 15: | |
| 721 case 28: | |
| 722 case 29: | |
| 723 rect->height += guard_descent; | |
| 724 break; | |
| 725 } | |
| 726 i++; | |
| 727 } | |
| 728 } | |
| 729 } | |
| 730 | |
| 731 /* Add the text */ | |
| 732 | |
| 733 if (!hide_text) { | |
| 734 float textwidth; | |
| 735 | |
| 736 if (upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ | |
| 737 | |
| 738 float text_yposn = yoffset + symbol->height + font_height + text_gap - antialias_fudge; /* Baseline */ | |
| 739 if (symbol->border_width > 0 && (symbol->output_options & (BARCODE_BOX | BARCODE_BIND)) | |
| 740 && !(symbol->output_options & BARCODE_BIND_TOP)) { /* Trumps BARCODE_BOX & BARCODE_BIND */ | |
| 741 text_yposn += symbol->border_width; | |
| 742 } | |
| 743 | |
| 744 if (upceanflag == 6) { /* UPC-E */ | |
| 745 float text_xposn = -(5.0f - 0.35f) + xoffset_comp; | |
| 746 textwidth = 6.2f; | |
| 747 if (!vector_add_string(symbol, symbol->text, 1, text_xposn, text_yposn, upcae_outside_font_height, | |
| 748 textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 749 text_xposn = (24.0f + 0.5f) + xoffset_comp; | |
| 750 textwidth = 6.0f * 8.5f; | |
| 751 if (!vector_add_string(symbol, symbol->text + 1, 6, text_xposn, text_yposn, font_height, textwidth, | |
| 752 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 753 /* TODO: GS1 General Specs v24.0 5.2.5 Human readable interpretation says 3X but this could cause | |
| 754 digit's righthand to touch any add-on, now that they descend, so use 2X, until clarified */ | |
| 755 text_xposn = (51.0f - 0.35f) + 2.0f + xoffset_comp; | |
| 756 textwidth = 6.2f; | |
| 757 if (!vector_add_string(symbol, symbol->text + 7, 1, text_xposn, text_yposn, upcae_outside_font_height, | |
| 758 textwidth, 1 /*left align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 759 if (addon_len) { | |
| 760 text_xposn = (addon_len == 2 ? 61.0f : 75.0f) + xoffset_comp + addon_gap; | |
| 761 textwidth = addon_len * 8.5f; | |
| 762 if (!vector_add_string(symbol, addon, addon_len, text_xposn, addon_text_yposn, font_height, | |
| 763 textwidth, 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 764 if (upcean_guard_whitespace) { | |
| 765 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 766 textwidth = 8.5f; | |
| 767 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, addon_text_yposn, | |
| 768 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 769 } | |
| 770 } | |
| 771 | |
| 772 } else if (upceanflag == 8) { /* EAN-8 */ | |
| 773 float text_xposn; | |
| 774 if (upcean_guard_whitespace) { | |
| 775 text_xposn = -7.0f - gws_left_fudge + xoffset_comp; | |
| 776 textwidth = 8.5f; | |
| 777 if (!vector_add_string(symbol, (const unsigned char *) "<", 1, text_xposn, text_yposn, | |
| 778 font_height, textwidth, 1 /*left align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 779 } | |
| 780 text_xposn = (17.0f + 0.5f) + xoffset_comp; | |
| 781 textwidth = 4.0f * 8.5f; | |
| 782 if (!vector_add_string(symbol, symbol->text, 4, text_xposn, text_yposn, font_height, textwidth, | |
| 783 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 784 text_xposn = (50.0f - 0.5f) + xoffset_comp; | |
| 785 if (!vector_add_string(symbol, symbol->text + 4, 4, text_xposn, text_yposn, font_height, textwidth, | |
| 786 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 787 if (addon_len) { | |
| 788 text_xposn = (addon_len == 2 ? 77.0f : 91.0f) + xoffset_comp + addon_gap; | |
| 789 textwidth = addon_len * 8.5f; | |
| 790 if (!vector_add_string(symbol, addon, addon_len, text_xposn, addon_text_yposn, font_height, | |
| 791 textwidth, 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 792 if (upcean_guard_whitespace) { | |
| 793 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 794 textwidth = 8.5f; | |
| 795 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, addon_text_yposn, | |
| 796 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 797 } | |
| 798 } else if (upcean_guard_whitespace) { | |
| 799 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 800 textwidth = 8.5f; | |
| 801 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, text_yposn, | |
| 802 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 803 } | |
| 804 | |
| 805 } else if (upceanflag == 12) { /* UPC-A */ | |
| 806 float text_xposn = -(5.0f - 0.35f) + xoffset_comp; | |
| 807 textwidth = 6.2f; | |
| 808 if (!vector_add_string(symbol, symbol->text, 1, text_xposn, text_yposn, upcae_outside_font_height, | |
| 809 textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 810 text_xposn = 28.0f + xoffset_comp; | |
| 811 textwidth = 5.0f * 8.5f; | |
| 812 if (!vector_add_string(symbol, symbol->text + 1, 5, text_xposn, text_yposn, font_height, textwidth, | |
| 813 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 814 text_xposn = 67.0f + xoffset_comp; | |
| 815 if (!vector_add_string(symbol, symbol->text + 6, 5, text_xposn, text_yposn, font_height, textwidth, | |
| 816 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 817 /* TODO: GS1 General Specs v24.0 5.2.5 Human readable interpretation says 5X but this could cause | |
| 818 digit's righthand to touch any add-on, now that they descend, so use 4X, until clarified */ | |
| 819 text_xposn = (95.0f - 0.35f) + 4.0f + xoffset_comp; | |
| 820 textwidth = 6.2f; | |
| 821 if (!vector_add_string(symbol, symbol->text + 11, 1, text_xposn, text_yposn, | |
| 822 upcae_outside_font_height, textwidth, 1 /*left align*/, &last_string)) { | |
| 823 return ZINT_ERROR_MEMORY; | |
| 824 } | |
| 825 if (addon_len) { | |
| 826 text_xposn = (addon_len == 2 ? 105.0f : 119.0f) + xoffset_comp + addon_gap; | |
| 827 textwidth = addon_len * 8.5f; | |
| 828 if (!vector_add_string(symbol, addon, addon_len, text_xposn, addon_text_yposn, font_height, | |
| 829 textwidth, 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 830 if (upcean_guard_whitespace) { | |
| 831 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 832 textwidth = 8.5f; | |
| 833 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, addon_text_yposn, | |
| 834 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 835 } | |
| 836 } | |
| 837 | |
| 838 } else { /* EAN-13 */ | |
| 839 float text_xposn = -(5.0f - 0.1f) + xoffset_comp; | |
| 840 textwidth = 8.5f; | |
| 841 if (!vector_add_string(symbol, symbol->text, 1, text_xposn, text_yposn, font_height, textwidth, | |
| 842 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 843 text_xposn = (24.0f + 0.5f) + xoffset_comp; | |
| 844 textwidth = 6.0f * 8.5f; | |
| 845 if (!vector_add_string(symbol, symbol->text + 1, 6, text_xposn, text_yposn, font_height, textwidth, | |
| 846 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 847 text_xposn = (71.0f - 0.5f) + xoffset_comp; | |
| 848 if (!vector_add_string(symbol, symbol->text + 7, 6, text_xposn, text_yposn, font_height, textwidth, | |
| 849 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 850 if (addon_len) { | |
| 851 text_xposn = (addon_len == 2 ? 105.0f : 119.0f) + xoffset_comp + addon_gap; | |
| 852 textwidth = addon_len * 8.5f; | |
| 853 if (!vector_add_string(symbol, addon, addon_len, text_xposn, addon_text_yposn, font_height, | |
| 854 textwidth, 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 855 if (upcean_guard_whitespace) { | |
| 856 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 857 textwidth = 8.5f; | |
| 858 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, addon_text_yposn, | |
| 859 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 860 } | |
| 861 } else if (upcean_guard_whitespace) { | |
| 862 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 863 textwidth = 8.5f; | |
| 864 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, text_yposn, | |
| 865 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 866 } | |
| 867 } | |
| 868 | |
| 869 } else if (upceanflag) { /* EAN-2, EAN-5 (standalone add-ons) */ | |
| 870 /* Put at top (and centered) */ | |
| 871 float text_xposn = main_width / 2.0f + xoffset; | |
| 872 float text_yposn = yoffset + font_height - digit_ascender; | |
| 873 if (symbol->border_width > 0 | |
| 874 && (symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { | |
| 875 text_yposn -= symbol->border_width; | |
| 876 } | |
| 877 if (text_yposn < 0.0f) { | |
| 878 text_yposn = 0.0f; | |
| 879 } | |
| 880 addon_len = (int) ustrlen(symbol->text); | |
| 881 textwidth = addon_len * 8.5f; | |
| 882 if (!vector_add_string(symbol, symbol->text, addon_len, text_xposn, text_yposn, font_height, | |
| 883 textwidth, 0 /*centre align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 884 if (upcean_guard_whitespace) { | |
| 885 text_xposn = symbol->width + gws_right_fudge + qz_right + xoffset; | |
| 886 textwidth = 8.5f; | |
| 887 if (!vector_add_string(symbol, (const unsigned char *) ">", 1, text_xposn, text_yposn, | |
| 888 font_height, textwidth, 2 /*right align*/, &last_string)) return ZINT_ERROR_MEMORY; | |
| 889 } | |
| 890 | |
| 891 } else { | |
| 892 /* Put normal human readable text at the bottom (and centered) */ | |
| 893 float text_xposn = main_width / 2.0f + xoffset_comp; | |
| 894 float text_yposn = yoffset + symbol->height + font_height + text_gap; /* Calculated to bottom of text */ | |
| 895 text_yposn -= symbol->output_options & SMALL_TEXT ? descent_small : descent; | |
| 896 if (symbol->border_width > 0 && (symbol->output_options & (BARCODE_BOX | BARCODE_BIND)) | |
| 897 && !(symbol->output_options & BARCODE_BIND_TOP)) { /* Trumps BARCODE_BOX & BARCODE_BIND */ | |
| 898 text_yposn += symbol->border_width; | |
| 899 } | |
| 900 if (!vector_add_string(symbol, symbol->text, -1, text_xposn, text_yposn, font_height, symbol->width, 0, | |
| 901 &last_string)) return ZINT_ERROR_MEMORY; | |
| 902 } | |
| 903 } | |
| 904 | |
| 905 /* Separator binding for stacked barcodes */ | |
| 906 if ((symbol->output_options & BARCODE_BIND) && (symbol->rows > 1) && is_stackable(symbol->symbology)) { | |
| 907 float sep_xoffset = xoffset; | |
| 908 float sep_width = symbol->width; | |
| 909 float sep_height = 1.0f, sep_yoffset, sep_half_height; | |
| 910 if (symbol->option_3 > 0 && symbol->option_3 <= 4) { | |
| 911 sep_height = symbol->option_3; | |
| 912 } | |
| 913 sep_half_height = sep_height / 2.0f; | |
| 914 sep_yoffset = yoffset - sep_half_height; | |
| 915 if (is_codablockf) { | |
| 916 /* Avoid 11-module start and 13-module stop chars */ | |
| 917 sep_xoffset += 11; | |
| 918 sep_width -= 11 + 13; | |
| 919 } | |
| 920 /* Adjust original rectangles so don't overlap with separator(s) (important for RGBA) */ | |
| 921 for (r = 0; r < symbol->rows; r++) { | |
| 922 for (rect = first_row_rects[r], i = 0; rect && rect != first_row_rects[r + 1]; rect = rect->next, i++) { | |
| 923 if (is_codablockf) { /* Skip start and stop chars */ | |
| 924 if (i < 3) { | |
| 925 continue; | |
| 926 } | |
| 927 if ((i / 3) * 11 + 13 >= symbol->width) { /* 3 bars and 11 modules per char */ | |
| 928 break; | |
| 929 } | |
| 930 } | |
| 931 if (r != 0) { | |
| 932 rect->y += sep_height - sep_half_height; | |
| 933 rect->height -= r + 1 == symbol->rows ? sep_half_height : sep_height; | |
| 934 } else { | |
| 935 rect->height -= sep_half_height; | |
| 936 } | |
| 937 if (rect->height < 0) { | |
| 938 rect->height = 0.0f; | |
| 939 /* TODO: warn? */ | |
| 940 } | |
| 941 } | |
| 942 } | |
| 943 for (r = 1; r < symbol->rows; r++) { | |
| 944 const float row_height = symbol->row_height[r - 1] ? symbol->row_height[r - 1] : large_bar_height; | |
| 945 if (!vector_add_rect(symbol, sep_xoffset, (r * row_height) + sep_yoffset, sep_width, sep_height, | |
| 946 &last_rect)) return ZINT_ERROR_MEMORY; | |
| 947 } | |
| 948 } | |
| 949 | |
| 950 /* Bind/box */ | |
| 951 if (symbol->border_width > 0 && (symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { | |
| 952 const int horz_outside = is_fixed_ratio(symbol->symbology); | |
| 953 float ybind_top = yoffset - symbol->border_width; | |
| 954 /* Following equivalent to yoffset + symbol->height + dot_overspill except for BARCODE_MAXICODE */ | |
| 955 float ybind_bot = vector->height - textoffset - boffset; | |
| 956 if (horz_outside) { | |
| 957 ybind_top = 0; | |
| 958 ybind_bot = vector->height - symbol->border_width; | |
| 959 } else if (upceanflag == 2 || upceanflag == 5) { | |
| 960 ybind_top += textoffset; | |
| 961 ybind_bot += textoffset; | |
| 962 } | |
| 963 /* Top */ | |
| 964 if (!vector_add_rect(symbol, 0.0f, ybind_top, vector->width, symbol->border_width, &last_rect)) | |
| 965 return ZINT_ERROR_MEMORY; | |
| 966 if (!(symbol->output_options & BARCODE_BOX) && no_extend) { | |
| 967 /* CodaBlockF/DPD bind - does not extend over horizontal whitespace */ | |
| 968 last_rect->x = xoffset; | |
| 969 last_rect->width -= xoffset + roffset; | |
| 970 } | |
| 971 /* Bottom */ | |
| 972 if (!(symbol->output_options & BARCODE_BIND_TOP)) { /* Trumps BARCODE_BOX & BARCODE_BIND */ | |
| 973 if (!vector_add_rect(symbol, 0.0f, ybind_bot, vector->width, symbol->border_width, &last_rect)) | |
| 974 return ZINT_ERROR_MEMORY; | |
| 975 if (!(symbol->output_options & BARCODE_BOX) && no_extend) { | |
| 976 /* CodaBlockF/DPD bind - does not extend over horizontal whitespace */ | |
| 977 last_rect->x = xoffset; | |
| 978 last_rect->width -= xoffset + roffset; | |
| 979 } | |
| 980 } | |
| 981 if (symbol->output_options & BARCODE_BOX) { | |
| 982 const float xbox_right = vector->width - symbol->border_width; | |
| 983 float box_top = yoffset; | |
| 984 /* Following equivalent to symbol->height except for BARCODE_MAXICODE */ | |
| 985 float box_height = vector->height - textoffset - dot_overspill - yoffset - boffset; | |
| 986 if (horz_outside) { | |
| 987 box_top = symbol->border_width; | |
| 988 box_height = vector->height - symbol->border_width * 2; | |
| 989 } else if (upceanflag == 2 || upceanflag == 5) { | |
| 990 box_top += textoffset; | |
| 991 } | |
| 992 /* Left */ | |
| 993 if (!vector_add_rect(symbol, 0.0f, box_top, symbol->border_width, box_height, &last_rect)) | |
| 994 return ZINT_ERROR_MEMORY; | |
| 995 /* Right */ | |
| 996 if (!vector_add_rect(symbol, xbox_right, box_top, symbol->border_width, box_height, &last_rect)) | |
| 997 return ZINT_ERROR_MEMORY; | |
| 998 } | |
| 999 } | |
| 1000 | |
| 1001 vector_reduce_rectangles(symbol); | |
| 1002 | |
| 1003 vector_scale(symbol, file_type); | |
| 1004 | |
| 1005 if (file_type != OUT_EMF_FILE) { | |
| 1006 /* EMF does its own rotation (with mixed results in various apps) */ | |
| 1007 vector_rotate(symbol, rotate_angle); | |
| 1008 } | |
| 1009 | |
| 1010 switch (file_type) { | |
| 1011 case OUT_EPS_FILE: | |
| 1012 error_number = ps_plot(symbol); | |
| 1013 break; | |
| 1014 case OUT_SVG_FILE: | |
| 1015 error_number = svg_plot(symbol); | |
| 1016 break; | |
| 1017 case OUT_EMF_FILE: | |
| 1018 error_number = emf_plot(symbol, rotate_angle); | |
| 1019 break; | |
| 1020 /* case OUT_BUFFER: No more work needed */ | |
| 1021 } | |
| 1022 | |
| 1023 return error_number; | |
| 1024 } | |
| 1025 | |
| 1026 /* vim: set ts=4 sw=4 et : */ |
