#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include "common.h"
#include "filemem.h"
#include "output.h"
#include "emf.h"
#define emf_mul3dpf(m, arg) z_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;
}
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) {
if (*fsize == 0.0f) {
*fsize = string->fsize;
} else if (string->fsize != *fsize && *fsize2 == 0.0f) {
*fsize2 = string->fsize;
}
if (string->halign) {
if (string->halign == 1) {
*halign_left = string->halign;
} else {
*halign_right = string->halign;
}
}
strings++;
string = string->next;
}
return strings;
}
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) {
output[o] = input[i];
output[o + 1] = 0x00;
o += 2;
i++;
} else {
output[o] = ((input[i] & 0x1f) << 6) + (input[i + 1] & 0x3f);
output[o + 1] = 0x00;
o += 2;
i += 2;
}
} while (i < length);
}
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) {
i++;
}
}
return result;
}
INTERNAL int zint_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;
int frame_cmmx, frame_cmmy;
int device_pxx, device_pxy;
int mmx, mmy;
int micronx, microny;
const float dpmm = symbol->dpmm ? z_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 is_upcean = z_is_upcean(symbol->symbology);
struct zint_vector_rect *rect;
struct zint_vector_circle *circ;
struct zint_vector_hexagon *hex;
struct zint_vector_string *string;
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];
emr_selectobject_t emr_selectobject_fgbrush;
emr_selectobject_t emr_selectobject_bgbrush;
emr_selectobject_t emr_selectobject_colour[9];
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;
int halign_left;
emr_settextalign_t emr_settextalign_left;
int halign_right;
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 z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 643, "Vector header NULL");
}
(void) zint_out_colour_get_rgb(symbol->fgcolour, &fgred, &fggrn, &fgblu, NULL );
(void) zint_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);
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));
if (symbol->symbology == BARCODE_ULTRA) {
rect = symbol->vector->rectangles;
while (rect) {
if (rect->colour == -1) {
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;
bounds_pxy = height - 1;
device_pxx = width;
device_pxy = height;
if (dpmm) {
frame_cmmx = (int) roundf(z_stripf(width * 100.0f / dpmm)) - 1;
frame_cmmy = (int) roundf(z_stripf(height * 100.0f / dpmm)) - 1;
mmx = (int) roundf(z_stripf(width / dpmm));
mmy = (int) roundf(z_stripf(height / dpmm));
micronx = (int) roundf(z_stripf(width * 1000.0f / dpmm));
microny = (int) roundf(z_stripf(height * 1000.0f / dpmm));
} else {
frame_cmmx = (int) roundf(z_stripf(width * 100.0f)) - 1;
frame_cmmy = (int) roundf(z_stripf(height * 100.0f)) - 1;
mmx = (int) roundf(z_stripf(width));
mmy = (int) roundf(z_stripf(height));
micronx = (int) roundf(z_stripf(width * 1000.0f));
microny = (int) roundf(z_stripf(height * 1000.0f));
}
zint_out_le_u32(emr_header.type, 0x00000001);
zint_out_le_u32(emr_header.size, 108);
zint_out_le_i32(emr_header.emf_header.bounds.left, 0);
zint_out_le_i32(emr_header.emf_header.bounds.top, 0);
zint_out_le_i32(emr_header.emf_header.bounds.right, sideways ? bounds_pxy : bounds_pxx);
zint_out_le_i32(emr_header.emf_header.bounds.bottom, sideways ? bounds_pxx : bounds_pxy);
zint_out_le_i32(emr_header.emf_header.frame.left, 0);
zint_out_le_i32(emr_header.emf_header.frame.top, 0);
zint_out_le_i32(emr_header.emf_header.frame.right, sideways ? frame_cmmy : frame_cmmx);
zint_out_le_i32(emr_header.emf_header.frame.bottom, sideways ? frame_cmmx : frame_cmmy);
zint_out_le_u32(emr_header.emf_header.record_signature, 0x464d4520);
zint_out_le_u32(emr_header.emf_header.version, 0x00010000);
zint_out_le_u16(emr_header.emf_header.handles, (fsize2 != 0.0f ? 5 : 4) + ih_ultra_offset);
zint_out_le_u16(emr_header.emf_header.reserved, 0x0000);
zint_out_le_u32(emr_header.emf_header.n_description, 0);
zint_out_le_u32(emr_header.emf_header.off_description, 0);
zint_out_le_u32(emr_header.emf_header.n_pal_entries, 0);
zint_out_le_u32(emr_header.emf_header.device.cx, sideways ? device_pxy : device_pxx);
zint_out_le_u32(emr_header.emf_header.device.cy, sideways ? device_pxx : device_pxy);
zint_out_le_u32(emr_header.emf_header.millimeters.cx, sideways ? mmy : mmx);
zint_out_le_u32(emr_header.emf_header.millimeters.cy, sideways ? mmx : mmy);
zint_out_le_u32(emr_header.emf_header.cb_pixel_format, 0x0000);
zint_out_le_u32(emr_header.emf_header.off_pixel_format, 0x0000);
zint_out_le_u32(emr_header.emf_header.b_open_gl, 0x0000);
zint_out_le_u32(emr_header.emf_header.micrometers.cx, sideways ? microny : micronx);
zint_out_le_u32(emr_header.emf_header.micrometers.cy, sideways ? micronx : microny);
bytecount = 108;
recordcount = 1;
zint_out_le_u32(emr_mapmode.type, 0x00000011);
zint_out_le_u32(emr_mapmode.size, 12);
zint_out_le_u32(emr_mapmode.mapmode, 0x01);
bytecount += 12;
recordcount++;
if (rotate_angle) {
zint_out_le_u32(emr_setworldtransform.type, 0x00000023);
zint_out_le_u32(emr_setworldtransform.size, 32);
zint_out_le_float(emr_setworldtransform.m11, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? -1.0f : 0.0f);
zint_out_le_float(emr_setworldtransform.m12, rotate_angle == 90 ? 1.0f : rotate_angle == 180 ? 0.0f : -1.0f);
zint_out_le_float(emr_setworldtransform.m21, rotate_angle == 90 ? -1.0f : rotate_angle == 180 ? 0.0f : 1.0f);
zint_out_le_float(emr_setworldtransform.m22, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? -1.0f : 0.0f);
zint_out_le_float(emr_setworldtransform.dx, rotate_angle == 90 ? height : rotate_angle == 180 ? width : 0.0f);
zint_out_le_float(emr_setworldtransform.dy, rotate_angle == 90 ? 0.0f : rotate_angle == 180 ? height : width);
bytecount += 32;
recordcount++;
}
zint_out_le_u32(emr_createbrushindirect_bg.type, 0x00000027);
zint_out_le_u32(emr_createbrushindirect_bg.size, 24);
zint_out_le_u32(emr_createbrushindirect_bg.ih_brush, 0);
zint_out_le_u32(emr_createbrushindirect_bg.log_brush.brush_style, 0x0000);
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;
zint_out_le_u32(emr_createbrushindirect_bg.log_brush.brush_hatch, 0x0006);
bytecount += 24;
recordcount++;
if (symbol->symbology == BARCODE_ULTRA) {
static const unsigned char ultra_chars[9] = { '0', 'C', 'B', 'M', 'R', 'Y', 'G', 'K', 'W' };
for (i = 0; i < 9; i++) {
zint_out_le_u32(emr_createbrushindirect_colour[i].type, 0x00000027);
zint_out_le_u32(emr_createbrushindirect_colour[i].size, 24);
zint_out_le_u32(emr_createbrushindirect_colour[i].ih_brush, 1 + i);
zint_out_le_u32(emr_createbrushindirect_colour[i].log_brush.brush_style, 0x0000);
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 {
zint_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;
zint_out_le_u32(emr_createbrushindirect_colour[i].log_brush.brush_hatch, 0x0006);
}
bytecount += colours_used * 24;
recordcount += colours_used;
} else {
zint_out_le_u32(emr_createbrushindirect_fg.type, 0x00000027);
zint_out_le_u32(emr_createbrushindirect_fg.size, 24);
zint_out_le_u32(emr_createbrushindirect_fg.ih_brush, 1);
zint_out_le_u32(emr_createbrushindirect_fg.log_brush.brush_style, 0x0000);
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;
zint_out_le_u32(emr_createbrushindirect_fg.log_brush.brush_hatch, 0x0006);
bytecount += 24;
recordcount++;
}
zint_out_le_u32(emr_selectobject_bgbrush.type, 0x00000025);
zint_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++) {
zint_out_le_u32(emr_selectobject_colour[i].type, 0x00000025);
zint_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 {
zint_out_le_u32(emr_selectobject_fgbrush.type, 0x00000025);
zint_out_le_u32(emr_selectobject_fgbrush.size, 12);
emr_selectobject_fgbrush.ih_object = emr_createbrushindirect_fg.ih_brush;
bytecount += 12;
recordcount++;
}
zint_out_le_u32(emr_createpen.type, 0x00000026);
zint_out_le_u32(emr_createpen.size, 28);
zint_out_le_u32(emr_createpen.ih_pen, 2 + ih_ultra_offset);
zint_out_le_u32(emr_createpen.log_pen.pen_style, 0x00000005);
zint_out_le_i32(emr_createpen.log_pen.width.x, 1);
zint_out_le_i32(emr_createpen.log_pen.width.y, 0);
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++;
zint_out_le_u32(emr_selectobject_pen.type, 0x00000025);
zint_out_le_u32(emr_selectobject_pen.size, 12);
emr_selectobject_pen.ih_object = emr_createpen.ih_pen;
bytecount += 12;
recordcount++;
if (draw_background) {
zint_out_le_u32(background.type, 0x0000002b);
zint_out_le_u32(background.size, 24);
zint_out_le_i32(background.box.top, 0);
zint_out_le_i32(background.box.left, 0);
zint_out_le_i32(background.box.right, width);
zint_out_le_i32(background.box.bottom, height);
bytecount += 24;
recordcount++;
}
rect = symbol->vector->rectangles;
this_rectangle = 0;
while (rect) {
zint_out_le_u32(rectangle[this_rectangle].type, 0x0000002b);
zint_out_le_u32(rectangle[this_rectangle].size, 24);
zint_out_le_i32(rectangle[this_rectangle].box.top, rect->y);
zint_out_le_i32(rectangle[this_rectangle].box.bottom, z_stripf(rect->y + rect->height));
zint_out_le_i32(rectangle[this_rectangle].box.left, rect->x);
zint_out_le_i32(rectangle[this_rectangle].box.right, z_stripf(rect->x + rect->width));
this_rectangle++;
bytecount += 24;
recordcount++;
rect = rect->next;
}
previous_diameter = radius = 0.0f;
circ = symbol->vector->circles;
this_circle = 0;
while (circ) {
if (previous_diameter != circ->diameter + circ->width) {
previous_diameter = circ->diameter + circ->width;
radius = emf_mul3dpf(0.5f, previous_diameter);
}
zint_out_le_u32(circle[this_circle].type, 0x0000002a);
zint_out_le_u32(circle[this_circle].size, 24);
zint_out_le_i32(circle[this_circle].box.top, z_stripf(circ->y - radius));
zint_out_le_i32(circle[this_circle].box.bottom, z_stripf(circ->y + radius));
zint_out_le_i32(circle[this_circle].box.left, z_stripf(circ->x - radius));
zint_out_le_i32(circle[this_circle].box.right, z_stripf(circ->x + radius));
this_circle++;
bytecount += 24;
recordcount++;
if (symbol->symbology == BARCODE_MAXICODE) {
float inner_radius = radius - circ->width;
zint_out_le_u32(circle[this_circle].type, 0x0000002a);
zint_out_le_u32(circle[this_circle].size, 24);
zint_out_le_i32(circle[this_circle].box.top, z_stripf(circ->y - inner_radius));
zint_out_le_i32(circle[this_circle].box.bottom, z_stripf(circ->y + inner_radius));
zint_out_le_i32(circle[this_circle].box.left, z_stripf(circ->x - inner_radius));
zint_out_le_i32(circle[this_circle].box.right, z_stripf(circ->x + inner_radius));
this_circle++;
bytecount += 24;
recordcount++;
}
circ = circ->next;
}
previous_diameter = radius = half_radius = half_sqrt3_radius = 0.0f;
hex = symbol->vector->hexagons;
this_hexagon = 0;
while (hex) {
zint_out_le_u32(hexagon[this_hexagon].type, 0x00000003);
zint_out_le_u32(hexagon[this_hexagon].size, 76);
zint_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);
}
zint_out_le_i32(hexagon[this_hexagon].a_points_a.x, hex->x);
zint_out_le_i32(hexagon[this_hexagon].a_points_a.y, z_stripf(hex->y + radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_b.x, z_stripf(hex->x + half_sqrt3_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_b.y, z_stripf(hex->y + half_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_c.x, z_stripf(hex->x + half_sqrt3_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_c.y, z_stripf(hex->y - half_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_d.x, hex->x);
zint_out_le_i32(hexagon[this_hexagon].a_points_d.y, z_stripf(hex->y - radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_e.x, z_stripf(hex->x - half_sqrt3_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_e.y, z_stripf(hex->y - half_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_f.x, z_stripf(hex->x - half_sqrt3_radius));
zint_out_le_i32(hexagon[this_hexagon].a_points_f.y, z_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;
}
if (symbol->vector->strings) {
bold = (symbol->output_options & BOLD_TEXT) && !z_is_upcean(symbol->symbology);
memset(&emr_extcreatefontindirectw, 0, sizeof(emr_extcreatefontindirectw));
zint_out_le_u32(emr_extcreatefontindirectw.type, 0x00000052);
zint_out_le_u32(emr_extcreatefontindirectw.size, 104);
zint_out_le_u32(emr_extcreatefontindirectw.ih_fonts, 3 + ih_ultra_offset);
zint_out_le_i32(emr_extcreatefontindirectw.elw.height, fsize);
zint_out_le_i32(emr_extcreatefontindirectw.elw.width, 0);
zint_out_le_i32(emr_extcreatefontindirectw.elw.weight, bold ? 700 : 400);
emr_extcreatefontindirectw.elw.char_set = 0x00;
emr_extcreatefontindirectw.elw.out_precision = 0x00;
emr_extcreatefontindirectw.elw.clip_precision = 0x00;
emr_extcreatefontindirectw.elw.pitch_and_family = 0x02 | (0x02 << 6);
emf_utfle_copy(emr_extcreatefontindirectw.elw.facename, (const unsigned char *) "sans-serif", 10);
bytecount += 104;
recordcount++;
zint_out_le_u32(emr_selectobject_font.type, 0x00000025);
zint_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));
zint_out_le_u32(emr_extcreatefontindirectw2.ih_fonts, 4 + ih_ultra_offset);
zint_out_le_i32(emr_extcreatefontindirectw2.elw.height, fsize2);
bytecount += 104;
recordcount++;
zint_out_le_u32(emr_selectobject_font2.type, 0x00000025);
zint_out_le_u32(emr_selectobject_font2.size, 12);
emr_selectobject_font2.ih_object = emr_extcreatefontindirectw2.ih_fonts;
bytecount += 12;
recordcount++;
}
zint_out_le_u32(emr_settextalign_centre.type, 0x00000016);
zint_out_le_u32(emr_settextalign_centre.size, 12);
zint_out_le_u32(emr_settextalign_centre.text_alignment_mode, 0x0006 | 0x0018);
if (halign_left) {
zint_out_le_u32(emr_settextalign_left.type, 0x00000016);
zint_out_le_u32(emr_settextalign_left.size, 12);
zint_out_le_u32(emr_settextalign_left.text_alignment_mode, 0x0000 | 0x0018);
}
if (halign_right) {
zint_out_le_u32(emr_settextalign_right.type, 0x00000016);
zint_out_le_u32(emr_settextalign_right.size, 12);
zint_out_le_u32(emr_settextalign_right.text_alignment_mode, 0x0002 | 0x0018);
}
zint_out_le_u32(emr_settextcolor.type, 0x0000018);
zint_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++;
}
this_text = 0;
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 z_errtxt(ZINT_ERROR_MEMORY, symbol, 641, "Insufficient memory for EMF string buffer");
}
memset(this_string[this_text], 0, text_bumped_lens[this_text]);
zint_out_le_u32(text[this_text].type, 0x00000054);
zint_out_le_u32(text[this_text].size, 76 + text_bumped_lens[this_text]);
zint_out_le_i32(text[this_text].bounds.top, 0);
zint_out_le_i32(text[this_text].bounds.left, 0);
zint_out_le_i32(text[this_text].bounds.right, 0xffffffff);
zint_out_le_i32(text[this_text].bounds.bottom, 0xffffffff);
zint_out_le_u32(text[this_text].i_graphics_mode, 0x00000002);
zint_out_le_float(text[this_text].ex_scale, 1.0f);
zint_out_le_float(text[this_text].ey_scale, 1.0f);
if (is_upcean && string->halign == 1 && string->text[0] == '<') {
const float gws_left_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale;
zint_out_le_i32(text[this_text].w_emr_text.reference.x, string->x + gws_left_fudge);
} else if (is_upcean && string->halign == 2 && string->text[0] == '>') {
const float gws_right_fudge = symbol->scale < 0.1f ? 0.1f : symbol->scale;
zint_out_le_i32(text[this_text].w_emr_text.reference.x, string->x - gws_right_fudge);
} else {
zint_out_le_i32(text[this_text].w_emr_text.reference.x, string->x);
}
zint_out_le_i32(text[this_text].w_emr_text.reference.y, string->y);
zint_out_le_u32(text[this_text].w_emr_text.chars, utfle_len);
zint_out_le_u32(text[this_text].w_emr_text.off_string, 76);
zint_out_le_u32(text[this_text].w_emr_text.options, 0);
zint_out_le_i32(text[this_text].w_emr_text.rectangle.top, 0);
zint_out_le_i32(text[this_text].w_emr_text.rectangle.left, 0);
zint_out_le_i32(text[this_text].w_emr_text.rectangle.right, 0xffffffff);
zint_out_le_i32(text[this_text].w_emr_text.rectangle.bottom, 0xffffffff);
zint_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;
}
}
assert(this_text == string_count);
zint_out_le_u32(emr_eof.type, 0x0000000e);
zint_out_le_u32(emr_eof.size, 20);
zint_out_le_u32(emr_eof.n_pal_entries, 0);
zint_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;
}
zint_out_le_u32(emr_header.emf_header.bytes, bytecount);
zint_out_le_u32(emr_header.emf_header.records, recordcount);
if (!zint_fm_open(fmp, symbol, "wb")) {
return ZEXT z_errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 640, "Could not open EMF output file (%1$d: %2$s)",
fmp->err, strerror(fmp->err));
}
zint_fm_write(&emr_header, sizeof(emr_header_t), 1, fmp);
zint_fm_write(&emr_mapmode, sizeof(emr_mapmode_t), 1, fmp);
if (rotate_angle) {
zint_fm_write(&emr_setworldtransform, sizeof(emr_setworldtransform_t), 1, fmp);
}
zint_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]) {
zint_fm_write(&emr_createbrushindirect_colour[i], sizeof(emr_createbrushindirect_t), 1, fmp);
}
}
} else {
zint_fm_write(&emr_createbrushindirect_fg, sizeof(emr_createbrushindirect_t), 1, fmp);
}
zint_fm_write(&emr_createpen, sizeof(emr_createpen_t), 1, fmp);
if (symbol->vector->strings) {
zint_fm_write(&emr_extcreatefontindirectw, sizeof(emr_extcreatefontindirectw_t), 1, fmp);
if (fsize2) {
zint_fm_write(&emr_extcreatefontindirectw2, sizeof(emr_extcreatefontindirectw_t), 1, fmp);
}
}
zint_fm_write(&emr_selectobject_bgbrush, sizeof(emr_selectobject_t), 1, fmp);
zint_fm_write(&emr_selectobject_pen, sizeof(emr_selectobject_t), 1, fmp);
if (draw_background) {
zint_fm_write(&background, sizeof(emr_rectangle_t), 1, fmp);
}
if (symbol->symbology == BARCODE_ULTRA) {
for (i = 0; i < 9; i++) {
if (rectangle_bycolour[i]) {
zint_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) {
zint_fm_write(&rectangle[this_rectangle], sizeof(emr_rectangle_t), 1, fmp);
}
this_rectangle++;
rect = rect->next;
}
}
}
} else {
zint_fm_write(&emr_selectobject_fgbrush, sizeof(emr_selectobject_t), 1, fmp);
for (i = 0; i < rectangle_count; i++) {
zint_fm_write(&rectangle[i], sizeof(emr_rectangle_t), 1, fmp);
}
}
for (i = 0; i < hexagon_count; i++) {
zint_fm_write(&hexagon[i], sizeof(emr_polygon_t), 1, fmp);
}
if (symbol->symbology == BARCODE_MAXICODE) {
for (i = 0; i < circle_count; i++) {
zint_fm_write(&circle[i], sizeof(emr_ellipse_t), 1, fmp);
if (i < circle_count - 1) {
if (i % 2) {
zint_fm_write(&emr_selectobject_fgbrush, sizeof(emr_selectobject_t), 1, fmp);
} else {
zint_fm_write(&emr_selectobject_bgbrush, sizeof(emr_selectobject_t), 1, fmp);
}
}
}
} else {
for (i = 0; i < circle_count; i++) {
zint_fm_write(&circle[i], sizeof(emr_ellipse_t), 1, fmp);
}
}
if (string_count > 0) {
zint_fm_write(&emr_selectobject_font, sizeof(emr_selectobject_t), 1, fmp);
zint_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];
zint_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) {
zint_fm_write(&emr_settextalign_centre, sizeof(emr_settextalign_t), 1, fmp);
} else if (current_halign == 1) {
zint_fm_write(&emr_settextalign_left, sizeof(emr_settextalign_t), 1, fmp);
} else {
zint_fm_write(&emr_settextalign_right, sizeof(emr_settextalign_t), 1, fmp);
}
}
zint_fm_write(&text[i], sizeof(emr_exttextoutw_t), 1, fmp);
zint_fm_write(this_string[i], text_bumped_lens[i], 1, fmp);
free(this_string[i]);
}
zint_fm_write(&emr_eof, sizeof(emr_eof_t), 1, fmp);
if (zint_fm_error(fmp)) {
ZEXT z_errtxtf(0, symbol, 644, "Incomplete write of EMF output (%1$d: %2$s)", fmp->err, strerror(fmp->err));
(void) zint_fm_close(fmp, symbol);
return ZINT_ERROR_FILE_WRITE;
}
if (!zint_fm_close(fmp, symbol)) {
return ZEXT z_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;
}