Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/ps.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 /* ps.c - Post Script output */ | |
| 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 #include <assert.h> | |
| 34 #include <errno.h> | |
| 35 #include <math.h> | |
| 36 #include <stdio.h> | |
| 37 #include "common.h" | |
| 38 #include "filemem.h" | |
| 39 #include "output.h" | |
| 40 | |
| 41 /* Output Ultracode rectangle colour as PostScript setrgbcolor/setcmykcolor */ | |
| 42 static void ps_put_colour(const int is_rgb, const int colour, struct filemem *const fmp) { | |
| 43 const int idx = colour >= 1 && colour <= 8 ? colour - 1 : 6 /*black*/; | |
| 44 if (is_rgb) { | |
| 45 /* Use RGB colour space */ | |
| 46 static const char ps_rgbs[8][6] = { | |
| 47 "0 1 1", /* 0: Cyan (1) */ | |
| 48 "0 0 1", /* 1: Blue (2) */ | |
| 49 "1 0 1", /* 2: Magenta (3) */ | |
| 50 "1 0 0", /* 3: Red (4) */ | |
| 51 "1 1 0", /* 4: Yellow (5) */ | |
| 52 "0 1 0", /* 5: Green (6) */ | |
| 53 "0 0 0", /* 6: Black (7) */ | |
| 54 "1 1 1", /* 7: White (8) */ | |
| 55 }; | |
| 56 fm_puts(ps_rgbs[idx], fmp); | |
| 57 fm_puts(" setrgbcolor\n", fmp); | |
| 58 } else { | |
| 59 static const char ps_cmyks[8][8] = { | |
| 60 "1 0 0 0", /* 0: Cyan (1) */ | |
| 61 "1 1 0 0", /* 1: Blue (2) */ | |
| 62 "0 1 0 0", /* 2: Magenta (3) */ | |
| 63 "0 1 1 0", /* 3: Red (4) */ | |
| 64 "0 0 1 0", /* 4: Yellow (5) */ | |
| 65 "1 0 1 0", /* 5: Green (6) */ | |
| 66 "0 0 0 1", /* 6: Black (7) */ | |
| 67 "0 0 0 0", /* 7: White (8) */ | |
| 68 }; | |
| 69 fm_puts(ps_cmyks[idx], fmp); | |
| 70 fm_puts(" setcmykcolor\n", fmp); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 /* Escape special PostScript chars. Assumes valid UTF-8-encoded ISO/IEC 8859-1 */ | |
| 75 static void ps_convert(const unsigned char *string, unsigned char *ps_string) { | |
| 76 const unsigned char *s; | |
| 77 unsigned char *p = ps_string; | |
| 78 | |
| 79 for (s = string; *s; s++) { | |
| 80 switch (*s) { | |
| 81 case '(': | |
| 82 case ')': | |
| 83 case '\\': | |
| 84 *p++ = '\\'; | |
| 85 *p++ = *s; | |
| 86 break; | |
| 87 case 0xC2: | |
| 88 *p++ = *++s; /* C2 80-BF -> 80-BF */ | |
| 89 break; | |
| 90 case 0xC3: | |
| 91 *p++ = *++s + 0x40; /* C3 80-BF -> C0-FF */ | |
| 92 break; | |
| 93 default: | |
| 94 if (*s < 0x80) { /* ASCII - all other Unicode points > U+00FF ignored */ | |
| 95 *p++ = *s; | |
| 96 } | |
| 97 break; | |
| 98 | |
| 99 } | |
| 100 } | |
| 101 *p = '\0'; | |
| 102 } | |
| 103 | |
| 104 #ifdef ZINT_TEST /* Wrapper for direct testing */ | |
| 105 INTERNAL void ps_convert_test(const unsigned char *string, unsigned char *ps_string) { | |
| 106 ps_convert(string, ps_string); | |
| 107 } | |
| 108 #endif | |
| 109 | |
| 110 /* Helper to output RGB colour */ | |
| 111 static void ps_put_rgbcolor(const float red, const float green, const float blue, | |
| 112 struct filemem *const fmp) { | |
| 113 fm_putsf("", 2, red, fmp); | |
| 114 fm_putsf(" ", 2, green, fmp); | |
| 115 fm_putsf(" ", 2, blue, fmp); | |
| 116 fm_puts(" setrgbcolor\n", fmp); | |
| 117 } | |
| 118 | |
| 119 /* Helper to output CMYK colour */ | |
| 120 static void ps_put_cmykcolor(const float cyan, const float magenta, const float yellow, const float black, | |
| 121 struct filemem *const fmp) { | |
| 122 fm_putsf("", 2, cyan, fmp); | |
| 123 fm_putsf(" ", 2, magenta, fmp); | |
| 124 fm_putsf(" ", 2, yellow, fmp); | |
| 125 fm_putsf(" ", 2, black, fmp); | |
| 126 fm_puts(" setcmykcolor\n", fmp); | |
| 127 } | |
| 128 | |
| 129 /* Helper to output rectangle */ | |
| 130 static void ps_put_rect(const struct zint_symbol *symbol, const struct zint_vector_rect *rect, const int type, | |
| 131 struct filemem *const fmp) { | |
| 132 if (type == 0 || type == 1) { | |
| 133 fm_putsf("", 2, rect->height, fmp); | |
| 134 fm_putsf(" ", 2, (symbol->vector->height - rect->y) - rect->height, fmp); | |
| 135 } | |
| 136 fm_putsf(type == 0 ? " " : type == 1 ? " I " : type == 2 ? "I " : "", 2, rect->x, fmp); | |
| 137 fm_putsf(" ", 2, rect->width, fmp); | |
| 138 fm_puts(" R\n", fmp); | |
| 139 } | |
| 140 | |
| 141 /* Helper to output circle/disc */ | |
| 142 static void ps_put_circle(const struct zint_symbol *symbol, const struct zint_vector_circle *circle, | |
| 143 const float radius, const int type, struct filemem *const fmp) { | |
| 144 if (circle->width) { | |
| 145 fm_putsf("", 2, circle->x, fmp); | |
| 146 fm_putsf(" ", 2, symbol->vector->height - circle->y, fmp); | |
| 147 fm_putsf(" ", 4, radius, fmp); | |
| 148 fm_putsf(" ", 4, circle->width, fmp); | |
| 149 fm_puts(" C\n", fmp); | |
| 150 } else { | |
| 151 if (type == 0 || type == 1) { | |
| 152 fm_putsf("", 2, symbol->vector->height - circle->y, fmp); | |
| 153 fm_putsf(" ", 4, radius, fmp); | |
| 154 } | |
| 155 fm_putsf(type == 0 ? " " : type == 1 ? " I " : type == 2 ? "I " : "", 2, circle->x, fmp); | |
| 156 fm_puts(" D\n", fmp); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 /* Helper to count rectangles */ | |
| 161 static int ps_count_rectangles(const struct zint_symbol *symbol) { | |
| 162 int rectangles = 0; | |
| 163 const struct zint_vector_rect *rect; | |
| 164 | |
| 165 for (rect = symbol->vector->rectangles; rect; rect = rect->next) { | |
| 166 rectangles++; | |
| 167 } | |
| 168 | |
| 169 return rectangles; | |
| 170 } | |
| 171 | |
| 172 INTERNAL int ps_plot(struct zint_symbol *symbol) { | |
| 173 struct filemem fm; | |
| 174 struct filemem *const fmp = &fm; | |
| 175 unsigned char fgred, fggrn, fgblu, bgred, bggrn, bgblu, bgalpha; | |
| 176 int fgcyan, fgmagenta, fgyellow, fgblack, bgcyan, bgmagenta, bgyellow, bgblack; | |
| 177 float red_ink = 0.0f, green_ink = 0.0f, blue_ink = 0.0f; /* Suppress `-Wmaybe-uninitialized` */ | |
| 178 float red_paper = 0.0f, green_paper = 0.0f, blue_paper = 0.0f; | |
| 179 float cyan_ink = 0.0f, magenta_ink = 0.0f, yellow_ink = 0.0f, black_ink = 0.0f; | |
| 180 float cyan_paper = 0.0f, magenta_paper = 0.0f, yellow_paper = 0.0f, black_paper = 0.0f; | |
| 181 float previous_diameter; | |
| 182 float radius; | |
| 183 int colour_rect_flag; | |
| 184 int type_latch; | |
| 185 int draw_background = 1; | |
| 186 struct zint_vector_rect *rect; | |
| 187 struct zint_vector_hexagon *hex; | |
| 188 struct zint_vector_circle *circle; | |
| 189 struct zint_vector_string *string; | |
| 190 int i, len; | |
| 191 int ps_len = 0; | |
| 192 int iso_latin1 = 0; | |
| 193 int have_circles_with_width = 0, have_circles_without_width = 0; | |
| 194 const int upcean = is_upcean(symbol->symbology); | |
| 195 const int is_rgb = (symbol->output_options & CMYK_COLOUR) == 0; | |
| 196 | |
| 197 if (symbol->vector == NULL) { | |
| 198 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 646, "Vector header NULL"); | |
| 199 } | |
| 200 if (!fm_open(fmp, symbol, "w")) { | |
| 201 return errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 645, "Could not open EPS output file (%1$d: %2$s)", fmp->err, | |
| 202 strerror(fmp->err)); | |
| 203 } | |
| 204 | |
| 205 if (is_rgb) { | |
| 206 (void) out_colour_get_rgb(symbol->fgcolour, &fgred, &fggrn, &fgblu, NULL /*alpha*/); | |
| 207 red_ink = fgred / 255.0f; | |
| 208 green_ink = fggrn / 255.0f; | |
| 209 blue_ink = fgblu / 255.0f; | |
| 210 | |
| 211 (void) out_colour_get_rgb(symbol->bgcolour, &bgred, &bggrn, &bgblu, &bgalpha); | |
| 212 red_paper = bgred / 255.0f; | |
| 213 green_paper = bggrn / 255.0f; | |
| 214 blue_paper = bgblu / 255.0f; | |
| 215 } else { | |
| 216 (void) out_colour_get_cmyk(symbol->fgcolour, &fgcyan, &fgmagenta, &fgyellow, &fgblack, NULL /*rgb_alpha*/); | |
| 217 cyan_ink = fgcyan / 100.0f; | |
| 218 magenta_ink = fgmagenta / 100.0f; | |
| 219 yellow_ink = fgyellow / 100.0f; | |
| 220 black_ink = fgblack / 100.0f; | |
| 221 | |
| 222 (void) out_colour_get_cmyk(symbol->bgcolour, &bgcyan, &bgmagenta, &bgyellow, &bgblack, &bgalpha); | |
| 223 cyan_paper = bgcyan / 100.0f; | |
| 224 magenta_paper = bgmagenta / 100.0f; | |
| 225 yellow_paper = bgyellow / 100.0f; | |
| 226 black_paper = bgblack / 100.0f; | |
| 227 } | |
| 228 if (bgalpha == 0) { | |
| 229 draw_background = 0; | |
| 230 } | |
| 231 | |
| 232 for (i = 0, len = (int) ustrlen(symbol->text); i < len; i++) { | |
| 233 switch (symbol->text[i]) { | |
| 234 case '(': | |
| 235 case ')': | |
| 236 case '\\': | |
| 237 ps_len += 2; | |
| 238 break; | |
| 239 default: | |
| 240 if (!iso_latin1 && symbol->text[i] >= 0x80) { | |
| 241 iso_latin1 = 1; | |
| 242 } | |
| 243 ps_len++; /* Will overcount 2 byte UTF-8 chars */ | |
| 244 break; | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 /* Check for circle widths */ | |
| 249 for (circle = symbol->vector->circles; circle; circle = circle->next) { | |
| 250 if (circle->width) { | |
| 251 have_circles_with_width = 1; | |
| 252 if (have_circles_without_width) { | |
| 253 break; | |
| 254 } | |
| 255 } else { | |
| 256 have_circles_without_width = 1; | |
| 257 if (have_circles_with_width) { | |
| 258 break; | |
| 259 } | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 /* Start writing the header */ | |
| 264 fm_puts("%!PS-Adobe-3.0 EPSF-3.0\n" | |
| 265 "%%Creator: Zint ", fmp); | |
| 266 #if ZINT_VERSION_BUILD | |
| 267 fm_printf(fmp, "%d.%d.%d.%d\n", ZINT_VERSION_MAJOR, ZINT_VERSION_MINOR, ZINT_VERSION_RELEASE, ZINT_VERSION_BUILD); | |
| 268 #else | |
| 269 fm_printf(fmp, "%d.%d.%d\n", ZINT_VERSION_MAJOR, ZINT_VERSION_MINOR, ZINT_VERSION_RELEASE); | |
| 270 #endif | |
| 271 fm_puts("%%Title: Zint Generated Symbol\n" | |
| 272 "%%Pages: 0\n" | |
| 273 "%%BoundingBox: 0 0 ", fmp); | |
| 274 fm_printf(fmp, "%d %d\n", (int) ceilf(symbol->vector->width), (int) ceilf(symbol->vector->height)); | |
| 275 fm_puts("%%EndComments\n", fmp); | |
| 276 | |
| 277 /* Definitions */ | |
| 278 if (have_circles_without_width) { | |
| 279 /* Disc: y radius x D */ | |
| 280 fm_puts("/D { newpath 3 1 roll 0 360 arc fill } bind def\n", fmp); | |
| 281 } | |
| 282 if (have_circles_with_width) { | |
| 283 /* Circle (ring): x y radius width C (adapted from BWIPP renmaxicode.ps) */ | |
| 284 fm_puts("/C { newpath 4 1 roll 3 copy 0 360 arc closepath 4 -1 roll add 360 0 arcn closepath fill }" | |
| 285 " bind def\n", fmp); | |
| 286 } | |
| 287 if (symbol->vector->hexagons) { | |
| 288 /* Hexagon: radius half_radius half_sqrt3_radius x y */ | |
| 289 if (symbol->vector->hexagons->rotation == 0 || symbol->vector->hexagons->rotation == 180) { | |
| 290 fm_puts("/H { newpath moveto 2 copy exch neg exch rmoveto 2 index neg 0 exch rlineto 2 copy neg rlineto" | |
| 291 " 2 copy rlineto 3 -1 roll 0 exch rlineto exch neg exch rlineto closepath fill }" | |
| 292 " bind def\n", fmp); | |
| 293 } else { | |
| 294 fm_puts("/H { newpath moveto 2 copy neg exch neg rmoveto 2 index 0 rlineto 2 copy exch rlineto" | |
| 295 " 2 copy neg exch rlineto 3 -1 roll neg 0 rlineto neg exch neg rlineto closepath fill }" | |
| 296 " bind def\n", fmp); | |
| 297 } | |
| 298 /* Copy r hr hsr for repeat use without having to specify them subsequently */ | |
| 299 fm_puts("/J { 3 copy } bind def\n", fmp); | |
| 300 /* TODO: Save repeating x also */ | |
| 301 } | |
| 302 if (symbol->vector->rectangles || draw_background) { | |
| 303 /* Rectangle: h y x w */ | |
| 304 fm_puts("/R { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill }" | |
| 305 " bind def\n", fmp); | |
| 306 } | |
| 307 if (symbol->vector->rectangles || have_circles_without_width) { | |
| 308 /* Copy h y (rect) or y r (disc) for repeat use without having to specify them subsequently */ | |
| 309 fm_puts("/I { 2 copy } bind def\n", fmp); | |
| 310 } | |
| 311 | |
| 312 /* Now the actual representation */ | |
| 313 | |
| 314 /* Background */ | |
| 315 if (draw_background) { | |
| 316 if (is_rgb) { | |
| 317 ps_put_rgbcolor(red_paper, green_paper, blue_paper, fmp); | |
| 318 } else { | |
| 319 ps_put_cmykcolor(cyan_paper, magenta_paper, yellow_paper, black_paper, fmp); | |
| 320 } | |
| 321 | |
| 322 fm_putsf("", 2, symbol->vector->height, fmp); | |
| 323 fm_putsf(" 0 0 ", 2, symbol->vector->width, fmp); /* y x w */ | |
| 324 fm_puts(" R\n", fmp); | |
| 325 } | |
| 326 | |
| 327 if (symbol->symbology != BARCODE_ULTRA) { | |
| 328 if (is_rgb) { | |
| 329 ps_put_rgbcolor(red_ink, green_ink, blue_ink, fmp); | |
| 330 } else { | |
| 331 ps_put_cmykcolor(cyan_ink, magenta_ink, yellow_ink, black_ink, fmp); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 /* Rectangles */ | |
| 336 if (symbol->symbology == BARCODE_ULTRA) { | |
| 337 /* Group rectangles by colour */ | |
| 338 const int rect_cnt = ps_count_rectangles(symbol); | |
| 339 struct zint_vector_rect **ultra_rects | |
| 340 = (struct zint_vector_rect **) z_alloca(sizeof(struct zint_vector_rect *) * (rect_cnt ? rect_cnt : 1)); | |
| 341 int u_i = 0; | |
| 342 for (i = 0; i <= 8; i++) { | |
| 343 for (rect = symbol->vector->rectangles; rect; rect = rect->next) { | |
| 344 if ((i == 0 && rect->colour == -1) || rect->colour == i) { | |
| 345 ultra_rects[u_i++] = rect; | |
| 346 } | |
| 347 } | |
| 348 } | |
| 349 assert(u_i == ps_count_rectangles(symbol)); | |
| 350 | |
| 351 colour_rect_flag = 0; | |
| 352 type_latch = 0; | |
| 353 for (i = 0; i < u_i; i++) { | |
| 354 rect = ultra_rects[i]; | |
| 355 if (i == 0 || rect->colour != ultra_rects[i - 1]->colour) { | |
| 356 if (rect->colour == -1) { | |
| 357 if (colour_rect_flag == 0) { | |
| 358 /* Set foreground colour */ | |
| 359 if (is_rgb) { | |
| 360 ps_put_rgbcolor(red_ink, green_ink, blue_ink, fmp); | |
| 361 } else { | |
| 362 ps_put_cmykcolor(cyan_ink, magenta_ink, yellow_ink, black_ink, fmp); | |
| 363 } | |
| 364 colour_rect_flag = 1; | |
| 365 } | |
| 366 } else { | |
| 367 /* Set new colour */ | |
| 368 ps_put_colour(is_rgb, rect->colour, fmp); | |
| 369 } | |
| 370 } | |
| 371 if (i + 1 < u_i && rect->height == ultra_rects[i + 1]->height && rect->y == ultra_rects[i + 1]->y) { | |
| 372 ps_put_rect(symbol, rect, type_latch ? 2 : 1, fmp); | |
| 373 type_latch = 1; | |
| 374 } else { | |
| 375 ps_put_rect(symbol, rect, type_latch ? 3 : 0, fmp); | |
| 376 type_latch = 0; | |
| 377 } | |
| 378 } | |
| 379 } else { | |
| 380 type_latch = 0; | |
| 381 for (rect = symbol->vector->rectangles; rect; rect = rect->next) { | |
| 382 if (rect->next && rect->height == rect->next->height && rect->y == rect->next->y) { | |
| 383 ps_put_rect(symbol, rect, type_latch ? 2 : 1, fmp); | |
| 384 type_latch = 1; | |
| 385 } else { | |
| 386 ps_put_rect(symbol, rect, type_latch ? 3 : 0, fmp); | |
| 387 type_latch = 0; | |
| 388 } | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 /* Hexagons */ | |
| 393 previous_diameter = 0.0f; | |
| 394 for (hex = symbol->vector->hexagons; hex; hex = hex->next) { | |
| 395 float hy = symbol->vector->height - hex->y; | |
| 396 if (previous_diameter != hex->diameter) { | |
| 397 previous_diameter = hex->diameter; | |
| 398 fm_putsf("", 4, 0.5f * previous_diameter /*radius*/, fmp); | |
| 399 fm_putsf(" ", 4, 0.43301270189221932338f * previous_diameter /*half_sqrt3_radius*/, fmp); | |
| 400 fm_putsf(" ", 4, 0.25f * previous_diameter /*half_radius*/, fmp); | |
| 401 fm_putc('\n', fmp); | |
| 402 } | |
| 403 if (hex->next) { | |
| 404 fm_putsf("J ", 2, hex->x, fmp); | |
| 405 } else { | |
| 406 fm_putsf("", 2, hex->x, fmp); | |
| 407 } | |
| 408 fm_putsf(" ", 2, hy, fmp); | |
| 409 fm_puts(" H\n", fmp); | |
| 410 } | |
| 411 | |
| 412 /* Circles */ | |
| 413 previous_diameter = radius = 0.0f; | |
| 414 type_latch = 0; | |
| 415 for (circle = symbol->vector->circles; circle; circle = circle->next) { | |
| 416 if (previous_diameter != circle->diameter - circle->width) { | |
| 417 previous_diameter = circle->diameter - circle->width; | |
| 418 radius = 0.5f * previous_diameter; | |
| 419 } | |
| 420 if (circle->colour) { /* Legacy - no longer used */ | |
| 421 /* A 'white' circle */ | |
| 422 if (is_rgb) { | |
| 423 ps_put_rgbcolor(red_paper, green_paper, blue_paper, fmp); | |
| 424 } else { | |
| 425 ps_put_cmykcolor(cyan_paper, magenta_paper, yellow_paper, black_paper, fmp); | |
| 426 } | |
| 427 ps_put_circle(symbol, circle, radius, 0 /*type*/, fmp); | |
| 428 if (circle->next) { | |
| 429 if (is_rgb) { | |
| 430 ps_put_rgbcolor(red_ink, green_ink, blue_ink, fmp); | |
| 431 } else { | |
| 432 ps_put_cmykcolor(cyan_ink, magenta_ink, yellow_ink, black_ink, fmp); | |
| 433 } | |
| 434 } | |
| 435 } else { | |
| 436 /* A 'black' circle */ | |
| 437 if (circle->next && circle->y == circle->next->y && circle->diameter == circle->next->diameter) { | |
| 438 ps_put_circle(symbol, circle, radius, type_latch ? 2 : 1, fmp); | |
| 439 type_latch = 1; | |
| 440 } else { | |
| 441 ps_put_circle(symbol, circle, radius, type_latch ? 3 : 0, fmp); | |
| 442 type_latch = 0; | |
| 443 } | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 /* Text */ | |
| 448 | |
| 449 string = symbol->vector->strings; | |
| 450 | |
| 451 if (string) { | |
| 452 float previous_fsize = 0.0f; | |
| 453 const char *font; | |
| 454 unsigned char *ps_string = (unsigned char *) z_alloca(ps_len + 1); | |
| 455 | |
| 456 if ((symbol->output_options & BOLD_TEXT) && !upcean) { | |
| 457 font = "Helvetica-Bold"; | |
| 458 } else { | |
| 459 font = "Helvetica"; | |
| 460 } | |
| 461 if (iso_latin1) { | |
| 462 /* Change encoding to ISO 8859-1, see Postscript Language Reference Manual 2nd Edition Example 5.6 */ | |
| 463 fm_printf(fmp, "/%s findfont\n", font); | |
| 464 fm_puts("dup length dict begin\n" | |
| 465 "{1 index /FID ne {def} {pop pop} ifelse} forall\n" | |
| 466 "/Encoding ISOLatin1Encoding def\n" | |
| 467 "currentdict\n" | |
| 468 "end\n" | |
| 469 "/Helvetica-ISOLatin1 exch definefont pop\n", fmp); | |
| 470 font = "Helvetica-ISOLatin1"; | |
| 471 } | |
| 472 do { | |
| 473 ps_convert(string->text, ps_string); | |
| 474 if (string->fsize != previous_fsize) { | |
| 475 fm_printf(fmp, "/%s findfont", font); | |
| 476 /* Compensate for Helvetica being smaller than Zint's OCR-B */ | |
| 477 fm_putsf( " ", 2, upcean ? string->fsize * 1.07f : string->fsize, fmp); | |
| 478 fm_puts(" scalefont setfont\n", fmp); | |
| 479 previous_fsize = string->fsize; | |
| 480 } | |
| 481 /* Unhack the guard whitespace `gws_left_fudge`/`gws_right_fudge` hack */ | |
| 482 if (upcean && string->halign == 1 && string->text[0] == '<') { | |
| 483 const float gws_left_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale; /* 0.5 * 2 * scale */ | |
| 484 fm_putsf(" ", 2, string->x + gws_left_fudge, fmp); | |
| 485 } else if (upcean && string->halign == 2 && string->text[0] == '>') { | |
| 486 const float gws_right_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale; /* 0.5 * 2 * scale */ | |
| 487 fm_putsf(" ", 2, string->x - gws_right_fudge, fmp); | |
| 488 } else { | |
| 489 fm_putsf(" ", 2, string->x, fmp); | |
| 490 } | |
| 491 fm_putsf(" ", 2, symbol->vector->height - string->y, fmp); | |
| 492 fm_puts(" moveto\n", fmp); | |
| 493 if (string->rotation != 0) { | |
| 494 fm_puts(" gsave\n", fmp); | |
| 495 fm_printf(fmp, " %d rotate\n", 360 - string->rotation); | |
| 496 } | |
| 497 if (string->halign == 0 || string->halign == 2) { /* Need width for middle or right align */ | |
| 498 fm_printf(fmp, " (%s) stringwidth pop" /* Returns "width height" - discard "height" */ | |
| 499 " %s 0 rmoveto\n", ps_string, string->halign == 2 ? "neg" : "-2 div"); | |
| 500 } | |
| 501 fm_printf(fmp, " (%s) show\n", ps_string); | |
| 502 if (string->rotation != 0) { | |
| 503 fm_puts(" grestore\n", fmp); | |
| 504 } | |
| 505 string = string->next; | |
| 506 } while (string); | |
| 507 } | |
| 508 | |
| 509 if (fm_error(fmp)) { | |
| 510 errtxtf(0, symbol, 647, "Incomplete write of EPS output (%1$d: %2$s)", fmp->err, strerror(fmp->err)); | |
| 511 (void) fm_close(fmp, symbol); | |
| 512 return ZINT_ERROR_FILE_WRITE; | |
| 513 } | |
| 514 | |
| 515 if (!fm_close(fmp, symbol)) { | |
| 516 return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 649, "Failure on closing EPS output file (%1$d: %2$s)", | |
| 517 fmp->err, strerror(fmp->err)); | |
| 518 } | |
| 519 | |
| 520 return 0; | |
| 521 } | |
| 522 | |
| 523 /* vim: set ts=4 sw=4 et : */ |
