Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/emf.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 /* emf.c - Support for Microsoft Enhanced Metafile Format */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2016-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 /* Developed according to [MS-EMF] - v20160714, Released July 14, 2016 | |
| 34 * and [MS-WMF] - v20160714, Released July 14, 2016 */ | |
| 35 | |
| 36 #include <errno.h> | |
| 37 #include <stdio.h> | |
| 38 #include <assert.h> | |
| 39 #include <math.h> | |
| 40 #include "common.h" | |
| 41 #include "filemem.h" | |
| 42 #include "output.h" | |
| 43 #include "emf.h" | |
| 44 | |
| 45 /* Multiply truncating to 3 decimal places (avoids rounding differences on various platforms) */ | |
| 46 #define emf_mul3dpf(m, arg) stripf(roundf((m) * (arg) * 1000.0f) / 1000.0f) | |
| 47 | |
| 48 static int emf_count_rectangles(const struct zint_symbol *symbol) { | |
| 49 int rectangles = 0; | |
| 50 const struct zint_vector_rect *rect; | |
| 51 | |
| 52 rect = symbol->vector->rectangles; | |
| 53 while (rect) { | |
| 54 rectangles++; | |
| 55 rect = rect->next; | |
| 56 } | |
| 57 | |
| 58 return rectangles; | |
| 59 } | |
| 60 | |
| 61 static int emf_count_circles(const struct zint_symbol *symbol) { | |
| 62 int circles = 0; | |
| 63 const struct zint_vector_circle *circ; | |
| 64 | |
| 65 circ = symbol->vector->circles; | |
| 66 while (circ) { | |
| 67 circles++; | |
| 68 circ = circ->next; | |
| 69 } | |
| 70 | |
| 71 /* Hack for MaxiCode */ | |
| 72 return symbol->symbology == BARCODE_MAXICODE ? circles * 2 : circles; | |
| 73 } | |
| 74 | |
| 75 static int emf_count_hexagons(const struct zint_symbol *symbol) { | |
| 76 int hexagons = 0; | |
| 77 const struct zint_vector_hexagon *hex; | |
| 78 | |
| 79 hex = symbol->vector->hexagons; | |
| 80 while (hex) { | |
| 81 hexagons++; | |
| 82 hex = hex->next; | |
| 83 } | |
| 84 | |
| 85 return hexagons; | |
| 86 } | |
| 87 | |
| 88 static int emf_count_strings(const struct zint_symbol *symbol, float *fsize, float *fsize2, int *halign_left, | |
| 89 int *halign_right) { | |
| 90 int strings = 0; | |
| 91 const struct zint_vector_string *string; | |
| 92 | |
| 93 *fsize = *fsize2 = 0.0f; | |
| 94 *halign_left = *halign_right = 0; | |
| 95 | |
| 96 string = symbol->vector->strings; | |
| 97 while (string) { | |
| 98 /* Allow 2 font sizes */ | |
| 99 if (*fsize == 0.0f) { | |
| 100 *fsize = string->fsize; | |
| 101 } else if (string->fsize != *fsize && *fsize2 == 0.0f) { | |
| 102 *fsize2 = string->fsize; | |
| 103 } | |
| 104 /* Only 3 haligns possible and centre align always assumed used */ | |
| 105 if (string->halign) { /* Left or right align */ | |
| 106 if (string->halign == 1) { /* Left align */ | |
| 107 *halign_left = string->halign; | |
| 108 } else { /* Right align */ | |
| 109 *halign_right = string->halign; | |
| 110 } | |
| 111 } | |
| 112 strings++; | |
| 113 string = string->next; | |
| 114 } | |
| 115 | |
| 116 return strings; | |
| 117 } | |
| 118 | |
| 119 /* Convert UTF-8 to UTF-16LE - only needs to handle characters <= U+00FF */ | |
| 120 static void emf_utfle_copy(unsigned char *output, const unsigned char *input, const int length) { | |
| 121 int i; | |
| 122 int o; | |
| 123 | |
| 124 i = 0; | |
| 125 o = 0; | |
| 126 do { | |
| 127 if (input[i] <= 0x7f) { | |
| 128 /* 1 byte mode (7-bit ASCII) */ | |
| 129 output[o] = input[i]; | |
| 130 output[o + 1] = 0x00; | |
| 131 o += 2; | |
| 132 i++; | |
| 133 } else { | |
| 134 /* 2 byte mode */ | |
| 135 output[o] = ((input[i] & 0x1f) << 6) + (input[i + 1] & 0x3f); | |
| 136 output[o + 1] = 0x00; | |
| 137 o += 2; | |
| 138 i += 2; | |
| 139 } | |
| 140 } while (i < length); | |
| 141 } | |
| 142 | |
| 143 /* Strings length must be a multiple of 4 bytes */ | |
| 144 static int emf_bump_up(const int input) { | |
| 145 return (input + (input & 1)) << 1; | |
| 146 } | |
| 147 | |
| 148 static int emf_utfle_length(const unsigned char *input, const int length) { | |
| 149 int result = 0; | |
| 150 int i; | |
| 151 | |
| 152 for (i = 0; i < length; i++) { | |
| 153 result++; | |
| 154 if (input[i] >= 0x80) { /* 2 byte UTF-8 counts as one UTF-16LE character */ | |
| 155 i++; | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 return result; | |
| 160 } | |
| 161 | |
| 162 INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle) { | |
| 163 int i; | |
| 164 struct filemem fm; | |
| 165 struct filemem *const fmp = &fm; | |
| 166 unsigned char fgred, fggrn, fgblu, bgred, bggrn, bgblu, bgalpha; | |
| 167 int error_number = 0; | |
| 168 int rectangle_count, this_rectangle; | |
| 169 int circle_count, this_circle; | |
| 170 int hexagon_count, this_hexagon; | |
| 171 int string_count, this_text; | |
| 172 int bytecount, recordcount; | |
| 173 float previous_diameter; | |
| 174 float radius, half_radius, half_sqrt3_radius; | |
| 175 int colours_used = 0; | |
| 176 int rectangle_bycolour[9] = {0}; | |
| 177 | |
| 178 int width, height; | |
| 179 int bounds_pxx, bounds_pxy; /* Pixels */ | |
| 180 int frame_cmmx, frame_cmmy; /* Hundredths of a mm, i.e. "centi-millimeters" */ | |
| 181 int device_pxx, device_pxy; /* Pixels */ | |
| 182 int mmx, mmy; /* Millimeters */ | |
| 183 int micronx, microny; /* Micrometers */ | |
| 184 const float dpmm = symbol->dpmm ? stripf(symbol->dpmm) | |
| 185 : ZBarcode_XdimDp_From_Scale(symbol->symbology, symbol->scale, | |
| 186 ZBarcode_Default_Xdim(symbol->symbology), "EMF"); | |
| 187 const int sideways = rotate_angle == 90 || rotate_angle == 270; | |
| 188 | |
| 189 int draw_background = 1; | |
| 190 int bold; | |
| 191 const int upcean = is_upcean(symbol->symbology); | |
| 192 | |
| 193 struct zint_vector_rect *rect; | |
| 194 struct zint_vector_circle *circ; | |
| 195 struct zint_vector_hexagon *hex; | |
| 196 struct zint_vector_string *string; | |
| 197 | |
| 198 /* Allow for up to 6 strings (current max 3 for UPC/EAN) */ | |
| 199 unsigned char *this_string[6]; | |
| 200 emr_exttextoutw_t text[6]; | |
| 201 float text_fsizes[6]; | |
| 202 int text_haligns[6]; | |
| 203 int text_bumped_lens[6]; | |
| 204 | |
| 205 emr_header_t emr_header; | |
| 206 emr_eof_t emr_eof; | |
| 207 emr_mapmode_t emr_mapmode; | |
| 208 emr_setworldtransform_t emr_setworldtransform; | |
| 209 emr_createbrushindirect_t emr_createbrushindirect_fg; | |
| 210 emr_createbrushindirect_t emr_createbrushindirect_bg; | |
| 211 emr_createbrushindirect_t emr_createbrushindirect_colour[9]; /* Used for colour symbols only */ | |
| 212 emr_selectobject_t emr_selectobject_fgbrush; | |
| 213 emr_selectobject_t emr_selectobject_bgbrush; | |
| 214 emr_selectobject_t emr_selectobject_colour[9]; /* Used for colour symbols only */ | |
| 215 emr_createpen_t emr_createpen; | |
| 216 emr_selectobject_t emr_selectobject_pen; | |
| 217 emr_rectangle_t background; | |
| 218 emr_settextcolor_t emr_settextcolor; | |
| 219 | |
| 220 float fsize; | |
| 221 emr_extcreatefontindirectw_t emr_extcreatefontindirectw; | |
| 222 emr_selectobject_t emr_selectobject_font; | |
| 223 float fsize2; | |
| 224 emr_extcreatefontindirectw_t emr_extcreatefontindirectw2; | |
| 225 emr_selectobject_t emr_selectobject_font2; | |
| 226 emr_settextalign_t emr_settextalign_centre; /* Centre align */ | |
| 227 int halign_left; /* Set if left halign used */ | |
| 228 emr_settextalign_t emr_settextalign_left; | |
| 229 int halign_right; /* Set if right halign used */ | |
| 230 emr_settextalign_t emr_settextalign_right; | |
| 231 | |
| 232 float current_fsize; | |
| 233 int current_halign; | |
| 234 | |
| 235 emr_rectangle_t *rectangle; | |
| 236 emr_ellipse_t *circle; | |
| 237 emr_polygon_t *hexagon; | |
| 238 | |
| 239 const int ih_ultra_offset = symbol->symbology == BARCODE_ULTRA ? 8 : 0; | |
| 240 | |
| 241 if (symbol->vector == NULL) { | |
| 242 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 643, "Vector header NULL"); | |
| 243 } | |
| 244 | |
| 245 (void) out_colour_get_rgb(symbol->fgcolour, &fgred, &fggrn, &fgblu, NULL /*alpha*/); | |
| 246 (void) out_colour_get_rgb(symbol->bgcolour, &bgred, &bggrn, &bgblu, &bgalpha); | |
| 247 if (bgalpha == 0) { | |
| 248 draw_background = 0; | |
| 249 } | |
| 250 | |
| 251 rectangle_count = emf_count_rectangles(symbol); | |
| 252 circle_count = emf_count_circles(symbol); | |
| 253 hexagon_count = emf_count_hexagons(symbol); | |
| 254 string_count = emf_count_strings(symbol, &fsize, &fsize2, &halign_left, &halign_right); | |
| 255 | |
| 256 /* Avoid sanitize runtime error by making always non-zero */ | |
| 257 rectangle = (emr_rectangle_t *) z_alloca(sizeof(emr_rectangle_t) * (rectangle_count ? rectangle_count : 1)); | |
| 258 circle = (emr_ellipse_t *) z_alloca(sizeof(emr_ellipse_t) * (circle_count ? circle_count : 1)); | |
| 259 hexagon = (emr_polygon_t *) z_alloca(sizeof(emr_polygon_t) * (hexagon_count ? hexagon_count : 1)); | |
| 260 | |
| 261 /* Calculate how many coloured rectangles */ | |
| 262 if (symbol->symbology == BARCODE_ULTRA) { | |
| 263 | |
| 264 rect = symbol->vector->rectangles; | |
| 265 while (rect) { | |
| 266 if (rect->colour == -1) { /* Foreground colour */ | |
| 267 if (rectangle_bycolour[0] == 0) { | |
| 268 colours_used++; | |
| 269 rectangle_bycolour[0] = 1; | |
| 270 } | |
| 271 } else { | |
| 272 if (rectangle_bycolour[rect->colour] == 0) { | |
| 273 colours_used++; | |
| 274 rectangle_bycolour[rect->colour] = 1; | |
| 275 } | |
| 276 } | |
| 277 rect = rect->next; | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 width = (int) ceilf(symbol->vector->width); | |
| 282 height = (int) ceilf(symbol->vector->height); | |
| 283 | |
| 284 bounds_pxx = width - 1; /* Following Inkscape, bounds "inclusive-inclusive", so size 1 less */ | |
| 285 bounds_pxy = height - 1; | |
| 286 device_pxx = width; /* device */ | |
| 287 device_pxy = height; | |
| 288 | |
| 289 if (dpmm) { | |
| 290 frame_cmmx = (int) roundf(stripf(width * 100.0f / dpmm)) - 1; /* frame also "inclusive-inclusive" */ | |
| 291 frame_cmmy = (int) roundf(stripf(height * 100.0f / dpmm)) - 1; | |
| 292 mmx = (int) roundf(stripf(width / dpmm)); /* millimeters */ | |
| 293 mmy = (int) roundf(stripf(height / dpmm)); | |
| 294 micronx = (int) roundf(stripf(width * 1000.0f / dpmm)); /* micrometers */ | |
| 295 microny = (int) roundf(stripf(height * 1000.0f / dpmm)); | |
| 296 } else { /* Should only happen if `symbol->scale` zero. */ | |
| 297 frame_cmmx = (int) roundf(stripf(width * 100.0f)) - 1; | |
| 298 frame_cmmy = (int) roundf(stripf(height * 100.0f)) - 1; | |
| 299 mmx = (int) roundf(stripf(width)); | |
| 300 mmy = (int) roundf(stripf(height)); | |
| 301 micronx = (int) roundf(stripf(width * 1000.0f)); | |
| 302 microny = (int) roundf(stripf(height * 1000.0f)); | |
| 303 } | |
| 304 | |
| 305 /* Header */ | |
| 306 out_le_u32(emr_header.type, 0x00000001); /* EMR_HEADER */ | |
| 307 out_le_u32(emr_header.size, 108); /* Including extensions */ | |
| 308 out_le_i32(emr_header.emf_header.bounds.left, 0); | |
| 309 out_le_i32(emr_header.emf_header.bounds.top, 0); | |
| 310 out_le_i32(emr_header.emf_header.bounds.right, sideways ? bounds_pxy : bounds_pxx); | |
| 311 out_le_i32(emr_header.emf_header.bounds.bottom, sideways ? bounds_pxx : bounds_pxy); | |
| 312 out_le_i32(emr_header.emf_header.frame.left, 0); | |
| 313 out_le_i32(emr_header.emf_header.frame.top, 0); | |
| 314 out_le_i32(emr_header.emf_header.frame.right, sideways ? frame_cmmy : frame_cmmx); | |
| 315 out_le_i32(emr_header.emf_header.frame.bottom, sideways ? frame_cmmx : frame_cmmy); | |
| 316 out_le_u32(emr_header.emf_header.record_signature, 0x464d4520); /* ENHMETA_SIGNATURE */ | |
| 317 out_le_u32(emr_header.emf_header.version, 0x00010000); | |
| 318 out_le_u16(emr_header.emf_header.handles, (fsize2 != 0.0f ? 5 : 4) + ih_ultra_offset); /* No. of graphics objs */ | |
| 319 out_le_u16(emr_header.emf_header.reserved, 0x0000); | |
| 320 out_le_u32(emr_header.emf_header.n_description, 0); | |
| 321 out_le_u32(emr_header.emf_header.off_description, 0); | |
| 322 out_le_u32(emr_header.emf_header.n_pal_entries, 0); | |
| 323 out_le_u32(emr_header.emf_header.device.cx, sideways ? device_pxy : device_pxx); | |
| 324 out_le_u32(emr_header.emf_header.device.cy, sideways ? device_pxx : device_pxy); | |
| 325 out_le_u32(emr_header.emf_header.millimeters.cx, sideways ? mmy : mmx); | |
| 326 out_le_u32(emr_header.emf_header.millimeters.cy, sideways ? mmx : mmy); | |
| 327 /* HeaderExtension1 */ | |
| 328 out_le_u32(emr_header.emf_header.cb_pixel_format, 0x0000); /* None set */ | |
| 329 out_le_u32(emr_header.emf_header.off_pixel_format, 0x0000); /* None set */ | |
| 330 out_le_u32(emr_header.emf_header.b_open_gl, 0x0000); /* OpenGL not present */ | |
| 331 /* HeaderExtension2 */ | |
| 332 out_le_u32(emr_header.emf_header.micrometers.cx, sideways ? microny : micronx); | |
| 333 out_le_u32(emr_header.emf_header.micrometers.cy, sideways ? micronx : microny); | |
| 334 bytecount = 108; | |
| 335 recordcount = 1; | |
| 336 | |
| 337 out_le_u32(emr_mapmode.type, 0x00000011); /* EMR_SETMAPMODE */ | |
| 338 out_le_u32(emr_mapmode.size, 12); | |
| 339 out_le_u32(emr_mapmode.mapmode, 0x01); /* MM_TEXT */ | |
| 340 bytecount += 12; | |
| 341 recordcount++; | |
| 342 | |
| 343 if (rotate_angle) { | |
| 344 out_le_u32(emr_setworldtransform.type, 0x00000023); /* EMR_SETWORLDTRANSFORM */ | |
| 345 out_le_u32(emr_setworldtransform.size, 32); | |
| 346 out_le_float(emr_setworldtransform.m11, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? -1.0f : 0.0f); | |
| 347 out_le_float(emr_setworldtransform.m12, rotate_angle == 90 ? 1.0f : rotate_angle == 180 ? 0.0f : -1.0f); | |
| 348 out_le_float(emr_setworldtransform.m21, rotate_angle == 90 ? -1.0f : rotate_angle == 180 ? 0.0f : 1.0f); | |
| 349 out_le_float(emr_setworldtransform.m22, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? -1.0f : 0.0f); | |
| 350 out_le_float(emr_setworldtransform.dx, rotate_angle == 90 ? height : rotate_angle == 180 ? width : 0.0f); | |
| 351 out_le_float(emr_setworldtransform.dy, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? height : width); | |
| 352 bytecount += 32; | |
| 353 recordcount++; | |
| 354 } | |
| 355 | |
| 356 /* Create Brushes */ | |
| 357 out_le_u32(emr_createbrushindirect_bg.type, 0x00000027); /* EMR_CREATEBRUSHINDIRECT */ | |
| 358 out_le_u32(emr_createbrushindirect_bg.size, 24); | |
| 359 out_le_u32(emr_createbrushindirect_bg.ih_brush, 0); | |
| 360 out_le_u32(emr_createbrushindirect_bg.log_brush.brush_style, 0x0000); /* BS_SOLID */ | |
| 361 emr_createbrushindirect_bg.log_brush.color.red = bgred; | |
| 362 emr_createbrushindirect_bg.log_brush.color.green = bggrn; | |
| 363 emr_createbrushindirect_bg.log_brush.color.blue = bgblu; | |
| 364 emr_createbrushindirect_bg.log_brush.color.reserved = 0; | |
| 365 out_le_u32(emr_createbrushindirect_bg.log_brush.brush_hatch, 0x0006); /* HS_SOLIDCLR */ | |
| 366 bytecount += 24; | |
| 367 recordcount++; | |
| 368 | |
| 369 if (symbol->symbology == BARCODE_ULTRA) { | |
| 370 static const char ultra_chars[] = { '0', 'C', 'B', 'M', 'R', 'Y', 'G', 'K', 'W' }; | |
| 371 for (i = 0; i < 9; i++) { | |
| 372 out_le_u32(emr_createbrushindirect_colour[i].type, 0x00000027); /* EMR_CREATEBRUSHINDIRECT */ | |
| 373 out_le_u32(emr_createbrushindirect_colour[i].size, 24); | |
| 374 out_le_u32(emr_createbrushindirect_colour[i].ih_brush, 1 + i); | |
| 375 out_le_u32(emr_createbrushindirect_colour[i].log_brush.brush_style, 0x0000); /* BS_SOLID */ | |
| 376 if (i == 0) { | |
| 377 emr_createbrushindirect_colour[i].log_brush.color.red = fgred; | |
| 378 emr_createbrushindirect_colour[i].log_brush.color.green = fggrn; | |
| 379 emr_createbrushindirect_colour[i].log_brush.color.blue = fgblu; | |
| 380 } else { | |
| 381 out_colour_char_to_rgb(ultra_chars[i], | |
| 382 &emr_createbrushindirect_colour[i].log_brush.color.red, | |
| 383 &emr_createbrushindirect_colour[i].log_brush.color.green, | |
| 384 &emr_createbrushindirect_colour[i].log_brush.color.blue); | |
| 385 } | |
| 386 emr_createbrushindirect_colour[i].log_brush.color.reserved = 0; | |
| 387 out_le_u32(emr_createbrushindirect_colour[i].log_brush.brush_hatch, 0x0006); /* HS_SOLIDCLR */ | |
| 388 } | |
| 389 bytecount += colours_used * 24; | |
| 390 recordcount += colours_used; | |
| 391 } else { | |
| 392 out_le_u32(emr_createbrushindirect_fg.type, 0x00000027); /* EMR_CREATEBRUSHINDIRECT */ | |
| 393 out_le_u32(emr_createbrushindirect_fg.size, 24); | |
| 394 out_le_u32(emr_createbrushindirect_fg.ih_brush, 1); | |
| 395 out_le_u32(emr_createbrushindirect_fg.log_brush.brush_style, 0x0000); /* BS_SOLID */ | |
| 396 emr_createbrushindirect_fg.log_brush.color.red = fgred; | |
| 397 emr_createbrushindirect_fg.log_brush.color.green = fggrn; | |
| 398 emr_createbrushindirect_fg.log_brush.color.blue = fgblu; | |
| 399 emr_createbrushindirect_fg.log_brush.color.reserved = 0; | |
| 400 out_le_u32(emr_createbrushindirect_fg.log_brush.brush_hatch, 0x0006); /* HS_SOLIDCLR */ | |
| 401 bytecount += 24; | |
| 402 recordcount++; | |
| 403 } | |
| 404 | |
| 405 out_le_u32(emr_selectobject_bgbrush.type, 0x00000025); /* EMR_SELECTOBJECT */ | |
| 406 out_le_u32(emr_selectobject_bgbrush.size, 12); | |
| 407 emr_selectobject_bgbrush.ih_object = emr_createbrushindirect_bg.ih_brush; | |
| 408 bytecount += 12; | |
| 409 recordcount++; | |
| 410 | |
| 411 if (symbol->symbology == BARCODE_ULTRA) { | |
| 412 for (i = 0; i < 9; i++) { | |
| 413 out_le_u32(emr_selectobject_colour[i].type, 0x00000025); /* EMR_SELECTOBJECT */ | |
| 414 out_le_u32(emr_selectobject_colour[i].size, 12); | |
| 415 emr_selectobject_colour[i].ih_object = emr_createbrushindirect_colour[i].ih_brush; | |
| 416 } | |
| 417 bytecount += colours_used * 12; | |
| 418 recordcount += colours_used; | |
| 419 } else { | |
| 420 out_le_u32(emr_selectobject_fgbrush.type, 0x00000025); /* EMR_SELECTOBJECT */ | |
| 421 out_le_u32(emr_selectobject_fgbrush.size, 12); | |
| 422 emr_selectobject_fgbrush.ih_object = emr_createbrushindirect_fg.ih_brush; | |
| 423 bytecount += 12; | |
| 424 recordcount++; | |
| 425 } | |
| 426 | |
| 427 /* Create Pens */ | |
| 428 out_le_u32(emr_createpen.type, 0x00000026); /* EMR_CREATEPEN */ | |
| 429 out_le_u32(emr_createpen.size, 28); | |
| 430 out_le_u32(emr_createpen.ih_pen, 2 + ih_ultra_offset); | |
| 431 out_le_u32(emr_createpen.log_pen.pen_style, 0x00000005); /* PS_NULL */ | |
| 432 out_le_i32(emr_createpen.log_pen.width.x, 1); | |
| 433 out_le_i32(emr_createpen.log_pen.width.y, 0); /* ignored */ | |
| 434 emr_createpen.log_pen.color_ref.red = 0; | |
| 435 emr_createpen.log_pen.color_ref.green = 0; | |
| 436 emr_createpen.log_pen.color_ref.blue = 0; | |
| 437 emr_createpen.log_pen.color_ref.reserved = 0; | |
| 438 bytecount += 28; | |
| 439 recordcount++; | |
| 440 | |
| 441 out_le_u32(emr_selectobject_pen.type, 0x00000025); /* EMR_SELECTOBJECT */ | |
| 442 out_le_u32(emr_selectobject_pen.size, 12); | |
| 443 emr_selectobject_pen.ih_object = emr_createpen.ih_pen; | |
| 444 bytecount += 12; | |
| 445 recordcount++; | |
| 446 | |
| 447 if (draw_background) { | |
| 448 /* Make background from a rectangle */ | |
| 449 out_le_u32(background.type, 0x0000002b); /* EMR_RECTANGLE */ | |
| 450 out_le_u32(background.size, 24); | |
| 451 out_le_i32(background.box.top, 0); | |
| 452 out_le_i32(background.box.left, 0); | |
| 453 out_le_i32(background.box.right, width); | |
| 454 out_le_i32(background.box.bottom, height); | |
| 455 bytecount += 24; | |
| 456 recordcount++; | |
| 457 } | |
| 458 | |
| 459 /* Rectangles */ | |
| 460 rect = symbol->vector->rectangles; | |
| 461 this_rectangle = 0; | |
| 462 while (rect) { | |
| 463 out_le_u32(rectangle[this_rectangle].type, 0x0000002b); /* EMR_RECTANGLE */ | |
| 464 out_le_u32(rectangle[this_rectangle].size, 24); | |
| 465 out_le_i32(rectangle[this_rectangle].box.top, rect->y); | |
| 466 out_le_i32(rectangle[this_rectangle].box.bottom, stripf(rect->y + rect->height)); | |
| 467 out_le_i32(rectangle[this_rectangle].box.left, rect->x); | |
| 468 out_le_i32(rectangle[this_rectangle].box.right, stripf(rect->x + rect->width)); | |
| 469 this_rectangle++; | |
| 470 bytecount += 24; | |
| 471 recordcount++; | |
| 472 rect = rect->next; | |
| 473 } | |
| 474 | |
| 475 /* Circles */ | |
| 476 previous_diameter = radius = 0.0f; | |
| 477 circ = symbol->vector->circles; | |
| 478 this_circle = 0; | |
| 479 while (circ) { | |
| 480 /* Note using circle width the proper way, with a non-null pen of specified width and a null brush for fill, | |
| 481 causes various different rendering issues for LibreOffice Draw and Inkscape, so using following hack */ | |
| 482 if (previous_diameter != circ->diameter + circ->width) { /* Drawing MaxiCode bullseye using overlayed discs */ | |
| 483 previous_diameter = circ->diameter + circ->width; | |
| 484 radius = emf_mul3dpf(0.5f, previous_diameter); | |
| 485 } | |
| 486 out_le_u32(circle[this_circle].type, 0x0000002a); /* EMR_ELLIPSE */ | |
| 487 out_le_u32(circle[this_circle].size, 24); | |
| 488 out_le_i32(circle[this_circle].box.top, stripf(circ->y - radius)); | |
| 489 out_le_i32(circle[this_circle].box.bottom, stripf(circ->y + radius)); | |
| 490 out_le_i32(circle[this_circle].box.left, stripf(circ->x - radius)); | |
| 491 out_le_i32(circle[this_circle].box.right, stripf(circ->x + radius)); | |
| 492 this_circle++; | |
| 493 bytecount += 24; | |
| 494 recordcount++; | |
| 495 | |
| 496 if (symbol->symbology == BARCODE_MAXICODE) { /* Drawing MaxiCode bullseye using overlayed discs */ | |
| 497 float inner_radius = radius - circ->width; | |
| 498 out_le_u32(circle[this_circle].type, 0x0000002a); /* EMR_ELLIPSE */ | |
| 499 out_le_u32(circle[this_circle].size, 24); | |
| 500 out_le_i32(circle[this_circle].box.top, stripf(circ->y - inner_radius)); | |
| 501 out_le_i32(circle[this_circle].box.bottom, stripf(circ->y + inner_radius)); | |
| 502 out_le_i32(circle[this_circle].box.left, stripf(circ->x - inner_radius)); | |
| 503 out_le_i32(circle[this_circle].box.right, stripf(circ->x + inner_radius)); | |
| 504 this_circle++; | |
| 505 bytecount += 24; | |
| 506 recordcount++; | |
| 507 } | |
| 508 | |
| 509 circ = circ->next; | |
| 510 } | |
| 511 | |
| 512 /* Hexagons */ | |
| 513 previous_diameter = radius = half_radius = half_sqrt3_radius = 0.0f; | |
| 514 hex = symbol->vector->hexagons; | |
| 515 this_hexagon = 0; | |
| 516 while (hex) { | |
| 517 out_le_u32(hexagon[this_hexagon].type, 0x00000003); /* EMR_POLYGON */ | |
| 518 out_le_u32(hexagon[this_hexagon].size, 76); | |
| 519 out_le_u32(hexagon[this_hexagon].count, 6); | |
| 520 | |
| 521 if (previous_diameter != hex->diameter) { | |
| 522 previous_diameter = hex->diameter; | |
| 523 radius = emf_mul3dpf(0.5f, previous_diameter); | |
| 524 half_radius = emf_mul3dpf(0.25f, previous_diameter); | |
| 525 half_sqrt3_radius = emf_mul3dpf(0.43301270189221932338f, previous_diameter); | |
| 526 } | |
| 527 | |
| 528 /* Note rotation done via world transform */ | |
| 529 out_le_i32(hexagon[this_hexagon].a_points_a.x, hex->x); | |
| 530 out_le_i32(hexagon[this_hexagon].a_points_a.y, stripf(hex->y + radius)); | |
| 531 out_le_i32(hexagon[this_hexagon].a_points_b.x, stripf(hex->x + half_sqrt3_radius)); | |
| 532 out_le_i32(hexagon[this_hexagon].a_points_b.y, stripf(hex->y + half_radius)); | |
| 533 out_le_i32(hexagon[this_hexagon].a_points_c.x, stripf(hex->x + half_sqrt3_radius)); | |
| 534 out_le_i32(hexagon[this_hexagon].a_points_c.y, stripf(hex->y - half_radius)); | |
| 535 out_le_i32(hexagon[this_hexagon].a_points_d.x, hex->x); | |
| 536 out_le_i32(hexagon[this_hexagon].a_points_d.y, stripf(hex->y - radius)); | |
| 537 out_le_i32(hexagon[this_hexagon].a_points_e.x, stripf(hex->x - half_sqrt3_radius)); | |
| 538 out_le_i32(hexagon[this_hexagon].a_points_e.y, stripf(hex->y - half_radius)); | |
| 539 out_le_i32(hexagon[this_hexagon].a_points_f.x, stripf(hex->x - half_sqrt3_radius)); | |
| 540 out_le_i32(hexagon[this_hexagon].a_points_f.y, stripf(hex->y + half_radius)); | |
| 541 | |
| 542 hexagon[this_hexagon].bounds.top = hexagon[this_hexagon].a_points_d.y; | |
| 543 hexagon[this_hexagon].bounds.bottom = hexagon[this_hexagon].a_points_a.y; | |
| 544 hexagon[this_hexagon].bounds.left = hexagon[this_hexagon].a_points_e.x; | |
| 545 hexagon[this_hexagon].bounds.right = hexagon[this_hexagon].a_points_c.x; | |
| 546 this_hexagon++; | |
| 547 bytecount += 76; | |
| 548 recordcount++; | |
| 549 hex = hex->next; | |
| 550 } | |
| 551 | |
| 552 /* Create font records, alignment records and text color */ | |
| 553 if (symbol->vector->strings) { | |
| 554 bold = (symbol->output_options & BOLD_TEXT) && !is_upcean(symbol->symbology); | |
| 555 memset(&emr_extcreatefontindirectw, 0, sizeof(emr_extcreatefontindirectw)); | |
| 556 out_le_u32(emr_extcreatefontindirectw.type, 0x00000052); /* EMR_EXTCREATEFONTINDIRECTW */ | |
| 557 out_le_u32(emr_extcreatefontindirectw.size, 104); | |
| 558 out_le_u32(emr_extcreatefontindirectw.ih_fonts, 3 + ih_ultra_offset); | |
| 559 out_le_i32(emr_extcreatefontindirectw.elw.height, fsize); | |
| 560 out_le_i32(emr_extcreatefontindirectw.elw.width, 0); /* automatic */ | |
| 561 out_le_i32(emr_extcreatefontindirectw.elw.weight, bold ? 700 : 400); | |
| 562 emr_extcreatefontindirectw.elw.char_set = 0x00; /* ANSI_CHARSET */ | |
| 563 emr_extcreatefontindirectw.elw.out_precision = 0x00; /* OUT_DEFAULT_PRECIS */ | |
| 564 emr_extcreatefontindirectw.elw.clip_precision = 0x00; /* CLIP_DEFAULT_PRECIS */ | |
| 565 emr_extcreatefontindirectw.elw.pitch_and_family = 0x02 | (0x02 << 6); /* FF_SWISS | VARIABLE_PITCH */ | |
| 566 emf_utfle_copy(emr_extcreatefontindirectw.elw.facename, (const unsigned char *) "sans-serif", 10); | |
| 567 bytecount += 104; | |
| 568 recordcount++; | |
| 569 | |
| 570 out_le_u32(emr_selectobject_font.type, 0x00000025); /* EMR_SELECTOBJECT */ | |
| 571 out_le_u32(emr_selectobject_font.size, 12); | |
| 572 emr_selectobject_font.ih_object = emr_extcreatefontindirectw.ih_fonts; | |
| 573 bytecount += 12; | |
| 574 recordcount++; | |
| 575 | |
| 576 if (fsize2) { | |
| 577 memcpy(&emr_extcreatefontindirectw2, &emr_extcreatefontindirectw, sizeof(emr_extcreatefontindirectw)); | |
| 578 out_le_u32(emr_extcreatefontindirectw2.ih_fonts, 4 + ih_ultra_offset); | |
| 579 out_le_i32(emr_extcreatefontindirectw2.elw.height, fsize2); | |
| 580 bytecount += 104; | |
| 581 recordcount++; | |
| 582 | |
| 583 out_le_u32(emr_selectobject_font2.type, 0x00000025); /* EMR_SELECTOBJECT */ | |
| 584 out_le_u32(emr_selectobject_font2.size, 12); | |
| 585 emr_selectobject_font2.ih_object = emr_extcreatefontindirectw2.ih_fonts; | |
| 586 bytecount += 12; | |
| 587 recordcount++; | |
| 588 } | |
| 589 | |
| 590 /* Note select aligns counted below in strings loop */ | |
| 591 | |
| 592 out_le_u32(emr_settextalign_centre.type, 0x00000016); /* EMR_SETTEXTALIGN */ | |
| 593 out_le_u32(emr_settextalign_centre.size, 12); | |
| 594 out_le_u32(emr_settextalign_centre.text_alignment_mode, 0x0006 | 0x0018); /* TA_CENTER | TA_BASELINE */ | |
| 595 if (halign_left) { | |
| 596 out_le_u32(emr_settextalign_left.type, 0x00000016); /* EMR_SETTEXTALIGN */ | |
| 597 out_le_u32(emr_settextalign_left.size, 12); | |
| 598 out_le_u32(emr_settextalign_left.text_alignment_mode, 0x0000 | 0x0018); /* TA_LEFT | TA_BASELINE */ | |
| 599 } | |
| 600 if (halign_right) { | |
| 601 out_le_u32(emr_settextalign_right.type, 0x00000016); /* EMR_SETTEXTALIGN */ | |
| 602 out_le_u32(emr_settextalign_right.size, 12); | |
| 603 out_le_u32(emr_settextalign_right.text_alignment_mode, 0x0002 | 0x0018); /* TA_RIGHT | TA_BASELINE */ | |
| 604 } | |
| 605 | |
| 606 out_le_u32(emr_settextcolor.type, 0x0000018); /* EMR_SETTEXTCOLOR */ | |
| 607 out_le_u32(emr_settextcolor.size, 12); | |
| 608 emr_settextcolor.color.red = fgred; | |
| 609 emr_settextcolor.color.green = fggrn; | |
| 610 emr_settextcolor.color.blue = fgblu; | |
| 611 emr_settextcolor.color.reserved = 0; | |
| 612 bytecount += 12; | |
| 613 recordcount++; | |
| 614 } | |
| 615 | |
| 616 /* Text */ | |
| 617 this_text = 0; | |
| 618 /* Loop over font sizes so that they're grouped together, so only have to select font twice at most */ | |
| 619 for (i = 0, current_fsize = fsize; i < 2 && current_fsize; i++, current_fsize = fsize2) { | |
| 620 string = symbol->vector->strings; | |
| 621 current_halign = -1; | |
| 622 while (string) { | |
| 623 int utfle_len; | |
| 624 if (string->fsize != current_fsize) { | |
| 625 string = string->next; | |
| 626 continue; | |
| 627 } | |
| 628 text_fsizes[this_text] = string->fsize; | |
| 629 text_haligns[this_text] = string->halign; | |
| 630 if (text_haligns[this_text] != current_halign) { | |
| 631 current_halign = text_haligns[this_text]; | |
| 632 bytecount += 12; | |
| 633 recordcount++; | |
| 634 } | |
| 635 assert(string->length > 0); | |
| 636 utfle_len = emf_utfle_length(string->text, string->length); | |
| 637 text_bumped_lens[this_text] = emf_bump_up(utfle_len); | |
| 638 if (!(this_string[this_text] = (unsigned char *) malloc(text_bumped_lens[this_text]))) { | |
| 639 for (i = 0; i < this_text; i++) { | |
| 640 free(this_string[i]); | |
| 641 } | |
| 642 return errtxt(ZINT_ERROR_MEMORY, symbol, 641, "Insufficient memory for EMF string buffer"); | |
| 643 } | |
| 644 memset(this_string[this_text], 0, text_bumped_lens[this_text]); | |
| 645 out_le_u32(text[this_text].type, 0x00000054); /* EMR_EXTTEXTOUTW */ | |
| 646 out_le_u32(text[this_text].size, 76 + text_bumped_lens[this_text]); | |
| 647 out_le_i32(text[this_text].bounds.top, 0); /* ignored */ | |
| 648 out_le_i32(text[this_text].bounds.left, 0); /* ignored */ | |
| 649 out_le_i32(text[this_text].bounds.right, 0xffffffff); /* ignored */ | |
| 650 out_le_i32(text[this_text].bounds.bottom, 0xffffffff); /* ignored */ | |
| 651 out_le_u32(text[this_text].i_graphics_mode, 0x00000002); /* GM_ADVANCED */ | |
| 652 out_le_float(text[this_text].ex_scale, 1.0f); | |
| 653 out_le_float(text[this_text].ey_scale, 1.0f); | |
| 654 /* Unhack the guard whitespace `gws_left_fudge`/`gws_right_fudge` hack */ | |
| 655 if (upcean && string->halign == 1 && string->text[0] == '<') { | |
| 656 const float gws_left_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale; /* 0.5 * 2 * scale */ | |
| 657 out_le_i32(text[this_text].w_emr_text.reference.x, string->x + gws_left_fudge); | |
| 658 } else if (upcean && string->halign == 2 && string->text[0] == '>') { | |
| 659 const float gws_right_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale; /* 0.5 * 2 * scale */ | |
| 660 out_le_i32(text[this_text].w_emr_text.reference.x, string->x - gws_right_fudge); | |
| 661 } else { | |
| 662 out_le_i32(text[this_text].w_emr_text.reference.x, string->x); | |
| 663 } | |
| 664 out_le_i32(text[this_text].w_emr_text.reference.y, string->y); | |
| 665 out_le_u32(text[this_text].w_emr_text.chars, utfle_len); | |
| 666 out_le_u32(text[this_text].w_emr_text.off_string, 76); | |
| 667 out_le_u32(text[this_text].w_emr_text.options, 0); | |
| 668 out_le_i32(text[this_text].w_emr_text.rectangle.top, 0); | |
| 669 out_le_i32(text[this_text].w_emr_text.rectangle.left, 0); | |
| 670 out_le_i32(text[this_text].w_emr_text.rectangle.right, 0xffffffff); | |
| 671 out_le_i32(text[this_text].w_emr_text.rectangle.bottom, 0xffffffff); | |
| 672 out_le_u32(text[this_text].w_emr_text.off_dx, 0); | |
| 673 emf_utfle_copy(this_string[this_text], string->text, string->length); | |
| 674 bytecount += 76 + text_bumped_lens[this_text]; | |
| 675 recordcount++; | |
| 676 | |
| 677 this_text++; | |
| 678 string = string->next; | |
| 679 } | |
| 680 } | |
| 681 /* Suppress clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */ | |
| 682 assert(this_text == string_count); | |
| 683 | |
| 684 /* Create EOF record */ | |
| 685 out_le_u32(emr_eof.type, 0x0000000e); /* EMR_EOF */ | |
| 686 out_le_u32(emr_eof.size, 20); /* Assuming no palette entries */ | |
| 687 out_le_u32(emr_eof.n_pal_entries, 0); | |
| 688 out_le_u32(emr_eof.off_pal_entries, 0); | |
| 689 emr_eof.size_last = emr_eof.size; | |
| 690 bytecount += 20; | |
| 691 recordcount++; | |
| 692 | |
| 693 if (symbol->symbology == BARCODE_MAXICODE) { | |
| 694 bytecount += 5 * sizeof(emr_selectobject_t); | |
| 695 recordcount += 5; | |
| 696 } | |
| 697 | |
| 698 /* Put final counts in header */ | |
| 699 out_le_u32(emr_header.emf_header.bytes, bytecount); | |
| 700 out_le_u32(emr_header.emf_header.records, recordcount); | |
| 701 | |
| 702 /* Send EMF data to file */ | |
| 703 if (!fm_open(fmp, symbol, "wb")) { | |
| 704 return errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 640, "Could not open EMF output file (%1$d: %2$s)", fmp->err, | |
| 705 strerror(fmp->err)); | |
| 706 } | |
| 707 | |
| 708 fm_write(&emr_header, sizeof(emr_header_t), 1, fmp); | |
| 709 | |
| 710 fm_write(&emr_mapmode, sizeof(emr_mapmode_t), 1, fmp); | |
| 711 | |
| 712 if (rotate_angle) { | |
| 713 fm_write(&emr_setworldtransform, sizeof(emr_setworldtransform_t), 1, fmp); | |
| 714 } | |
| 715 | |
| 716 fm_write(&emr_createbrushindirect_bg, sizeof(emr_createbrushindirect_t), 1, fmp); | |
| 717 | |
| 718 if (symbol->symbology == BARCODE_ULTRA) { | |
| 719 for (i = 0; i < 9; i++) { | |
| 720 if (rectangle_bycolour[i]) { | |
| 721 fm_write(&emr_createbrushindirect_colour[i], sizeof(emr_createbrushindirect_t), 1, fmp); | |
| 722 } | |
| 723 } | |
| 724 } else { | |
| 725 fm_write(&emr_createbrushindirect_fg, sizeof(emr_createbrushindirect_t), 1, fmp); | |
| 726 } | |
| 727 | |
| 728 fm_write(&emr_createpen, sizeof(emr_createpen_t), 1, fmp); | |
| 729 | |
| 730 if (symbol->vector->strings) { | |
| 731 fm_write(&emr_extcreatefontindirectw, sizeof(emr_extcreatefontindirectw_t), 1, fmp); | |
| 732 if (fsize2) { | |
| 733 fm_write(&emr_extcreatefontindirectw2, sizeof(emr_extcreatefontindirectw_t), 1, fmp); | |
| 734 } | |
| 735 } | |
| 736 | |
| 737 fm_write(&emr_selectobject_bgbrush, sizeof(emr_selectobject_t), 1, fmp); | |
| 738 fm_write(&emr_selectobject_pen, sizeof(emr_selectobject_t), 1, fmp); | |
| 739 if (draw_background) { | |
| 740 fm_write(&background, sizeof(emr_rectangle_t), 1, fmp); | |
| 741 } | |
| 742 | |
| 743 if (symbol->symbology == BARCODE_ULTRA) { | |
| 744 for (i = 0; i < 9; i++) { | |
| 745 if (rectangle_bycolour[i]) { | |
| 746 fm_write(&emr_selectobject_colour[i], sizeof(emr_selectobject_t), 1, fmp); | |
| 747 | |
| 748 rect = symbol->vector->rectangles; | |
| 749 this_rectangle = 0; | |
| 750 while (rect) { | |
| 751 if ((i == 0 && rect->colour == -1) || rect->colour == i) { | |
| 752 fm_write(&rectangle[this_rectangle], sizeof(emr_rectangle_t), 1, fmp); | |
| 753 } | |
| 754 this_rectangle++; | |
| 755 rect = rect->next; | |
| 756 } | |
| 757 } | |
| 758 } | |
| 759 } else { | |
| 760 fm_write(&emr_selectobject_fgbrush, sizeof(emr_selectobject_t), 1, fmp); | |
| 761 | |
| 762 /* Rectangles */ | |
| 763 for (i = 0; i < rectangle_count; i++) { | |
| 764 fm_write(&rectangle[i], sizeof(emr_rectangle_t), 1, fmp); | |
| 765 } | |
| 766 } | |
| 767 | |
| 768 /* Hexagons */ | |
| 769 for (i = 0; i < hexagon_count; i++) { | |
| 770 fm_write(&hexagon[i], sizeof(emr_polygon_t), 1, fmp); | |
| 771 } | |
| 772 | |
| 773 /* Circles */ | |
| 774 if (symbol->symbology == BARCODE_MAXICODE) { | |
| 775 /* Bullseye needed */ | |
| 776 for (i = 0; i < circle_count; i++) { | |
| 777 fm_write(&circle[i], sizeof(emr_ellipse_t), 1, fmp); | |
| 778 if (i < circle_count - 1) { | |
| 779 if (i % 2) { | |
| 780 fm_write(&emr_selectobject_fgbrush, sizeof(emr_selectobject_t), 1, fmp); | |
| 781 } else { | |
| 782 fm_write(&emr_selectobject_bgbrush, sizeof(emr_selectobject_t), 1, fmp); | |
| 783 } | |
| 784 } | |
| 785 } | |
| 786 } else { | |
| 787 for (i = 0; i < circle_count; i++) { | |
| 788 fm_write(&circle[i], sizeof(emr_ellipse_t), 1, fmp); | |
| 789 } | |
| 790 } | |
| 791 | |
| 792 /* Text */ | |
| 793 if (string_count > 0) { | |
| 794 fm_write(&emr_selectobject_font, sizeof(emr_selectobject_t), 1, fmp); | |
| 795 fm_write(&emr_settextcolor, sizeof(emr_settextcolor_t), 1, fmp); | |
| 796 } | |
| 797 | |
| 798 current_fsize = fsize; | |
| 799 current_halign = -1; | |
| 800 for (i = 0; i < string_count; i++) { | |
| 801 if (text_fsizes[i] != current_fsize) { | |
| 802 current_fsize = text_fsizes[i]; | |
| 803 fm_write(&emr_selectobject_font2, sizeof(emr_selectobject_t), 1, fmp); | |
| 804 } | |
| 805 if (text_haligns[i] != current_halign) { | |
| 806 current_halign = text_haligns[i]; | |
| 807 if (current_halign == 0) { | |
| 808 fm_write(&emr_settextalign_centre, sizeof(emr_settextalign_t), 1, fmp); | |
| 809 } else if (current_halign == 1) { | |
| 810 fm_write(&emr_settextalign_left, sizeof(emr_settextalign_t), 1, fmp); | |
| 811 } else { | |
| 812 fm_write(&emr_settextalign_right, sizeof(emr_settextalign_t), 1, fmp); | |
| 813 } | |
| 814 } | |
| 815 fm_write(&text[i], sizeof(emr_exttextoutw_t), 1, fmp); | |
| 816 fm_write(this_string[i], text_bumped_lens[i], 1, fmp); | |
| 817 free(this_string[i]); | |
| 818 } | |
| 819 | |
| 820 fm_write(&emr_eof, sizeof(emr_eof_t), 1, fmp); | |
| 821 | |
| 822 if (fm_error(fmp)) { | |
| 823 errtxtf(0, symbol, 644, "Incomplete write of EMF output (%1$d: %2$s)", fmp->err, strerror(fmp->err)); | |
| 824 (void) fm_close(fmp, symbol); | |
| 825 return ZINT_ERROR_FILE_WRITE; | |
| 826 } | |
| 827 | |
| 828 if (!fm_close(fmp, symbol)) { | |
| 829 return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 941, "Failure on closing EMF output file (%1$d: %2$s)", | |
| 830 fmp->err, strerror(fmp->err)); | |
| 831 } | |
| 832 return error_number; | |
| 833 } | |
| 834 | |
| 835 /* vim: set ts=4 sw=4 et : */ |
