| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835 |
- /* emf.c - Support for Microsoft Enhanced Metafile Format */
- /*
- libzint - the open source barcode library
- Copyright (C) 2016-2024 Robin Stuart <rstuart114@gmail.com>
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the project nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- */
- /* SPDX-License-Identifier: BSD-3-Clause */
- /* Developed according to [MS-EMF] - v20160714, Released July 14, 2016
- * and [MS-WMF] - v20160714, Released July 14, 2016 */
- #include <errno.h>
- #include <stdio.h>
- #include <assert.h>
- #include <math.h>
- #include "common.h"
- #include "filemem.h"
- #include "output.h"
- #include "emf.h"
- /* Multiply truncating to 3 decimal places (avoids rounding differences on various platforms) */
- #define emf_mul3dpf(m, arg) stripf(roundf((m) * (arg) * 1000.0f) / 1000.0f)
- static int emf_count_rectangles(const struct zint_symbol *symbol) {
- int rectangles = 0;
- const struct zint_vector_rect *rect;
- rect = symbol->vector->rectangles;
- while (rect) {
- rectangles++;
- rect = rect->next;
- }
- return rectangles;
- }
- static int emf_count_circles(const struct zint_symbol *symbol) {
- int circles = 0;
- const struct zint_vector_circle *circ;
- circ = symbol->vector->circles;
- while (circ) {
- circles++;
- circ = circ->next;
- }
- /* Hack for MaxiCode */
- return symbol->symbology == BARCODE_MAXICODE ? circles * 2 : circles;
- }
- static int emf_count_hexagons(const struct zint_symbol *symbol) {
- int hexagons = 0;
- const struct zint_vector_hexagon *hex;
- hex = symbol->vector->hexagons;
- while (hex) {
- hexagons++;
- hex = hex->next;
- }
- return hexagons;
- }
- static int emf_count_strings(const struct zint_symbol *symbol, float *fsize, float *fsize2, int *halign_left,
- int *halign_right) {
- int strings = 0;
- const struct zint_vector_string *string;
- *fsize = *fsize2 = 0.0f;
- *halign_left = *halign_right = 0;
- string = symbol->vector->strings;
- while (string) {
- /* Allow 2 font sizes */
- if (*fsize == 0.0f) {
- *fsize = string->fsize;
- } else if (string->fsize != *fsize && *fsize2 == 0.0f) {
- *fsize2 = string->fsize;
- }
- /* Only 3 haligns possible and centre align always assumed used */
- if (string->halign) { /* Left or right align */
- if (string->halign == 1) { /* Left align */
- *halign_left = string->halign;
- } else { /* Right align */
- *halign_right = string->halign;
- }
- }
- strings++;
- string = string->next;
- }
- return strings;
- }
- /* Convert UTF-8 to UTF-16LE - only needs to handle characters <= U+00FF */
- static void emf_utfle_copy(unsigned char *output, const unsigned char *input, const int length) {
- int i;
- int o;
- i = 0;
- o = 0;
- do {
- if (input[i] <= 0x7f) {
- /* 1 byte mode (7-bit ASCII) */
- output[o] = input[i];
- output[o + 1] = 0x00;
- o += 2;
- i++;
- } else {
- /* 2 byte mode */
- output[o] = ((input[i] & 0x1f) << 6) + (input[i + 1] & 0x3f);
- output[o + 1] = 0x00;
- o += 2;
- i += 2;
- }
- } while (i < length);
- }
- /* Strings length must be a multiple of 4 bytes */
- static int emf_bump_up(const int input) {
- return (input + (input & 1)) << 1;
- }
- static int emf_utfle_length(const unsigned char *input, const int length) {
- int result = 0;
- int i;
- for (i = 0; i < length; i++) {
- result++;
- if (input[i] >= 0x80) { /* 2 byte UTF-8 counts as one UTF-16LE character */
- i++;
- }
- }
- return result;
- }
- INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle) {
- int i;
- struct filemem fm;
- struct filemem *const fmp = &fm;
- unsigned char fgred, fggrn, fgblu, bgred, bggrn, bgblu, bgalpha;
- int error_number = 0;
- int rectangle_count, this_rectangle;
- int circle_count, this_circle;
- int hexagon_count, this_hexagon;
- int string_count, this_text;
- int bytecount, recordcount;
- float previous_diameter;
- float radius, half_radius, half_sqrt3_radius;
- int colours_used = 0;
- int rectangle_bycolour[9] = {0};
- int width, height;
- int bounds_pxx, bounds_pxy; /* Pixels */
- int frame_cmmx, frame_cmmy; /* Hundredths of a mm, i.e. "centi-millimeters" */
- int device_pxx, device_pxy; /* Pixels */
- int mmx, mmy; /* Millimeters */
- int micronx, microny; /* Micrometers */
- const float dpmm = symbol->dpmm ? stripf(symbol->dpmm)
- : ZBarcode_XdimDp_From_Scale(symbol->symbology, symbol->scale,
- ZBarcode_Default_Xdim(symbol->symbology), "EMF");
- const int sideways = rotate_angle == 90 || rotate_angle == 270;
- int draw_background = 1;
- int bold;
- const int upcean = is_upcean(symbol->symbology);
- struct zint_vector_rect *rect;
- struct zint_vector_circle *circ;
- struct zint_vector_hexagon *hex;
- struct zint_vector_string *string;
- /* Allow for up to 6 strings (current max 3 for UPC/EAN) */
- unsigned char *this_string[6];
- emr_exttextoutw_t text[6];
- float text_fsizes[6];
- int text_haligns[6];
- int text_bumped_lens[6];
- emr_header_t emr_header;
- emr_eof_t emr_eof;
- emr_mapmode_t emr_mapmode;
- emr_setworldtransform_t emr_setworldtransform;
- emr_createbrushindirect_t emr_createbrushindirect_fg;
- emr_createbrushindirect_t emr_createbrushindirect_bg;
- emr_createbrushindirect_t emr_createbrushindirect_colour[9]; /* Used for colour symbols only */
- emr_selectobject_t emr_selectobject_fgbrush;
- emr_selectobject_t emr_selectobject_bgbrush;
- emr_selectobject_t emr_selectobject_colour[9]; /* Used for colour symbols only */
- emr_createpen_t emr_createpen;
- emr_selectobject_t emr_selectobject_pen;
- emr_rectangle_t background;
- emr_settextcolor_t emr_settextcolor;
- float fsize;
- emr_extcreatefontindirectw_t emr_extcreatefontindirectw;
- emr_selectobject_t emr_selectobject_font;
- float fsize2;
- emr_extcreatefontindirectw_t emr_extcreatefontindirectw2;
- emr_selectobject_t emr_selectobject_font2;
- emr_settextalign_t emr_settextalign_centre; /* Centre align */
- int halign_left; /* Set if left halign used */
- emr_settextalign_t emr_settextalign_left;
- int halign_right; /* Set if right halign used */
- emr_settextalign_t emr_settextalign_right;
- float current_fsize;
- int current_halign;
- emr_rectangle_t *rectangle;
- emr_ellipse_t *circle;
- emr_polygon_t *hexagon;
- const int ih_ultra_offset = symbol->symbology == BARCODE_ULTRA ? 8 : 0;
- if (symbol->vector == NULL) {
- return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 643, "Vector header NULL");
- }
- (void) out_colour_get_rgb(symbol->fgcolour, &fgred, &fggrn, &fgblu, NULL /*alpha*/);
- (void) out_colour_get_rgb(symbol->bgcolour, &bgred, &bggrn, &bgblu, &bgalpha);
- if (bgalpha == 0) {
- draw_background = 0;
- }
- rectangle_count = emf_count_rectangles(symbol);
- circle_count = emf_count_circles(symbol);
- hexagon_count = emf_count_hexagons(symbol);
- string_count = emf_count_strings(symbol, &fsize, &fsize2, &halign_left, &halign_right);
- /* Avoid sanitize runtime error by making always non-zero */
- rectangle = (emr_rectangle_t *) z_alloca(sizeof(emr_rectangle_t) * (rectangle_count ? rectangle_count : 1));
- circle = (emr_ellipse_t *) z_alloca(sizeof(emr_ellipse_t) * (circle_count ? circle_count : 1));
- hexagon = (emr_polygon_t *) z_alloca(sizeof(emr_polygon_t) * (hexagon_count ? hexagon_count : 1));
- /* Calculate how many coloured rectangles */
- if (symbol->symbology == BARCODE_ULTRA) {
- rect = symbol->vector->rectangles;
- while (rect) {
- if (rect->colour == -1) { /* Foreground colour */
- if (rectangle_bycolour[0] == 0) {
- colours_used++;
- rectangle_bycolour[0] = 1;
- }
- } else {
- if (rectangle_bycolour[rect->colour] == 0) {
- colours_used++;
- rectangle_bycolour[rect->colour] = 1;
- }
- }
- rect = rect->next;
- }
- }
- width = (int) ceilf(symbol->vector->width);
- height = (int) ceilf(symbol->vector->height);
- bounds_pxx = width - 1; /* Following Inkscape, bounds "inclusive-inclusive", so size 1 less */
- bounds_pxy = height - 1;
- device_pxx = width; /* device */
- device_pxy = height;
- if (dpmm) {
- frame_cmmx = (int) roundf(stripf(width * 100.0f / dpmm)) - 1; /* frame also "inclusive-inclusive" */
- frame_cmmy = (int) roundf(stripf(height * 100.0f / dpmm)) - 1;
- mmx = (int) roundf(stripf(width / dpmm)); /* millimeters */
- mmy = (int) roundf(stripf(height / dpmm));
- micronx = (int) roundf(stripf(width * 1000.0f / dpmm)); /* micrometers */
- microny = (int) roundf(stripf(height * 1000.0f / dpmm));
- } else { /* Should only happen if `symbol->scale` zero. */
- frame_cmmx = (int) roundf(stripf(width * 100.0f)) - 1;
- frame_cmmy = (int) roundf(stripf(height * 100.0f)) - 1;
- mmx = (int) roundf(stripf(width));
- mmy = (int) roundf(stripf(height));
- micronx = (int) roundf(stripf(width * 1000.0f));
- microny = (int) roundf(stripf(height * 1000.0f));
- }
- /* Header */
- out_le_u32(emr_header.type, 0x00000001); /* EMR_HEADER */
- out_le_u32(emr_header.size, 108); /* Including extensions */
- out_le_i32(emr_header.emf_header.bounds.left, 0);
- out_le_i32(emr_header.emf_header.bounds.top, 0);
- out_le_i32(emr_header.emf_header.bounds.right, sideways ? bounds_pxy : bounds_pxx);
- out_le_i32(emr_header.emf_header.bounds.bottom, sideways ? bounds_pxx : bounds_pxy);
- out_le_i32(emr_header.emf_header.frame.left, 0);
- out_le_i32(emr_header.emf_header.frame.top, 0);
- out_le_i32(emr_header.emf_header.frame.right, sideways ? frame_cmmy : frame_cmmx);
- out_le_i32(emr_header.emf_header.frame.bottom, sideways ? frame_cmmx : frame_cmmy);
- out_le_u32(emr_header.emf_header.record_signature, 0x464d4520); /* ENHMETA_SIGNATURE */
- out_le_u32(emr_header.emf_header.version, 0x00010000);
- out_le_u16(emr_header.emf_header.handles, (fsize2 != 0.0f ? 5 : 4) + ih_ultra_offset); /* No. of graphics objs */
- out_le_u16(emr_header.emf_header.reserved, 0x0000);
- out_le_u32(emr_header.emf_header.n_description, 0);
- out_le_u32(emr_header.emf_header.off_description, 0);
- out_le_u32(emr_header.emf_header.n_pal_entries, 0);
- out_le_u32(emr_header.emf_header.device.cx, sideways ? device_pxy : device_pxx);
- out_le_u32(emr_header.emf_header.device.cy, sideways ? device_pxx : device_pxy);
- out_le_u32(emr_header.emf_header.millimeters.cx, sideways ? mmy : mmx);
- out_le_u32(emr_header.emf_header.millimeters.cy, sideways ? mmx : mmy);
- /* HeaderExtension1 */
- out_le_u32(emr_header.emf_header.cb_pixel_format, 0x0000); /* None set */
- out_le_u32(emr_header.emf_header.off_pixel_format, 0x0000); /* None set */
- out_le_u32(emr_header.emf_header.b_open_gl, 0x0000); /* OpenGL not present */
- /* HeaderExtension2 */
- out_le_u32(emr_header.emf_header.micrometers.cx, sideways ? microny : micronx);
- out_le_u32(emr_header.emf_header.micrometers.cy, sideways ? micronx : microny);
- bytecount = 108;
- recordcount = 1;
- out_le_u32(emr_mapmode.type, 0x00000011); /* EMR_SETMAPMODE */
- out_le_u32(emr_mapmode.size, 12);
- out_le_u32(emr_mapmode.mapmode, 0x01); /* MM_TEXT */
- bytecount += 12;
- recordcount++;
- if (rotate_angle) {
- out_le_u32(emr_setworldtransform.type, 0x00000023); /* EMR_SETWORLDTRANSFORM */
- out_le_u32(emr_setworldtransform.size, 32);
- out_le_float(emr_setworldtransform.m11, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? -1.0f : 0.0f);
- out_le_float(emr_setworldtransform.m12, rotate_angle == 90 ? 1.0f : rotate_angle == 180 ? 0.0f : -1.0f);
- out_le_float(emr_setworldtransform.m21, rotate_angle == 90 ? -1.0f : rotate_angle == 180 ? 0.0f : 1.0f);
- out_le_float(emr_setworldtransform.m22, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? -1.0f : 0.0f);
- out_le_float(emr_setworldtransform.dx, rotate_angle == 90 ? height : rotate_angle == 180 ? width : 0.0f);
- out_le_float(emr_setworldtransform.dy, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? height : width);
- bytecount += 32;
- recordcount++;
- }
- /* Create Brushes */
- out_le_u32(emr_createbrushindirect_bg.type, 0x00000027); /* EMR_CREATEBRUSHINDIRECT */
- out_le_u32(emr_createbrushindirect_bg.size, 24);
- out_le_u32(emr_createbrushindirect_bg.ih_brush, 0);
- out_le_u32(emr_createbrushindirect_bg.log_brush.brush_style, 0x0000); /* BS_SOLID */
- emr_createbrushindirect_bg.log_brush.color.red = bgred;
- emr_createbrushindirect_bg.log_brush.color.green = bggrn;
- emr_createbrushindirect_bg.log_brush.color.blue = bgblu;
- emr_createbrushindirect_bg.log_brush.color.reserved = 0;
- out_le_u32(emr_createbrushindirect_bg.log_brush.brush_hatch, 0x0006); /* HS_SOLIDCLR */
- bytecount += 24;
- recordcount++;
- if (symbol->symbology == BARCODE_ULTRA) {
- static const char ultra_chars[] = { '0', 'C', 'B', 'M', 'R', 'Y', 'G', 'K', 'W' };
- for (i = 0; i < 9; i++) {
- out_le_u32(emr_createbrushindirect_colour[i].type, 0x00000027); /* EMR_CREATEBRUSHINDIRECT */
- out_le_u32(emr_createbrushindirect_colour[i].size, 24);
- out_le_u32(emr_createbrushindirect_colour[i].ih_brush, 1 + i);
- out_le_u32(emr_createbrushindirect_colour[i].log_brush.brush_style, 0x0000); /* BS_SOLID */
- if (i == 0) {
- emr_createbrushindirect_colour[i].log_brush.color.red = fgred;
- emr_createbrushindirect_colour[i].log_brush.color.green = fggrn;
- emr_createbrushindirect_colour[i].log_brush.color.blue = fgblu;
- } else {
- out_colour_char_to_rgb(ultra_chars[i],
- &emr_createbrushindirect_colour[i].log_brush.color.red,
- &emr_createbrushindirect_colour[i].log_brush.color.green,
- &emr_createbrushindirect_colour[i].log_brush.color.blue);
- }
- emr_createbrushindirect_colour[i].log_brush.color.reserved = 0;
- out_le_u32(emr_createbrushindirect_colour[i].log_brush.brush_hatch, 0x0006); /* HS_SOLIDCLR */
- }
- bytecount += colours_used * 24;
- recordcount += colours_used;
- } else {
- out_le_u32(emr_createbrushindirect_fg.type, 0x00000027); /* EMR_CREATEBRUSHINDIRECT */
- out_le_u32(emr_createbrushindirect_fg.size, 24);
- out_le_u32(emr_createbrushindirect_fg.ih_brush, 1);
- out_le_u32(emr_createbrushindirect_fg.log_brush.brush_style, 0x0000); /* BS_SOLID */
- emr_createbrushindirect_fg.log_brush.color.red = fgred;
- emr_createbrushindirect_fg.log_brush.color.green = fggrn;
- emr_createbrushindirect_fg.log_brush.color.blue = fgblu;
- emr_createbrushindirect_fg.log_brush.color.reserved = 0;
- out_le_u32(emr_createbrushindirect_fg.log_brush.brush_hatch, 0x0006); /* HS_SOLIDCLR */
- bytecount += 24;
- recordcount++;
- }
- out_le_u32(emr_selectobject_bgbrush.type, 0x00000025); /* EMR_SELECTOBJECT */
- out_le_u32(emr_selectobject_bgbrush.size, 12);
- emr_selectobject_bgbrush.ih_object = emr_createbrushindirect_bg.ih_brush;
- bytecount += 12;
- recordcount++;
- if (symbol->symbology == BARCODE_ULTRA) {
- for (i = 0; i < 9; i++) {
- out_le_u32(emr_selectobject_colour[i].type, 0x00000025); /* EMR_SELECTOBJECT */
- out_le_u32(emr_selectobject_colour[i].size, 12);
- emr_selectobject_colour[i].ih_object = emr_createbrushindirect_colour[i].ih_brush;
- }
- bytecount += colours_used * 12;
- recordcount += colours_used;
- } else {
- out_le_u32(emr_selectobject_fgbrush.type, 0x00000025); /* EMR_SELECTOBJECT */
- out_le_u32(emr_selectobject_fgbrush.size, 12);
- emr_selectobject_fgbrush.ih_object = emr_createbrushindirect_fg.ih_brush;
- bytecount += 12;
- recordcount++;
- }
- /* Create Pens */
- out_le_u32(emr_createpen.type, 0x00000026); /* EMR_CREATEPEN */
- out_le_u32(emr_createpen.size, 28);
- out_le_u32(emr_createpen.ih_pen, 2 + ih_ultra_offset);
- out_le_u32(emr_createpen.log_pen.pen_style, 0x00000005); /* PS_NULL */
- out_le_i32(emr_createpen.log_pen.width.x, 1);
- out_le_i32(emr_createpen.log_pen.width.y, 0); /* ignored */
- emr_createpen.log_pen.color_ref.red = 0;
- emr_createpen.log_pen.color_ref.green = 0;
- emr_createpen.log_pen.color_ref.blue = 0;
- emr_createpen.log_pen.color_ref.reserved = 0;
- bytecount += 28;
- recordcount++;
- out_le_u32(emr_selectobject_pen.type, 0x00000025); /* EMR_SELECTOBJECT */
- out_le_u32(emr_selectobject_pen.size, 12);
- emr_selectobject_pen.ih_object = emr_createpen.ih_pen;
- bytecount += 12;
- recordcount++;
- if (draw_background) {
- /* Make background from a rectangle */
- out_le_u32(background.type, 0x0000002b); /* EMR_RECTANGLE */
- out_le_u32(background.size, 24);
- out_le_i32(background.box.top, 0);
- out_le_i32(background.box.left, 0);
- out_le_i32(background.box.right, width);
- out_le_i32(background.box.bottom, height);
- bytecount += 24;
- recordcount++;
- }
- /* Rectangles */
- rect = symbol->vector->rectangles;
- this_rectangle = 0;
- while (rect) {
- out_le_u32(rectangle[this_rectangle].type, 0x0000002b); /* EMR_RECTANGLE */
- out_le_u32(rectangle[this_rectangle].size, 24);
- out_le_i32(rectangle[this_rectangle].box.top, rect->y);
- out_le_i32(rectangle[this_rectangle].box.bottom, stripf(rect->y + rect->height));
- out_le_i32(rectangle[this_rectangle].box.left, rect->x);
- out_le_i32(rectangle[this_rectangle].box.right, stripf(rect->x + rect->width));
- this_rectangle++;
- bytecount += 24;
- recordcount++;
- rect = rect->next;
- }
- /* Circles */
- previous_diameter = radius = 0.0f;
- circ = symbol->vector->circles;
- this_circle = 0;
- while (circ) {
- /* Note using circle width the proper way, with a non-null pen of specified width and a null brush for fill,
- causes various different rendering issues for LibreOffice Draw and Inkscape, so using following hack */
- if (previous_diameter != circ->diameter + circ->width) { /* Drawing MaxiCode bullseye using overlayed discs */
- previous_diameter = circ->diameter + circ->width;
- radius = emf_mul3dpf(0.5f, previous_diameter);
- }
- out_le_u32(circle[this_circle].type, 0x0000002a); /* EMR_ELLIPSE */
- out_le_u32(circle[this_circle].size, 24);
- out_le_i32(circle[this_circle].box.top, stripf(circ->y - radius));
- out_le_i32(circle[this_circle].box.bottom, stripf(circ->y + radius));
- out_le_i32(circle[this_circle].box.left, stripf(circ->x - radius));
- out_le_i32(circle[this_circle].box.right, stripf(circ->x + radius));
- this_circle++;
- bytecount += 24;
- recordcount++;
- if (symbol->symbology == BARCODE_MAXICODE) { /* Drawing MaxiCode bullseye using overlayed discs */
- float inner_radius = radius - circ->width;
- out_le_u32(circle[this_circle].type, 0x0000002a); /* EMR_ELLIPSE */
- out_le_u32(circle[this_circle].size, 24);
- out_le_i32(circle[this_circle].box.top, stripf(circ->y - inner_radius));
- out_le_i32(circle[this_circle].box.bottom, stripf(circ->y + inner_radius));
- out_le_i32(circle[this_circle].box.left, stripf(circ->x - inner_radius));
- out_le_i32(circle[this_circle].box.right, stripf(circ->x + inner_radius));
- this_circle++;
- bytecount += 24;
- recordcount++;
- }
- circ = circ->next;
- }
- /* Hexagons */
- previous_diameter = radius = half_radius = half_sqrt3_radius = 0.0f;
- hex = symbol->vector->hexagons;
- this_hexagon = 0;
- while (hex) {
- out_le_u32(hexagon[this_hexagon].type, 0x00000003); /* EMR_POLYGON */
- out_le_u32(hexagon[this_hexagon].size, 76);
- out_le_u32(hexagon[this_hexagon].count, 6);
- if (previous_diameter != hex->diameter) {
- previous_diameter = hex->diameter;
- radius = emf_mul3dpf(0.5f, previous_diameter);
- half_radius = emf_mul3dpf(0.25f, previous_diameter);
- half_sqrt3_radius = emf_mul3dpf(0.43301270189221932338f, previous_diameter);
- }
- /* Note rotation done via world transform */
- out_le_i32(hexagon[this_hexagon].a_points_a.x, hex->x);
- out_le_i32(hexagon[this_hexagon].a_points_a.y, stripf(hex->y + radius));
- out_le_i32(hexagon[this_hexagon].a_points_b.x, stripf(hex->x + half_sqrt3_radius));
- out_le_i32(hexagon[this_hexagon].a_points_b.y, stripf(hex->y + half_radius));
- out_le_i32(hexagon[this_hexagon].a_points_c.x, stripf(hex->x + half_sqrt3_radius));
- out_le_i32(hexagon[this_hexagon].a_points_c.y, stripf(hex->y - half_radius));
- out_le_i32(hexagon[this_hexagon].a_points_d.x, hex->x);
- out_le_i32(hexagon[this_hexagon].a_points_d.y, stripf(hex->y - radius));
- out_le_i32(hexagon[this_hexagon].a_points_e.x, stripf(hex->x - half_sqrt3_radius));
- out_le_i32(hexagon[this_hexagon].a_points_e.y, stripf(hex->y - half_radius));
- out_le_i32(hexagon[this_hexagon].a_points_f.x, stripf(hex->x - half_sqrt3_radius));
- out_le_i32(hexagon[this_hexagon].a_points_f.y, stripf(hex->y + half_radius));
- hexagon[this_hexagon].bounds.top = hexagon[this_hexagon].a_points_d.y;
- hexagon[this_hexagon].bounds.bottom = hexagon[this_hexagon].a_points_a.y;
- hexagon[this_hexagon].bounds.left = hexagon[this_hexagon].a_points_e.x;
- hexagon[this_hexagon].bounds.right = hexagon[this_hexagon].a_points_c.x;
- this_hexagon++;
- bytecount += 76;
- recordcount++;
- hex = hex->next;
- }
- /* Create font records, alignment records and text color */
- if (symbol->vector->strings) {
- bold = (symbol->output_options & BOLD_TEXT) && !is_upcean(symbol->symbology);
- memset(&emr_extcreatefontindirectw, 0, sizeof(emr_extcreatefontindirectw));
- out_le_u32(emr_extcreatefontindirectw.type, 0x00000052); /* EMR_EXTCREATEFONTINDIRECTW */
- out_le_u32(emr_extcreatefontindirectw.size, 104);
- out_le_u32(emr_extcreatefontindirectw.ih_fonts, 3 + ih_ultra_offset);
- out_le_i32(emr_extcreatefontindirectw.elw.height, fsize);
- out_le_i32(emr_extcreatefontindirectw.elw.width, 0); /* automatic */
- out_le_i32(emr_extcreatefontindirectw.elw.weight, bold ? 700 : 400);
- emr_extcreatefontindirectw.elw.char_set = 0x00; /* ANSI_CHARSET */
- emr_extcreatefontindirectw.elw.out_precision = 0x00; /* OUT_DEFAULT_PRECIS */
- emr_extcreatefontindirectw.elw.clip_precision = 0x00; /* CLIP_DEFAULT_PRECIS */
- emr_extcreatefontindirectw.elw.pitch_and_family = 0x02 | (0x02 << 6); /* FF_SWISS | VARIABLE_PITCH */
- emf_utfle_copy(emr_extcreatefontindirectw.elw.facename, (const unsigned char *) "sans-serif", 10);
- bytecount += 104;
- recordcount++;
- out_le_u32(emr_selectobject_font.type, 0x00000025); /* EMR_SELECTOBJECT */
- out_le_u32(emr_selectobject_font.size, 12);
- emr_selectobject_font.ih_object = emr_extcreatefontindirectw.ih_fonts;
- bytecount += 12;
- recordcount++;
- if (fsize2) {
- memcpy(&emr_extcreatefontindirectw2, &emr_extcreatefontindirectw, sizeof(emr_extcreatefontindirectw));
- out_le_u32(emr_extcreatefontindirectw2.ih_fonts, 4 + ih_ultra_offset);
- out_le_i32(emr_extcreatefontindirectw2.elw.height, fsize2);
- bytecount += 104;
- recordcount++;
- out_le_u32(emr_selectobject_font2.type, 0x00000025); /* EMR_SELECTOBJECT */
- out_le_u32(emr_selectobject_font2.size, 12);
- emr_selectobject_font2.ih_object = emr_extcreatefontindirectw2.ih_fonts;
- bytecount += 12;
- recordcount++;
- }
- /* Note select aligns counted below in strings loop */
- out_le_u32(emr_settextalign_centre.type, 0x00000016); /* EMR_SETTEXTALIGN */
- out_le_u32(emr_settextalign_centre.size, 12);
- out_le_u32(emr_settextalign_centre.text_alignment_mode, 0x0006 | 0x0018); /* TA_CENTER | TA_BASELINE */
- if (halign_left) {
- out_le_u32(emr_settextalign_left.type, 0x00000016); /* EMR_SETTEXTALIGN */
- out_le_u32(emr_settextalign_left.size, 12);
- out_le_u32(emr_settextalign_left.text_alignment_mode, 0x0000 | 0x0018); /* TA_LEFT | TA_BASELINE */
- }
- if (halign_right) {
- out_le_u32(emr_settextalign_right.type, 0x00000016); /* EMR_SETTEXTALIGN */
- out_le_u32(emr_settextalign_right.size, 12);
- out_le_u32(emr_settextalign_right.text_alignment_mode, 0x0002 | 0x0018); /* TA_RIGHT | TA_BASELINE */
- }
- out_le_u32(emr_settextcolor.type, 0x0000018); /* EMR_SETTEXTCOLOR */
- out_le_u32(emr_settextcolor.size, 12);
- emr_settextcolor.color.red = fgred;
- emr_settextcolor.color.green = fggrn;
- emr_settextcolor.color.blue = fgblu;
- emr_settextcolor.color.reserved = 0;
- bytecount += 12;
- recordcount++;
- }
- /* Text */
- this_text = 0;
- /* Loop over font sizes so that they're grouped together, so only have to select font twice at most */
- for (i = 0, current_fsize = fsize; i < 2 && current_fsize; i++, current_fsize = fsize2) {
- string = symbol->vector->strings;
- current_halign = -1;
- while (string) {
- int utfle_len;
- if (string->fsize != current_fsize) {
- string = string->next;
- continue;
- }
- text_fsizes[this_text] = string->fsize;
- text_haligns[this_text] = string->halign;
- if (text_haligns[this_text] != current_halign) {
- current_halign = text_haligns[this_text];
- bytecount += 12;
- recordcount++;
- }
- assert(string->length > 0);
- utfle_len = emf_utfle_length(string->text, string->length);
- text_bumped_lens[this_text] = emf_bump_up(utfle_len);
- if (!(this_string[this_text] = (unsigned char *) malloc(text_bumped_lens[this_text]))) {
- for (i = 0; i < this_text; i++) {
- free(this_string[i]);
- }
- return errtxt(ZINT_ERROR_MEMORY, symbol, 641, "Insufficient memory for EMF string buffer");
- }
- memset(this_string[this_text], 0, text_bumped_lens[this_text]);
- out_le_u32(text[this_text].type, 0x00000054); /* EMR_EXTTEXTOUTW */
- out_le_u32(text[this_text].size, 76 + text_bumped_lens[this_text]);
- out_le_i32(text[this_text].bounds.top, 0); /* ignored */
- out_le_i32(text[this_text].bounds.left, 0); /* ignored */
- out_le_i32(text[this_text].bounds.right, 0xffffffff); /* ignored */
- out_le_i32(text[this_text].bounds.bottom, 0xffffffff); /* ignored */
- out_le_u32(text[this_text].i_graphics_mode, 0x00000002); /* GM_ADVANCED */
- out_le_float(text[this_text].ex_scale, 1.0f);
- out_le_float(text[this_text].ey_scale, 1.0f);
- /* Unhack the guard whitespace `gws_left_fudge`/`gws_right_fudge` hack */
- if (upcean && string->halign == 1 && string->text[0] == '<') {
- const float gws_left_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale; /* 0.5 * 2 * scale */
- out_le_i32(text[this_text].w_emr_text.reference.x, string->x + gws_left_fudge);
- } else if (upcean && string->halign == 2 && string->text[0] == '>') {
- const float gws_right_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale; /* 0.5 * 2 * scale */
- out_le_i32(text[this_text].w_emr_text.reference.x, string->x - gws_right_fudge);
- } else {
- out_le_i32(text[this_text].w_emr_text.reference.x, string->x);
- }
- out_le_i32(text[this_text].w_emr_text.reference.y, string->y);
- out_le_u32(text[this_text].w_emr_text.chars, utfle_len);
- out_le_u32(text[this_text].w_emr_text.off_string, 76);
- out_le_u32(text[this_text].w_emr_text.options, 0);
- out_le_i32(text[this_text].w_emr_text.rectangle.top, 0);
- out_le_i32(text[this_text].w_emr_text.rectangle.left, 0);
- out_le_i32(text[this_text].w_emr_text.rectangle.right, 0xffffffff);
- out_le_i32(text[this_text].w_emr_text.rectangle.bottom, 0xffffffff);
- out_le_u32(text[this_text].w_emr_text.off_dx, 0);
- emf_utfle_copy(this_string[this_text], string->text, string->length);
- bytecount += 76 + text_bumped_lens[this_text];
- recordcount++;
- this_text++;
- string = string->next;
- }
- }
- /* Suppress clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */
- assert(this_text == string_count);
- /* Create EOF record */
- out_le_u32(emr_eof.type, 0x0000000e); /* EMR_EOF */
- out_le_u32(emr_eof.size, 20); /* Assuming no palette entries */
- out_le_u32(emr_eof.n_pal_entries, 0);
- out_le_u32(emr_eof.off_pal_entries, 0);
- emr_eof.size_last = emr_eof.size;
- bytecount += 20;
- recordcount++;
- if (symbol->symbology == BARCODE_MAXICODE) {
- bytecount += 5 * sizeof(emr_selectobject_t);
- recordcount += 5;
- }
- /* Put final counts in header */
- out_le_u32(emr_header.emf_header.bytes, bytecount);
- out_le_u32(emr_header.emf_header.records, recordcount);
- /* Send EMF data to file */
- if (!fm_open(fmp, symbol, "wb")) {
- return errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 640, "Could not open EMF output file (%1$d: %2$s)", fmp->err,
- strerror(fmp->err));
- }
- fm_write(&emr_header, sizeof(emr_header_t), 1, fmp);
- fm_write(&emr_mapmode, sizeof(emr_mapmode_t), 1, fmp);
- if (rotate_angle) {
- fm_write(&emr_setworldtransform, sizeof(emr_setworldtransform_t), 1, fmp);
- }
- fm_write(&emr_createbrushindirect_bg, sizeof(emr_createbrushindirect_t), 1, fmp);
- if (symbol->symbology == BARCODE_ULTRA) {
- for (i = 0; i < 9; i++) {
- if (rectangle_bycolour[i]) {
- fm_write(&emr_createbrushindirect_colour[i], sizeof(emr_createbrushindirect_t), 1, fmp);
- }
- }
- } else {
- fm_write(&emr_createbrushindirect_fg, sizeof(emr_createbrushindirect_t), 1, fmp);
- }
- fm_write(&emr_createpen, sizeof(emr_createpen_t), 1, fmp);
- if (symbol->vector->strings) {
- fm_write(&emr_extcreatefontindirectw, sizeof(emr_extcreatefontindirectw_t), 1, fmp);
- if (fsize2) {
- fm_write(&emr_extcreatefontindirectw2, sizeof(emr_extcreatefontindirectw_t), 1, fmp);
- }
- }
- fm_write(&emr_selectobject_bgbrush, sizeof(emr_selectobject_t), 1, fmp);
- fm_write(&emr_selectobject_pen, sizeof(emr_selectobject_t), 1, fmp);
- if (draw_background) {
- fm_write(&background, sizeof(emr_rectangle_t), 1, fmp);
- }
- if (symbol->symbology == BARCODE_ULTRA) {
- for (i = 0; i < 9; i++) {
- if (rectangle_bycolour[i]) {
- fm_write(&emr_selectobject_colour[i], sizeof(emr_selectobject_t), 1, fmp);
- rect = symbol->vector->rectangles;
- this_rectangle = 0;
- while (rect) {
- if ((i == 0 && rect->colour == -1) || rect->colour == i) {
- fm_write(&rectangle[this_rectangle], sizeof(emr_rectangle_t), 1, fmp);
- }
- this_rectangle++;
- rect = rect->next;
- }
- }
- }
- } else {
- fm_write(&emr_selectobject_fgbrush, sizeof(emr_selectobject_t), 1, fmp);
- /* Rectangles */
- for (i = 0; i < rectangle_count; i++) {
- fm_write(&rectangle[i], sizeof(emr_rectangle_t), 1, fmp);
- }
- }
- /* Hexagons */
- for (i = 0; i < hexagon_count; i++) {
- fm_write(&hexagon[i], sizeof(emr_polygon_t), 1, fmp);
- }
- /* Circles */
- if (symbol->symbology == BARCODE_MAXICODE) {
- /* Bullseye needed */
- for (i = 0; i < circle_count; i++) {
- fm_write(&circle[i], sizeof(emr_ellipse_t), 1, fmp);
- if (i < circle_count - 1) {
- if (i % 2) {
- fm_write(&emr_selectobject_fgbrush, sizeof(emr_selectobject_t), 1, fmp);
- } else {
- fm_write(&emr_selectobject_bgbrush, sizeof(emr_selectobject_t), 1, fmp);
- }
- }
- }
- } else {
- for (i = 0; i < circle_count; i++) {
- fm_write(&circle[i], sizeof(emr_ellipse_t), 1, fmp);
- }
- }
- /* Text */
- if (string_count > 0) {
- fm_write(&emr_selectobject_font, sizeof(emr_selectobject_t), 1, fmp);
- fm_write(&emr_settextcolor, sizeof(emr_settextcolor_t), 1, fmp);
- }
- current_fsize = fsize;
- current_halign = -1;
- for (i = 0; i < string_count; i++) {
- if (text_fsizes[i] != current_fsize) {
- current_fsize = text_fsizes[i];
- fm_write(&emr_selectobject_font2, sizeof(emr_selectobject_t), 1, fmp);
- }
- if (text_haligns[i] != current_halign) {
- current_halign = text_haligns[i];
- if (current_halign == 0) {
- fm_write(&emr_settextalign_centre, sizeof(emr_settextalign_t), 1, fmp);
- } else if (current_halign == 1) {
- fm_write(&emr_settextalign_left, sizeof(emr_settextalign_t), 1, fmp);
- } else {
- fm_write(&emr_settextalign_right, sizeof(emr_settextalign_t), 1, fmp);
- }
- }
- fm_write(&text[i], sizeof(emr_exttextoutw_t), 1, fmp);
- fm_write(this_string[i], text_bumped_lens[i], 1, fmp);
- free(this_string[i]);
- }
- fm_write(&emr_eof, sizeof(emr_eof_t), 1, fmp);
- if (fm_error(fmp)) {
- errtxtf(0, symbol, 644, "Incomplete write of EMF output (%1$d: %2$s)", fmp->err, strerror(fmp->err));
- (void) fm_close(fmp, symbol);
- return ZINT_ERROR_FILE_WRITE;
- }
- if (!fm_close(fmp, symbol)) {
- return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 941, "Failure on closing EMF output file (%1$d: %2$s)",
- fmp->err, strerror(fmp->err));
- }
- return error_number;
- }
- /* vim: set ts=4 sw=4 et : */
|