diff options
| author | Martin Owens <doctormo@gmail.com> | 2013-08-30 00:13:57 +0000 |
|---|---|---|
| committer | Martin Owens <doctormo@gmail.com> | 2013-08-30 00:13:57 +0000 |
| commit | 4e5d08311dc4a19a020fc678020e782c85f3d209 (patch) | |
| tree | 202c9f36ac51152a97a174a6f8a843692e951a5c /src/extension | |
| parent | Updating outdated test. Fixes bug #1202271. (diff) | |
| parent | fix make check (POTFILES.in) (diff) | |
| download | inkscape-4e5d08311dc4a19a020fc678020e782c85f3d209.tar.gz inkscape-4e5d08311dc4a19a020fc678020e782c85f3d209.zip | |
Merge emf/wmf work
(bzr r12488)
Diffstat (limited to 'src/extension')
31 files changed, 41207 insertions, 3697 deletions
diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index 4507d9ce2..e3e15a19f 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -37,8 +37,8 @@ set(extension_SRC internal/cairo-renderer.cpp internal/cairo-renderer-pdf-out.cpp internal/cdr-input.cpp - internal/emf-win32-inout.cpp - internal/emf-win32-print.cpp + internal/emf-inout.cpp + internal/emf-print.cpp internal/gdkpixbuf-input.cpp internal/gimpgrad.cpp internal/grid.cpp @@ -53,6 +53,8 @@ set(extension_SRC internal/svg.cpp internal/svgz.cpp internal/vsd-input.cpp + internal/wmf-inout.cpp + internal/wmf-print.cpp internal/filter/filter-all.cpp internal/filter/filter-file.cpp @@ -101,8 +103,8 @@ set(extension_SRC internal/cairo-renderer.h internal/cdr-input.h internal/clear-n_.h - internal/emf-win32-inout.h - internal/emf-win32-print.h + internal/emf-inout.h + internal/emf-print.h internal/filter/bevels.h internal/filter/blurs.h internal/filter/bumps.h @@ -134,6 +136,8 @@ set(extension_SRC internal/svg.h internal/svgz.h internal/vsd-input.h + internal/wmf-inout.h + internal/wmf-print.h ) if(WIN32) diff --git a/src/extension/init.cpp b/src/extension/init.cpp index d403d270f..1a163d4c2 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -34,10 +34,10 @@ #include "system.h" #include "db.h" #include "internal/svgz.h" -#ifdef WIN32 -# include "internal/emf-win32-inout.h" -# include "internal/emf-win32-print.h" -#endif +# include "internal/emf-inout.h" +# include "internal/emf-print.h" +# include "internal/wmf-inout.h" +# include "internal/wmf-print.h" #ifdef HAVE_CAIRO_PDF # include "internal/cairo-renderer-pdf-out.h" # include "internal/cairo-png-out.h" @@ -181,10 +181,10 @@ init() Internal::PdfInputCairo::init(); } #endif -#ifdef WIN32 - Internal::PrintEmfWin32::init(); - Internal::EmfWin32::init(); -#endif + Internal::PrintEmf::init(); + Internal::Emf::init(); + Internal::PrintWmf::init(); + Internal::Wmf::init(); Internal::PovOutput::init(); Internal::JavaFXOutput::init(); Internal::OdfOutput::init(); @@ -324,7 +324,7 @@ build_module_from_dir(gchar const *dirname) continue; } - gchar *pathname = g_build_filename(dirname, filename, NULL); + gchar *pathname = g_build_filename(dirname, filename, (char *) NULL); build_from_file(pathname); g_free(pathname); } diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index 9e55598df..341973870 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -156,10 +156,26 @@ ink_common_sources += \ extension/internal/filter/filter-file.cpp \ extension/internal/filter/filter.cpp \ extension/internal/filter/filter.h \ - extension/internal/emf-win32-print.h \ - extension/internal/emf-win32-print.cpp \ - extension/internal/emf-win32-inout.h \ - extension/internal/emf-win32-inout.cpp \ + extension/internal/text_reassemble.c \ + extension/internal/text_reassemble.h \ + extension/internal/uemf.c \ + extension/internal/uemf.h \ + extension/internal/uemf_utf.c \ + extension/internal/uemf_utf.h \ + extension/internal/uemf_endian.c \ + extension/internal/uemf_endian.h \ + extension/internal/uwmf.c \ + extension/internal/uwmf.h \ + extension/internal/uwmf_endian.c \ + extension/internal/uwmf_endian.h \ + extension/internal/emf-print.h \ + extension/internal/emf-print.cpp \ + extension/internal/emf-inout.h \ + extension/internal/emf-inout.cpp \ + extension/internal/wmf-print.h \ + extension/internal/wmf-print.cpp \ + extension/internal/wmf-inout.h \ + extension/internal/wmf-inout.cpp \ extension/internal/image-resolution.h \ extension/internal/image-resolution.cpp diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp new file mode 100644 index 000000000..9dba3b77c --- /dev/null +++ b/src/extension/internal/emf-inout.cpp @@ -0,0 +1,3549 @@ +/** @file + * @brief Windows-only Enhanced Metafile input and output. + */ +/* Authors: + * Ulf Erikson <ulferikson@users.sf.net> + * Jon A. Cruz <jon@joncruz.org> + * Abhishek Sharma + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + * + * References: + * - How to Create & Play Enhanced Metafiles in Win32 + * http://support.microsoft.com/kb/q145999/ + * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles + * http://support.microsoft.com/kb/q66949/ + * - Metafile Functions + * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp + * - Metafile Structures + * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#define EMF_DRIVER // work around for SPStyle issue +#include "sp-root.h" +#include "sp-path.h" +#include "style.h" +#include "print.h" +#include "extension/system.h" +#include "extension/print.h" +#include "extension/db.h" +#include "extension/input.h" +#include "extension/output.h" +#include "display/drawing.h" +#include "display/drawing-item.h" +#include "clear-n_.h" +#include "document.h" +#include "libunicode-convert/unicode-convert.h" +#include "util/units.h" + +#include "emf-print.h" +#include "emf-inout.h" + +#define PRINT_EMF "org.inkscape.print.emf" + +#ifndef U_PS_JOIN_MASK +#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND) +#endif + +namespace Inkscape { +namespace Extension { +namespace Internal { + +static U_RECTL rc_old = rectl_set(pointl_set(-1,-1),pointl_set(-1,-1)); +static bool clipset = false; +static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented +static uint32_t BLTmode = 0; + +/** Construct a PNG in memory from an RGB from the EMF file + +from: +http://www.lemoda.net/c/write-png/ + +which was based on: +http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng + +gcc -Wall -o testpng testpng.c -lpng + +Originally here, but moved up + +#include <png.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +*/ + + +/* Given "bitmap", this returns the pixel of bitmap at the point + ("x", "y"). */ + +pixel_t * Emf::pixel_at (bitmap_t * bitmap, int x, int y) +{ + return bitmap->pixels + bitmap->width * y + x; +} + + +/* Write "bitmap" to a PNG file specified by "path"; returns 0 on + success, non-zero on error. */ + +void +Emf::my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + PMEMPNG p=(PMEMPNG)png_get_io_ptr(png_ptr); + + size_t nsize = p->size + length; + + /* allocate or grow buffer */ + if(p->buffer){ p->buffer = (char *) realloc(p->buffer, nsize); } + else{ p->buffer = (char *) malloc(nsize); } + + if(!p->buffer){ png_error(png_ptr, "Write Error"); } + + /* copy new bytes to end of buffer */ + memcpy(p->buffer + p->size, data, length); + p->size += length; +} + +void Emf::toPNG(PMEMPNG accum, int width, int height, const char *px){ + bitmap_t bmStore; + bitmap_t *bitmap = &bmStore; + accum->buffer=NULL; // PNG constructed in memory will end up here, caller must free(). + accum->size=0; + bitmap->pixels=(pixel_t *)px; + bitmap->width = width; + bitmap->height = height; + + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + size_t x, y; + png_byte ** row_pointers = NULL; + /* The following number is set by trial and error only. I cannot + see where it it is documented in the libpng manual. + */ + int pixel_size = 3; + int depth = 8; + + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL){ + accum->buffer=NULL; + return; + } + + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL){ + png_destroy_write_struct (&png_ptr, &info_ptr); + accum->buffer=NULL; + return; + } + + /* Set up error handling. */ + + if (setjmp (png_jmpbuf (png_ptr))) { + png_destroy_write_struct (&png_ptr, &info_ptr); + accum->buffer=NULL; + return; + } + + /* Set image attributes. */ + + png_set_IHDR ( + png_ptr, + info_ptr, + bitmap->width, + bitmap->height, + depth, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT + ); + + /* Initialize rows of PNG. */ + + row_pointers = (png_byte **) png_malloc (png_ptr, bitmap->height * sizeof (png_byte *)); + for (y = 0; y < bitmap->height; ++y) { + png_byte *row = + (png_byte *) png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size); + row_pointers[bitmap->height - y - 1] = row; // Row order in EMF is reversed. + for (x = 0; x < bitmap->width; ++x) { + pixel_t * pixel = pixel_at (bitmap, x, y); + *row++ = pixel->red; // R & B channels were set correctly by DIB_to_RGB + *row++ = pixel->green; + *row++ = pixel->blue; + } + } + + /* Write the image data to memory */ + + png_set_rows (png_ptr, info_ptr, row_pointers); + + png_set_write_fn(png_ptr, accum, my_png_write_data, NULL); + + png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + for (y = 0; y < bitmap->height; y++) { + png_free (png_ptr, row_pointers[y]); + } + png_free (png_ptr, row_pointers); + png_destroy_write_struct(&png_ptr, &info_ptr); + +} + + +/* convert an EMF RGB(A) color to 0RGB +inverse of gethexcolor() in emf-print.cpp +*/ +uint32_t Emf::sethexcolor(U_COLORREF color){ + + uint32_t out; + out = (U_RGBAGetR(color) << 16) + + (U_RGBAGetG(color) << 8 ) + + (U_RGBAGetB(color) ); + return(out); +} + + +Emf::Emf (void) // The null constructor +{ + return; +} + + +Emf::~Emf (void) //The destructor +{ + return; +} + + +bool +Emf::check (Inkscape::Extension::Extension * /*module*/) +{ + if (NULL == Inkscape::Extension::db.get(PRINT_EMF)) + return FALSE; + return TRUE; +} + + +void +Emf::print_document_to_file(SPDocument *doc, const gchar *filename) +{ + Inkscape::Extension::Print *mod; + SPPrintContext context; + const gchar *oldconst; + gchar *oldoutput; + unsigned int ret; + + doc->ensureUpToDate(); + + mod = Inkscape::Extension::get_print(PRINT_EMF); + oldconst = mod->get_param_string("destination"); + oldoutput = g_strdup(oldconst); + mod->set_param_string("destination", filename); + +/* Start */ + context.module = mod; + /* fixme: This has to go into module constructor somehow */ + /* Create new arena */ + mod->base = doc->getRoot(); + Inkscape::Drawing drawing; + mod->dkey = SPItem::display_key_new(1); + mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(mod->root); + /* Print document */ + ret = mod->begin(doc); + if (ret) { + g_free(oldoutput); + throw Inkscape::Extension::Output::save_failed(); + } + mod->base->invoke_print(&context); + ret = mod->finish(); + /* Release arena */ + mod->base->invoke_hide(mod->dkey); + mod->base = NULL; + mod->root = NULL; // deleted by invoke_hide +/* end */ + + mod->set_param_string("destination", oldoutput); + g_free(oldoutput); + + return; +} + + +void +Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) +{ + Inkscape::Extension::Extension * ext; + + ext = Inkscape::Extension::db.get(PRINT_EMF); + if (ext == NULL) + return; + + bool new_val = mod->get_param_bool("textToPath"); + bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug + // reserve FixPPT2 for opacity bug. Currently EMF does not export opacity values + bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug + bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug + bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard EMF hatch + bool new_FixImageRot = mod->get_param_bool("FixImageRot"); // remove rotations on images + + TableGen( //possibly regenerate the unicode-convert tables + mod->get_param_bool("TnrToSymbol"), + mod->get_param_bool("TnrToWingdings"), + mod->get_param_bool("TnrToZapfDingbats"), + mod->get_param_bool("UsePUA") + ); + + ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result! + ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine); + ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys); + ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch); + ext->set_param_bool("FixImageRot",new_FixImageRot); + ext->set_param_bool("textToPath", new_val); + + print_document_to_file(doc, filename); + + return; +} + + +enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE}; // apply to either fill or stroke + + + +/* given the transformation matrix from worldTranform return the scale in the matrix part. Assumes that the + matrix is not used to skew, invert, or make another distorting transformation. */ +double Emf::current_scale(PEMF_CALLBACK_DATA d){ + double scale = + d->dc[d->level].worldTransform.eM11 * d->dc[d->level].worldTransform.eM22 - + d->dc[d->level].worldTransform.eM12 * d->dc[d->level].worldTransform.eM21; + if(scale <= 0.0)scale=1.0; /* something is dreadfully wrong with the matrix, but do not crash over it */ + scale=sqrt(scale); + return(scale); +} + +/* given the transformation matrix from worldTranform and the current x,y position in inkscape coordinates, + generate an SVG transform that gives the same amount of rotation, no scaling, and maps x,y back onto x,y. This is used for + rotating objects when the location of at least one point in that object is known. Returns: + "matrix(a,b,c,d,e,f)" (WITH the double quotes) +*/ +std::string Emf::current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset){ + std::stringstream cxform; + double scale = current_scale(d); + cxform << "\"matrix("; + cxform << d->dc[d->level].worldTransform.eM11/scale; cxform << ","; + cxform << d->dc[d->level].worldTransform.eM12/scale; cxform << ","; + cxform << d->dc[d->level].worldTransform.eM21/scale; cxform << ","; + cxform << d->dc[d->level].worldTransform.eM22/scale; cxform << ","; + if(useoffset){ + /* for the "new" coordinates drop the worldtransform translations, not used here */ + double newx = x * d->dc[d->level].worldTransform.eM11/scale + y * d->dc[d->level].worldTransform.eM21/scale; + double newy = x * d->dc[d->level].worldTransform.eM12/scale + y * d->dc[d->level].worldTransform.eM22/scale; + cxform << x - newx; cxform << ","; + cxform << y - newy; + } + else { + cxform << "0,0"; + } + cxform << ")\""; + return(cxform.str()); +} + +/* given the transformation matrix from worldTranform return the rotation angle in radians. + counter clocwise from the x axis. */ +double Emf::current_rotation(PEMF_CALLBACK_DATA d){ + return -std::atan2(d->dc[d->level].worldTransform.eM12, d->dc[d->level].worldTransform.eM11); +} + +/* Add another 100 blank slots to the hatches array. +*/ +void Emf::enlarge_hatches(PEMF_CALLBACK_DATA d){ + d->hatches.size += 100; + d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *)); +} + +/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) +*/ +int Emf::in_hatches(PEMF_CALLBACK_DATA d, char *test){ + int i; + for(i=0; i<d->hatches.count; i++){ + if(strcmp(test,d->hatches.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one + does not exist it is added to the hatches list and also entered into <defs>. + This is also used to add the path part of the hatches, which they reference with a xlink:href +*/ +uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){ + char hatchname[64]; // big enough + char hpathname[64]; // big enough + char hbkname[64]; // big enough + char tmpcolor[8]; + char bkcolor[8]; + uint32_t idx; + + switch(hatchType){ + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor)); + break; + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor)); + break; + default: + sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor)); + break; + } + + /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch. + This will be used late to compose, or recompose the transparent or opaque final hatch.*/ + + std::string refpath; // used to reference later the path pieces which are about to be created + sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor); + idx = in_hatches(d,hpathname); + if(!idx){ // add path/color if not already present + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hpathname); + + *(d->defs) += "\n"; + switch(hatchType){ + case U_HS_HORIZONTAL: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_VERTICAL: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_FDIAGONAL: + *(d->defs) += " <line id=\"sub"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + break; + case U_HS_BDIAGONAL: + *(d->defs) += " <line id=\"sub"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + break; + case U_HS_CROSS: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_DIAGCROSS: + *(d->defs) += " <line id=\"subfd"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + *(d->defs) += " <line id=\"subbd"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + break; + case U_HS_SOLIDCLR: + case U_HS_DITHEREDCLR: + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + default: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; + *(d->defs) += tmpcolor; + *(d->defs) += ";stroke:none"; + *(d->defs) += "\" />\n"; + break; + } + } + + // References to paths possibly just created above. These will be used in the actual patterns. + switch(hatchType){ + case U_HS_HORIZONTAL: + case U_HS_VERTICAL: + case U_HS_CROSS: + case U_HS_SOLIDCLR: + case U_HS_DITHEREDCLR: + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + default: + refpath += " <use xlink:href=\"#"; + refpath += hpathname; + refpath += "\" />\n"; + break; + case U_HS_FDIAGONAL: + case U_HS_BDIAGONAL: + refpath += " <use xlink:href=\"#sub"; + refpath += hpathname; + refpath += "\" />\n"; + refpath += " <use xlink:href=\"#sub"; + refpath += hpathname; + refpath += "\" transform=\"translate(6,0)\" />\n"; + refpath += " <use xlink:href=\"#sub"; + refpath += hpathname; + refpath += "\" transform=\"translate(-6,0)\" />\n"; + break; + case U_HS_DIAGCROSS: + refpath += " <use xlink:href=\"#subfd"; + refpath += hpathname; + refpath += "\" />\n"; + refpath += " <use xlink:href=\"#subfd"; + refpath += hpathname; + refpath += "\" transform=\"translate(6,0)\"/>\n"; + refpath += " <use xlink:href=\"#subfd"; + refpath += hpathname; + refpath += "\" transform=\"translate(-6,0)\"/>\n"; + refpath += " <use xlink:href=\"#subbd"; + refpath += hpathname; + refpath += "\" />\n"; + refpath += " <use xlink:href=\"#subbd"; + refpath += hpathname; + refpath += "\" transform=\"translate(6,0)\"/>\n"; + refpath += " <use xlink:href=\"#subbd"; + refpath += hpathname; + refpath += "\" transform=\"translate(-6,0)\"/>\n"; + break; + } + + if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){ + sprintf(hatchname,"EMFhatch%d_%s",hatchType,tmpcolor); + sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor); + idx = in_hatches(d,hatchname); + if(!idx){ // add it if not already present + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hatchname); + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += hatchname; + *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n"; + *(d->defs) += refpath; + *(d->defs) += " </pattern>\n"; + idx = d->hatches.count; + } + } + else { // bkMode==U_OPAQUE + /* Set up an object in the defs for this background, if there is not one already there */ + sprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor)); + sprintf(hbkname,"EMFhbkclr_%s",bkcolor); + idx = in_hatches(d,hbkname); + if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name. + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hbkname); + + *(d->defs) += "\n"; + *(d->defs) += " <rect id=\""; + *(d->defs) += hbkname; + *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#"; + *(d->defs) += bkcolor; + *(d->defs) += "\" />\n"; + } + + // this is the pattern, its name will show up in Inkscape's pattern selector + sprintf(hatchname,"EMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor); + idx = in_hatches(d,hatchname); + if(!idx){ // add it if not already present + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hatchname); + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += hatchname; + *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n"; + *(d->defs) += " <use xlink:href=\"#"; + *(d->defs) += hbkname; + *(d->defs) += "\" />\n"; + *(d->defs) += refpath; + *(d->defs) += " </pattern>\n"; + idx = d->hatches.count; + } + } + return(idx-1); +} + +/* Add another 100 blank slots to the images array. +*/ +void Emf::enlarge_images(PEMF_CALLBACK_DATA d){ + d->images.size += 100; + d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *)); +} + +/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1) +*/ +int Emf::in_images(PEMF_CALLBACK_DATA d, char *test){ + int i; + for(i=0; i<d->images.count; i++){ + if(strcmp(test,d->images.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add an image. If a matching image already exists nothing happens. If one + does not exist it is added to the images list and also entered into <defs>. + + U_EMRCREATEMONOBRUSH records only work when the bitmap is monochrome. If we hit one that isn't + set idx to 2^32-1 and let the caller handle it. +*/ +uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi, + uint32_t iUsage, uint32_t offBits, uint32_t offBmi){ + + uint32_t idx; + char imagename[64]; // big enough + char imrotname[64]; // big enough + char xywh[64]; // big enough + int dibparams; + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px = NULL; // RGBA pixels + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // DIB color table + U_RGBQUAD ct2[2]; + uint32_t width, height, colortype, numCt, invert; + if( !cbBits || + !cbBmi || + (iUsage != U_DIB_RGB_COLORS) || + !(dibparams = get_DIB_params( // this returns pointers and values, but allocates no memory + pEmr, + offBits, + offBmi, + &px, + (const U_RGBQUAD **) &ct, + &numCt, + &width, + &height, + &colortype, + &invert + )) + ){ + + // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map. + if(((PU_EMR)pEmr)->iType == U_EMR_CREATEMONOBRUSH){ + if(numCt==2){ + ct2[0] = U_RGB2BGR(d->dc[d->level].textColor); + ct2[1] = U_RGB2BGR(d->dc[d->level].bkColor); + ct = &ct2[0]; + } + else { // createmonobrush renders on other platforms this way + return(0xFFFFFFFF); + } + } + + if(!DIB_to_RGBA( + px, // DIB pixel array + ct, // DIB color table + numCt, // DIB color table number of entries + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array in record + height, // Height of pixel array in record + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + ) && + rgba_px + ){ + toPNG( // Get the image from the RGBA px into mempng + &mempng, + width, height, // of the SRC bitmap + rgba_px + ); + free(rgba_px); + } + } + gchar *base64String; + if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ + base64String = g_base64_encode((guchar*) px, numCt ); + idx = in_images(d, (char *) base64String); + } + else if(mempng.buffer){ + base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + idx = in_images(d, (char *) base64String); + } + else { + // insert a random 3x4 blotch otherwise + width = 3; + height = 4; + base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); + idx = in_images(d, (char *) base64String); + } + if(!idx){ // add it if not already present - we looked at the actual data for comparison + if(d->images.count == d->images.size){ enlarge_images(d); } + idx = d->images.count; + d->images.strings[d->images.count++]=strdup(base64String); + + sprintf(imagename,"EMFimage%d",idx++); + sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer + + *(d->defs) += "\n"; + *(d->defs) += " <image id=\""; + *(d->defs) += imagename; + *(d->defs) += "\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n"; + if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; } + else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; } + *(d->defs) += base64String; + *(d->defs) += "\"\n"; + *(d->defs) += " />\n"; + + + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += imagename; + *(d->defs) += "_ref\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; + *(d->defs) += " >\n"; + *(d->defs) += " <use id=\""; + *(d->defs) += imagename; + *(d->defs) += "_ign\" "; + *(d->defs) += " xlink:href=\"#"; + *(d->defs) += imagename; + *(d->defs) += "\" />\n"; + *(d->defs) += " "; + *(d->defs) += " </pattern>\n"; + } + g_free(base64String); + + /* image allows the inner image to be rotated nicely, load this one second only if needed + imagename retained from above + Here comes a dreadful hack. How do we determine if this rotation of the base image has already + been loaded? The image names contain no identifying information, they are just numbered sequentially. + So the rotated name is EMFrotimage###_XXXXXX, where ### is the number of the referred to image, and + XXXX is the rotation in radians x 1000000 and truncated. That is then stored in BASE64 as the "image". + The corresponding SVG generated though is not for an image, but a reference to an image. + The name of the pattern MUST stil be EMFimage###_ref or output_style() will not be able to use it. + */ + if(current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001){ /* some rotation, allow a little rounding error around 0 degrees */ + int tangle = round(current_rotation(d)*1000000.0); + sprintf(imrotname,"EMFrotimage%d_%d",idx-1,tangle); + base64String = g_base64_encode((guchar*) imrotname, strlen(imrotname) ); + idx = in_images(d, (char *) base64String); // scan for this "image" + if(!idx){ + if(d->images.count == d->images.size){ enlarge_images(d); } + idx = d->images.count; + d->images.strings[d->images.count++]=strdup(base64String); + sprintf(imrotname,"EMFimage%d",idx++); + + *(d->defs) += "\n"; + *(d->defs) += " <pattern\n"; + *(d->defs) += " id=\""; + *(d->defs) += imrotname; + *(d->defs) += "_ref\"\n"; + *(d->defs) += " xlink:href=\"#"; + *(d->defs) += imagename; + *(d->defs) += "_ref\"\n"; + *(d->defs) += " patternTransform="; + *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0 + *(d->defs) += " />\n"; + } + g_free(base64String); + } + + return(idx-1); +} + + +void +Emf::output_style(PEMF_CALLBACK_DATA d, int iType) +{ +// SVGOStringStream tmp_id; + SVGOStringStream tmp_style; + char tmp[1024] = {0}; + + float fill_rgb[3]; + sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb ); + float stroke_rgb[3]; + sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb); + + // for U_EMR_BITBLT with no image, try to approximate some of these operations/ + // Assume src color is "white" + if(d->dwRop3){ + switch(d->dwRop3){ + case U_PATINVERT: // treat all of these as black + case U_SRCINVERT: + case U_DSTINVERT: + case U_BLACKNESS: + case U_SRCERASE: + case U_NOTSRCCOPY: + fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0; + break; + case U_SRCCOPY: // treat all of these as white + case U_NOTSRCERASE: + case U_PATCOPY: + case U_WHITENESS: + fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0; + break; + case U_SRCPAINT: // use the existing color + case U_SRCAND: + case U_MERGECOPY: + case U_MERGEPAINT: + case U_PATPAINT: + default: + break; + } + d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT + } + + // Implement some of these, the ones where the original screen color does not matter. + // The options that merge screen and pen colors cannot be done correctly because we + // have no way of knowing what color is already on the screen. For those just pass the + // pen color through. + switch(d->dwRop2){ + case U_R2_BLACK: + fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0; + stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0; + break; + case U_R2_NOTMERGEPEN: + case U_R2_MASKNOTPEN: + break; + case U_R2_NOTCOPYPEN: + fill_rgb[0] = 1.0 - fill_rgb[0]; + fill_rgb[1] = 1.0 - fill_rgb[1]; + fill_rgb[2] = 1.0 - fill_rgb[2]; + stroke_rgb[0] = 1.0 - stroke_rgb[0]; + stroke_rgb[1] = 1.0 - stroke_rgb[1]; + stroke_rgb[2] = 1.0 - stroke_rgb[2]; + break; + case U_R2_MASKPENNOT: + case U_R2_NOT: + case U_R2_XORPEN: + case U_R2_NOTMASKPEN: + case U_R2_NOTXORPEN: + case U_R2_NOP: + case U_R2_MERGENOTPEN: + case U_R2_COPYPEN: + case U_R2_MASKPEN: + case U_R2_MERGEPENNOT: + case U_R2_MERGEPEN: + break; + case U_R2_WHITE: + fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0; + stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0; + break; + default: + break; + } + + +// tmp_id << "\n\tid=\"" << (d->id++) << "\""; +// *(d->outsvg) += tmp_id.str().c_str(); + *(d->outsvg) += "\n\tstyle=\""; + if (iType == U_EMR_STROKEPATH || !d->dc[d->level].fill_set) { + tmp_style << "fill:none;"; + } else { + switch(d->dc[d->level].fill_mode){ + // both of these use the url(#) method + case DRAW_PATTERN: + snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]); + tmp_style << tmp; + break; + case DRAW_IMAGE: + snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx); + tmp_style << tmp; + break; + case DRAW_PAINT: + default: // <-- this should never happen, but just in case... + snprintf( + tmp, 1023, + "fill:#%02x%02x%02x;", + SP_COLOR_F_TO_U(fill_rgb[0]), + SP_COLOR_F_TO_U(fill_rgb[1]), + SP_COLOR_F_TO_U(fill_rgb[2]) + ); + tmp_style << tmp; + break; + } + snprintf( + tmp, 1023, + "fill-rule:%s;", + (d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero") + ); + tmp_style << tmp; + tmp_style << "fill-opacity:1;"; + + // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately + if( + (d->dc[d->level].fill_set ) && + (d->dc[d->level].stroke_set ) && + (d->dc[d->level].style.stroke_width.value == 1 ) && + (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) && + ( + (d->dc[d->level].fill_mode != DRAW_PAINT) || + ( + (fill_rgb[0]==stroke_rgb[0]) && + (fill_rgb[1]==stroke_rgb[1]) && + (fill_rgb[2]==stroke_rgb[2]) + ) + ) + ){ + d->dc[d->level].stroke_set = false; + } + } + + if (iType == U_EMR_FILLPATH || !d->dc[d->level].stroke_set) { + tmp_style << "stroke:none;"; + } else { + switch(d->dc[d->level].stroke_mode){ + // both of these use the url(#) method + case DRAW_PATTERN: + snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]); + tmp_style << tmp; + break; + case DRAW_IMAGE: + snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx); + tmp_style << tmp; + break; + case DRAW_PAINT: + default: // <-- this should never happen, but just in case... + snprintf( + tmp, 1023, + "stroke:#%02x%02x%02x;", + SP_COLOR_F_TO_U(stroke_rgb[0]), + SP_COLOR_F_TO_U(stroke_rgb[1]), + SP_COLOR_F_TO_U(stroke_rgb[2]) + ); + tmp_style << tmp; + break; + } + tmp_style << "stroke-width:" << + MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;"; + + tmp_style << "stroke-linecap:" << + ( + d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" : + d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" : + d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" : + "unknown" + ) << ";"; + + tmp_style << "stroke-linejoin:" << + ( + d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" : + d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" : + d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" : + "unknown" + ) << ";"; + + // Set miter limit if known, even if it is not needed immediately (not miter) + tmp_style << "stroke-miterlimit:" << + MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; + + if (d->dc[d->level].style.stroke_dasharray_set && + d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) + { + tmp_style << "stroke-dasharray:"; + for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) { + if (i) + tmp_style << ","; + tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; + } + tmp_style << ";"; + tmp_style << "stroke-dashoffset:0;"; + } else { + tmp_style << "stroke-dasharray:none;"; + } + tmp_style << "stroke-opacity:1;"; + } + tmp_style << "\" "; + if (clipset) + tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" "; + clipset = false; + + *(d->outsvg) += tmp_style.str().c_str(); +} + + +double +Emf::_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) +{ + double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); + double tmp; + tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX; + tmp -= d->ulCornerOutX; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner + return(tmp); +} + +double +Emf::_pix_y_to_point(PEMF_CALLBACK_DATA d, double py) +{ + double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0); + double tmp; + tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY; + tmp -= d->ulCornerOutY; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner + return(tmp); +} + + +double +Emf::pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) +{ + double wpx = px * d->dc[d->level].worldTransform.eM11 + py * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; + double x = _pix_x_to_point(d, wpx); + + return x; +} + +double +Emf::pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) +{ + + double wpy = px * d->dc[d->level].worldTransform.eM12 + py * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; + double y = _pix_y_to_point(d, wpy); + + return y; + +} + +double +Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px) +{ + double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d)); + return ppx; +} + +/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates +*/ +std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){ + std::stringstream cxform; + cxform << pix_to_x_point(d,x,y); + cxform << ","; + cxform << pix_to_y_point(d,x,y); + return(cxform.str()); +} + + +void +Emf::select_pen(PEMF_CALLBACK_DATA d, int index) +{ + PU_EMRCREATEPEN pEmr = NULL; + + if (index >= 0 && index < d->n_obj){ + pEmr = (PU_EMRCREATEPEN) d->emf_obj[index].lpEMFR; + } + + if (!pEmr){ return; } + + switch (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK) { + case U_PS_DASH: + case U_PS_DOT: + case U_PS_DASHDOT: + case U_PS_DASHDOTDOT: + { + int i = 0; + int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK); + d->dc[d->level].style.stroke_dash.n_dash = + penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 3; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + if (penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + + d->dc[d->level].style.stroke_dasharray_set = 1; + break; + } + + case U_PS_SOLID: + default: + { + d->dc[d->level].style.stroke_dasharray_set = 0; + break; + } + } + + switch (pEmr->lopn.lopnStyle & U_PS_ENDCAP_MASK) { + case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; } + case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; } + case U_PS_ENDCAP_FLAT: + default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; } + } + + switch (pEmr->lopn.lopnStyle & U_PS_JOIN_MASK) { + case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; } + case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; } + case U_PS_JOIN_ROUND: + default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; } + } + + d->dc[d->level].stroke_set = true; + + if (pEmr->lopn.lopnStyle == U_PS_NULL) { + d->dc[d->level].style.stroke_width.value = 0; + d->dc[d->level].stroke_set = false; + } else if (pEmr->lopn.lopnWidth.x) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_abs_size( d, pEmr->lopn.lopnWidth.x ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + //d->dc[d->level].style.stroke_width.value = 1.0; + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_abs_size( d, 1 ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } + + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lopn.lopnColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lopn.lopnColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lopn.lopnColor) ); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); +} + + +void +Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) +{ + PU_EMREXTCREATEPEN pEmr = NULL; + + if (index >= 0 && index < d->n_obj) + pEmr = (PU_EMREXTCREATEPEN) d->emf_obj[index].lpEMFR; + + if (!pEmr) + return; + + switch (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK) { + case U_PS_USERSTYLE: + { + if (pEmr->elp.elpNumEntries) { + d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries]; + for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; +// Doing it this way typically results in a pattern that is tiny, better to assume the array +// is the same scale as for dot/dash below, that is, no scaling should be applied +// double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); + double dash_length = pEmr->elp.elpStyleEntry[i]; + d->level = cur_level; + d->dc[d->level].style.stroke_dash.dash[i] = dash_length; + } + d->dc[d->level].style.stroke_dasharray_set = 1; + } else { + d->dc[d->level].style.stroke_dasharray_set = 0; + } + break; + } + + case U_PS_DASH: + case U_PS_DOT: + case U_PS_DASHDOT: + case U_PS_DASHDOTDOT: + { + int i = 0; + int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK); + d->dc[d->level].style.stroke_dash.n_dash = + penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 3; + d->dc[d->level].style.stroke_dash.dash[i++] = 2; + } + if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 2; + } + if (penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 2; + } + + d->dc[d->level].style.stroke_dasharray_set = 1; + break; + } + case U_PS_SOLID: +/* includes these for now, some should maybe not be in here + case U_PS_NULL: + case U_PS_INSIDEFRAME: + case U_PS_ALTERNATE: + case U_PS_STYLE_MASK: +*/ + default: + { + d->dc[d->level].style.stroke_dasharray_set = 0; + break; + } + } + + switch (pEmr->elp.elpPenStyle & U_PS_ENDCAP_MASK) { + case U_PS_ENDCAP_ROUND: + { + d->dc[d->level].style.stroke_linecap.computed = 1; + break; + } + case U_PS_ENDCAP_SQUARE: + { + d->dc[d->level].style.stroke_linecap.computed = 2; + break; + } + case U_PS_ENDCAP_FLAT: + default: + { + d->dc[d->level].style.stroke_linecap.computed = 0; + break; + } + } + + switch (pEmr->elp.elpPenStyle & U_PS_JOIN_MASK) { + case U_PS_JOIN_BEVEL: + { + d->dc[d->level].style.stroke_linejoin.computed = 2; + break; + } + case U_PS_JOIN_MITER: + { + d->dc[d->level].style.stroke_linejoin.computed = 0; + break; + } + case U_PS_JOIN_ROUND: + default: + { + d->dc[d->level].style.stroke_linejoin.computed = 1; + break; + } + } + + d->dc[d->level].stroke_set = true; + + if (pEmr->elp.elpPenStyle == U_PS_NULL) { // draw nothing, but fill out all the values with something + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].style.stroke_width.value = 0; + d->dc[d->level].stroke_set = false; + d->dc[d->level].stroke_mode = DRAW_PAINT; + } + else { + if (pEmr->elp.elpWidth) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_abs_size( d, pEmr->elp.elpWidth ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + //d->dc[d->level].style.stroke_width.value = 1.0; + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_abs_size( d, 1 ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } + + if( pEmr->elp.elpBrushStyle == U_BS_SOLID){ + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) ); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + } + else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){ + d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor); + d->dc[d->level].stroke_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes + d->dc[d->level].stroke_mode = DRAW_PATTERN; + d->dc[d->level].stroke_set = true; + } + else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){ + d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); + d->dc[d->level].stroke_mode = DRAW_IMAGE; + d->dc[d->level].stroke_set = true; + } + else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + } + } +} + + +void +Emf::select_brush(PEMF_CALLBACK_DATA d, int index) +{ + uint32_t tidx; + uint32_t iType; + + if (index >= 0 && index < d->n_obj){ + iType = ((PU_EMR) (d->emf_obj[index].lpEMFR))->iType; + if(iType == U_EMR_CREATEBRUSHINDIRECT){ + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR; + if( pEmr->lb.lbStyle == U_BS_SOLID){ + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lb.lbColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lb.lbColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lb.lbColor) ); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = true; + } + else if(pEmr->lb.lbStyle == U_BS_HATCHED){ + d->dc[d->level].fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor); + d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes + d->dc[d->level].fill_mode = DRAW_PATTERN; + d->dc[d->level].fill_set = true; + } + } + else if(iType == U_EMR_CREATEDIBPATTERNBRUSHPT || iType == U_EMR_CREATEMONOBRUSH){ + PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) d->emf_obj[index].lpEMFR; + tidx = add_image(d, (void *) pEmr, pEmr->cbBits, pEmr->cbBmi, pEmr->iUsage, pEmr->offBits, pEmr->offBmi); + if(tidx == 0xFFFFFFFF){ // This happens if createmonobrush has a DIB that isn't monochrome + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + } + else { + d->dc[d->level].fill_idx = tidx; + d->dc[d->level].fill_mode = DRAW_IMAGE; + } + d->dc[d->level].fill_set = true; + } + } +} + + +void +Emf::select_font(PEMF_CALLBACK_DATA d, int index) +{ + PU_EMREXTCREATEFONTINDIRECTW pEmr = NULL; + + if (index >= 0 && index < d->n_obj) + pEmr = (PU_EMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR; + + if (!pEmr)return; + + + /* The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW + is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont + is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored + */ + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double font_size = pix_to_abs_size( d, pEmr->elfw.elfLogFont.lfHeight ); + /* snap the font_size to the nearest 1/32nd of a point. + (The size is converted from Pixels to points, snapped, and converted back.) + See the notes where d->D2Pscale[XY] are set for the reason why. + Typically this will set the font to the desired exact size. If some peculiar size + was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */ + font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8); + d->level = cur_level; + d->dc[d->level].style.font_size.computed = font_size; + d->dc[d->level].style.font_weight.value = + pEmr->elfw.elfLogFont.lfWeight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : + pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : + U_FW_NORMAL; + d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); + d->dc[d->level].style.text_decoration_line.underline = pEmr->elfw.elfLogFont.lfUnderline; + d->dc[d->level].style.text_decoration_line.line_through = pEmr->elfw.elfLogFont.lfStrikeOut; + d->dc[d->level].style.text_decoration_line.set = true; + d->dc[d->level].style.text_decoration_line.inherit = false; + // malformed EMF with empty filename may exist, ignore font change if encountered + char *ctmp = U_Utf16leToUtf8((uint16_t *) (pEmr->elfw.elfLogFont.lfFaceName), U_LF_FACESIZE, NULL); + if(ctmp){ + if (d->dc[d->level].font_name){ free(d->dc[d->level].font_name); } + if(*ctmp){ + d->dc[d->level].font_name = ctmp; + } + else { // Malformed EMF might specify an empty font name + free(ctmp); + d->dc[d->level].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants + } + } + d->dc[d->level].style.baseline_shift.value = round((double)((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600)) / 10.0; // use baseline_shift instead of text_transform to avoid overflow +} + +void +Emf::delete_object(PEMF_CALLBACK_DATA d, int index) +{ + if (index >= 0 && index < d->n_obj) { + d->emf_obj[index].type = 0; +// We are keeping a copy of the EMR rather than just a structure. Currently that is not necessary as the entire +// EMF is read in at once and is stored in a big malloc. However, in past versions it was handled +// reord by record, and we might need to do that again at some point in the future if we start running into EMF +// files too big to fit into memory. + if (d->emf_obj[index].lpEMFR) + free(d->emf_obj[index].lpEMFR); + d->emf_obj[index].lpEMFR = NULL; + } +} + + +void +Emf::insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj) +{ + if (index >= 0 && index < d->n_obj) { + delete_object(d, index); + d->emf_obj[index].type = type; + d->emf_obj[index].level = d->level; + d->emf_obj[index].lpEMFR = emr_dup((char *) pObj); + } +} + +/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling. + The few so far observed all had this format. +*/ +int Emf::AI_hack(PU_EMRHEADER pEmr){ + int ret=0; + char *ptr; + ptr = (char *)pEmr; + PU_EMRSETMAPMODE nEmr = (PU_EMRSETMAPMODE) (ptr + pEmr->emr.nSize); + char *string = NULL; + if(pEmr->nDescription)string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL); + if(string){ + if((pEmr->nDescription >= 13) && + (0==strcmp("Adobe Systems",string)) && + (nEmr->emr.iType == U_EMR_SETMAPMODE) && + (nEmr->iMode == U_MM_ANISOTROPIC)){ ret=1; } + free(string); + } + return(ret); +} + +/** + \fn create a UTF-32LE buffer and fill it with UNICODE unknown character + \param count number of copies of the Unicode unknown character to fill with +*/ +uint32_t *Emf::unknown_chars(size_t count){ + uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1)); + if(!res)throw "Inkscape fatal memory allocation error - cannot continue"; + for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; } + res[count]=0; + return res; +} + +/** + \fn store SVG for an image given the pixmap and various coordinate information + \param d + \param pEmr + \param dx (double) destination x in inkscape pixels + \param dy (double) destination y in inkscape pixels + \param dw (double) destination width in inkscape pixels + \param dh (double) destination height in inkscape pixels + \param sx (int) source x in src image pixels + \param sy (int) source y in src image pixels + \param iUsage + \param offBits + \param cbBits + \param offBmi + \param cbBmi +*/ +void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, + double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, + uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){ + + SVGOStringStream tmp_image; + int dibparams; + + tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; + + // The image ID is filled in much later when tmp_image is converted + + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px = NULL; // RGBA pixels + char *sub_px = NULL; // RGBA pixels, subarray + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // DIB color table + uint32_t width, height, colortype, numCt, invert; + if(!cbBits || + !cbBmi || + (iUsage != U_DIB_RGB_COLORS) || + !(dibparams = get_DIB_params( // this returns pointers and values, but allocates no memory + pEmr, + offBits, + offBmi, + &px, + (const U_RGBQUAD **) &ct, + &numCt, + &width, + &height, + &colortype, + &invert + )) + ){ + if(sw == 0 || sh == 0){ + sw = width; + sh = height; + } + + if(!DIB_to_RGBA( + px, // DIB pixel array + ct, // DIB color table + numCt, // DIB color table number of entries + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array + height, // Height of pixel array + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + ) && + rgba_px + ){ + sub_px = RGBA_to_RGBA( + rgba_px, // full pixel array from DIB + width, // Width of pixel array + height, // Height of pixel array + sx,sy, // starting point in pixel array + &sw,&sh // columns/rows to extract from the pixel array (output array size) + ); + + if(!sub_px)sub_px=rgba_px; + toPNG( // Get the image from the RGBA px into mempng + &mempng, + sw, sh, // size of the extracted pixel array + sub_px + ); + free(sub_px); + } + } + gchar *base64String; + if(dibparams == U_BI_JPEG){ + tmp_image << " xlink:href=\"data:image/jpeg;base64,"; + base64String = g_base64_encode((guchar*) px, numCt ); + tmp_image << base64String ; + g_free(base64String); + } + else if(dibparams==U_BI_PNG){ + tmp_image << " xlink:href=\"data:image/png;base64,"; + base64String = g_base64_encode((guchar*) px, numCt ); + tmp_image << base64String ; + g_free(base64String); + } + else if(mempng.buffer){ + tmp_image << " xlink:href=\"data:image/png;base64,"; + gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + tmp_image << base64String ; + g_free(base64String); + } + else { + tmp_image << " xlink:href=\"data:image/png;base64,"; + // insert a random 3x4 blotch otherwise + tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; + } + + tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; + + tmp_image << " transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset + *(d->outsvg) += "\n\t <image\n"; + *(d->outsvg) += tmp_image.str().c_str(); + + *(d->outsvg) += "/> \n"; + *(d->path) = ""; +} + +/** + \fn myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA lpData) + \param contents binary contents of an EMF file + \param length length in bytes of contents + \param d Inkscape data structures returned by this call +*/ +//THis was a callback, just build it into a normal function +int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d) +{ + uint32_t off=0; + uint32_t emr_mask; + int OK =1; + PU_ENHMETARECORD lpEMFR; + TCHUNK_SPECS tsp; + uint32_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written + U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor + + /* initialize the tsp for text reassembly */ + tsp.string = NULL; + tsp.ori = 0.0; /* degrees */ + tsp.fs = 12.0; /* font size */ + tsp.x = 0.0; + tsp.y = 0.0; + tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/ + tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ + tsp.taln = ALILEFT + ALIBASE; + tsp.ldir = LDIR_LR; + tsp.color.Red = 0; /* RGB Black */ + tsp.color.Green = 0; /* RGB Black */ + tsp.color.Blue = 0; /* RGB Black */ + tsp.color.Reserved = 0; /* not used */ + tsp.italics = 0; + tsp.weight = 80; + tsp.decoration = TXTDECOR_NONE; + tsp.condensed = 100; + tsp.co = 0; + tsp.fi_idx = -1; /* set to an invalid */ + + while(OK){ + if(off>=length)return(0); //normally should exit from while after EMREOF sets OK to false. + + lpEMFR = (PU_ENHMETARECORD)(contents + off); +// Uncomment the following to track down toxic records +//std::cout << "record type: " << lpEMFR->iType << " length: " << lpEMFR->nSize << " offset: " << off <<std::endl; + off += lpEMFR->nSize; + + SVGOStringStream tmp_outsvg; + SVGOStringStream tmp_path; + SVGOStringStream tmp_str; + SVGOStringStream dbg_str; + + emr_mask = emr_properties(lpEMFR->iType); + if(emr_mask == U_EMR_INVALID){ throw "Inkscape fatal memory allocation error - cannot continue"; } + +/* Uncomment the following to track down text problems */ +//std::cout << "tri->dirty:"<< d->tri->dirty << " emr_mask: " << std::hex << emr_mask << std::dec << std::endl; + + // incompatible change to text drawing detected (color or background change) forces out existing text + // OR + // next record is valid type and forces pending text to be drawn immediately + if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((emr_mask != 0xFFFFFFFF) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){ + TR_layout_analyze(d->tri); + TR_layout_2_svg(d->tri); + SVGOStringStream ts; + ts << d->tri->out; + *(d->outsvg) += ts.str().c_str(); + d->tri = trinfo_clear(d->tri); + } + if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag + d->dc[d->level].bkMode = tbkMode; + memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF)); + + if(d->dc[d->level].dirty & DIRTY_TEXT){ + // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing... + if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); } + else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque + } + + /* It is possible to have a series of EMF records that would result in + the following creating hash patterns which are never used. For instance, if + there were a series of records that changed the background color but did nothing + else. + */ + if((d->dc[d->level].stroke_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_STROKE)){ + select_extpen(d, d->dc[d->level].stroke_recidx); + } + + if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){ + select_brush(d, d->dc[d->level].fill_recidx); + } + + d->dc[d->level].dirty = 0; + } + +//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; +/* +std::cout << "BEFORE DRAW" + << " test0 " << ( d->mask & U_DRAW_VISIBLE) + << " test1 " << ( d->mask & U_DRAW_FORCE) + << " test2 " << (emr_mask & U_DRAW_ALTERS) + << " test3 " << (emr_mask & U_DRAW_VISIBLE) + << " test4 " << !(d->mask & U_DRAW_ONLYTO) + << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) ) + << std::endl; +*/ + + if( + (emr_mask != 0xFFFFFFFF) && // next record is valid type + (d->mask & U_DRAW_VISIBLE) && // Current set of objects are drawable + ( + (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH + (emr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way + ( + (emr_mask & U_DRAW_VISIBLE) && // Next record is visible... + ( + ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible + ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records + ) + ) + ) + ){ +// std::cout << "PATH DRAW at TOP" << std::endl; + *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!! + if(d->drawtype){ // explicit draw type EMR record + output_style(d, d->drawtype); + } + else if(d->mask & U_DRAW_CLOSED){ // implicit draw type + output_style(d, U_EMR_STROKEANDFILLPATH); + } + else { + output_style(d, U_EMR_STROKEPATH); + } + *(d->outsvg) += "\n\t"; + *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! + *(d->outsvg) += *(d->path); + *(d->outsvg) += " \" /> \n"; + *(d->path) = ""; + // reset the flags + d->mask = 0; + d->drawtype = 0; + } +// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; + + switch (lpEMFR->iType) + { + case U_EMR_HEADER: + { + dbg_str << "<!-- U_EMR_HEADER -->\n"; + + *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"; + + if (d->pDesc) { + *(d->outdef) += "<!-- "; + *(d->outdef) += d->pDesc; + *(d->outdef) += " -->\n"; + } + + PU_EMRHEADER pEmr = (PU_EMRHEADER) lpEMFR; + SVGOStringStream tmp_outdef; + tmp_outdef << "<svg\n"; + tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n"; + tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n"; + tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"; + tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role + tmp_outdef << " version=\"1.0\"\n"; + + + /* inclusive-inclusive, so the size is 1 more than the difference */ + d->MM100InX = pEmr->rclFrame.right - pEmr->rclFrame.left + 1; + d->MM100InY = pEmr->rclFrame.bottom - pEmr->rclFrame.top + 1; + d->PixelsInX = pEmr->rclBounds.right - pEmr->rclBounds.left + 1; + d->PixelsInY = pEmr->rclBounds.bottom - pEmr->rclBounds.top + 1; + + /* + calculate ratio of Inkscape dpi/EMF device dpi + This can cause problems later due to accuracy limits in the EMF. A high resolution + EMF might have a final D2Pscale[XY] of 0.074998, and adjusting the (integer) device size + by 1 will still not get it exactly to 0.075. Later when the font size is calculated it + can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by + snapping font sizes to the nearest .01. The best estimate is made by using both values. + */ + if ((pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy) && ( pEmr->szlDevice.cx + pEmr->szlDevice.cy)){ + d->E2IdirY = 1.0; // assume MM_TEXT, if not, this will be changed later + d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "mm", "px") * + (double)(pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/ + (double)( pEmr->szlDevice.cx + pEmr->szlDevice.cy); + } + trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */ + + /* Adobe Illustrator files set mapmode to MM_ANISOTROPIC and somehow or other this + converts the rclFrame values from MM_HIMETRIC to MM_HIENGLISH, with another factor of 3 thrown + in for good measure. Ours not to question why... + */ + if(AI_hack(pEmr)){ + d->MM100InX *= 25.4/(10.0*3.0); + d->MM100InY *= 25.4/(10.0*3.0); + d->D2PscaleX *= 25.4/(10.0*3.0); + d->D2PscaleY *= 25.4/(10.0*3.0); + } + + d->MMX = d->MM100InX / 100.0; + d->MMY = d->MM100InY / 100.0; + + d->PixelsOutX = d->MMX * Inkscape::Util::Quantity::convert(1, "mm", "px"); + d->PixelsOutY = d->MMY * Inkscape::Util::Quantity::convert(1, "mm", "px"); + + // Upper left corner, from header rclBounds, in device units, usually both 0, but not always + d->ulCornerInX = pEmr->rclBounds.left; + d->ulCornerInY = pEmr->rclBounds.top; + d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX; + d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY; + + tmp_outdef << + " width=\"" << d->MMX << "mm\"\n" << + " height=\"" << d->MMY << "mm\">\n"; + *(d->outdef) += tmp_outdef.str().c_str(); + *(d->outdef) += "<defs>"; // temporary end of header + + // d->defs holds any defines which are read in. + + tmp_outsvg << "\n</defs>\n\n"; // start of main body + + if (pEmr->nHandles) { + d->n_obj = pEmr->nHandles; + d->emf_obj = new EMF_OBJECT[d->n_obj]; + + // Init the new emf_obj list elements to null, provided the + // dynamic allocation succeeded. + if ( d->emf_obj != NULL ) + { + for( int i=0; i < d->n_obj; ++i ) + d->emf_obj[i].lpEMFR = NULL; + } //if + + } else { + d->emf_obj = NULL; + } + + break; + } + case U_EMR_POLYBEZIER: + { + dbg_str << "<!-- U_EMR_POLYBEZIER -->\n"; + + PU_EMRPOLYBEZIER pEmr = (PU_EMRPOLYBEZIER) lpEMFR; + uint32_t i,j; + + if (pEmr->cptl<4) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; + + for (i=1; i<pEmr->cptl; ) { + tmp_str << "\n\tC "; + for (j=0; j<3 && i<pEmr->cptl; j++,i++) { + tmp_str << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y) << " "; + } + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYGON: + { + dbg_str << "<!-- U_EMR_POLYGON -->\n"; + + PU_EMRPOLYGON pEmr = (PU_EMRPOLYGON) lpEMFR; + uint32_t i; + + if (pEmr->cptl < 2) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; + + for (i=1; i<pEmr->cptl; i++) { + tmp_str << + "\n\tL " << + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + + tmp_path << tmp_str.str().c_str(); + tmp_path << " z"; + + break; + } + case U_EMR_POLYLINE: + { + dbg_str << "<!-- U_EMR_POLYLINE -->\n"; + + PU_EMRPOLYLINE pEmr = (PU_EMRPOLYLINE) lpEMFR; + uint32_t i; + + if (pEmr->cptl<2) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; + + for (i=1; i<pEmr->cptl; i++) { + tmp_str << + "\n\tL " << + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYBEZIERTO: + { + dbg_str << "<!-- U_EMR_POLYBEZIERTO -->\n"; + + PU_EMRPOLYBEZIERTO pEmr = (PU_EMRPOLYBEZIERTO) lpEMFR; + uint32_t i,j; + + d->mask |= emr_mask; + + for (i=0; i<pEmr->cptl;) { + tmp_path << "\n\tC "; + for (j=0; j<3 && i<pEmr->cptl; j++,i++) { + tmp_path << + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + } + + break; + } + case U_EMR_POLYLINETO: + { + dbg_str << "<!-- U_EMR_POLYLINETO -->\n"; + + PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) lpEMFR; + uint32_t i; + + d->mask |= emr_mask; + + for (i=0; i<pEmr->cptl;i++) { + tmp_path << + "\n\tL " << + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + + break; + } + case U_EMR_POLYPOLYLINE: + case U_EMR_POLYPOLYGON: + { + if (lpEMFR->iType == U_EMR_POLYPOLYLINE) + dbg_str << "<!-- U_EMR_POLYPOLYLINE -->\n"; + if (lpEMFR->iType == U_EMR_POLYPOLYGON) + dbg_str << "<!-- U_EMR_POLYPOLYGON -->\n"; + + PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) lpEMFR; + unsigned int n, i, j; + + d->mask |= emr_mask; + + U_POINTL *aptl = (PU_POINTL) &pEmr->aPolyCounts[pEmr->nPolys]; + + i = 0; + for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) { + SVGOStringStream poly_path; + + poly_path << "\n\tM " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " "; + i++; + + for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) { + poly_path << "\n\tL " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " "; + i++; + } + + tmp_str << poly_path.str().c_str(); + if (lpEMFR->iType == U_EMR_POLYPOLYGON) + tmp_str << " z"; + tmp_str << " \n"; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_SETWINDOWEXTEX: + { + dbg_str << "<!-- U_EMR_SETWINDOWEXTEX -->\n"; + + PU_EMRSETWINDOWEXTEX pEmr = (PU_EMRSETWINDOWEXTEX) lpEMFR; + + d->dc[d->level].sizeWnd = pEmr->szlExtent; + + if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; + if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].sizeWnd.cx = d->PixelsOutX; + d->dc[d->level].sizeWnd.cy = d->PixelsOutY; + } + } + + if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { + d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; + } + + /* scales logical to EMF pixels, transfer a negative sign on Y, if any */ + if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy; + if(d->dc[d->level].ScaleInY < 0){ + d->dc[d->level].ScaleInY *= -1.0; + d->E2IdirY = -1.0; + } + } + else { + d->dc[d->level].ScaleInX = 1; + d->dc[d->level].ScaleInY = 1; + } + break; + } + case U_EMR_SETWINDOWORGEX: + { + dbg_str << "<!-- U_EMR_SETWINDOWORGEX -->\n"; + + PU_EMRSETWINDOWORGEX pEmr = (PU_EMRSETWINDOWORGEX) lpEMFR; + d->dc[d->level].winorg = pEmr->ptlOrigin; + break; + } + case U_EMR_SETVIEWPORTEXTEX: + { + dbg_str << "<!-- U_EMR_SETVIEWPORTEXTEX -->\n"; + + PU_EMRSETVIEWPORTEXTEX pEmr = (PU_EMRSETVIEWPORTEXTEX) lpEMFR; + + d->dc[d->level].sizeView = pEmr->szlExtent; + + if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { + d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; + if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { + d->dc[d->level].sizeView.cx = d->PixelsOutX; + d->dc[d->level].sizeView.cy = d->PixelsOutY; + } + } + + if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; + } + + /* scales logical to EMF pixels, transfer a negative sign on Y, if any */ + if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy; + if( d->dc[d->level].ScaleInY < 0){ + d->dc[d->level].ScaleInY *= -1.0; + d->E2IdirY = -1.0; + } + } + else { + d->dc[d->level].ScaleInX = 1; + d->dc[d->level].ScaleInY = 1; + } + break; + } + case U_EMR_SETVIEWPORTORGEX: + { + dbg_str << "<!-- U_EMR_SETVIEWPORTORGEX -->\n"; + + PU_EMRSETVIEWPORTORGEX pEmr = (PU_EMRSETVIEWPORTORGEX) lpEMFR; + d->dc[d->level].vieworg = pEmr->ptlOrigin; + break; + } + case U_EMR_SETBRUSHORGEX: dbg_str << "<!-- U_EMR_SETBRUSHORGEX -->\n"; break; + case U_EMR_EOF: + { + dbg_str << "<!-- U_EMR_EOF -->\n"; + + tmp_outsvg << "</svg>\n"; + *(d->outsvg) = *(d->outdef) + *(d->defs) + *(d->outsvg); + OK=0; + break; + } + case U_EMR_SETPIXELV: dbg_str << "<!-- U_EMR_SETPIXELV -->\n"; break; + case U_EMR_SETMAPPERFLAGS: dbg_str << "<!-- U_EMR_SETMAPPERFLAGS -->\n"; break; + case U_EMR_SETMAPMODE: + { + dbg_str << "<!-- U_EMR_SETMAPMODE -->\n"; + PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE) lpEMFR; + switch (pEmr->iMode){ + case U_MM_TEXT: + default: + // Use all values from the header. + break; + /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex + and show up in ScaleIn[XY] + */ + case U_MM_LOMETRIC: // 1 LU = 0.1 mm, + case U_MM_HIMETRIC: // 1 LU = 0.01 mm + case U_MM_LOENGLISH: // 1 LU = 0.1 in + case U_MM_HIENGLISH: // 1 LU = 0.01 in + case U_MM_TWIPS: // 1 LU = 1/1440 in + d->E2IdirY = -1.0; + // Use d->D2Pscale[XY] values from the header. + break; + case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX + case U_MM_ANISOTROPIC: + break; + } + break; + } + case U_EMR_SETBKMODE: + { + dbg_str << "<!-- U_EMR_SETBKMODE -->\n"; + PU_EMRSETBKMODE pEmr = (PU_EMRSETBKMODE) lpEMFR; + tbkMode = pEmr->iMode; + if(tbkMode != d->dc[d->level].bkMode){ + d->dc[d->level].dirty |= DIRTY_TEXT; + if(tbkMode != d->dc[d->level].bkMode){ + if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; } + if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; } + } + memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF)); + } + break; + } + case U_EMR_SETPOLYFILLMODE: + { + dbg_str << "<!-- U_EMR_SETPOLYFILLMODE -->\n"; + + PU_EMRSETPOLYFILLMODE pEmr = (PU_EMRSETPOLYFILLMODE) lpEMFR; + d->dc[d->level].style.fill_rule.value = + (pEmr->iMode == U_ALTERNATE ? 0 : (pEmr->iMode == U_WINDING ? 1 : 0)); + break; + } + case U_EMR_SETROP2: + { + dbg_str << "<!-- U_EMR_SETROP2 -->\n"; + PU_EMRSETROP2 pEmr = (PU_EMRSETROP2) lpEMFR; + d->dwRop2 = pEmr->iMode; + break; + } + case U_EMR_SETSTRETCHBLTMODE: + { + PU_EMRSETSTRETCHBLTMODE pEmr = (PU_EMRSETSTRETCHBLTMODE) lpEMFR; // from wingdi.h + BLTmode = pEmr->iMode; + dbg_str << "<!-- U_EMR_SETSTRETCHBLTMODE -->\n"; + break; + } + case U_EMR_SETTEXTALIGN: + { + dbg_str << "<!-- U_EMR_SETTEXTALIGN -->\n"; + + PU_EMRSETTEXTALIGN pEmr = (PU_EMRSETTEXTALIGN) lpEMFR; + d->dc[d->level].textAlign = pEmr->iMode; + break; + } + case U_EMR_SETCOLORADJUSTMENT: + dbg_str << "<!-- U_EMR_SETCOLORADJUSTMENT -->\n"; + break; + case U_EMR_SETTEXTCOLOR: + { + dbg_str << "<!-- U_EMR_SETTEXTCOLOR -->\n"; + + PU_EMRSETTEXTCOLOR pEmr = (PU_EMRSETTEXTCOLOR) lpEMFR; + d->dc[d->level].textColor = pEmr->crColor; + if(tbkMode != d->dc[d->level].bkMode){ + if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; } + if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; } + } + // not text_dirty, because multicolored complex text is supported in libTERE + break; + } + case U_EMR_SETBKCOLOR: + { + dbg_str << "<!-- U_EMR_SETBKCOLOR -->\n"; + + PU_EMRSETBKCOLOR pEmr = (PU_EMRSETBKCOLOR) lpEMFR; + tbkColor = pEmr->crColor; + if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){ + d->dc[d->level].dirty |= DIRTY_TEXT; + if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; } + if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; } + tbkMode = d->dc[d->level].bkMode; + } + break; + } + case U_EMR_OFFSETCLIPRGN: dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n"; break; + case U_EMR_MOVETOEX: + { + dbg_str << "<!-- U_EMR_MOVETOEX -->\n"; + + PU_EMRMOVETOEX pEmr = (PU_EMRMOVETOEX) lpEMFR; + + d->mask |= emr_mask; + + d->dc[d->level].cur = pEmr->ptl; + + tmp_path << + "\n\tM " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + break; + } + case U_EMR_SETMETARGN: dbg_str << "<!-- U_EMR_SETMETARGN -->\n"; break; + case U_EMR_EXCLUDECLIPRECT: dbg_str << "<!-- U_EMR_EXCLUDECLIPRECT -->\n"; break; + case U_EMR_INTERSECTCLIPRECT: + { + dbg_str << "<!-- U_EMR_INTERSECTCLIPRECT -->\n"; + + PU_EMRINTERSECTCLIPRECT pEmr = (PU_EMRINTERSECTCLIPRECT) lpEMFR; + U_RECTL rc = pEmr->rclClip; + clipset = true; + if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) + break; + rc_old = rc; + + double dx = pix_to_x_point( d, rc.left, rc.top ); + double dy = pix_to_y_point( d, rc.left, rc.top ); + double dw = pix_to_abs_size( d, rc.right - rc.left + 1); + double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" "; + tmp_rectangle << "\nid=\"clipEmfPath" << ++(d->id) << "\" >"; + tmp_rectangle << "\n<rect "; + tmp_rectangle << "\n x=\"" << dx << "\" "; + tmp_rectangle << "\n y=\"" << dy << "\" "; + tmp_rectangle << "\n width=\"" << dw << "\" "; + tmp_rectangle << "\n height=\"" << dh << "\" />"; + tmp_rectangle << "\n transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset + tmp_rectangle << "\n</clipPath>"; + + *(d->outdef) += tmp_rectangle.str().c_str(); + *(d->path) = ""; + break; + } + case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "<!-- U_EMR_SCALEVIEWPORTEXTEX -->\n"; break; + case U_EMR_SCALEWINDOWEXTEX: dbg_str << "<!-- U_EMR_SCALEWINDOWEXTEX -->\n"; break; + case U_EMR_SAVEDC: + dbg_str << "<!-- U_EMR_SAVEDC -->\n"; + + if (d->level < EMF_MAX_DC) { + d->dc[d->level + 1] = d->dc[d->level]; + if(d->dc[d->level].font_name){ + d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated + } + d->level = d->level + 1; + } + break; + case U_EMR_RESTOREDC: + { + dbg_str << "<!-- U_EMR_RESTOREDC -->\n"; + + PU_EMRRESTOREDC pEmr = (PU_EMRRESTOREDC) lpEMFR; + int old_level = d->level; + if (pEmr->iRelative >= 0) { + if (pEmr->iRelative < d->level) + d->level = pEmr->iRelative; + } + else { + if (d->level + pEmr->iRelative >= 0) + d->level = d->level + pEmr->iRelative; + } + while (old_level > d->level) { + if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))){ + delete[] d->dc[old_level].style.stroke_dash.dash; + } + if(d->dc[old_level].font_name){ + free(d->dc[old_level].font_name); // else memory leak + d->dc[old_level].font_name = NULL; + } + old_level--; + } + break; + } + case U_EMR_SETWORLDTRANSFORM: + { + dbg_str << "<!-- U_EMR_SETWORLDTRANSFORM -->\n"; + + PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM) lpEMFR; + d->dc[d->level].worldTransform = pEmr->xform; + break; + } + case U_EMR_MODIFYWORLDTRANSFORM: + { + dbg_str << "<!-- U_EMR_MODIFYWORLDTRANSFORM -->\n"; + + PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM) lpEMFR; + switch (pEmr->iMode) + { + case U_MWT_IDENTITY: + d->dc[d->level].worldTransform.eM11 = 1.0; + d->dc[d->level].worldTransform.eM12 = 0.0; + d->dc[d->level].worldTransform.eM21 = 0.0; + d->dc[d->level].worldTransform.eM22 = 1.0; + d->dc[d->level].worldTransform.eDx = 0.0; + d->dc[d->level].worldTransform.eDy = 0.0; + break; + case U_MWT_LEFTMULTIPLY: + { +// d->dc[d->level].worldTransform = pEmr->xform * worldTransform; + + float a11 = pEmr->xform.eM11; + float a12 = pEmr->xform.eM12; + float a13 = 0.0; + float a21 = pEmr->xform.eM21; + float a22 = pEmr->xform.eM22; + float a23 = 0.0; + float a31 = pEmr->xform.eDx; + float a32 = pEmr->xform.eDy; + float a33 = 1.0; + + float b11 = d->dc[d->level].worldTransform.eM11; + float b12 = d->dc[d->level].worldTransform.eM12; + //float b13 = 0.0; + float b21 = d->dc[d->level].worldTransform.eM21; + float b22 = d->dc[d->level].worldTransform.eM22; + //float b23 = 0.0; + float b31 = d->dc[d->level].worldTransform.eDx; + float b32 = d->dc[d->level].worldTransform.eDy; + //float b33 = 1.0; + + float c11 = a11*b11 + a12*b21 + a13*b31;; + float c12 = a11*b12 + a12*b22 + a13*b32;; + //float c13 = a11*b13 + a12*b23 + a13*b33;; + float c21 = a21*b11 + a22*b21 + a23*b31;; + float c22 = a21*b12 + a22*b22 + a23*b32;; + //float c23 = a21*b13 + a22*b23 + a23*b33;; + float c31 = a31*b11 + a32*b21 + a33*b31;; + float c32 = a31*b12 + a32*b22 + a33*b32;; + //float c33 = a31*b13 + a32*b23 + a33*b33;; + + d->dc[d->level].worldTransform.eM11 = c11;; + d->dc[d->level].worldTransform.eM12 = c12;; + d->dc[d->level].worldTransform.eM21 = c21;; + d->dc[d->level].worldTransform.eM22 = c22;; + d->dc[d->level].worldTransform.eDx = c31; + d->dc[d->level].worldTransform.eDy = c32; + + break; + } + case U_MWT_RIGHTMULTIPLY: + { +// d->dc[d->level].worldTransform = worldTransform * pEmr->xform; + + float a11 = d->dc[d->level].worldTransform.eM11; + float a12 = d->dc[d->level].worldTransform.eM12; + float a13 = 0.0; + float a21 = d->dc[d->level].worldTransform.eM21; + float a22 = d->dc[d->level].worldTransform.eM22; + float a23 = 0.0; + float a31 = d->dc[d->level].worldTransform.eDx; + float a32 = d->dc[d->level].worldTransform.eDy; + float a33 = 1.0; + + float b11 = pEmr->xform.eM11; + float b12 = pEmr->xform.eM12; + //float b13 = 0.0; + float b21 = pEmr->xform.eM21; + float b22 = pEmr->xform.eM22; + //float b23 = 0.0; + float b31 = pEmr->xform.eDx; + float b32 = pEmr->xform.eDy; + //float b33 = 1.0; + + float c11 = a11*b11 + a12*b21 + a13*b31;; + float c12 = a11*b12 + a12*b22 + a13*b32;; + //float c13 = a11*b13 + a12*b23 + a13*b33;; + float c21 = a21*b11 + a22*b21 + a23*b31;; + float c22 = a21*b12 + a22*b22 + a23*b32;; + //float c23 = a21*b13 + a22*b23 + a23*b33;; + float c31 = a31*b11 + a32*b21 + a33*b31;; + float c32 = a31*b12 + a32*b22 + a33*b32;; + //float c33 = a31*b13 + a32*b23 + a33*b33;; + + d->dc[d->level].worldTransform.eM11 = c11;; + d->dc[d->level].worldTransform.eM12 = c12;; + d->dc[d->level].worldTransform.eM21 = c21;; + d->dc[d->level].worldTransform.eM22 = c22;; + d->dc[d->level].worldTransform.eDx = c31; + d->dc[d->level].worldTransform.eDy = c32; + + break; + } +// case MWT_SET: + default: + d->dc[d->level].worldTransform = pEmr->xform; + break; + } + break; + } + case U_EMR_SELECTOBJECT: + { + dbg_str << "<!-- U_EMR_SELECTOBJECT -->\n"; + + PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT) lpEMFR; + unsigned int index = pEmr->ihObject; + + if (index & U_STOCK_OBJECT) { + switch (index) { + case U_NULL_BRUSH: + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = false; + break; + case U_BLACK_BRUSH: + case U_DKGRAY_BRUSH: + case U_GRAY_BRUSH: + case U_LTGRAY_BRUSH: + case U_WHITE_BRUSH: + { + float val = 0; + switch (index) { + case U_BLACK_BRUSH: + val = 0.0 / 255.0; + break; + case U_DKGRAY_BRUSH: + val = 64.0 / 255.0; + break; + case U_GRAY_BRUSH: + val = 128.0 / 255.0; + break; + case U_LTGRAY_BRUSH: + val = 192.0 / 255.0; + break; + case U_WHITE_BRUSH: + val = 255.0 / 255.0; + break; + } + d->dc[d->level].style.fill.value.color.set( val, val, val ); + + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = true; + break; + } + case U_NULL_PEN: + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = false; + break; + case U_BLACK_PEN: + case U_WHITE_PEN: + { + float val = index == U_BLACK_PEN ? 0 : 1; + d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_width.value = 1.0; + d->dc[d->level].style.stroke.value.color.set( val, val, val ); + + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + + break; + } + } + } else { + if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) { + switch (d->emf_obj[index].type) + { + case U_EMR_CREATEPEN: + select_pen(d, index); + break; + case U_EMR_CREATEBRUSHINDIRECT: + case U_EMR_CREATEDIBPATTERNBRUSHPT: + case U_EMR_CREATEMONOBRUSH: + select_brush(d, index); + break; + case U_EMR_EXTCREATEPEN: + select_extpen(d, index); + break; + case U_EMR_EXTCREATEFONTINDIRECTW: + select_font(d, index); + break; + } + } + } + break; + } + case U_EMR_CREATEPEN: + { + dbg_str << "<!-- U_EMR_CREATEPEN -->\n"; + + PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN) lpEMFR; + insert_object(d, pEmr->ihPen, U_EMR_CREATEPEN, lpEMFR); + break; + } + case U_EMR_CREATEBRUSHINDIRECT: + { + dbg_str << "<!-- U_EMR_CREATEBRUSHINDIRECT -->\n"; + + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) lpEMFR; + insert_object(d, pEmr->ihBrush, U_EMR_CREATEBRUSHINDIRECT, lpEMFR); + break; + } + case U_EMR_DELETEOBJECT: + dbg_str << "<!-- U_EMR_DELETEOBJECT -->\n"; + // Objects here are not deleted until the draw completes, new ones may write over an existing one. + break; + case U_EMR_ANGLEARC: + dbg_str << "<!-- U_EMR_ANGLEARC -->\n"; + break; + case U_EMR_ELLIPSE: + { + dbg_str << "<!-- U_EMR_ELLIPSE -->\n"; + + PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE) lpEMFR; + U_RECTL rclBox = pEmr->rclBox; + + double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); + double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); + double rx = pix_to_abs_size( d, fabs(rclBox.right - rclBox.left )/2.0 ); + double ry = pix_to_abs_size( d, fabs(rclBox.top - rclBox.bottom)/2.0 ); + + SVGOStringStream tmp_ellipse; + tmp_ellipse << "cx=\"" << cx << "\" "; + tmp_ellipse << "cy=\"" << cy << "\" "; + tmp_ellipse << "rx=\"" << rx << "\" "; + tmp_ellipse << "ry=\"" << ry << "\" "; + + d->mask |= emr_mask; + + *(d->outsvg) += " <ellipse "; + output_style(d, lpEMFR->iType); // + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_ellipse.str().c_str(); + *(d->outsvg) += "/> \n"; + *(d->path) = ""; + break; + } + case U_EMR_RECTANGLE: + { + dbg_str << "<!-- U_EMR_RECTANGLE -->\n"; + + PU_EMRRECTANGLE pEmr = (PU_EMRRECTANGLE) lpEMFR; + U_RECTL rc = pEmr->rclBox; + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, rc.left , rc.top ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.top ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.bottom ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.left, rc.bottom ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= emr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_EMR_ROUNDRECT: + { + dbg_str << "<!-- U_EMR_ROUNDRECT -->\n"; + + PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT) lpEMFR; + U_RECTL rc = pEmr->rclBox; + U_SIZEL corner = pEmr->szlCorner; + double f = 4.*(sqrt(2) - 1)/3; + double f1 = 1.0 - f; + double cnx = corner.cx/2; + double cny = corner.cy/2; + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n" + << " M " + << pix_to_xy(d, rc.left , rc.top + cny ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.left , rc.top + cny*f1 ) + << " " + << pix_to_xy(d, rc.left + cnx*f1 , rc.top ) + << " " + << pix_to_xy(d, rc.left + cnx , rc.top ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, rc.right - cnx , rc.top ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.right - cnx*f1 , rc.top ) + << " " + << pix_to_xy(d, rc.right , rc.top + cny*f1 ) + << " " + << pix_to_xy(d, rc.right , rc.top + cny ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, rc.right , rc.bottom - cny ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.right , rc.bottom - cny*f1 ) + << " " + << pix_to_xy(d, rc.right - cnx*f1 , rc.bottom ) + << " " + << pix_to_xy(d, rc.right - cnx , rc.bottom ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, rc.left + cnx , rc.bottom ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.left + cnx*f1 , rc.bottom ) + << " " + << pix_to_xy(d, rc.left , rc.bottom - cny*f1 ) + << " " + << pix_to_xy(d, rc.left , rc.bottom - cny ) + << "\n"; + tmp_rectangle << " z\n"; + + + d->mask |= emr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_EMR_ARC: + { + dbg_str << "<!-- U_EMR_ARC -->\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + int stat = emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size); + if(!stat){ + tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; + d->mask |= emr_mask; + } + else { + dbg_str << "<!-- ARC record is invalid -->\n"; + } + break; + } + case U_EMR_CHORD: + { + dbg_str << "<!-- U_EMR_CHORD -->\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; + tmp_path << " z "; + d->mask |= emr_mask; + } + else { + dbg_str << "<!-- CHORD record is invalid -->\n"; + } + break; + } + case U_EMR_PIE: + { + dbg_str << "<!-- U_EMR_PIE -->\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y); + tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; + tmp_path << " z "; + d->mask |= emr_mask; + } + else { + dbg_str << "<!-- PIE record is invalid -->\n"; + } + break; + } + case U_EMR_SELECTPALETTE: dbg_str << "<!-- U_EMR_SELECTPALETTE -->\n"; break; + case U_EMR_CREATEPALETTE: dbg_str << "<!-- U_EMR_CREATEPALETTE -->\n"; break; + case U_EMR_SETPALETTEENTRIES: dbg_str << "<!-- U_EMR_SETPALETTEENTRIES -->\n"; break; + case U_EMR_RESIZEPALETTE: dbg_str << "<!-- U_EMR_RESIZEPALETTE -->\n"; break; + case U_EMR_REALIZEPALETTE: dbg_str << "<!-- U_EMR_REALIZEPALETTE -->\n"; break; + case U_EMR_EXTFLOODFILL: dbg_str << "<!-- U_EMR_EXTFLOODFILL -->\n"; break; + case U_EMR_LINETO: + { + dbg_str << "<!-- U_EMR_LINETO -->\n"; + + PU_EMRLINETO pEmr = (PU_EMRLINETO) lpEMFR; + + d->mask |= emr_mask; + + tmp_path << + "\n\tL " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y) << " "; + break; + } + case U_EMR_ARCTO: + { + dbg_str << "<!-- U_EMR_ARCTO -->\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + // draw a line from current position to start, arc from there + tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y)<< " "; + + d->mask |= emr_mask; + } + else { + dbg_str << "<!-- ARCTO record is invalid -->\n"; + } + break; + } + case U_EMR_POLYDRAW: dbg_str << "<!-- U_EMR_POLYDRAW -->\n"; break; + case U_EMR_SETARCDIRECTION: + { + dbg_str << "<!-- U_EMR_SETARCDIRECTION -->\n"; + PU_EMRSETARCDIRECTION pEmr = (PU_EMRSETARCDIRECTION) lpEMFR; + if(d->arcdir == U_AD_CLOCKWISE || d->arcdir == U_AD_COUNTERCLOCKWISE){ // EMF file could be corrupt + d->arcdir = pEmr->iArcDirection; + } + break; + } + case U_EMR_SETMITERLIMIT: + { + dbg_str << "<!-- U_EMR_SETMITERLIMIT -->\n"; + + PU_EMRSETMITERLIMIT pEmr = (PU_EMRSETMITERLIMIT) lpEMFR; + + //The function takes a float but saves a 32 bit int in the U_EMR_SETMITERLIMIT record. + float miterlimit = *((int32_t *) &(pEmr->eMiterLimit)); + d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size + if (d->dc[d->level].style.stroke_miterlimit.value < 2) + d->dc[d->level].style.stroke_miterlimit.value = 2.0; + break; + } + case U_EMR_BEGINPATH: + { + dbg_str << "<!-- U_EMR_BEGINPATH -->\n"; + // The next line should never be needed, should have been handled before main switch + *(d->path) = ""; + d->mask |= emr_mask; + break; + } + case U_EMR_ENDPATH: + { + dbg_str << "<!-- U_EMR_ENDPATH -->\n"; + d->mask &= (0xFFFFFFFF - U_DRAW_ONLYTO); // clear the OnlyTo bit (it might not have been set), prevents any further path extension + break; + } + case U_EMR_CLOSEFIGURE: + { + dbg_str << "<!-- U_EMR_CLOSEFIGURE -->\n"; + // EMF may contain multiple closefigures on one path + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + break; + } + case U_EMR_FILLPATH: + { + dbg_str << "<!-- U_EMR_FILLPATH -->\n"; + if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths + if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + } + d->mask |= emr_mask; + d->drawtype = U_EMR_FILLPATH; + } + break; + } + case U_EMR_STROKEANDFILLPATH: + { + dbg_str << "<!-- U_EMR_STROKEANDFILLPATH -->\n"; + if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths + if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + } + d->mask |= emr_mask; + d->drawtype = U_EMR_STROKEANDFILLPATH; + } + break; + } + case U_EMR_STROKEPATH: + { + dbg_str << "<!-- U_EMR_STROKEPATH -->\n"; + if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths + d->mask |= emr_mask; + d->drawtype = U_EMR_STROKEPATH; + } + break; + } + case U_EMR_FLATTENPATH: dbg_str << "<!-- U_EMR_FLATTENPATH -->\n"; break; + case U_EMR_WIDENPATH: dbg_str << "<!-- U_EMR_WIDENPATH -->\n"; break; + case U_EMR_SELECTCLIPPATH: dbg_str << "<!-- U_EMR_SELECTCLIPPATH -->\n"; break; + case U_EMR_ABORTPATH: + { + dbg_str << "<!-- U_EMR_ABORTPATH -->\n"; + *(d->path) = ""; + d->drawtype = 0; + break; + } + case U_EMR_UNDEF69: dbg_str << "<!-- U_EMR_UNDEF69 -->\n"; break; + case U_EMR_COMMENT: + { + dbg_str << "<!-- U_EMR_COMMENT -->\n"; + + PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT) lpEMFR; + + char *szTxt = (char *) pEmr->Data; + + for (uint32_t i = 0; i < pEmr->cbData; i++) { + if ( *szTxt) { + if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) { + tmp_str << *szTxt; + } + szTxt++; + } + } + + if (0 && strlen(tmp_str.str().c_str())) { + tmp_outsvg << " <!-- \""; + tmp_outsvg << tmp_str.str().c_str(); + tmp_outsvg << "\" -->\n"; + } + + break; + } + case U_EMR_FILLRGN: dbg_str << "<!-- U_EMR_FILLRGN -->\n"; break; + case U_EMR_FRAMERGN: dbg_str << "<!-- U_EMR_FRAMERGN -->\n"; break; + case U_EMR_INVERTRGN: dbg_str << "<!-- U_EMR_INVERTRGN -->\n"; break; + case U_EMR_PAINTRGN: dbg_str << "<!-- U_EMR_PAINTRGN -->\n"; break; + case U_EMR_EXTSELECTCLIPRGN: + { + dbg_str << "<!-- U_EMR_EXTSELECTCLIPRGN -->\n"; + + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) lpEMFR; + if (pEmr->iMode == U_RGN_COPY) + clipset = false; + break; + } + case U_EMR_BITBLT: + { + dbg_str << "<!-- U_EMR_BITBLT -->\n"; + + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR; + // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at + // least it leaves objects where the operations should have been. + if (!pEmr->cbBmiSrc) { + // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead + + int32_t dx = pEmr->Dest.x; + int32_t dy = pEmr->Dest.y; + int32_t dw = pEmr->cDest.x; + int32_t dh = pEmr->cDest.y; + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= emr_mask; + d->dwRop3 = pEmr->dwRop; // we will try to approximate SOME of these + d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that + + tmp_path << tmp_rectangle.str().c_str(); + } + else { + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + //source position within the bitmap, in pixels + int sx = pEmr->Src.x + pEmr->xformSrc.eDx; + int sy = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = 0; // extract all of the image + int sh = 0; + if(sx<0)sx=0; + if(sy<0)sy=0; + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, + pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); + } + break; + } + case U_EMR_STRETCHBLT: + { + dbg_str << "<!-- U_EMR_STRETCHBLT -->\n"; + PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) lpEMFR; + // Always grab image, ignore modes. + if (pEmr->cbBmiSrc) { + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + //source position within the bitmap, in pixels + int sx = pEmr->Src.x + pEmr->xformSrc.eDx; + int sy = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = pEmr->cSrc.x; // extract the specified amount of the image + int sh = pEmr->cSrc.y; + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, + pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); + } + break; + } + case U_EMR_MASKBLT: + { + dbg_str << "<!-- U_EMR_MASKBLT -->\n"; + PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) lpEMFR; + // Always grab image, ignore masks and modes. + if (pEmr->cbBmiSrc) { + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels + int sy = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = 0; // extract all of the image + int sh = 0; + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, + pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); + } + break; + } + case U_EMR_PLGBLT: dbg_str << "<!-- U_EMR_PLGBLT -->\n"; break; + case U_EMR_SETDIBITSTODEVICE: dbg_str << "<!-- U_EMR_SETDIBITSTODEVICE -->\n"; break; + case U_EMR_STRETCHDIBITS: + { + // Some applications use multiple EMF operations, including multiple STRETCHDIBITS to create + // images with transparent regions. PowerPoint does this with rotated images, for instance. + // Parsing all of that to derive a single resultant image object is left for a later version + // of this code. In the meantime, every STRETCHDIBITS goes directly to an image. The Inkscape + // user can sort out transparency later using Gimp, if need be. + + PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) lpEMFR; + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + int sx = pEmr->Src.x; //source position within the bitmap, in pixels + int sy = pEmr->Src.y; + int sw = pEmr->cSrc.x; // extract the specified amount of the image + int sh = pEmr->cSrc.y; + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, + pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); + + dbg_str << "<!-- U_EMR_STRETCHDIBITS -->\n"; + break; + } + case U_EMR_EXTCREATEFONTINDIRECTW: + { + dbg_str << "<!-- U_EMR_EXTCREATEFONTINDIRECTW -->\n"; + + PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) lpEMFR; + insert_object(d, pEmr->ihFont, U_EMR_EXTCREATEFONTINDIRECTW, lpEMFR); + break; + } + case U_EMR_EXTTEXTOUTA: + case U_EMR_EXTTEXTOUTW: + case U_EMR_SMALLTEXTOUT: + { + dbg_str << "<!-- U_EMR_EXTTEXTOUTA/W -->\n"; + + PU_EMREXTTEXTOUTW pEmr = (PU_EMREXTTEXTOUTW) lpEMFR; + PU_EMRSMALLTEXTOUT pEmrS = (PU_EMRSMALLTEXTOUT) lpEMFR; + + double x1,y1; + int roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields, only used with U_EMR_SMALLTEXTOUT + int cChars; + if(lpEMFR->iType==U_EMR_SMALLTEXTOUT){ + x1 = pEmrS->Dest.x; + y1 = pEmrS->Dest.y; + cChars = pEmrS->cChars; + if(!(pEmrS->fuOptions & U_ETO_NO_RECT)){ roff += sizeof(U_RECTL); } + } + else { + x1 = pEmr->emrtext.ptlReference.x; + y1 = pEmr->emrtext.ptlReference.y; + cChars = 0; + } + uint32_t fOptions = pEmr->emrtext.fOptions; + + if (d->dc[d->level].textAlign & U_TA_UPDATECP) { + x1 = d->dc[d->level].cur.x; + y1 = d->dc[d->level].cur.y; + } + + double x = pix_to_x_point(d, x1, y1); + double y = pix_to_y_point(d, x1, y1); + + /* Rotation issues are handled entirely in libTERE now */ + + uint32_t *dup_wt = NULL; + + if( lpEMFR->iType==U_EMR_EXTTEXTOUTA){ + /* These should be JUST ASCII, but they might not be... + If it holds Utf-8 or plain ASCII the first call will succeed. + If not, assume that it holds Latin1. + If that fails then someting is really screwed up! + */ + dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL); + if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL); + if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars); + } + else if( lpEMFR->iType==U_EMR_EXTTEXTOUTW){ + dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL); + if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars); + } + else { // U_EMR_SMALLTEXTOUT + if(pEmrS->fuOptions & U_ETO_SMALL_CHARS){ + dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, NULL); + } + else { + dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmrS + roff), cChars, NULL); + } + if(!dup_wt)dup_wt = unknown_chars(cChars); + } + + msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats + + if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){ + free(d->dc[d->level].font_name); + d->dc[d->level].font_name = strdup("Times New Roman"); + } + + char *ansi_text; + ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, NULL); + free(dup_wt); + // Empty string or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse + if(*((uint8_t *)ansi_text) <= 0x1F){ + free(ansi_text); + ansi_text=NULL; + } + + if (ansi_text) { + + SVGOStringStream ts; + + gchar *escaped_text = g_markup_escape_text(ansi_text, -1); + + tsp.x = x*0.8; // TERE expects sizes in points. + tsp.y = y*0.8; + tsp.color.Red = d->dc[d->level].textColor.Red; + tsp.color.Green = d->dc[d->level].textColor.Green; + tsp.color.Blue = d->dc[d->level].textColor.Blue; + tsp.color.Reserved = 0; + switch(d->dc[d->level].style.font_style.value){ + case SP_CSS_FONT_STYLE_OBLIQUE: + tsp.italics = FC_SLANT_OBLIQUE; break; + case SP_CSS_FONT_STYLE_ITALIC: + tsp.italics = FC_SLANT_ITALIC; break; + default: + case SP_CSS_FONT_STYLE_NORMAL: + tsp.italics = FC_SLANT_ROMAN; break; + } + switch(d->dc[d->level].style.font_weight.value){ + case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break; + case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; + case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break; + case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break; + case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break; + case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break; + case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break; + case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; + case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break; + case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break; + case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break; + case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; + case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; + default: tsp.weight = FC_WEIGHT_NORMAL ; break; + } + // EMF only supports two types of text decoration + tsp.decoration = TXTDECOR_NONE; + if(d->dc[d->level].style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; } + if(d->dc[d->level].style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;} + + // EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left + tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER : + (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT : + ALIRIGHT); + tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE : + ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT : + ALITOP)); + + // language direction can be encoded two ways, U_TA_RTLREADING is preferred + if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; } + else{ tsp.ldir = LDIR_LR; } + + tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet) + tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement + tsp.ori += 180.0 * current_rotation(d)/ M_PI; // radians to degrees + tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear(). + tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points + char *fontspec = TR_construct_fontspec(&tsp, d->dc[d->level].font_name); + tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec); + free(fontspec); + // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though + // as the metrics from fontconfig may not match, or the font may not be present. + if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; } + else { tsp.co=0; } + + int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement + if(status==-1){ // change of escapement, emit what we have and reset + TR_layout_analyze(d->tri); + TR_layout_2_svg(d->tri); + ts << d->tri->out; + *(d->outsvg) += ts.str().c_str(); + d->tri = trinfo_clear(d->tri); + (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work + } + + g_free(escaped_text); + free(ansi_text); + } + + break; + } + case U_EMR_POLYBEZIER16: + { + dbg_str << "<!-- U_EMR_POLYBEZIER16 -->\n"; + + PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i,j; + + if (pEmr->cpts<4) + break; + + d->mask |= emr_mask; + + tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " "; + + for (i=1; i<pEmr->cpts; ) { + tmp_str << "\n\tC "; + for (j=0; j<3 && i<pEmr->cpts; j++,i++) { + tmp_str << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; + } + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYGON16: + { + dbg_str << "<!-- U_EMR_POLYGON16 -->\n"; + + PU_EMRPOLYGON16 pEmr = (PU_EMRPOLYGON16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + SVGOStringStream tmp_poly; + unsigned int i; + unsigned int first = 0; + + d->mask |= emr_mask; + + // skip the first point? + tmp_poly << "\n\tM " << pix_to_xy( d, apts[first].x, apts[first].y ) << " "; + + for (i=first+1; i<pEmr->cpts; i++) { + tmp_poly << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; + } + + tmp_path << tmp_poly.str().c_str(); + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + + break; + } + case U_EMR_POLYLINE16: + { + dbg_str << "<!-- U_EMR_POLYLINE16 -->\n"; + + PU_EMRPOLYLINE16 pEmr = (PU_EMRPOLYLINE16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i; + + if (pEmr->cpts<2) + break; + + d->mask |= emr_mask; + + tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " "; + + for (i=1; i<pEmr->cpts; i++) { + tmp_str << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYBEZIERTO16: + { + dbg_str << "<!-- U_EMR_POLYBEZIERTO16 -->\n"; + + PU_EMRPOLYBEZIERTO16 pEmr = (PU_EMRPOLYBEZIERTO16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i,j; + + d->mask |= emr_mask; + + for (i=0; i<pEmr->cpts;) { + tmp_path << "\n\tC "; + for (j=0; j<3 && i<pEmr->cpts; j++,i++) { + tmp_path << pix_to_xy( d, apts[i].x, apts[i].y) << " "; + } + } + + break; + } + case U_EMR_POLYLINETO16: + { + dbg_str << "<!-- U_EMR_POLYLINETO16 -->\n"; + + PU_EMRPOLYLINETO16 pEmr = (PU_EMRPOLYLINETO16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i; + + d->mask |= emr_mask; + + for (i=0; i<pEmr->cpts;i++) { + tmp_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; + } + + break; + } + case U_EMR_POLYPOLYLINE16: + case U_EMR_POLYPOLYGON16: + { + if (lpEMFR->iType == U_EMR_POLYPOLYLINE16) + dbg_str << "<!-- U_EMR_POLYPOLYLINE16 -->\n"; + if (lpEMFR->iType == U_EMR_POLYPOLYGON16) + dbg_str << "<!-- U_EMR_POLYPOLYGON16 -->\n"; + + PU_EMRPOLYPOLYGON16 pEmr = (PU_EMRPOLYPOLYGON16) lpEMFR; + unsigned int n, i, j; + + d->mask |= emr_mask; + + PU_POINT16 apts = (PU_POINT16) &pEmr->aPolyCounts[pEmr->nPolys]; + + i = 0; + for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) { + SVGOStringStream poly_path; + + poly_path << "\n\tM " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; + i++; + + for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) { + poly_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; + i++; + } + + tmp_str << poly_path.str().c_str(); + if (lpEMFR->iType == U_EMR_POLYPOLYGON16) + tmp_str << " z"; + tmp_str << " \n"; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYDRAW16: dbg_str << "<!-- U_EMR_POLYDRAW16 -->\n"; break; + case U_EMR_CREATEMONOBRUSH: + { + dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n"; + + PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) lpEMFR; + insert_object(d, pEmr->ihBrush, U_EMR_CREATEMONOBRUSH, lpEMFR); + break; + } + case U_EMR_CREATEDIBPATTERNBRUSHPT: + { + dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n"; + + PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) lpEMFR; + insert_object(d, pEmr->ihBrush, U_EMR_CREATEDIBPATTERNBRUSHPT, lpEMFR); + break; + } + case U_EMR_EXTCREATEPEN: + { + dbg_str << "<!-- U_EMR_EXTCREATEPEN -->\n"; + + PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN) lpEMFR; + insert_object(d, pEmr->ihPen, U_EMR_EXTCREATEPEN, lpEMFR); + break; + } + case U_EMR_POLYTEXTOUTA: dbg_str << "<!-- U_EMR_POLYTEXTOUTA -->\n"; break; + case U_EMR_POLYTEXTOUTW: dbg_str << "<!-- U_EMR_POLYTEXTOUTW -->\n"; break; + case U_EMR_SETICMMODE: + { + dbg_str << "<!-- U_EMR_SETICMMODE -->\n"; + PU_EMRSETICMMODE pEmr = (PU_EMRSETICMMODE) lpEMFR; + ICMmode= pEmr->iMode; + break; + } + case U_EMR_CREATECOLORSPACE: dbg_str << "<!-- U_EMR_CREATECOLORSPACE -->\n"; break; + case U_EMR_SETCOLORSPACE: dbg_str << "<!-- U_EMR_SETCOLORSPACE -->\n"; break; + case U_EMR_DELETECOLORSPACE: dbg_str << "<!-- U_EMR_DELETECOLORSPACE -->\n"; break; + case U_EMR_GLSRECORD: dbg_str << "<!-- U_EMR_GLSRECORD -->\n"; break; + case U_EMR_GLSBOUNDEDRECORD: dbg_str << "<!-- U_EMR_GLSBOUNDEDRECORD -->\n"; break; + case U_EMR_PIXELFORMAT: dbg_str << "<!-- U_EMR_PIXELFORMAT -->\n"; break; + case U_EMR_DRAWESCAPE: dbg_str << "<!-- U_EMR_DRAWESCAPE -->\n"; break; + case U_EMR_EXTESCAPE: dbg_str << "<!-- U_EMR_EXTESCAPE -->\n"; break; + case U_EMR_UNDEF107: dbg_str << "<!-- U_EMR_UNDEF107 -->\n"; break; + // U_EMR_SMALLTEXTOUT is handled with U_EMR_EXTTEXTOUTA/W above + case U_EMR_FORCEUFIMAPPING: dbg_str << "<!-- U_EMR_FORCEUFIMAPPING -->\n"; break; + case U_EMR_NAMEDESCAPE: dbg_str << "<!-- U_EMR_NAMEDESCAPE -->\n"; break; + case U_EMR_COLORCORRECTPALETTE: dbg_str << "<!-- U_EMR_COLORCORRECTPALETTE -->\n"; break; + case U_EMR_SETICMPROFILEA: dbg_str << "<!-- U_EMR_SETICMPROFILEA -->\n"; break; + case U_EMR_SETICMPROFILEW: dbg_str << "<!-- U_EMR_SETICMPROFILEW -->\n"; break; + case U_EMR_ALPHABLEND: dbg_str << "<!-- U_EMR_ALPHABLEND -->\n"; break; + case U_EMR_SETLAYOUT: dbg_str << "<!-- U_EMR_SETLAYOUT -->\n"; break; + case U_EMR_TRANSPARENTBLT: dbg_str << "<!-- U_EMR_TRANSPARENTBLT -->\n"; break; + case U_EMR_UNDEF117: dbg_str << "<!-- U_EMR_UNDEF117 -->\n"; break; + case U_EMR_GRADIENTFILL: dbg_str << "<!-- U_EMR_GRADIENTFILL -->\n"; break; + /* Gradient fill is doable for rectangles because those correspond to linear gradients. However, + the general case for the triangle fill, with a different color in each corner of the triangle, + has no SVG equivalent and cannot be easily emulated with SVG gradients. Except that so far + I (DM) have not been able to make an EMF with a rectangular gradientfill record which is not + completely toxic to other EMF readers. So far now, do nothing. + */ + case U_EMR_SETLINKEDUFIS: dbg_str << "<!-- U_EMR_SETLINKEDUFIS -->\n"; break; + case U_EMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_EMR_SETTEXTJUSTIFICATION -->\n"; break; + case U_EMR_COLORMATCHTOTARGETW: dbg_str << "<!-- U_EMR_COLORMATCHTOTARGETW -->\n"; break; + case U_EMR_CREATECOLORSPACEW: dbg_str << "<!-- U_EMR_CREATECOLORSPACEW -->\n"; break; + default: + dbg_str << "<!-- U_EMR_??? -->\n"; + break; + } //end of switch +// When testing, uncomment the following to place a comment for each processed EMR record in the SVG +// *(d->outsvg) += dbg_str.str().c_str(); + *(d->outsvg) += tmp_outsvg.str().c_str(); + *(d->path) += tmp_path.str().c_str(); + + } //end of while +// When testing, uncomment the following to show the final SVG derived from the EMF +//std::cout << *(d->outsvg) << std::endl; + (void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant + + return 1; +} + + +// Aldus Placeable Header =================================================== +// Since we are a 32bit app, we have to be sure this structure compiles to +// be identical to a 16 bit app's version. To do this, we use the #pragma +// to adjust packing, we use a uint16_t for the hmf handle, and a SMALL_RECT +// for the bbox rectangle. +#pragma pack( push ) +#pragma pack( 2 ) +typedef struct _SMALL_RECT { + int16_t Left; + int16_t Top; + int16_t Right; + int16_t Bottom; +} SMALL_RECT, *PSMALL_RECT; +typedef struct +{ + uint32_t dwKey; + uint16_t hmf; + SMALL_RECT bbox; + uint16_t wInch; + uint32_t dwReserved; + uint16_t wCheckSum; +} APMHEADER, *PAPMHEADER; +#pragma pack( pop ) + +void Emf::free_emf_strings(EMF_STRINGS name){ + if(name.count){ + for(int i=0; i< name.count; i++){ free(name.strings[i]); } + free(name.strings); + } +} + +SPDocument * +Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) +{ + EMF_CALLBACK_DATA d; + +// memset(&d, 0, sizeof(d)); + memset(&d, 0, sizeof(EMF_CALLBACK_DATA)); + + for(int i = 0; i < EMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with + memset(&(d.dc[i]),0,sizeof(EMF_DEVICE_CONTEXT)); + } + + d.dc[0].worldTransform.eM11 = 1.0; + d.dc[0].worldTransform.eM12 = 0.0; + d.dc[0].worldTransform.eM21 = 0.0; + d.dc[0].worldTransform.eM22 = 1.0; + d.dc[0].worldTransform.eDx = 0.0; + d.dc[0].worldTransform.eDy = 0.0; + d.dc[0].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants + d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black) + d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white) + d.dc[0].bkMode = U_TRANSPARENT; + d.dc[0].dirty = 0; + + if (uri == NULL) { + return NULL; + } + + d.outsvg = new Glib::ustring(""); + d.path = new Glib::ustring(""); + d.outdef = new Glib::ustring(""); + d.defs = new Glib::ustring(""); + d.mask = 0; + d.drawtype = 0; + d.arcdir = U_AD_COUNTERCLOCKWISE; + d.dwRop2 = U_R2_COPYPEN; + d.dwRop3 = 0; + d.E2IdirY = 1.0; + d.D2PscaleX = 1.0; + d.D2PscaleY = 1.0; + d.hatches.size = 0; + d.hatches.count = 0; + d.hatches.strings = NULL; + d.images.size = 0; + d.images.count = 0; + d.images.strings = NULL; + + // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. + + *(d.defs) += "\n"; + *(d.defs) += " <pattern id=\"EMFhbasepattern\" \n"; + *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n"; + *(d.defs) += " width=\"6\" \n"; + *(d.defs) += " height=\"6\" \n"; + *(d.defs) += " x=\"0\" \n"; + *(d.defs) += " y=\"0\"> \n"; + *(d.defs) += " </pattern> \n"; + + + size_t length; + char *contents; + if(emf_readdata(uri, &contents, &length))return(NULL); + + d.pDesc = NULL; + + // set up the text reassembly system + if(!(d.tri = trinfo_init(NULL)))return(NULL); + (void) trinfo_load_ft_opts(d.tri, 1, + FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, + FT_KERNING_UNSCALED); + + (void) myEnhMetaFileProc(contents,length, &d); + free(contents); + + if (d.pDesc){ free( d.pDesc ); } + +// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; + + SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); + + delete d.outsvg; + delete d.path; + delete d.outdef; + delete d.defs; + free_emf_strings(d.hatches); + free_emf_strings(d.images); + + if (d.emf_obj) { + int i; + for (i=0; i<d.n_obj; i++) + delete_object(&d, i); + delete[] d.emf_obj; + } + + if (d.dc[0].style.stroke_dash.dash) + delete[] d.dc[0].style.stroke_dash.dash; + + for(int i=0; i<=d.level;i++){ + if(d.dc[i].font_name)free(d.dc[i].font_name); + } + + d.tri = trinfo_release_except_FC(d.tri); + + return doc; +} + + +void +Emf::init (void) +{ + /* EMF in */ + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("EMF Input") "</name>\n" + "<id>org.inkscape.input.emf</id>\n" + "<input>\n" + "<extension>.emf</extension>\n" + "<mimetype>image/x-emf</mimetype>\n" + "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n" + "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n" + "<output_extension>org.inkscape.output.emf</output_extension>\n" + "</input>\n" + "</inkscape-extension>", new Emf()); + + /* EMF out */ + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("EMF Output") "</name>\n" + "<id>org.inkscape.output.emf</id>\n" + "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n" + "<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"boolean\">true</param>\n" + "<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"boolean\">true</param>\n" + "<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"boolean\">true</param>\n" + "<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard EMF hatches") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixImageRot\" gui-text=\"" N_("Ignore image rotations") "\" type=\"boolean\">false</param>\n" + "<output>\n" + "<extension>.emf</extension>\n" + "<mimetype>image/x-emf</mimetype>\n" + "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n" + "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n" + "</output>\n" + "</inkscape-extension>", new Emf()); + + return; +} + + +} } } /* namespace Inkscape, Extension, Implementation */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h new file mode 100644 index 000000000..b723f067f --- /dev/null +++ b/src/extension/internal/emf-inout.h @@ -0,0 +1,211 @@ +/** @file + * @brief Enhanced Metafile Input/Output + */ +/* Authors: + * Ulf Erikson <ulferikson@users.sf.net> + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef SEEN_EXTENSION_INTERNAL_EMF_H +#define SEEN_EXTENSION_INTERNAL_EMF_H + +#define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler +#include <png.h> +#include "extension/implementation/implementation.h" +#include "style.h" +#include "uemf.h" +#include "text_reassemble.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { + +#define DIRTY_NONE 0x00 +#define DIRTY_TEXT 0x01 +#define DIRTY_FILL 0x02 +#define DIRTY_STROKE 0x04 + +typedef struct { + int type; + int level; + char *lpEMFR; +} EMF_OBJECT, *PEMF_OBJECT; + +typedef struct { + int size; // number of slots allocated in strings + int count; // number of slots used in strings + char **strings; // place to store strings +} EMF_STRINGS, *PEMF_STRINGS; + +typedef struct emf_device_context { + struct SPStyle style; + char *font_name; + bool stroke_set; + int stroke_mode; // enumeration from drawmode, not used if fill_set is not True + int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill + int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change + bool fill_set; + int fill_mode; // enumeration from drawmode, not used if fill_set is not True + int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill + int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change + int dirty; // holds the dirty bits for text, stroke, fill + U_SIZEL sizeWnd; + U_SIZEL sizeView; + U_POINTL winorg; + U_POINTL vieworg; + double ScaleInX, ScaleInY; + double ScaleOutX, ScaleOutY; + uint16_t bkMode; + U_COLORREF bkColor; + U_COLORREF textColor; + uint32_t textAlign; + U_XFORM worldTransform; + U_POINTL cur; +} EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT; + +#define EMF_MAX_DC 128 + +/* + both emf-inout.h and wmf-inout.h are included by init.cpp, so whichever one goes in first defines these ommon types +*/ +#ifndef SEEN_EXTENSION_INTERNAL_METAFILECOMMON_ +#define SEEN_EXTENSION_INTERNAL_METAFILECOMMON_ +/* A coloured pixel. */ +typedef struct { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t opacity; +} pixel_t; + +/* A picture. */ + +typedef struct { + pixel_t *pixels; + size_t width; + size_t height; +} bitmap_t; + +/* structure to store PNG image bytes */ +typedef struct { + char *buffer; + size_t size; +} MEMPNG, *PMEMPNG; +#endif + +typedef struct { + Glib::ustring *outsvg; + Glib::ustring *path; + Glib::ustring *outdef; + Glib::ustring *defs; + + EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic.. + int level; + + double E2IdirY; // EMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc. + double D2PscaleX,D2PscaleY; // EMF device to Inkscape Page scale. + float MM100InX, MM100InY; // size of the drawing in hundredths of a millimeter + float PixelsInX, PixelsInY; // size of the drawing, in EMF device pixels + float PixelsOutX, PixelsOutY; // size of the drawing, in Inkscape pixels + double ulCornerInX,ulCornerInY; // Upper left corner, from header rclBounds, in logical units + double ulCornerOutX,ulCornerOutY; // Upper left corner, in Inkscape pixels + uint32_t mask; // Draw properties + int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 + + uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested) + uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested) + + float MMX; + float MMY; + + unsigned int id; + unsigned int drawtype; // one of 0 or U_EMR_FILLPATH, U_EMR_STROKEPATH, U_EMR_STROKEANDFILLPATH + char *pDesc; + // both of these end up in <defs> under the names shown here. These structures allow duplicates to be avoided. + EMF_STRINGS hatches; // hold pattern names, all like EMFhatch#_$$$$$$ where # is the EMF hatch code and $$$$$$ is the color + EMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives. + TR_INFO *tri; // Text Reassembly data structure + + + int n_obj; + PEMF_OBJECT emf_obj; +} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA; + +class Emf : Inkscape::Extension::Implementation::Implementation { //This is a derived class + +public: + + Emf(); // Empty constructor + + virtual ~Emf();//Destructor + + bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) + + void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename + SPDocument *doc, + gchar const *filename); + + virtual SPDocument *open( Inkscape::Extension::Input *mod, + const gchar *uri ); + + static void init(void);//Initialize the class + +private: + +protected: + + static pixel_t *pixel_at (bitmap_t * bitmap, int x, int y); + static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); + static void toPNG(PMEMPNG accum, int width, int height, const char *px); + static uint32_t sethexcolor(U_COLORREF color); + static void print_document_to_file(SPDocument *doc, const gchar *filename); + static double current_scale(PEMF_CALLBACK_DATA d); + static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset); + static double current_rotation(PEMF_CALLBACK_DATA d); + static void enlarge_hatches(PEMF_CALLBACK_DATA d); + static int in_hatches(PEMF_CALLBACK_DATA d, char *test); + static uint32_t add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor); + static void enlarge_images(PEMF_CALLBACK_DATA d); + static int in_images(PEMF_CALLBACK_DATA d, char *test); + static uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi, + uint32_t iUsage, uint32_t offBits, uint32_t offBmi); + static void output_style(PEMF_CALLBACK_DATA d, int iType); + static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px); + static double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py); + static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py); + static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py); + static double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px); + static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y); + static void select_pen(PEMF_CALLBACK_DATA d, int index); + static void select_extpen(PEMF_CALLBACK_DATA d, int index); + static void select_brush(PEMF_CALLBACK_DATA d, int index); + static void select_font(PEMF_CALLBACK_DATA d, int index); + static void delete_object(PEMF_CALLBACK_DATA d, int index); + static void insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj); + static int AI_hack(PU_EMRHEADER pEmr); + static uint32_t *unknown_chars(size_t count); + static void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, + double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, + uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi); + static int myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d); + static void free_emf_strings(EMF_STRINGS name); + +}; + +} } } /* namespace Inkscape, Extension, Implementation */ + + +#endif /* EXTENSION_INTERNAL_EMF_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp new file mode 100644 index 000000000..33834bea8 --- /dev/null +++ b/src/extension/internal/emf-print.cpp @@ -0,0 +1,2202 @@ +/** @file + * @brief Enhanced Metafile printing + */ +/* Authors: + * Ulf Erikson <ulferikson@users.sf.net> + * Jon A. Cruz <jon@joncruz.org> + * Abhishek Sharma + * David Mathog + * + * Copyright (C) 2006-2009 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +/* + * References: + * - How to Create & Play Enhanced Metafiles in Win32 + * http://support.microsoft.com/kb/q145999/ + * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles + * http://support.microsoft.com/kb/q66949/ + * - Metafile Functions + * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp + * - Metafile Structures + * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include "2geom/sbasis-to-bezier.h" +#include "2geom/svg-elliptical-arc.h" + +#include "2geom/path.h" +#include "2geom/pathvector.h" +#include "2geom/rect.h" +#include "2geom/bezier-curve.h" +#include "2geom/hvlinesegment.h" +#include "helper/geom.h" +#include "helper/geom-curves.h" +#include "sp-item.h" +#include "util/units.h" + +#include "style.h" +#include "inkscape-version.h" +#include "sp-root.h" + +#include "extension/system.h" +#include "extension/print.h" +#include "document.h" +#include "path-prefix.h" +#include "sp-pattern.h" +#include "sp-image.h" +#include "sp-gradient.h" +#include "sp-radial-gradient.h" +#include "sp-linear-gradient.h" + +#include "splivarot.h" // pieces for union on shapes +#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path +#include "display/canvas-bpath.h" // for SPWindRule + +#include "emf-print.h" + + +#include <string.h> +extern "C" { +#include "libunicode-convert/unicode-convert.h" +} + + +namespace Inkscape { +namespace Extension { +namespace Internal { + +#define PXPERMETER 2835 + + +enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT}; + +struct FFNEXUS { + char *fontname; //Font name + FFNEXUS *next; //link to next nexus, NULL if this is the last + double f1; //Vertical (rotating) offset factor (* font height) + double f2; //Vertical (nonrotating) offset factor (* font height) + double f3; //Horizontal (nonrotating) offset factor (* font height) +}; + +struct GRADVALUES{ + Geom::Point p1; // center or start + Geom::Point p2; // xhandle or end + Geom::Point p3; // yhandle or unused + double r; // radius or unused + void *grad; // to access the stops information + int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value + U_COLORREF bgc; // document background color, this is as good a place as any to keep it + float rgb[3]; // also background color, but as 0-1 float. +}; + +/* globals */ +static double PX2WORLD = 20.0f; +static U_XFORM worldTransform; +static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot; +static FFNEXUS *emf_short_fflist = NULL; //only those fonts so far encountered. This is SHARED with wmf-print.cpp +static FFNEXUS *emf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf +static EMFTRACK *et = NULL; +static EMFHANDLES *eht = NULL; +static GRADVALUES gv; + +void PrintEmf::read_system_fflist(void){ //this is not called by any other source files + FFNEXUS *temp=NULL; + FFNEXUS *ptr=NULL; + std::fstream fffile; + std::string instr; + char fontname[128]; + double f1,f2,f3; + std::string path_to_ffconf; + + if(emf_long_fflist)return; + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + + path_to_ffconf=INKSCAPE_EXTENSIONDIR; +#ifdef WIN32 + path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax +#else + path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax +#endif + //open the input + fffile.open(path_to_ffconf.c_str(), std::ios::in); + if(!fffile.is_open()){ + g_error("Unable to open file: %s\n", path_to_ffconf.c_str()); + } + while (std::getline(fffile,instr)){ + if(instr[0]=='#')continue; + // not a comment, get the 4 values from the line + int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]); + if(elements!=4){ + g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str()); + } + temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed + temp->f1=f1; + temp->f2=f2; + temp->f3=f3; + temp->fontname=strdup(fontname); //This will never be freed + temp->next=NULL; //just to be explicit, it is already 0 + if(ptr){ + ptr->next=temp; + ptr=temp; + } + else { + emf_long_fflist=ptr=temp; + } + } + fffile.close(); + + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); +} + +/* Looks for the fontname in the long list. If it does not find it, it adds the default values +to the short list with this fontname. If it does find it, then it adds the specified values. +*/ +void PrintEmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files + FFNEXUS *ptr=NULL; + FFNEXUS *tmp=emf_long_fflist; + if(!emf_long_fflist){ + g_error("Programming error search_long_fflist called before read_system_fflist\n"); + } + ptr=emf_long_fflist; + while(ptr){ + if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; } + ptr=ptr->next; + } + //tmp points at either the found name, or the default, the first entry in long_fflist + if(!emf_short_fflist){ + ptr=emf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS)); + } + else { + ptr=emf_short_fflist; + while(ptr->next){ ptr=ptr->next; } + ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS)); + ptr=ptr->next; + } + ptr->fontname=strdup(tmp->fontname); + *f1 = ptr->f1 = tmp->f1; + *f2 = ptr->f2 = tmp->f2; + *f3 = ptr->f3 = tmp->f3; + ptr->next=NULL; +} + +/* Looks for the fontname in the short list. If it does not find it, it looks in the long_fflist. +Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default. +*/ +void PrintEmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files + FFNEXUS *ptr=NULL; + static FFNEXUS *last=NULL; + + if(!emf_long_fflist){ + g_error("Programming error search_short_fflist called before read_system_fflist\n"); + } + // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately + if(last && !strcmp(last->fontname,fontname)){ ptr=last; } + else { ptr=emf_short_fflist; } // short_fflist may still be NULL + while(ptr){ + if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; } + ptr=ptr->next; + } + //reach this point only if there is no match + search_long_fflist(fontname, f1, f2, f3); +} + +void PrintEmf::smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale){ + float fdx; + int i; + uint32_t *ladx; + const char *cptr=&string[strlen(string)+1]; // this works because of the first fake terminator + + *adx = NULL; + *ky = 0.0; // set a default value + sscanf(cptr,"%7d",ndx); + if(!*ndx)return; // this could happen with an empty string + cptr += 7; + ladx = (uint32_t *) malloc(*ndx * sizeof(uint32_t) ); + if(!ladx)g_message("Out of memory"); + *adx=ladx; + for(i=0; i<*ndx; i++,cptr+=7, ladx++){ + sscanf(cptr,"%7f",&fdx); + *ladx=(uint32_t) round(fdx * scale); + } + cptr++; // skip 2nd fake terminator + sscanf(cptr,"%7f",&fdx); + *ky=fdx; + cptr += 7; // advance over ky and its space + sscanf(cptr,"%07d",rtl); +} + +/* convert an 0RGB color to EMF U_COLORREF. +inverse of sethexcolor() in emf-inout.cpp +*/ +U_COLORREF PrintEmf::gethexcolor(uint32_t color){ + U_COLORREF out; + out = U_RGB( + (color >> 16) & 0xFF, + (color >> 8) & 0xFF, + (color >> 0) & 0xFF + ); + return(out); +} + + +/* Translate inkscape weights to EMF weights. +*/ +uint32_t PrintEmf::transweight(const unsigned int inkweight){ + if(inkweight == SP_CSS_FONT_WEIGHT_400)return(U_FW_NORMAL); + if(inkweight == SP_CSS_FONT_WEIGHT_100)return(U_FW_THIN); + if(inkweight == SP_CSS_FONT_WEIGHT_200)return(U_FW_EXTRALIGHT); + if(inkweight == SP_CSS_FONT_WEIGHT_300)return(U_FW_LIGHT); + // 400 is tested first, as it is the most common case + if(inkweight == SP_CSS_FONT_WEIGHT_500)return(U_FW_MEDIUM); + if(inkweight == SP_CSS_FONT_WEIGHT_600)return(U_FW_SEMIBOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_700)return(U_FW_BOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_800)return(U_FW_EXTRABOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_900)return(U_FW_HEAVY); + return(U_FW_NORMAL); +} + +PrintEmf::PrintEmf (void) +{ + // all of the class variables are initialized elsewhere, many in PrintEmf::Begin, +} + + +PrintEmf::~PrintEmf (void) +{ + + /* restore default signal handling for SIGPIPE */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_DFL); +#endif + return; +} + + +unsigned int PrintEmf::setup (Inkscape::Extension::Print * /*mod*/) +{ + return TRUE; +} + + +unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) +{ + U_SIZEL szlDev, szlMm; + U_RECTL rclBounds, rclFrame; + char *rec; + gchar const *utf8_fn = mod->get_param_string("destination"); + + FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); + FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); + FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); + FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); + FixImageRot = mod->get_param_bool("FixImageRot"); + + (void) emf_start(utf8_fn, 1000000, 250000, &et); // Initialize the et structure + (void) htable_create(128, 128, &eht); // Initialize the eht structure + + char *ansi_uri = (char *) utf8_fn; + + + // width and height in px + _width = doc->getWidth(); + _height = doc->getHeight(); + + // initialize a few global variables + hbrush = hbrushOld = hpen = 0; + htextalignment = U_TA_BASELINE | U_TA_LEFT; + use_stroke = use_fill = simple_shape = usebk = false; + + Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview"); + if(nv){ + const char *p1 = nv->attribute("pagecolor"); + char *p2; + uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123" + if(*p2)lc=0; + gv.bgc = gethexcolor(lc); + gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0; + gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0; + gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0; + } + + bool pageBoundingBox; + pageBoundingBox = mod->get_param_bool("pageBoundingBox"); + + Geom::Rect d; + if (pageBoundingBox) { + d = Geom::Rect::from_xywh(0, 0, _width, _height); + } else { + SPItem* doc_item = doc->getRoot(); + Geom::OptRect bbox = doc_item->desktopVisualBounds(); + if (bbox) d = *bbox; + } + + d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in")); + + float dwInchesX = d.width(); + float dwInchesY = d.height(); + + // dwInchesX x dwInchesY in micrometer units, dpi=90 -> 3543.3 dpm + (void) drawing_size((int) ceil(dwInchesX*25.4), (int) ceil(dwInchesY*25.4), 3.543307, &rclBounds, &rclFrame); + + // set up the reference device as 100 X A4 horizontal, (1200 dpi/25.4 -> dpmm). Extra digits maintain dpi better in EMF + int MMX = 21600; + int MMY = 27900; + (void) device_size(MMX, MMY, 1200.0/25.4, &szlDev, &szlMm); + int PixelsX = szlDev.cx; + int PixelsY = szlDev.cy; + + // set up the description: (version string)0(file)00 + char buff[1024]; + memset(buff,0, sizeof(buff)); + char *p1 = strrchr(ansi_uri, '\\'); + char *p2 = strrchr(ansi_uri, '/'); + char *p = MAX(p1, p2); + if (p) + p++; + else + p = ansi_uri; + snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)\1%s\1", Inkscape::version_string, __DATE__,p); + uint16_t *Description = U_Utf8ToUtf16le(buff, 0, NULL); + int cbDesc = 2 + wchar16len(Description); // also count the final terminator + (void) U_Utf16leEdit(Description, '\1', '\0'); // swap the temporary \1 characters for nulls + + // construct the EMRHEADER record and append it to the EMF in memory + rec = U_EMRHEADER_set( rclBounds, rclFrame, NULL, cbDesc, Description, szlDev, szlMm, 0); + free(Description); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at EMRHEADER"); + } + + + // Simplest mapping mode, supply all coordinates in pixels + rec = U_EMRSETMAPMODE_set(U_MM_TEXT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at EMRSETMAPMODE"); + } + + + // Correct for dpi in EMF (1200) vs dpi in Inkscape (always 90). + // Also correct for the scaling in PX2WORLD, which is set to 20. + + worldTransform.eM11 = 1200./(90.0*PX2WORLD); + worldTransform.eM12 = 0.0; + worldTransform.eM21 = 0.0; + worldTransform.eM22 = 1200./(90.0*PX2WORLD); + worldTransform.eDx = 0; + worldTransform.eDy = 0; + + rec = U_EMRMODIFYWORLDTRANSFORM_set(worldTransform, U_MWT_LEFTMULTIPLY); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM"); + } + + + if (1) { + snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY); + rec = textcomment_set(buff); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1"); + } + + snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * Inkscape::Util::Quantity::convert(1, "in", "mm"), dwInchesY * Inkscape::Util::Quantity::convert(1, "in", "mm")); + rec = textcomment_set(buff); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1"); + } + } + + /* set some parameters, else the program that reads the EMF may default to other values */ + + rec = U_EMRSETBKMODE_set(U_TRANSPARENT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at U_EMRSETBKMODE_set"); + } + + hpolyfillmode=U_WINDING; + rec = U_EMRSETPOLYFILLMODE_set(U_WINDING); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at U_EMRSETPOLYFILLMODE_set"); + } + + // Text alignment: (only changed if RTL text is encountered ) + // - (x,y) coordinates received by this filter are those of the point where the text + // actually starts, and already takes into account the text object's alignment; + // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT. + htextalignment = U_TA_BASELINE | U_TA_LEFT; + rec = U_EMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at U_EMRSETTEXTALIGN_set"); + } + + htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; + rec = U_EMRSETTEXTCOLOR_set(U_RGB(0,0,0)); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at U_EMRSETTEXTCOLOR_set"); + } + + rec = U_EMRSETROP2_set(U_R2_COPYPEN); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::begin at U_EMRSETROP2_set"); + } + + /* miterlimit is set with eah pen, so no need to check for it changes as in WMF */ + + return 0; +} + + +unsigned int PrintEmf::finish (Inkscape::Extension::Print * /*mod*/) +{ + char *rec; + if (!et) return 0; + + + // earlier versions had flush of fill here, but it never executed and was removed + + rec = U_EMREOF_set(0,NULL,et); // generate the EOF record + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::finish"); + } + (void) emf_finish(et, eht); // Finalize and write out the EMF + emf_free(&et); // clean up + htable_free(&eht); // clean up + + return 0; +} + + +unsigned int PrintEmf::comment ( + Inkscape::Extension::Print * /*module*/, + const char * /*comment*/) +{ + if (!et) return 0; + + // earlier versions had flush of fill here, but it never executed and was removed + + return 0; +} + +// Extract hatchType, hatchColor from a name like +// EMFhatch<hatchType>_<hatchColor> +// Where the first one is a number and the second a color in hex. +// hatchType and hatchColor have been set with defaults before this is called. +// +void PrintEmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ + int val; + uint32_t hcolor=0; + uint32_t bcolor=0; + + // name should be EMFhatch or WMFhatch but *MFhatch will be accepted + if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse + name += 8; // EMFhatch already detected + val = 0; + while(*name && isdigit(*name)){ + val = 10*val + *name - '0'; + name++; + } + *hatchType = val; + if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify + *hatchType = -1; + } + else { + name++; + if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background + if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify + *hatchColor = gethexcolor(hcolor); + } + else { + *hatchColor = gethexcolor(hcolor); + *bkColor = gethexcolor(bcolor); + usebk = true; + } + } + /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */ + if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR; +} + +// +// Recurse down from a brush pattern, try to figure out what it is. +// If an image is found set a pointer to the epixbuf, else set that to NULL +// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t), +// otherwise hatchType is set to -1 and hatchColor is not defined. +// + +void PrintEmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ + if(depth==0){ + *epixbuf = NULL; + *hatchType = -1; + *hatchColor = U_RGB(0,0,0); + *bkColor = U_RGB(255,255,255); + } + depth++; + // first look along the pattern chain, if there is one + if(SP_IS_PATTERN(parent)){ + for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + if(SP_IS_IMAGE(pat_i)){ + *epixbuf = ((SPImage *)pat_i)->pixbuf; + return; + } + char temp[32]; // large enough + temp[31]='\0'; + strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_###### + hatch_classify(temp, hatchType, hatchColor, bkColor); + if(*hatchType != -1)return; + + // still looking? Look at this pattern's children, if there are any + SPObject *child = pat_i->firstChild(); + while(child && !(*epixbuf) && (*hatchType == -1)){ + brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); + child = child->getNext(); + } + } + } + else if(SP_IS_IMAGE(parent)){ + *epixbuf = ((SPImage *)parent)->pixbuf; + return; + } + else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either. + SPObject *child = parent->firstChild(); + while(child && !(*epixbuf) && (*hatchType == -1)){ + brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); + child = child->getNext(); + } + } +} + +//swap R/B in 4 byte pixel +void PrintEmf::swapRBinRGBA(char *px, int pixels){ + char tmp; + for(int i=0;i<pixels*4;px+=4,i+=4){ + tmp=px[2]; + px[2]=px[0]; + px[0]=tmp; + } +} + +/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */ +inline float opweight(float v1, float v2, float op){ + return v1*op + v2*(1.0-op); +} + +U_COLORREF PrintEmf::avg_stop_color(SPGradient *gr){ + U_COLORREF cr; + int last = gr->vector.stops.size() -1; + if(last>=1){ + float rgbs[3]; + float rgbe[3]; + float ops,ope; + + ops = gr->vector.stops[0 ].opacity; + ope = gr->vector.stops[last].opacity; + sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs); + sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe); + + /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */ + cr = U_RGB( + 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0), + 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0), + 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0) + ); + } + else { + cr = U_RGB(0, 0, 0); // The default fill + } + return cr; +} + +int PrintEmf::hold_gradient(void *gr, int mode){ + gv.mode = mode; + gv.grad = gr; + if(mode==DRAW_RADIAL_GRADIENT){ + SPRadialGradient *rg = (SPRadialGradient *) gr; + gv.r = rg->r.computed; // radius, but of what??? + gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center + gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle + gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle + if (rg->gradientTransform_set) { + gv.p1 = gv.p1 * rg->gradientTransform; + gv.p2 = gv.p2 * rg->gradientTransform; + gv.p3 = gv.p3 * rg->gradientTransform; + } + } + else if(mode==DRAW_LINEAR_GRADIENT){ + SPLinearGradient *lg = (SPLinearGradient *) gr; + gv.r = 0; // unused + gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start + gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end + gv.p3 = Geom::Point (0, 0); // unused + if (lg->gradientTransform_set) { + gv.p1 = gv.p1 * lg->gradientTransform; + gv.p2 = gv.p2 * lg->gradientTransform; + } + } + else { + g_error("Fatal programming error, hold_gradient() in emf-print.cpp called with invalid draw mode"); + } + return 1; +} + +// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring. +int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) +{ + float rgb[3]; + char *rec; + U_LOGBRUSH lb; + uint32_t brush, fmode; + enum drawmode fill_mode; + GdkPixbuf *pixbuf; + uint32_t brushStyle; + int hatchType; + U_COLORREF hatchColor; + U_COLORREF bkColor; + uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required. + uint32_t height = 0; + + if (!et) return 0; + + // set a default fill in case we can't figure out a better way to do it + fmode = U_ALTERNATE; + fill_mode = DRAW_PAINT; + brushStyle = U_BS_SOLID; + hatchType = U_HS_SOLIDCLR; + bkColor = U_RGB(0, 0, 0); + if(fcolor){ hatchColor = *fcolor; } + else { hatchColor = U_RGB(0, 0, 0); } + + if (!fcolor && style) { + if(style->fill.isColor()){ + fill_mode = DRAW_PAINT; + float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); + if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill + + sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); + hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + + fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE); + } + else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server + SPPaintServer *paintserver = style->fill.value.href->getObject(); + SPPattern *pat = SP_PATTERN (paintserver); + double dwidth = pattern_width(pat); + double dheight = pattern_height(pat); + width = dwidth; + height = dheight; + brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor); + if(pixbuf){ fill_mode = DRAW_IMAGE; } + else { // pattern + fill_mode = DRAW_PATTERN; + if(hatchType == -1){ // Not a standard hatch, so force it to something + hatchType = U_HS_CROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + if(FixPPTPatternAsHatch){ + if(hatchType == -1){ // image or unclassified + fill_mode = DRAW_PATTERN; + hatchType = U_HS_DIAGCROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + brushStyle = U_BS_HATCHED; + } + else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient + // currently we do not do anything with gradients, the code below just sets the color to the average of the stops + SPPaintServer *paintserver = style->fill.value.href->getObject(); + SPLinearGradient *lg = NULL; + SPRadialGradient *rg = NULL; + + if (SP_IS_LINEARGRADIENT (paintserver)) { + lg = SP_LINEARGRADIENT(paintserver); + SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built + fill_mode = DRAW_LINEAR_GRADIENT; + } + else if (SP_IS_RADIALGRADIENT (paintserver)) { + rg = SP_RADIALGRADIENT(paintserver); + SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built + fill_mode = DRAW_RADIAL_GRADIENT; + } + else { + // default fill + } + + if(rg){ + if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); } + else { hatchColor = avg_stop_color(rg); } + } + else if(lg){ + if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); } + else { hatchColor = avg_stop_color(lg); } + } + } + } + else { // if (!style) + // default fill + } + + lb = logbrush_set(brushStyle, hatchColor, hatchType); + + switch(fill_mode){ + case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices + case DRAW_RADIAL_GRADIENT: // ditto + case DRAW_PAINT: + case DRAW_PATTERN: + // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. + if(usebk){ + rec = U_EMRSETBKCOLOR_set(bkColor); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKCOLOR_set"); + } + rec = U_EMRSETBKMODE_set(U_OPAQUE); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKMODE_set"); + } + } + rec = createbrushindirect_set(&brush, eht, lb); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_brush at createbrushindirect_set"); + } + break; + case DRAW_IMAGE: + char *px; + char *rgba_px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width*height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set"); + } + free(px); + free(Bmi); // ct will be NULL because of colortype + break; + } + + hbrush = brush; // need this later for destroy_brush + rec = selectobject_set(brush, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_brush at selectobject_set"); + } + + if(fmode != hpolyfillmode){ + hpolyfillmode=fmode; + rec = U_EMRSETPOLYFILLMODE_set(fmode); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETPOLYdrawmode_set"); + } + } + + return 0; +} + + +void PrintEmf::destroy_brush() +{ + char *rec; + // before an object may be safely deleted it must no longer be selected + // select in a stock object to deselect this one, the stock object should + // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work? + rec = selectobject_set(U_NULL_BRUSH, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::destroy_brush at selectobject_set"); + } + if (hbrush){ + rec = deleteobject_set(&hbrush, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::destroy_brush"); + } + hbrush = 0; + } +} + + +int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) +{ + U_EXTLOGPEN *elp; + U_NUM_STYLEENTRY n_dash = 0; + U_STYLEENTRY *dash = NULL; + char *rec = NULL; + int linestyle = U_PS_SOLID; + int linecap = 0; + int linejoin = 0; + uint32_t pen; + uint32_t brushStyle; + GdkPixbuf *pixbuf; + int hatchType; + U_COLORREF hatchColor; + U_COLORREF bkColor; + uint32_t width,height; + char *px=NULL; + char *rgba_px; + uint32_t cbPx=0; + uint32_t colortype; + PU_RGBQUAD ct=NULL; + int numCt=0; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi=NULL; + + if (!et) return 0; + + // set a default stroke in case we can't figure out a better way to do it + brushStyle = U_BS_SOLID; + hatchColor = U_RGB(0, 0, 0); + hatchType = U_HS_HORIZONTAL; + bkColor = U_RGB(0, 0, 0); + + if (style) { + float rgb[3]; + + if(SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))){ // must be paint-server + SPPaintServer *paintserver = style->stroke.value.href->getObject(); + SPPattern *pat = SP_PATTERN (paintserver); + double dwidth = pattern_width(pat); + double dheight = pattern_height(pat); + width = dwidth; + height = dheight; + brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor); + if(pixbuf){ + brushStyle = U_BS_DIBPATTERN; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width*height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + } + else { // pattern + brushStyle = U_BS_HATCHED; + if(usebk){ // OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. + rec = U_EMRSETBKCOLOR_set(bkColor); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKCOLOR_set"); + } + rec = U_EMRSETBKMODE_set(U_OPAQUE); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKMODE_set"); + } + } + if(hatchType == -1){ // Not a standard hatch, so force it to something + hatchType = U_HS_CROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + if(FixPPTPatternAsHatch){ + if(hatchType == -1){ // image or unclassified + brushStyle = U_BS_HATCHED; + hatchType = U_HS_DIAGCROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + } + else if(SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))){ // must be a gradient + // currently we do not do anything with gradients, the code below has no net effect. + + SPPaintServer *paintserver = style->stroke.value.href->getObject(); + if (SP_IS_LINEARGRADIENT (paintserver)) { + SPLinearGradient *lg=SP_LINEARGRADIENT(paintserver); + + SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built + + Geom::Point p1 (lg->x1.computed, lg->y1.computed); + Geom::Point p2 (lg->x2.computed, lg->y2.computed); + + if (lg->gradientTransform_set) { + p1 = p1 * lg->gradientTransform; + p2 = p2 * lg->gradientTransform; + } + hatchColor = avg_stop_color(lg); + } + else if (SP_IS_RADIALGRADIENT (paintserver)) { + SPRadialGradient *rg=SP_RADIALGRADIENT(paintserver); + + SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built + double r = rg->r.computed; + + Geom::Point c (rg->cx.computed, rg->cy.computed); + Geom::Point xhandle_point(r, 0); + Geom::Point yhandle_point(0, -r); + yhandle_point += c; + xhandle_point += c; + if (rg->gradientTransform_set) { + c = c * rg->gradientTransform; + yhandle_point = yhandle_point * rg->gradientTransform; + xhandle_point = xhandle_point * rg->gradientTransform; + } + hatchColor = avg_stop_color(rg); + } + else { + // default fill + } + } + else if(style->stroke.isColor()){ // test last, always seems to be set, even for other types above + sp_color_get_rgb_floatv( &style->stroke.value.color, rgb ); + brushStyle = U_BS_SOLID; + hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + hatchType = U_HS_SOLIDCLR; + } + else { + // default fill + } + + + + using Geom::X; + using Geom::Y; + + Geom::Point zero(0, 0); + Geom::Point one(1, 1); + Geom::Point p0(zero * transform); + Geom::Point p1(one * transform); + Geom::Point p(p1 - p0); + + double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); + + if(!style->stroke_width.computed){return 0;} //if width is 0 do not (reset) the pen, it should already be NULL_PEN + uint32_t linewidth = MAX( 1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD) ); + + if ( style->stroke_linecap.computed == 0){ linecap = U_PS_ENDCAP_FLAT; } + else if (style->stroke_linecap.computed == 1){ linecap = U_PS_ENDCAP_ROUND; } + else if (style->stroke_linecap.computed == 2){ linecap = U_PS_ENDCAP_SQUARE; } + + if ( style->stroke_linejoin.computed == 0){ linejoin = U_PS_JOIN_MITER; } + else if (style->stroke_linejoin.computed == 1){ linejoin = U_PS_JOIN_ROUND; } + else if (style->stroke_linejoin.computed == 2){ linejoin = U_PS_JOIN_BEVEL; } + + if (style->stroke_dash.n_dash && + style->stroke_dash.dash ) + { + if(FixPPTDashLine){ // will break up line into many smaller lines. Override gradient if that was set, cannot do both. + brushStyle = U_BS_SOLID; + hatchType = U_HS_HORIZONTAL; + } + else { + int i = 0; + while ( (linestyle != U_PS_USERSTYLE) && (i < style->stroke_dash.n_dash) ){ + if (style->stroke_dash.dash[i] > 0.00000001){ linestyle = U_PS_USERSTYLE; } + i++; + } + + if (linestyle == U_PS_USERSTYLE) { + n_dash = style->stroke_dash.n_dash; + dash = new uint32_t[n_dash]; + for (i = 0; i < style->stroke_dash.n_dash; i++) { + dash[i] = (uint32_t) (style->stroke_dash.dash[i]); + } + } + } + } + + elp = extlogpen_set( + U_PS_GEOMETRIC | linestyle | linecap | linejoin, + linewidth, + brushStyle, + hatchColor, + hatchType, + n_dash, + dash); + + } + else { // if (!style) + linejoin=0; + elp = extlogpen_set( + linestyle, + 1, + U_BS_SOLID, + U_RGB(0,0,0), + U_HS_HORIZONTAL, + 0, + NULL); + } + + rec = extcreatepen_set(&pen, eht, Bmi, cbPx, px, elp ); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_pen at extcreatepen_set"); + } + free(elp); + if(Bmi)free(Bmi); + if(px)free(px); // ct will always be NULL + + rec = selectobject_set(pen, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_pen at selectobject_set"); + } + hpen = pen; // need this later for destroy_pen + + if (linejoin == U_PS_JOIN_MITER) { + float miterlimit = style->stroke_miterlimit.value; // This is a ratio. + + if (miterlimit < 1)miterlimit = 1; + + rec = U_EMRSETMITERLIMIT_set((uint32_t) miterlimit); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETMITERLIMIT_set"); + } + } + + if (n_dash) { delete[] dash; } + return 0; +} + +// set the current pen to the stock object NULL_PEN and then delete the defined pen object, if there is one. +void PrintEmf::destroy_pen() +{ + char *rec = NULL; + // before an object may be safely deleted it must no longer be selected + // select in a stock object to deselect this one, the stock object should + // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work? + rec = selectobject_set(U_NULL_PEN, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::destroy_pen at selectobject_set"); + } + if (hpen){ + rec = deleteobject_set(&hpen, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::destroy_pen"); + } + hpen = 0; + } +} + + + +unsigned int PrintEmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) +{ + if (!m_tr_stack.empty()) { + Geom::Affine tr_top = m_tr_stack.top(); + m_tr_stack.push(transform * tr_top); + } else { + m_tr_stack.push(transform); + } + + return 1; +} + +unsigned int PrintEmf::release(Inkscape::Extension::Print * /*mod*/) +{ + m_tr_stack.pop(); + return 1; +} + +#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) +inline U_COLORREF PrintEmf::weight_opacity(U_COLORREF c1){ + float opa = c1.Reserved/255.0; + U_COLORREF result = U_RGB( + 255*opweight((float)c1.Red /255.0, gv.rgb[0], opa), + 255*opweight((float)c1.Green/255.0, gv.rgb[1], opa), + 255*opweight((float)c1.Blue /255.0, gv.rgb[2], opa) + ); + return result; +} + + +// return the color between c1 and c2, c1 for t=0, c2 for t=1.0 +U_COLORREF PrintEmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){ + U_COLORREF result; + result.Red = clrweight(c1.Red, c2.Red, t); + result.Green = clrweight(c1.Green, c2.Green, t); + result.Blue = clrweight(c1.Blue, c2.Blue, t); + result.Reserved = clrweight(c1.Reserved, c2.Reserved, t); + + // now handle the opacity, mix the RGB with background at the weighted opacity + + if(result.Reserved != 255)result = weight_opacity(result); + + return result; +} + +/* convert from center ellipse to SVGEllipticalArc ellipse + + From: + http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter + A point (x,y) on the arc can be found by: + + {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT} + + where + {cx,cy} is the center of the ellipse + F is the rotation angle of the X axis of the ellipse from the true X axis + T is the rotation angle around the ellipse + {,,,} is the rotation matrix + rx,ry are the radii of the ellipse's axes + + For SVG parameterization need two points. + Arbitrarily we can use T=0 and T=pi + Since the sweep is 180 the flags are always 0: + + F is in RADIANS, but the SVGEllipticalArc needs degrees! + +*/ +Geom::PathVector PrintEmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ + using Geom::X; + using Geom::Y; + double x1,y1,x2,y2; + Geom::Path SVGep; + + x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); + y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); + x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); + y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); + + char text[256]; + sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + return outres; +} + + +/* rx2,ry2 must be larger than rx1,ry1! + angle is in RADIANS +*/ +Geom::PathVector PrintEmf::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F){ + using Geom::X; + using Geom::Y; + double x11,y11,x12,y12; + double x21,y21,x22,y22; + double degrot = F*360./(2.*M_PI); + + x11 = ctr[X] + cos(F) * rx1 * cos(0) + sin(-F) * ry1 * sin(0); + y11 = ctr[Y] + sin(F) * rx1 * cos(0) + cos(F) * ry1 * sin(0); + x12 = ctr[X] + cos(F) * rx1 * cos(M_PI) + sin(-F) * ry1 * sin(M_PI); + y12 = ctr[Y] + sin(F) * rx1 * cos(M_PI) + cos(F) * ry1 * sin(M_PI); + + x21 = ctr[X] + cos(F) * rx2 * cos(0) + sin(-F) * ry2 * sin(0); + y21 = ctr[Y] + sin(F) * rx2 * cos(0) + cos(F) * ry2 * sin(0); + x22 = ctr[X] + cos(F) * rx2 * cos(M_PI) + sin(-F) * ry2 * sin(M_PI); + y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI); + + char text[512]; + sprintf(text," M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", + x11,y11, rx1,ry1,degrot,x12,y12, rx1,ry1,degrot,x11,y11, + x21,y21, rx2,ry2,degrot,x22,y22, rx2,ry2,degrot,x21,y21); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + + return outres; +} + +/* Elliptical hole in a large square extending from -50k to +50k */ +Geom::PathVector PrintEmf::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ + using Geom::X; + using Geom::Y; + double x1,y1,x2,y2; + Geom::Path SVGep; + + x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); + y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); + x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); + y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); + + char text[256]; + sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", + x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + return outres; +} + +/* rectangular cutter. +ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges +pos vector from center to leading edge +neg vector from center to trailing edge +width vector to side edge +*/ +Geom::PathVector PrintEmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){ + std::vector<Geom::Path> outres; + Geom::Path cutter; + cutter.start( ctr + pos - width); + cutter.appendNew<Geom::LineSegment>(ctr + pos + width); + cutter.appendNew<Geom::LineSegment>(ctr + neg + width); + cutter.appendNew<Geom::LineSegment>(ctr + neg - width); + cutter.close(); + outres.push_back(cutter); + return outres; +} + +/* Convert from SPWindRule to livarot's FillRule + This is similar to what sp_selected_path_boolop() does +*/ +FillRule PrintEmf::SPWR_to_LVFR(SPWindRule wr){ + FillRule fr; + if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; } + else { fr = fill_nonZero; } + return fr; +} + + +unsigned int PrintEmf::fill( + Inkscape::Extension::Print * /*mod*/, + Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, + Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) +{ + using Geom::X; + using Geom::Y; + + Geom::Affine tf = m_tr_stack.top(); + + use_fill = true; + use_stroke = false; + + fill_transform = tf; + + if (create_brush(style, NULL)){ // only happens if the style is a gradient + /* + Handle gradients. Uses modified livarot as 2geom boolops is currently broken. + Can handle gradients with multiple stops. + + The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries. + There is an inevitable loss of accuracy saving through an EMF file because of the integer coordinate system. + Keep the overlap quite large so that loss of accuracy does not remove an overlap. + */ + destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below + Geom::Path cutter; + float rgb[3]; + U_COLORREF wc,c1,c2; + FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed); + double doff,doff_base,doff_range; + double divisions= 128.0; + int nstops; + int istop = 1; + float opa; // opacity at stop + + SPRadialGradient *tg = (SPRadialGradient *) (gv.grad); // linear/radial are the same here + nstops = tg->vector.stops.size(); + sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb); + opa = tg->vector.stops[0].opacity; + c1 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + sp_color_get_rgb_floatv(&tg->vector.stops[nstops-1].color, rgb); + opa = tg->vector.stops[nstops-1].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + doff = 0.0; + doff_base = 0.0; + doff_range = tg->vector.stops[1].offset; // next or last stop + + if(gv.mode==DRAW_RADIAL_GRADIENT){ + Geom::Point xv = gv.p2 - gv.p1; // X' vector + Geom::Point yv = gv.p3 - gv.p1; // Y' vector + Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector + double rx = hypot(xv[X],xv[Y]); + double ry = hypot(yv[X],yv[Y]); + double range = fmax(rx,ry); // length along the gradient + double step = range/divisions; // adequate approximation for gradient + double overlap = step/4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity". + Do this first so that outer colored ring will overlay it. + */ + pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y])); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb); + wc = weight_opacity(c2); + (void) create_brush(style, &wc); + print_pathv(pathvr, fill_transform); + + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + for(start = 0.0; start < range; start += step, doff += 1./divisions){ + stop = start + step + overlap; + if(stop > range)stop=range; + wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + (void) create_brush(style, &wc); + + pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y])); + + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if(doff >= doff_range - doff_base){ + istop++; + if(istop >= nstops)continue; // could happen on a rounding error + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1=c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + } + } + } + else if(gv.mode == DRAW_LINEAR_GRADIENT){ + Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector + Geom::Point puv = uv.cw(); // perp. to unit vector + double range = Geom::distance(gv.p1,gv.p2); // length along the gradient + double step = range/divisions; // adequate approximation for gradient + double overlap = step/4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* before lower end of gradient, overlap first slice position */ + wc = weight_opacity(c1); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p1, uv*(overlap), uv*(-50000.0), puv*50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); + + /* after high end of gradient, overlap last slice poosition */ + wc = weight_opacity(c2); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p2, uv*(-overlap), uv*(50000.0), puv*50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); + + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + for(start = 0.0; start < range; start += step, doff += 1./divisions){ + stop = start + step + overlap; + if(stop > range)stop=range; + pathvc = rect_cutter(gv.p1, uv*start, uv*stop, puv*50000.0); + + wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + (void) create_brush(style, &wc); + Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if(doff >= doff_range - doff_base){ + istop++; + if(istop >= nstops)continue; // could happen on a rounding error + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1=c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + } + } + } + else { + g_error("Fatal programming error in PrintEmf::fill, invalid gradient type detected"); + } + use_fill = false; // gradients handled, be sure stroke does not use stroke and fill + } + else { + /* + Inkscape was not calling create_pen for objects with no border. + This was because it never called stroke() (next method). + PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can + become a visible border. + To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill. + */ + if (style->stroke.noneSet || style->stroke_width.computed == 0.0){ + destroy_pen(); //this sets the NULL_PEN + } + + /* postpone fill in case stroke also required AND all stroke paths closed + Dashes converted to line segments will "open" a closed path. + */ + bool all_closed = true; + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){ + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){ + if (pit->end_default() != pit->end_closed()) { all_closed=false; } + } + } + if ( + (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) || + (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) || + !all_closed + ){ + print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv + use_fill = false; + } + } + + return 0; +} + + +unsigned int PrintEmf::stroke ( + Inkscape::Extension::Print * /*mod*/, + Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, + Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) +{ + + char *rec = NULL; + Geom::Affine tf = m_tr_stack.top(); + + use_stroke = true; +// use_fill was set in ::fill, if it is needed + + if (create_pen(style, tf))return 0; + + if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine ){ + // convert the path, gets its complete length, and then make a new path with parameter length instead of t + Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis + Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter + Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes + Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end + int n_dash = style->stroke_dash.n_dash; + int i=0; //dash index + double tlength; // length of tmp_pathpw + double slength=0.0; // start of gragment + double elength; // end of gragment + for (unsigned int i=0; i < pathv.size(); i++) { + tmp_pathpw.concat(pathv[i].toPwSb()); + } + tlength = length(tmp_pathpw,0.1); + tmp_pathpw2 = arc_length_parametrization(tmp_pathpw); + + // go around the dash array repeatedly until the entire path is consumed (but not beyond). + while(slength < tlength){ + elength = slength + style->stroke_dash.dash[i++]; + if(elength > tlength)elength = tlength; + Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength)); + if(slength){ tmp_pathpw3.concat(fragment); } + else { first_frag = fragment; } + slength = elength; + slength += style->stroke_dash.dash[i++]; // the gap + if(i>=n_dash)i=0; + } + tmp_pathpw3.concat(first_frag); // may merge line around start point + Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); + print_pathv(out_pathv, tf); + } + else { + print_pathv(pathv, tf); + } + + use_stroke = false; + use_fill = false; + + if(usebk){ // OPAQUE was set, revert to TRANSPARENT + usebk = false; + rec = U_EMRSETBKMODE_set(U_TRANSPARENT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::stroke at U_EMRSETBKMODE_set"); + } + } + + return 0; +} + + +// Draws simple_shapes, those with closed EMR_* primitives, like polygons, rectangles and ellipses. +// These use whatever the current pen/brush are and need not be followed by a FILLPATH or STROKEPATH. +// For other paths it sets a few flags and returns. +bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ + + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); + + int nodes = 0; + int moves = 0; + int lines = 0; + int curves = 0; + char *rec = NULL; + + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + moves++; + nodes++; + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + nodes++; + + if ( is_straight_curve(*cit) ) { lines++; } + else if(&*cit) { curves++; } + } + } + + if (!nodes) + return false; + + U_POINT *lpPoints = new U_POINT[moves + lines + curves*3]; + int i = 0; + + /** + * For all Subpaths in the <path> + */ + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + using Geom::X; + using Geom::Y; + + Geom::Point p0 = pit->initialPoint(); + + p0[X] = (p0[X] * PX2WORLD); + p0[Y] = (p0[Y] * PX2WORLD); + + int32_t const x0 = (int32_t) round(p0[X]); + int32_t const y0 = (int32_t) round(p0[Y]); + + lpPoints[i].x = x0; + lpPoints[i].y = y0; + i = i + 1; + + /** + * For all segments in the subpath + */ + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + if ( is_straight_curve(*cit) ) + { + //Geom::Point p0 = cit->initialPoint(); + Geom::Point p1 = cit->finalPoint(); + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + + lpPoints[i].x = x1; + lpPoints[i].y = y1; + i = i + 1; + } + else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) + { + std::vector<Geom::Point> points = cubic->points(); + //Geom::Point p0 = points[0]; + Geom::Point p1 = points[1]; + Geom::Point p2 = points[2]; + Geom::Point p3 = points[3]; + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + p2[X] = (p2[X] * PX2WORLD); + p3[X] = (p3[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + p2[Y] = (p2[Y] * PX2WORLD); + p3[Y] = (p3[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + int32_t const x2 = (int32_t) round(p2[X]); + int32_t const y2 = (int32_t) round(p2[Y]); + int32_t const x3 = (int32_t) round(p3[X]); + int32_t const y3 = (int32_t) round(p3[Y]); + + lpPoints[i].x = x1; + lpPoints[i].y = y1; + lpPoints[i+1].x = x2; + lpPoints[i+1].y = y2; + lpPoints[i+2].x = x3; + lpPoints[i+2].y = y3; + i = i + 3; + } + } + } + + bool done = false; + bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); + bool polygon = false; + bool rectangle = false; + bool ellipse = false; + + if (moves == 1 && moves+lines == nodes && closed) { + polygon = true; +// if (nodes==5) { // disable due to LP Bug 407394 +// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && +// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) +// { +// rectangle = true; +// } +// } + } + else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { +// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && +// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && +// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && +// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && +// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && +// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) +// { // disable due to LP Bug 407394 +// ellipse = true; +// } + } + + if (polygon || ellipse) { + + if (use_fill && !use_stroke) { // only fill + rec = selectobject_set(U_NULL_PEN, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen"); + } + } + else if(!use_fill && use_stroke) { // only stroke + rec = selectobject_set(U_NULL_BRUSH, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush"); + } + } + + if (polygon) { + if (rectangle){ + U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[0].x, lpPoints[0].y}, (U_POINTL) {lpPoints[2].x, lpPoints[2].y}); + rec = U_EMRRECTANGLE_set(rcl); + } + else { + rec = U_EMRPOLYGON_set(U_RCL_DEF, nodes, lpPoints); + } + } + else if (ellipse) { + U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[6].x, lpPoints[3].y}, (U_POINTL) {lpPoints[0].x, lpPoints[9].y}); + rec = U_EMRELLIPSE_set(rcl); + } + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_simple_shape at retangle/ellipse/polygon"); + } + + done = true; + + // replace the handle we moved above, assuming there was something set already + if (use_fill && !use_stroke && hpen) { // only fill + rec = selectobject_set(hpen, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen"); + } + } + else if (!use_fill && use_stroke && hbrush){ // only stroke + rec = selectobject_set(hbrush, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush"); + } + } + } + + delete[] lpPoints; + + return done; +} + +/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape + in the past (or will be in the future?) Not in current trunk. (4/19/2012) + + Limitations of this code: + 1. Transparency is lost on export. (Apparently a limitation of the EMF format.) + 2. Probably messes up if row stride != w*4 + 3. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine + that calls this one and passes px, but never removes the rest of the pixbuf. The first time + this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more. + If this routine is reduced to + if(1)return(0); + and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the + size of two bitmaps. +*/ + +unsigned int PrintEmf::image( + Inkscape::Extension::Print * /* module */, /** not used */ + unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */ + unsigned int w, /** width of bitmap */ + unsigned int h, /** height of bitmap */ + unsigned int rs, /** row stride (normally w*4) */ + Geom::Affine const &/*tf_ignore*/, /** WRONG affine transform, use the one from m_tr_stack */ + SPStyle const *style) /** provides indirect link to image object */ +{ + double x1,y1,dw,dh; + char *rec = NULL; + Geom::Affine tf = m_tr_stack.top(); + + rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::image at EMRHEADER"); + } + + x1= atof(style->object->getAttribute("x")); + y1= atof(style->object->getAttribute("y")); + dw= atof(style->object->getAttribute("width")); + dh= atof(style->object->getAttribute("height")); + Geom::Point pLL(x1,y1); + Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates + + char *px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w*4, colortype, 0, 1); + Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + + U_POINTL Dest = pointl_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD)); + U_POINTL cDest = pointl_set(round(dw * PX2WORLD), round(dh * PX2WORLD)); + U_POINTL Src = pointl_set(0,0); + U_POINTL cSrc = pointl_set(w,h); + if(!FixImageRot){ /* Rotate images - some programs cannot read them in correctly if they are rotated */ + tf[4] = tf[5] = 0.0; // get rid of the offset in the transform + Geom::Point pLL2prime = pLL2 * tf; + U_XFORM tmpTransform; + tmpTransform.eM11 = tf[0]; + tmpTransform.eM12 = tf[1]; + tmpTransform.eM21 = tf[2]; + tmpTransform.eM22 = tf[3]; + tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; //map pLL2 (now in EMF coordinates) back onto itself after the rotation + tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD; + + rec=U_EMRSAVEDC_set(); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set"); + } + + rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM"); + } + } + rec = U_EMRSTRETCHDIBITS_set( + U_RCL_DEF, //! Bounding rectangle in device units + Dest, //! Destination UL corner in logical units + cDest, //! Destination W & H in logical units + Src, //! Source UL corner in logical units + cSrc, //! Source W & H in logical units + U_DIB_RGB_COLORS, //! DIBColors Enumeration + U_SRCCOPY, //! RasterOPeration Enumeration + Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) + h*rs, //! size in bytes of px + px //! (Optional) bitmapbuffer (U_BITMAPINFO section) + ); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::image at U_EMRSTRETCHDIBITS_set"); + } + free(px); + free(Bmi); + if(numCt)free(ct); + + if(!FixImageRot){ + rec=U_EMRRESTOREDC_set(-1); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::image at U_EMRRESTOREDC_set"); + } + } + + return 0; +} + +// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything +unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ + Geom::Affine tf = transform; + char *rec = NULL; + + simple_shape = print_simple_shape(pathv, tf); + if (simple_shape || pathv.empty()){ + if (use_fill){ destroy_brush(); } // these must be cleared even if nothing is drawn or hbrush,hpen fill up + if (use_stroke){ destroy_pen(); } + return TRUE; + } + + /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform, + that is handled by the EMF MODIFYWORLDTRANSFORM record + */ + + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * tf ); + + rec = U_EMRBEGINPATH_set(); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRBEGINPATH_set"); + } + + /** + * For all Subpaths in the <path> + */ + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + using Geom::X; + using Geom::Y; + + + Geom::Point p0 = pit->initialPoint(); + + p0[X] = (p0[X] * PX2WORLD); + p0[Y] = (p0[Y] * PX2WORLD); + + U_POINTL ptl = pointl_set((int32_t) round(p0[X]), (int32_t) round(p0[Y])); + rec = U_EMRMOVETOEX_set(ptl); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRMOVETOEX_set"); + } + + /** + * For all segments in the subpath + */ + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + if ( is_straight_curve(*cit) ) + { + //Geom::Point p0 = cit->initialPoint(); + Geom::Point p1 = cit->finalPoint(); + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + + ptl = pointl_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); + rec = U_EMRLINETO_set(ptl); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set"); + } + } + else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) + { + std::vector<Geom::Point> points = cubic->points(); + //Geom::Point p0 = points[0]; + Geom::Point p1 = points[1]; + Geom::Point p2 = points[2]; + Geom::Point p3 = points[3]; + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + p2[X] = (p2[X] * PX2WORLD); + p3[X] = (p3[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + p2[Y] = (p2[Y] * PX2WORLD); + p3[Y] = (p3[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + int32_t const x2 = (int32_t) round(p2[X]); + int32_t const y2 = (int32_t) round(p2[Y]); + int32_t const x3 = (int32_t) round(p3[X]); + int32_t const y3 = (int32_t) round(p3[Y]); + + U_POINTL pt[3]; + pt[0].x = x1; + pt[0].y = y1; + pt[1].x = x2; + pt[1].y = y2; + pt[2].x = x3; + pt[2].y = y3; + + rec = U_EMRPOLYBEZIERTO_set(U_RCL_DEF, 3, pt); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRPOLYBEZIERTO_set"); + } + } + else + { + g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used"); + } + } + + if (pit->end_default() == pit->end_closed()) { // there may be multiples of this on a single path + rec = U_EMRCLOSEFIGURE_set(); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRCLOSEFIGURE_set"); + } + } + + } + + rec = U_EMRENDPATH_set(); // there may be only be one of these on a single path + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set"); + } + + // explicit FILL/STROKE commands are needed for each sub section of the path + if (use_fill && !use_stroke){ + rec = U_EMRFILLPATH_set(U_RCL_DEF); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set"); + } + } + else if (use_fill && use_stroke) { + rec = U_EMRSTROKEANDFILLPATH_set(U_RCL_DEF); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set"); + } + } + else if (!use_fill && use_stroke){ + rec = U_EMRSTROKEPATH_set(U_RCL_DEF); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set"); + } + } + + // clean out brush and pen, but only after all parts of the draw complete + if (use_fill){ + destroy_brush(); + } + if (use_stroke){ + destroy_pen(); + } + + return TRUE; +} + + +bool PrintEmf::textToPath(Inkscape::Extension::Print * ext) +{ + return ext->get_param_bool("textToPath"); +} + +unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, + SPStyle const *const style) +{ + if (!et) return 0; + + char *rec = NULL; + int ccount,newfont; + int fix90n=0; + uint32_t hfont = 0; + Geom::Affine tf = m_tr_stack.top(); + double rot = -1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation, - sign for MM_TEXT + double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below + double dx,dy; + double f1,f2,f3; + double ky; + + // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space + int ndx, rtl; + uint32_t *adx; + smuggle_adxkyrtl_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); // side effect: free() adx + + uint32_t textalignment; + if(rtl > 0){ textalignment = U_TA_BASELINE | U_TA_LEFT; } + else { textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; } + if(textalignment != htextalignment){ + htextalignment = textalignment; + rec = U_EMRSETTEXTALIGN_set(textalignment); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTALIGN_set"); + } + } + + char *text2 = strdup(text); // because U_Utf8ToUtf16le calls iconv which does not like a const char * + uint16_t *unicode_text = U_Utf8ToUtf16le( text2, 0, NULL ); + free(text2); + //translates Unicode to NonUnicode, if possible. If any translate, all will, and all to + //the same font, because of code in Layout::print + UnicodeToNon(unicode_text, &ccount, &newfont); + + //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value + //Some funky ones: Arial, Times New Roman + //Some not funky ones: Symbol and Verdana. + //Without a huge table we cannot catch them all, so just the most common problem ones. + if(FixPPTCharPos){ + switch(newfont){ + case CVTSYM: + search_short_fflist("Convert To Symbol", &f1, &f2, &f3); + break; + case CVTZDG: + search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3); + break; + case CVTWDG: + search_short_fflist("Convert To Wingdings", &f1, &f2, &f3); + break; + default: //also CVTNON + search_short_fflist(style->text->font_family.value, &f1, &f2, &f3); + break; + } + if(f2 || f3){ + int irem = ((int) round(rot)) % 900 ; + if(irem <=9 && irem >= -9){ + fix90n=1; //assume vertical + rot = (double) (((int) round(rot)) - irem); + rotb = rot*M_PI/1800.0; + if( abs(rot) == 900.0 ){ fix90n = 2; } + } + } + } + + /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision. + The EMF output files produced here have been designed so that the integer valued pt sizes + land right on an integer value in the EMF file, so those are exact. However, something like 18.1 pt will be + somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) + */ + int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); + if (!hfont) { + + // Get font face name. Use changed font name if unicode mapped to one + // of the special fonts. + uint16_t *wfacename; + if(!newfont){ wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL); } + else { wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL); } + + // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if + // it was streteched asymmetrically.) Few applications support text from EMF which is scaled + // differently by height/width, so leave lfWidth alone. + + U_LOGFONT lf = logfont_set( + textheight, + 0, + round(rot), + round(rot), + transweight(style->font_weight.computed), + (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), + style->text_decoration_line.underline, + style->text_decoration_line.line_through, + U_DEFAULT_CHARSET, + U_OUT_DEFAULT_PRECIS, + U_CLIP_DEFAULT_PRECIS, + U_DEFAULT_QUALITY, + U_DEFAULT_PITCH | U_FF_DONTCARE, + wfacename); + free(wfacename); + + rec = extcreatefontindirectw_set(&hfont, eht, (char *) &lf, NULL); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at extcreatefontindirectw_set"); + } + } + + rec = selectobject_set(hfont, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at selectobject_set"); + } + + float rgb[3]; + sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); + // only change the text color when it needs to be changed + if(memcmp(htextcolor_rgb,rgb,3*sizeof(float))){ + memcpy(htextcolor_rgb,rgb,3*sizeof(float)); + rec = U_EMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_set"); + } + } + + Geom::Point p2 = p * tf; + + //Handle super/subscripts and vertical kerning +/* Previously used this, but vertical kerning was not supported + p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); + p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); +*/ + p2[Geom::X] += ky * std::sin( rotb ); + p2[Geom::Y] += ky * std::cos( rotb ); + + //Conditionally handle compensation for PPT EMF import bug (affects PPT 2003-2010, at least) + if(FixPPTCharPos){ + if(fix90n==1){ //vertical + dx= 0.0; + dy= f3 * style->font_size.computed * std::cos( rotb ); + } + else if(fix90n==2){ //horizontal + dx= f2 * style->font_size.computed * std::sin( rotb ); + dy= 0.0; + } + else { + dx= f1 * style->font_size.computed * std::sin( rotb ); + dy= f1 * style->font_size.computed * std::cos( rotb ); + } + p2[Geom::X] += dx; + p2[Geom::Y] += dy; + } + + p2[Geom::X] = (p2[Geom::X] * PX2WORLD); + p2[Geom::Y] = (p2[Geom::Y] * PX2WORLD); + + int32_t const xpos = (int32_t) round(p2[Geom::X]); + int32_t const ypos = (int32_t) round(p2[Geom::Y]); + + + // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is + // the number of VISIBLE characters, since some may combine from the UTF (8 originally, + // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of + // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former. + +// This is currently being smuggled in from caller as part of text, works +// MUCH better than the fallback hack below +// uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up + char *rec2; + if(rtl>0){ + rec2 = emrtext_set( (U_POINTL) {xpos, ypos}, ndx, 2, unicode_text, U_ETO_NONE, U_RCL_DEF, adx); + } + else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case + rec2 = emrtext_set( (U_POINTL) {xpos, ypos}, ndx, 2, unicode_text, U_ETO_RTLREADING, U_RCL_DEF, adx); + } + free(unicode_text); + free(adx); + rec = U_EMREXTTEXTOUTW_set(U_RCL_DEF,U_GM_COMPATIBLE,1.0,1.0,(PU_EMRTEXT)rec2); + free(rec2); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at U_EMREXTTEXTOUTW_set"); + } + + // Must deselect an object before deleting it. Put the default font (back) in. + rec = selectobject_set(U_DEVICE_DEFAULT_FONT, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at selectobject_set"); + } + + if(hfont){ + rec = deleteobject_set(&hfont, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + g_error("Fatal programming error in PrintEmf::text at deleteobject_set"); + } + } + + return 0; +} + +void PrintEmf::init (void) +{ + read_system_fflist(); + + /* EMF print */ + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>Enhanced Metafile Print</name>\n" + "<id>org.inkscape.print.emf</id>\n" + "<param name=\"destination\" type=\"string\"></param>\n" + "<param name=\"textToPath\" type=\"boolean\">true</param>\n" + "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n" + "<param name=\"FixPPTCharPos\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTDashLine\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTGrad2Polys\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTPatternAsHatch\" type=\"boolean\">false</param>\n" + "<param name=\"FixImageRot\" type=\"boolean\">false</param>\n" + "<print/>\n" + "</inkscape-extension>", new PrintEmf()); + + return; +} + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h new file mode 100644 index 000000000..d42ba8a58 --- /dev/null +++ b/src/extension/internal/emf-print.h @@ -0,0 +1,138 @@ +/** @file + * @brief Enhanced Metafile printing - implementation + */ +/* Author: + * Ulf Erikson <ulferikson@users.sf.net> + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ +#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "uemf.h" + +#include "extension/implementation/implementation.h" +//#include "extension/extension.h" + +#include <2geom/pathvector.h> +#include "sp-gradient.h" +#include "splivarot.h" // pieces for union on shapes +#include "display/canvas-bpath.h" // for SPWindRule + +#include <stack> + +namespace Inkscape { +namespace Extension { +namespace Internal { + +class PrintEmf : public Inkscape::Extension::Implementation::Implementation +{ + double _width; + double _height; + U_RECTL rc; + + uint32_t htextalignment; + uint32_t hbrush, hbrushOld, hpen, hpenOld; + uint32_t hpolyfillmode; // used to minimize redundant records that set this + float htextcolor_rgb[3]; // used to minimize redundant records that set this + + std::stack<Geom::Affine> m_tr_stack; + Geom::PathVector fill_pathv; + Geom::Affine fill_transform; + bool use_stroke; + bool use_fill; + bool simple_shape; + bool usebk; + + unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); + bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); + +public: + PrintEmf (void); + virtual ~PrintEmf (void); + + /* Print functions */ + virtual unsigned int setup (Inkscape::Extension::Print * module); + + virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc); + virtual unsigned int finish (Inkscape::Extension::Print * module); + + /* Rendering methods */ + virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); + virtual unsigned int release(Inkscape::Extension::Print *module); + virtual unsigned int fill (Inkscape::Extension::Print *module, + Geom::PathVector const &pathv, + Geom::Affine const &ctm, SPStyle const *style, + Geom::OptRect const &pbox, Geom::OptRect const &dbox, + Geom::OptRect const &bbox); + virtual unsigned int stroke (Inkscape::Extension::Print * module, + Geom::PathVector const &pathv, + Geom::Affine const &ctm, SPStyle const *style, + Geom::OptRect const &pbox, Geom::OptRect const &dbox, + Geom::OptRect const &bbox); + virtual unsigned int image(Inkscape::Extension::Print *module, + unsigned char *px, + unsigned int w, + unsigned int h, + unsigned int rs, + Geom::Affine const &transform, + SPStyle const *style); + virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); + virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, + Geom::Point const &p, SPStyle const *style); + bool textToPath (Inkscape::Extension::Print * ext); + + static void init (void); +protected: + static void read_system_fflist(void); + static void search_long_fflist(const char *fontname, double *f1, double *f2, double *f3); + static void search_short_fflist(const char *fontname, double *f1, double *f2, double *f3); + static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale); + U_COLORREF gethexcolor(uint32_t color); + uint32_t transweight(const unsigned int inkweight); + + int create_brush(SPStyle const *style, PU_COLORREF fcolor); + void destroy_brush(); + int create_pen(SPStyle const *style, const Geom::Affine &transform); + void destroy_pen(); + + void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + void swapRBinRGBA(char *px, int pixels); + + U_COLORREF avg_stop_color(SPGradient *gr); + int hold_gradient(void *gr, int mode); + inline U_COLORREF weight_opacity(U_COLORREF c1); + U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t); + Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); + Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F); + Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); + Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width); + FillRule SPWR_to_LVFR(SPWindRule wr); + +}; + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + + +#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp deleted file mode 100644 index 60385f455..000000000 --- a/src/extension/internal/emf-win32-inout.cpp +++ /dev/null @@ -1,2582 +0,0 @@ -/** @file - * @brief Windows-only Enhanced Metafile input and output. - */ -/* Authors: - * Ulf Erikson <ulferikson@users.sf.net> - * Jon A. Cruz <jon@joncruz.org> - * Abhishek Sharma - * - * Copyright (C) 2006-2008 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - * - * References: - * - How to Create & Play Enhanced Metafiles in Win32 - * http://support.microsoft.com/kb/q145999/ - * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles - * http://support.microsoft.com/kb/q66949/ - * - Metafile Functions - * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp - * - Metafile Structures - * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp - */ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sp-root.h" -#include "sp-path.h" -#include "style.h" -#include "print.h" -#include "extension/system.h" -#include "extension/print.h" -#include "extension/db.h" -#include "extension/output.h" -#include "display/drawing.h" -#include "display/drawing-item.h" -#include "clear-n_.h" -#include "document.h" -#include "util/units.h" - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -#include "emf-win32-print.h" -#include "emf-win32-inout.h" - - -#define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32" - -#ifndef PS_JOIN_MASK -#define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND) -#endif - -#define DPA 0x00A000C9 // TernaryRasterOperation - -namespace Inkscape { -namespace Extension { -namespace Internal { - -static float device_scale = Inkscape::Util::Quantity::convert(1, "px", "pt"); -static float device_x; -static float device_y; -static RECTL rc_old; -static bool clipset = false; - -EmfWin32::EmfWin32 (void) // The null constructor -{ - return; -} - - -EmfWin32::~EmfWin32 (void) //The destructor -{ - return; -} - - -bool -EmfWin32::check (Inkscape::Extension::Extension * /*module*/) -{ - if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32)) - return FALSE; - return TRUE; -} - - -static void -emf_print_document_to_file(SPDocument *doc, gchar const *filename) -{ - Inkscape::Extension::Print *mod; - SPPrintContext context; - gchar const *oldconst; - gchar *oldoutput; - unsigned int ret; - - doc->ensureUpToDate(); - - mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32); - oldconst = mod->get_param_string("destination"); - oldoutput = g_strdup(oldconst); - mod->set_param_string("destination", filename); - -/* Start */ - context.module = mod; - /* fixme: This has to go into module constructor somehow */ - /* Create new arena */ - mod->base = doc->getRoot(); - Inkscape::Drawing drawing; - mod->dkey = SPItem::display_key_new(1); - mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); - drawing.setRoot(mod->root); - /* Print document */ - ret = mod->begin(doc); - if (ret) { - g_free(oldoutput); - throw Inkscape::Extension::Output::save_failed(); - } - mod->base->invoke_print(&context); - ret = mod->finish(); - if (ret) { - g_free(oldoutput); - throw Inkscape::Extension::Output::save_failed(); - } - /* Release arena */ - mod->base->invoke_hide(mod->dkey); - mod->base = NULL; - mod->root = NULL; // deleted by invoke_hide -/* end */ - - mod->set_param_string("destination", oldoutput); - g_free(oldoutput); - - return; -} - - -void -EmfWin32::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) -{ - Inkscape::Extension::Extension * ext; - - ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32); - if (ext == NULL) - return; - - bool old_textToPath = ext->get_param_bool("textToPath"); - bool new_val = mod->get_param_bool("textToPath"); - ext->set_param_bool("textToPath", new_val); - - emf_print_document_to_file(doc, filename); - - ext->set_param_bool("textToPath", old_textToPath); - - return; -} - - - -typedef struct { - int type; - int level; - ENHMETARECORD *lpEMFR; -} EMF_OBJECT, *PEMF_OBJECT; - -typedef struct emf_device_context { - struct SPStyle style; - class SPTextStyle tstyle; - bool stroke_set; - bool fill_set; - - SIZEL sizeWnd; - SIZEL sizeView; - float PixelsInX, PixelsInY; - float PixelsOutX, PixelsOutY; - POINTL winorg; - POINTL vieworg; - double ScaleInX, ScaleInY; - double ScaleOutX, ScaleOutY; - COLORREF textColor; - bool textColorSet; - DWORD textAlign; - XFORM worldTransform; - POINTL cur; -} EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT; - -#define EMF_MAX_DC 128 - -typedef struct emf_callback_data { - Glib::ustring *outsvg; - Glib::ustring *path; - Glib::ustring *outdef; - - EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic.. - int level; - - double xDPI, yDPI; - bool pathless_stroke; - bool inpath; - - float MMX; - float MMY; - float dwInchesX; - float dwInchesY; - - unsigned int id; - CHAR *pDesc; - - int n_obj; - PEMF_OBJECT emf_obj; -} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA; - - -static void -output_style(PEMF_CALLBACK_DATA d, int iType) -{ -// SVGOStringStream tmp_id; - SVGOStringStream tmp_style; - char tmp[1024] = {0}; - - float fill_rgb[3]; - sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb ); - - float stroke_rgb[3]; - sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb); - -// tmp_id << "\n\tid=\"" << (d->id++) << "\""; -// *(d->outsvg) += tmp_id.str().c_str(); - *(d->outsvg) += "\n\tstyle=\""; - if (iType == EMR_STROKEPATH || !d->dc[d->level].fill_set) { - tmp_style << "fill:none;"; - } else { - snprintf(tmp, 1023, - "fill:#%02x%02x%02x;", - SP_COLOR_F_TO_U(fill_rgb[0]), - SP_COLOR_F_TO_U(fill_rgb[1]), - SP_COLOR_F_TO_U(fill_rgb[2])); - tmp_style << tmp; - snprintf(tmp, 1023, - "fill-rule:%s;", - d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero"); - tmp_style << tmp; - tmp_style << "fill-opacity:1;"; - - if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 && - fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2]) - { - d->dc[d->level].stroke_set = false; - } - } - - if (iType == EMR_FILLPATH || !d->dc[d->level].stroke_set) { - tmp_style << "stroke:none;"; - } else { - snprintf(tmp, 1023, - "stroke:#%02x%02x%02x;", - SP_COLOR_F_TO_U(stroke_rgb[0]), - SP_COLOR_F_TO_U(stroke_rgb[1]), - SP_COLOR_F_TO_U(stroke_rgb[2])); - tmp_style << tmp; - - tmp_style << "stroke-width:" << - MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;"; - - tmp_style << "stroke-linecap:" << - (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" : - d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" : - d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" : - "unknown") << ";"; - - tmp_style << "stroke-linejoin:" << - (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" : - d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" : - d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" : - "unknown") << ";"; - - if (d->dc[d->level].style.stroke_linejoin.computed == 0) { - tmp_style << "stroke-miterlimit:" << - MAX( 0.01, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; - } - - if (d->dc[d->level].style.stroke_dasharray_set && - d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) - { - tmp_style << "stroke-dasharray:"; - for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) { - if (i) - tmp_style << ","; - tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; - } - tmp_style << ";"; - tmp_style << "stroke-dashoffset:0;"; - } else { - tmp_style << "stroke-dasharray:none;"; - } - tmp_style << "stroke-opacity:1;"; - } - tmp_style << "\" "; - if (clipset) - tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" "; - clipset = false; - - *(d->outsvg) += tmp_style.str().c_str(); -} - - -static double -_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) -{ - double tmp = px - d->dc[d->level].winorg.x; - tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0; - tmp += d->dc[d->level].vieworg.x; - return tmp; -} - -static double -_pix_y_to_point(PEMF_CALLBACK_DATA d, double px) -{ - double tmp = px - d->dc[d->level].winorg.y; - tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0; - tmp += d->dc[d->level].vieworg.y; - return tmp; -} - - -static double -pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) -{ - double ppx = px * d->dc[d->level].worldTransform.eM11 + py * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; - double x = _pix_x_to_point(d, ppx); - - x *= device_scale; - x -= device_x; - - return x; -} - -static double -pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) -{ - double ppy = px * d->dc[d->level].worldTransform.eM12 + py * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; - double y = _pix_y_to_point(d, ppy); - - y *= device_scale; - y -= device_y; - - return y; -} - -static double -pix_to_size_point(PEMF_CALLBACK_DATA d, double px) -{ - double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); - double ppy = 0; - - double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21; - dx *= device_scale; - double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22; - dy *= device_scale; - - double tmp = sqrt(dx * dx + dy * dy); - return tmp; -} - - -static void -select_pen(PEMF_CALLBACK_DATA d, int index) -{ - PEMRCREATEPEN pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) { - case PS_DASH: - case PS_DOT: - case PS_DASHDOT: - case PS_DASHDOTDOT: - { - int i = 0; - int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; - if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - } - if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - } - if (penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - } - - d->dc[d->level].style.stroke_dasharray_set = 1; - break; - } - - case PS_SOLID: - default: - { - d->dc[d->level].style.stroke_dasharray_set = 0; - break; - } - } - - switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) { - case PS_ENDCAP_ROUND: - { - d->dc[d->level].style.stroke_linecap.computed = 1; - break; - } - case PS_ENDCAP_SQUARE: - { - d->dc[d->level].style.stroke_linecap.computed = 2; - break; - } - case PS_ENDCAP_FLAT: - default: - { - d->dc[d->level].style.stroke_linecap.computed = 0; - break; - } - } - - switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) { - case PS_JOIN_BEVEL: - { - d->dc[d->level].style.stroke_linejoin.computed = 2; - break; - } - case PS_JOIN_MITER: - { - d->dc[d->level].style.stroke_linejoin.computed = 0; - break; - } - case PS_JOIN_ROUND: - default: - { - d->dc[d->level].style.stroke_linejoin.computed = 1; - break; - } - } - - d->dc[d->level].stroke_set = true; - - if (pEmr->lopn.lopnStyle == PS_NULL) { - d->dc[d->level].style.stroke_width.value = 0; - d->dc[d->level].stroke_set = false; - } else if (pEmr->lopn.lopnWidth.x) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, pEmr->lopn.lopnWidth.x ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) - //d->dc[d->level].style.stroke_width.value = 1.0; - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, 1 ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } - - double r, g, b; - r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) ); - g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) ); - b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) ); - d->dc[d->level].style.stroke.value.color.set( r, g, b ); -} - - -static void -select_extpen(PEMF_CALLBACK_DATA d, int index) -{ - PEMREXTCREATEPEN pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) { - case PS_USERSTYLE: - { - if (pEmr->elp.elpNumEntries) { - d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries]; - for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double dash_length = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] ); - d->level = cur_level; - d->dc[d->level].style.stroke_dash.dash[i] = dash_length; - } - d->dc[d->level].style.stroke_dasharray_set = 1; - } else { - d->dc[d->level].style.stroke_dasharray_set = 0; - } - break; - } - - case PS_DASH: - case PS_DOT: - case PS_DASHDOT: - case PS_DASHDOTDOT: - { - int i = 0; - int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; - if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; - } - if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; - } - if (penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; - } - - d->dc[d->level].style.stroke_dasharray_set = 1; - break; - } - - case PS_SOLID: - default: - { - d->dc[d->level].style.stroke_dasharray_set = 0; - break; - } - } - - switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) { - case PS_ENDCAP_ROUND: - { - d->dc[d->level].style.stroke_linecap.computed = 1; - break; - } - case PS_ENDCAP_SQUARE: - { - d->dc[d->level].style.stroke_linecap.computed = 2; - break; - } - case PS_ENDCAP_FLAT: - default: - { - d->dc[d->level].style.stroke_linecap.computed = 0; - break; - } - } - - switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) { - case PS_JOIN_BEVEL: - { - d->dc[d->level].style.stroke_linejoin.computed = 2; - break; - } - case PS_JOIN_MITER: - { - d->dc[d->level].style.stroke_linejoin.computed = 0; - break; - } - case PS_JOIN_ROUND: - default: - { - d->dc[d->level].style.stroke_linejoin.computed = 1; - break; - } - } - - d->dc[d->level].stroke_set = true; - - if (pEmr->elp.elpPenStyle == PS_NULL) { - d->dc[d->level].style.stroke_width.value = 0; - d->dc[d->level].stroke_set = false; - } else if (pEmr->elp.elpWidth) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) - //d->dc[d->level].style.stroke_width.value = 1.0; - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, 1 ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } - - double r, g, b; - r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) ); - g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) ); - b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) ); - - d->dc[d->level].style.stroke.value.color.set( r, g, b ); -} - - -static void -select_brush(PEMF_CALLBACK_DATA d, int index) -{ - PEMRCREATEBRUSHINDIRECT pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - if (pEmr->lb.lbStyle == BS_SOLID) { - double r, g, b; - r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) ); - g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) ); - b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) ); - d->dc[d->level].style.fill.value.color.set( r, g, b ); - } - - d->dc[d->level].fill_set = true; -} - - -static void -select_font(PEMF_CALLBACK_DATA d, int index) -{ - PEMREXTCREATEFONTINDIRECTW pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight ); - d->level = cur_level; - d->dc[d->level].style.font_size.computed = font_size; - d->dc[d->level].style.font_weight.value = - pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : - pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : - pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : - pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : - pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : - pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : - pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : - pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : - pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : - FW_NORMAL; - d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); - d->dc[d->level].style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline; - d->dc[d->level].style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut; - if (d->dc[d->level].tstyle.font_family.value) - g_free(d->dc[d->level].tstyle.font_family.value); - d->dc[d->level].tstyle.font_family.value = - (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL ); - d->dc[d->level].style.baseline_shift.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow -} - -static void -delete_object(PEMF_CALLBACK_DATA d, int index) -{ - if (index >= 0 && index < d->n_obj) { - d->emf_obj[index].type = 0; - if (d->emf_obj[index].lpEMFR) - free(d->emf_obj[index].lpEMFR); - d->emf_obj[index].lpEMFR = NULL; - } -} - - -static void -insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj) -{ - if (index >= 0 && index < d->n_obj) { - delete_object(d, index); - d->emf_obj[index].type = type; - d->emf_obj[index].level = d->level; - d->emf_obj[index].lpEMFR = pObj; - } -} - -static void -assert_empty_path(PEMF_CALLBACK_DATA d, const char * /*fun*/) -{ - if (!d->path->empty()) { - // g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun); - - *(d->outsvg) += "<!--\n"; - *(d->outsvg) += " <path \t"; - output_style(d, EMR_STROKEPATH); - if (strstr(d->path->c_str(), "d=\"") == NULL) { - *(d->outsvg) += "d=\""; - *(d->outsvg) += "\n\t"; - } - *(d->outsvg) += *(d->path); - *(d->outsvg) += " \" /> \n"; - *(d->outsvg) += "-->\n"; - - *(d->path) = ""; - } -} - - -static int CALLBACK -myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const *lpEMFR, int /*nObj*/, LPARAM lpData) -{ - PEMF_CALLBACK_DATA d; - SVGOStringStream tmp_outsvg; - SVGOStringStream tmp_path; - SVGOStringStream tmp_str; - SVGOStringStream dbg_str; - - d = (PEMF_CALLBACK_DATA) lpData; - - if (d->pathless_stroke) { - if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 && - lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 && - lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO && - lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 && - lpEMFR->iType!=EMR_SETBKMODE && lpEMFR->iType!=EMR_SELECTOBJECT && - lpEMFR->iType!=EMR_BEGINPATH) - { - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEPATH); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += *(d->path); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - d->pathless_stroke = false; - } - } - - switch (lpEMFR->iType) - { - case EMR_HEADER: - { - dbg_str << "<!-- EMR_HEADER -->\n"; - - *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"; - - if (d->pDesc) { - *(d->outdef) += "<!-- "; - *(d->outdef) += d->pDesc; - *(d->outdef) += " -->\n"; - } - - ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR; - SVGOStringStream tmp_outdef; - tmp_outdef << "<svg\n"; - tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n"; - tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n"; - tmp_outdef << " version=\"1.0\"\n"; - - d->xDPI = 2540; - d->yDPI = 2540; - - d->dc[d->level].PixelsInX = pEmr->rclFrame.right - pEmr->rclFrame.left; - d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom - pEmr->rclFrame.top; - device_x = pEmr->rclFrame.left/100.0*Inkscape::Util::Quantity::convert(1, "mm", "px"); - device_y = pEmr->rclFrame.top/100.0*Inkscape::Util::Quantity::convert(1, "mm", "px"); - - d->MMX = d->dc[d->level].PixelsInX / 100.0; - d->MMY = d->dc[d->level].PixelsInY / 100.0; - - d->dc[d->level].PixelsOutX = d->MMX * Inkscape::Util::Quantity::convert(1, "mm", "px"); - d->dc[d->level].PixelsOutY = d->MMY * Inkscape::Util::Quantity::convert(1, "mm", "px"); - - // calculate ratio of Inkscape dpi/device dpi - if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx) - device_scale = Inkscape::Util::Quantity::convert(1, "mm", "px")*pEmr->szlMillimeters.cx/pEmr->szlDevice.cx; - - tmp_outdef << - " width=\"" << d->MMX << "mm\"\n" << - " height=\"" << d->MMY << "mm\">\n"; - *(d->outdef) += tmp_outdef.str().c_str(); - *(d->outdef) += "<defs>"; // temporary end of header - - tmp_outsvg << "\n</defs>\n<g>\n"; // start of main body - - if (pEmr->nHandles) { - d->n_obj = pEmr->nHandles; - d->emf_obj = new EMF_OBJECT[d->n_obj]; - - // Init the new emf_obj list elements to null, provided the - // dynamic allocation succeeded. - if ( d->emf_obj != NULL ) - { - for( int i=0; i < d->n_obj; ++i ) - d->emf_obj[i].lpEMFR = NULL; - } //if - - } else { - d->emf_obj = NULL; - } - - break; - } - case EMR_POLYBEZIER: - { - dbg_str << "<!-- EMR_POLYBEZIER -->\n"; - - PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR; - DWORD i,j; - - if (pEmr->cptl<4) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYBEZIER"); - - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; - - for (i=1; i<pEmr->cptl; ) { - tmp_str << "\n\tC "; - for (j=0; j<3 && i<pEmr->cptl; j++,i++) { - tmp_str << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYGON: - { - dbg_str << "<!-- EMR_POLYGON -->\n"; - - EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR; - DWORD i; - - if (pEmr->cptl < 2) - break; - - assert_empty_path(d, "EMR_POLYGON"); - - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEANDFILLPATH); - *(d->outsvg) += "\n\td=\""; - - tmp_str << - "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; - - for (i=1; i<pEmr->cptl; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " z \" /> \n"; - - break; - } - case EMR_POLYLINE: - { - dbg_str << "<!-- EMR_POLYLINE -->\n"; - - EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR; - DWORD i; - - if (pEmr->cptl<2) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYLINE"); - - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; - - for (i=1; i<pEmr->cptl; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYBEZIERTO: - { - dbg_str << "<!-- EMR_POLYBEZIERTO -->\n"; - - PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR; - DWORD i,j; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; i<pEmr->cptl;) { - tmp_path << "\n\tC "; - for (j=0; j<3 && i<pEmr->cptl; j++,i++) { - tmp_path << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - } - - break; - } - case EMR_POLYLINETO: - { - dbg_str << "<!-- EMR_POLYLINETO -->\n"; - - PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR; - DWORD i; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; i<pEmr->cptl;i++) { - tmp_path << - "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - - break; - } - case EMR_POLYPOLYLINE: - case EMR_POLYPOLYGON: - { - if (lpEMFR->iType == EMR_POLYPOLYLINE) - dbg_str << "<!-- EMR_POLYPOLYLINE -->\n"; - if (lpEMFR->iType == EMR_POLYPOLYGON) - dbg_str << "<!-- EMR_POLYPOLYGON -->\n"; - - PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR; - unsigned int n, i, j; - - if (!d->inpath) { - assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE"); - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys]; - - i = 0; - for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) { - SVGOStringStream poly_path; - - poly_path << "\n\tM " << - pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << - pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; - i++; - - for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) { - poly_path << "\n\tL " << - pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << - pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; - i++; - } - - tmp_str << poly_path.str().c_str(); - if (lpEMFR->iType == EMR_POLYPOLYGON) - tmp_str << " z"; - tmp_str << " \n"; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_SETWINDOWEXTEX: - { - dbg_str << "<!-- EMR_SETWINDOWEXTEX -->\n"; - - PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR; - - d->dc[d->level].sizeWnd = pEmr->szlExtent; - - if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; - if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX; - d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY; - } - } - - if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; - } - - d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; - d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; - - if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { - d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; - d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; - } - else { - d->dc[d->level].ScaleInX = 1; - d->dc[d->level].ScaleInY = 1; - } - - break; - } - case EMR_SETWINDOWORGEX: - { - dbg_str << "<!-- EMR_SETWINDOWORGEX -->\n"; - - PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR; - d->dc[d->level].winorg = pEmr->ptlOrigin; - break; - } - case EMR_SETVIEWPORTEXTEX: - { - dbg_str << "<!-- EMR_SETVIEWPORTEXTEX -->\n"; - - PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR; - - d->dc[d->level].sizeView = pEmr->szlExtent; - - if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; - if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX; - d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY; - } - } - - if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; - } - - d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; - d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; - - if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { - d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; - d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; - } - else { - d->dc[d->level].ScaleInX = 1; - d->dc[d->level].ScaleInY = 1; - } - - break; - } - case EMR_SETVIEWPORTORGEX: - { - dbg_str << "<!-- EMR_SETVIEWPORTORGEX -->\n"; - - PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR; - d->dc[d->level].vieworg = pEmr->ptlOrigin; - break; - } - case EMR_SETBRUSHORGEX: - dbg_str << "<!-- EMR_SETBRUSHORGEX -->\n"; - break; - case EMR_EOF: - { - dbg_str << "<!-- EMR_EOF -->\n"; - - assert_empty_path(d, "EMR_EOF"); - tmp_outsvg << "</g>\n"; - tmp_outsvg << "</svg>\n"; - *(d->outsvg) = *(d->outdef) + *(d->outsvg); - break; - } - case EMR_SETPIXELV: - dbg_str << "<!-- EMR_SETPIXELV -->\n"; - break; - case EMR_SETMAPPERFLAGS: - dbg_str << "<!-- EMR_SETMAPPERFLAGS -->\n"; - break; - case EMR_SETMAPMODE: - dbg_str << "<!-- EMR_SETMAPMODE -->\n"; - break; - case EMR_SETBKMODE: - dbg_str << "<!-- EMR_SETBKMODE -->\n"; - break; - case EMR_SETPOLYFILLMODE: - { - dbg_str << "<!-- EMR_SETPOLYFILLMODE -->\n"; - - PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR; - d->dc[d->level].style.fill_rule.value = - (pEmr->iMode == ALTERNATE ? 0 : - pEmr->iMode == WINDING ? 1 : 0); - break; - } - case EMR_SETROP2: - dbg_str << "<!-- EMR_SETROP2 -->\n"; - break; - case EMR_SETSTRETCHBLTMODE: - dbg_str << "<!-- EMR_SETSTRETCHBLTMODE -->\n"; - break; - case EMR_SETTEXTALIGN: - { - dbg_str << "<!-- EMR_SETTEXTALIGN -->\n"; - - PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR; - d->dc[d->level].textAlign = pEmr->iMode; - break; - } - case EMR_SETCOLORADJUSTMENT: - dbg_str << "<!-- EMR_SETCOLORADJUSTMENT -->\n"; - break; - case EMR_SETTEXTCOLOR: - { - dbg_str << "<!-- EMR_SETTEXTCOLOR -->\n"; - - PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR; - d->dc[d->level].textColor = pEmr->crColor; - d->dc[d->level].textColorSet = true; - break; - } - case EMR_SETBKCOLOR: - dbg_str << "<!-- EMR_SETBKCOLOR -->\n"; - break; - case EMR_OFFSETCLIPRGN: - dbg_str << "<!-- EMR_OFFSETCLIPRGN -->\n"; - break; - case EMR_MOVETOEX: - { - dbg_str << "<!-- EMR_MOVETOEX -->\n"; - - PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - d->dc[d->level].cur = pEmr->ptl; - - tmp_path << - "\n\tM " << - pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << - pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; - break; - } - case EMR_SETMETARGN: - dbg_str << "<!-- EMR_SETMETARGN -->\n"; - break; - case EMR_EXCLUDECLIPRECT: - dbg_str << "<!-- EMR_EXCLUDECLIPRECT -->\n"; - break; - case EMR_INTERSECTCLIPRECT: - { - dbg_str << "<!-- EMR_INTERSECTCLIPRECT -->\n"; - - PEMRINTERSECTCLIPRECT pEmr = (PEMRINTERSECTCLIPRECT) lpEMFR; - RECTL rc = pEmr->rclClip; - clipset = true; - if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) - break; - rc_old = rc; - - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" "; - tmp_rectangle << "\n\tid=\"clipEmfPath" << ++(d->id) << "\" >"; - tmp_rectangle << "\n<rect "; - tmp_rectangle << "\n\tx=\"" << l << "\" "; - tmp_rectangle << "\n\ty=\"" << t << "\" "; - tmp_rectangle << "\n\twidth=\"" << r-l << "\" "; - tmp_rectangle << "\n\theight=\"" << b-t << "\" />"; - tmp_rectangle << "\n</clipPath>"; - - assert_empty_path(d, "EMR_RECTANGLE"); - - *(d->outdef) += tmp_rectangle.str().c_str(); - *(d->path) = ""; - break; - } - case EMR_SCALEVIEWPORTEXTEX: - dbg_str << "<!-- EMR_SCALEVIEWPORTEXTEX -->\n"; - break; - case EMR_SCALEWINDOWEXTEX: - dbg_str << "<!-- EMR_SCALEWINDOWEXTEX -->\n"; - break; - case EMR_SAVEDC: - dbg_str << "<!-- EMR_SAVEDC -->\n"; - - if (d->level < EMF_MAX_DC) { - d->dc[d->level + 1] = d->dc[d->level]; - d->level = d->level + 1; - } - break; - case EMR_RESTOREDC: - { - dbg_str << "<!-- EMR_RESTOREDC -->\n"; - - PEMRRESTOREDC pEmr = (PEMRRESTOREDC) lpEMFR; - int old_level = d->level; - if (pEmr->iRelative >= 0) { - if (pEmr->iRelative < d->level) - d->level = pEmr->iRelative; - } - else { - if (d->level + pEmr->iRelative >= 0) - d->level = d->level + pEmr->iRelative; - } - while (old_level > d->level) { - if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))) - delete[] d->dc[old_level].style.stroke_dash.dash; - old_level--; - } - break; - } - case EMR_SETWORLDTRANSFORM: - { - dbg_str << "<!-- EMR_SETWORLDTRANSFORM -->\n"; - - PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR; - d->dc[d->level].worldTransform = pEmr->xform; - break; - } - case EMR_MODIFYWORLDTRANSFORM: - { - dbg_str << "<!-- EMR_MODIFYWORLDTRANSFORM -->\n"; - - PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR; - switch (pEmr->iMode) - { - case MWT_IDENTITY: - d->dc[d->level].worldTransform.eM11 = 1.0; - d->dc[d->level].worldTransform.eM12 = 0.0; - d->dc[d->level].worldTransform.eM21 = 0.0; - d->dc[d->level].worldTransform.eM22 = 1.0; - d->dc[d->level].worldTransform.eDx = 0.0; - d->dc[d->level].worldTransform.eDy = 0.0; - break; - case MWT_LEFTMULTIPLY: - { -// d->dc[d->level].worldTransform = pEmr->xform * worldTransform; - - float a11 = pEmr->xform.eM11; - float a12 = pEmr->xform.eM12; - float a13 = 0.0; - float a21 = pEmr->xform.eM21; - float a22 = pEmr->xform.eM22; - float a23 = 0.0; - float a31 = pEmr->xform.eDx; - float a32 = pEmr->xform.eDy; - float a33 = 1.0; - - float b11 = d->dc[d->level].worldTransform.eM11; - float b12 = d->dc[d->level].worldTransform.eM12; - //float b13 = 0.0; - float b21 = d->dc[d->level].worldTransform.eM21; - float b22 = d->dc[d->level].worldTransform.eM22; - //float b23 = 0.0; - float b31 = d->dc[d->level].worldTransform.eDx; - float b32 = d->dc[d->level].worldTransform.eDy; - //float b33 = 1.0; - - float c11 = a11*b11 + a12*b21 + a13*b31;; - float c12 = a11*b12 + a12*b22 + a13*b32;; - //float c13 = a11*b13 + a12*b23 + a13*b33;; - float c21 = a21*b11 + a22*b21 + a23*b31;; - float c22 = a21*b12 + a22*b22 + a23*b32;; - //float c23 = a21*b13 + a22*b23 + a23*b33;; - float c31 = a31*b11 + a32*b21 + a33*b31;; - float c32 = a31*b12 + a32*b22 + a33*b32;; - //float c33 = a31*b13 + a32*b23 + a33*b33;; - - d->dc[d->level].worldTransform.eM11 = c11;; - d->dc[d->level].worldTransform.eM12 = c12;; - d->dc[d->level].worldTransform.eM21 = c21;; - d->dc[d->level].worldTransform.eM22 = c22;; - d->dc[d->level].worldTransform.eDx = c31; - d->dc[d->level].worldTransform.eDy = c32; - - break; - } - case MWT_RIGHTMULTIPLY: - { -// d->dc[d->level].worldTransform = worldTransform * pEmr->xform; - - float a11 = d->dc[d->level].worldTransform.eM11; - float a12 = d->dc[d->level].worldTransform.eM12; - float a13 = 0.0; - float a21 = d->dc[d->level].worldTransform.eM21; - float a22 = d->dc[d->level].worldTransform.eM22; - float a23 = 0.0; - float a31 = d->dc[d->level].worldTransform.eDx; - float a32 = d->dc[d->level].worldTransform.eDy; - float a33 = 1.0; - - float b11 = pEmr->xform.eM11; - float b12 = pEmr->xform.eM12; - //float b13 = 0.0; - float b21 = pEmr->xform.eM21; - float b22 = pEmr->xform.eM22; - //float b23 = 0.0; - float b31 = pEmr->xform.eDx; - float b32 = pEmr->xform.eDy; - //float b33 = 1.0; - - float c11 = a11*b11 + a12*b21 + a13*b31;; - float c12 = a11*b12 + a12*b22 + a13*b32;; - //float c13 = a11*b13 + a12*b23 + a13*b33;; - float c21 = a21*b11 + a22*b21 + a23*b31;; - float c22 = a21*b12 + a22*b22 + a23*b32;; - //float c23 = a21*b13 + a22*b23 + a23*b33;; - float c31 = a31*b11 + a32*b21 + a33*b31;; - float c32 = a31*b12 + a32*b22 + a33*b32;; - //float c33 = a31*b13 + a32*b23 + a33*b33;; - - d->dc[d->level].worldTransform.eM11 = c11;; - d->dc[d->level].worldTransform.eM12 = c12;; - d->dc[d->level].worldTransform.eM21 = c21;; - d->dc[d->level].worldTransform.eM22 = c22;; - d->dc[d->level].worldTransform.eDx = c31; - d->dc[d->level].worldTransform.eDy = c32; - - break; - } -// case MWT_SET: - default: - d->dc[d->level].worldTransform = pEmr->xform; - break; - } - break; - } - case EMR_SELECTOBJECT: - { - dbg_str << "<!-- EMR_SELECTOBJECT -->\n"; - - PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR; - unsigned int index = pEmr->ihObject; - - if (index >= ENHMETA_STOCK_OBJECT) { - index -= ENHMETA_STOCK_OBJECT; - switch (index) { - case NULL_BRUSH: - d->dc[d->level].fill_set = false; - break; - case BLACK_BRUSH: - case DKGRAY_BRUSH: - case GRAY_BRUSH: - case LTGRAY_BRUSH: - case WHITE_BRUSH: - { - float val = 0; - switch (index) { - case BLACK_BRUSH: - val = 0.0 / 255.0; - break; - case DKGRAY_BRUSH: - val = 64.0 / 255.0; - break; - case GRAY_BRUSH: - val = 128.0 / 255.0; - break; - case LTGRAY_BRUSH: - val = 192.0 / 255.0; - break; - case WHITE_BRUSH: - val = 255.0 / 255.0; - break; - } - d->dc[d->level].style.fill.value.color.set( val, val, val ); - - d->dc[d->level].fill_set = true; - break; - } - case NULL_PEN: - d->dc[d->level].stroke_set = false; - break; - case BLACK_PEN: - case WHITE_PEN: - { - float val = index == BLACK_PEN ? 0 : 1; - d->dc[d->level].style.stroke_dasharray_set = 0; - d->dc[d->level].style.stroke_width.value = 1.0; - d->dc[d->level].style.stroke.value.color.set( val, val, val ); - - d->dc[d->level].stroke_set = true; - - break; - } - } - } else { - if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) { - switch (d->emf_obj[index].type) - { - case EMR_CREATEPEN: - select_pen(d, index); - break; - case EMR_CREATEBRUSHINDIRECT: - select_brush(d, index); - break; - case EMR_EXTCREATEPEN: - select_extpen(d, index); - break; - case EMR_EXTCREATEFONTINDIRECTW: - select_font(d, index); - break; - } - } - } - break; - } - case EMR_CREATEPEN: - { - dbg_str << "<!-- EMR_CREATEPEN -->\n"; - - PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR; - int index = pEmr->ihPen; - - EMRCREATEPEN *pPen = - (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) ); - pPen->lopn = pEmr->lopn; - insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen); - - break; - } - case EMR_CREATEBRUSHINDIRECT: - { - dbg_str << "<!-- EMR_CREATEBRUSHINDIRECT -->\n"; - - PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR; - int index = pEmr->ihBrush; - - EMRCREATEBRUSHINDIRECT *pBrush = - (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) ); - pBrush->lb = pEmr->lb; - insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush); - - break; - } - case EMR_DELETEOBJECT: - dbg_str << "<!-- EMR_DELETEOBJECT -->\n"; - break; - case EMR_ANGLEARC: - dbg_str << "<!-- EMR_ANGLEARC -->\n"; - break; - case EMR_ELLIPSE: - { - dbg_str << "<!-- EMR_ELLIPSE -->\n"; - - PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR; - RECTL rclBox = pEmr->rclBox; - - double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top ); - double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top ); - double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom ); - double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom ); - - double cx = (l + r) / 2.0; - double cy = (t + b) / 2.0; - double rx = fabs(l - r) / 2.0; - double ry = fabs(t - b) / 2.0; - - SVGOStringStream tmp_ellipse; - tmp_ellipse << "cx=\"" << cx << "\" "; - tmp_ellipse << "cy=\"" << cy << "\" "; - tmp_ellipse << "rx=\"" << rx << "\" "; - tmp_ellipse << "ry=\"" << ry << "\" "; - - assert_empty_path(d, "EMR_ELLIPSE"); - - *(d->outsvg) += " <ellipse "; - output_style(d, lpEMFR->iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_ellipse.str().c_str(); - *(d->outsvg) += "/> \n"; - *(d->path) = ""; - break; - } - case EMR_RECTANGLE: - { - dbg_str << "<!-- EMR_RECTANGLE -->\n"; - - PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR; - RECTL rc = pEmr->rclBox; - - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "d=\""; - tmp_rectangle << "\n\tM " << l << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << b << " "; - tmp_rectangle << "\n\tL " << l << " " << b << " "; - tmp_rectangle << "\n\tz"; - - assert_empty_path(d, "EMR_RECTANGLE"); - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_rectangle.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - break; - } - case EMR_ROUNDRECT: - { - dbg_str << "<!-- EMR_ROUNDRECT -->\n"; - - PEMRROUNDRECT pEmr = (PEMRROUNDRECT) lpEMFR; - RECTL rc = pEmr->rclBox; - SIZEL corner = pEmr->szlCorner; - double f = 4.*(sqrt(2) - 1)/3; - - double l = pix_to_x_point(d, rc.left, rc.top); - double t = pix_to_y_point(d, rc.left, rc.top); - double r = pix_to_x_point(d, rc.right, rc.bottom); - double b = pix_to_y_point(d, rc.right, rc.bottom); - double cnx = pix_to_size_point(d, corner.cx/2); - double cny = pix_to_size_point(d, corner.cy/2); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "d=\""; - tmp_rectangle << "\n\tM " << l << ", " << t + cny << " "; - tmp_rectangle << "\n\tC " << l << ", " << t + (1-f)*cny << " " << l + (1-f)*cnx << ", " << t << " " << l + cnx << ", " << t << " "; - tmp_rectangle << "\n\tL " << r - cnx << ", " << t << " "; - tmp_rectangle << "\n\tC " << r - (1-f)*cnx << ", " << t << " " << r << ", " << t + (1-f)*cny << " " << r << ", " << t + cny << " "; - tmp_rectangle << "\n\tL " << r << ", " << b - cny << " "; - tmp_rectangle << "\n\tC " << r << ", " << b - (1-f)*cny << " " << r - (1-f)*cnx << ", " << b << " " << r - cnx << ", " << b << " "; - tmp_rectangle << "\n\tL " << l + cnx << ", " << b << " "; - tmp_rectangle << "\n\tC " << l + (1-f)*cnx << ", " << b << " " << l << ", " << b - (1-f)*cny << " " << l << ", " << b - cny << " "; - tmp_rectangle << "\n\tz"; - assert_empty_path(d, "EMR_ROUNDRECT"); - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_rectangle.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - break; - } - case EMR_ARC: - dbg_str << "<!-- EMR_ARC -->\n"; - break; - case EMR_CHORD: - dbg_str << "<!-- EMR_CHORD -->\n"; - break; - case EMR_PIE: - { - dbg_str << "<!-- EMR_PIE -->\n"; - - PEMRPIE pEmr = (PEMRPIE) lpEMFR; - RECTL rc = pEmr->rclBox; - - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - double x1 = pix_to_x_point( d, pEmr->ptlStart.x, pEmr->ptlStart.y ); - double y1 = pix_to_y_point( d, pEmr->ptlStart.x, pEmr->ptlStart.y ); - double x2 = pix_to_x_point( d, pEmr->ptlEnd.x, pEmr->ptlEnd.y ); - double y2 = pix_to_y_point( d, pEmr->ptlEnd.x, pEmr->ptlEnd.y ); - - SVGOStringStream tmp_pie; - tmp_pie << "d=\"" << - "\n\tM " << x1 << " " << y1 << " "; - - double angle1 = -atan2(y1 - (t + b) / 2.0, x1 - (l + r) / 2.0); - double angle2 = -atan2(y2 - (t + b) / 2.0, x2 - (l + r) / 2.0); - double angle = angle2 - angle1; - if (angle < 0) angle += 2*M_PI; - - bool large_arc_flag = false; - if (angle > M_PI) large_arc_flag = true; - - tmp_pie << "\n\tA " << - fabs(l - r) / 2.0 << " " << - fabs(t - b) / 2.0 << " " << - "0 " << large_arc_flag << " 0 " << - x2 << " " << y2 << " " << - "\n\tL " << (l + r) / 2.0 << " " << (t + b) / 2.0 << " " << - "\n\tz"; - - assert_empty_path(d, "EMR_PIE"); - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_pie.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - break; - } - case EMR_SELECTPALETTE: - dbg_str << "<!-- EMR_SELECTPALETTE -->\n"; - break; - case EMR_CREATEPALETTE: - dbg_str << "<!-- EMR_CREATEPALETTE -->\n"; - break; - case EMR_SETPALETTEENTRIES: - dbg_str << "<!-- EMR_SETPALETTEENTRIES -->\n"; - break; - case EMR_RESIZEPALETTE: - dbg_str << "<!-- EMR_RESIZEPALETTE -->\n"; - break; - case EMR_REALIZEPALETTE: - dbg_str << "<!-- EMR_REALIZEPALETTE -->\n"; - break; - case EMR_EXTFLOODFILL: - dbg_str << "<!-- EMR_EXTFLOODFILL -->\n"; - break; - case EMR_LINETO: - { - dbg_str << "<!-- EMR_LINETO -->\n"; - - PEMRLINETO pEmr = (PEMRLINETO) lpEMFR; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - tmp_path << - "\n\tL " << - pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << - pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; - break; - } - case EMR_ARCTO: - dbg_str << "<!-- EMR_ARCTO -->\n"; - break; - case EMR_POLYDRAW: - dbg_str << "<!-- EMR_POLYDRAW -->\n"; - break; - case EMR_SETARCDIRECTION: - dbg_str << "<!-- EMR_SETARCDIRECTION -->\n"; - break; - case EMR_SETMITERLIMIT: - { - dbg_str << "<!-- EMR_SETMITERLIMIT -->\n"; - - PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR; - - //BUG in SetMiterLimit() on mingw, possibly in underlying Windows(at least on XP?) - //The function takes a float but saves a 32 bit int in the EMR_SETMITERLIMIT record. - float miterlimit = *((int32_t *) &(pEmr->eMiterLimit)); - d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size - if (d->dc[d->level].style.stroke_miterlimit.value < 1.0) - d->dc[d->level].style.stroke_miterlimit.value = 1.0; - break; - } - case EMR_BEGINPATH: - { - dbg_str << "<!-- EMR_BEGINPATH -->\n"; - - if (!d->pathless_stroke) { - tmp_path << "d=\""; - *(d->path) = ""; - } - d->pathless_stroke = false; - d->inpath = true; - break; - } - case EMR_ENDPATH: - { - dbg_str << "<!-- EMR_ENDPATH -->\n"; - - tmp_path << "\""; - d->inpath = false; - break; - } - case EMR_CLOSEFIGURE: - { - dbg_str << "<!-- EMR_CLOSEFIGURE -->\n"; - - tmp_path << "\n\tz"; - break; - } - case EMR_FILLPATH: - case EMR_STROKEANDFILLPATH: - case EMR_STROKEPATH: - { - if (lpEMFR->iType == EMR_FILLPATH) - dbg_str << "<!-- EMR_FILLPATH -->\n"; - if (lpEMFR->iType == EMR_STROKEANDFILLPATH) - dbg_str << "<!-- EMR_STROKEANDFILLPATH -->\n"; - if (lpEMFR->iType == EMR_STROKEPATH) - dbg_str << "<!-- EMR_STROKEPATH -->\n"; - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += *(d->path); - *(d->outsvg) += " /> \n"; - *(d->path) = ""; - break; - } - case EMR_FLATTENPATH: - dbg_str << "<!-- EMR_FLATTENPATH -->\n"; - break; - case EMR_WIDENPATH: - dbg_str << "<!-- EMR_WIDENPATH -->\n"; - break; - case EMR_SELECTCLIPPATH: - dbg_str << "<!-- EMR_SELECTCLIPPATH -->\n"; - break; - case EMR_ABORTPATH: - dbg_str << "<!-- EMR_ABORTPATH -->\n"; - break; - case EMR_GDICOMMENT: - { - dbg_str << "<!-- EMR_GDICOMMENT -->\n"; - - PEMRGDICOMMENT pEmr = (PEMRGDICOMMENT) lpEMFR; - - CHAR *szTxt = (CHAR *) pEmr->Data; - - for (DWORD i = 0; i < pEmr->cbData; i++) { - if ( *szTxt) { - if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) { - tmp_str << *szTxt; - } - szTxt++; - } - } - - if (0 && strlen(tmp_str.str().c_str())) { - tmp_outsvg << " <!-- \""; - tmp_outsvg << tmp_str.str().c_str(); - tmp_outsvg << "\" -->\n"; - } - - break; - } - case EMR_FILLRGN: - dbg_str << "<!-- EMR_FILLRGN -->\n"; - break; - case EMR_FRAMERGN: - dbg_str << "<!-- EMR_FRAMERGN -->\n"; - break; - case EMR_INVERTRGN: - dbg_str << "<!-- EMR_INVERTRGN -->\n"; - break; - case EMR_PAINTRGN: - dbg_str << "<!-- EMR_PAINTRGN -->\n"; - break; - case EMR_EXTSELECTCLIPRGN: - { - dbg_str << "<!-- EMR_EXTSELECTCLIPRGN -->\n"; - - PEMREXTSELECTCLIPRGN pEmr = (PEMREXTSELECTCLIPRGN) lpEMFR; - if (pEmr->iMode == RGN_COPY) - clipset = false; - break; - } - case EMR_BITBLT: - { - dbg_str << "<!-- EMR_BITBLT -->\n"; - - PEMRBITBLT pEmr = (PEMRBITBLT) lpEMFR; - if ((pEmr->dwRop == PATCOPY) || (pEmr->dwRop == DPA)) { - // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead - double l = pix_to_x_point( d, pEmr->xDest, pEmr->yDest); - double t = pix_to_y_point( d, pEmr->xDest, pEmr->yDest); - double r = pix_to_x_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest); - double b = pix_to_y_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "d=\""; - tmp_rectangle << "\n\tM " << l << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << b << " "; - tmp_rectangle << "\n\tL " << l << " " << b << " "; - tmp_rectangle << "\n\tz"; - - assert_empty_path(d, "EMR_BITBLT"); - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_rectangle.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - } - break; - } - case EMR_STRETCHBLT: - dbg_str << "<!-- EMR_STRETCHBLT -->\n"; - break; - case EMR_MASKBLT: - dbg_str << "<!-- EMR_MASKBLT -->\n"; - break; - case EMR_PLGBLT: - dbg_str << "<!-- EMR_PLGBLT -->\n"; - break; - case EMR_SETDIBITSTODEVICE: - dbg_str << "<!-- EMR_SETDIBITSTODEVICE -->\n"; - break; - case EMR_STRETCHDIBITS: - dbg_str << "<!-- EMR_STRETCHDIBITS -->\n"; - break; - case EMR_EXTCREATEFONTINDIRECTW: - { - dbg_str << "<!-- EMR_EXTCREATEFONTINDIRECTW -->\n"; - - PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR; - int index = pEmr->ihFont; - - EMREXTCREATEFONTINDIRECTW *pFont = - (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) ); - pFont->elfw = pEmr->elfw; - insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont); - break; - } - case EMR_EXTTEXTOUTA: - { - dbg_str << "<!-- EMR_EXTTEXTOUTA -->\n"; - break; - } - case EMR_EXTTEXTOUTW: - { - dbg_str << "<!-- EMR_EXTTEXTOUTW -->\n"; - - PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR; - - double x1 = pEmr->emrtext.ptlReference.x; - double y1 = pEmr->emrtext.ptlReference.y; - - if (d->dc[d->level].textAlign & TA_UPDATECP) { - x1 = d->dc[d->level].cur.x; - y1 = d->dc[d->level].cur.y; - } - - double x = pix_to_x_point(d, x1, y1); - double y = pix_to_y_point(d, x1, y1); - - if (!(d->dc[d->level].textAlign & TA_BOTTOM)) - if (d->dc[d->level].style.baseline_shift.value) { - x += std::sin(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); - y += std::cos(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); - } - else - y += fabs(d->dc[d->level].style.font_size.computed); - - wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString); - - gchar *ansi_text = - (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL ); - - if (ansi_text) { - if ((wide_text[0] < 32) && (strlen(ansi_text) == 1)) { - g_free(ansi_text); // filter out isolated control characters - ansi_text = g_strdup(""); - } -// gchar *p = ansi_text; -// while (*p) { -// if (*p < 32 || *p >= 127) { -// g_free(ansi_text); -// ansi_text = g_strdup(""); -// break; -// } -// p++; -// } - - SVGOStringStream ts; - - gchar *escaped_text = g_markup_escape_text(ansi_text, -1); - -// float text_rgb[3]; -// sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb ); - -// if (!d->dc[d->level].textColorSet) { -// d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]), -// SP_COLOR_F_TO_U(text_rgb[1]), -// SP_COLOR_F_TO_U(text_rgb[2])); -// } - - char tmp[128]; - snprintf(tmp, 127, - "fill:#%02x%02x%02x;", - GetRValue(d->dc[d->level].textColor), - GetGValue(d->dc[d->level].textColor), - GetBValue(d->dc[d->level].textColor)); - - bool i = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_ITALIC); - //bool o = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE); - bool b = (d->dc[d->level].style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) || - (d->dc[d->level].style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->dc[d->level].style.font_weight.value <= SP_CSS_FONT_WEIGHT_900); - int lcr = ((d->dc[d->level].textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->dc[d->level].textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0; - - assert_empty_path(d, "EMR_EXTTEXTOUTW"); - - ts << " <text\n"; -// ts << " id=\"" << (d->id++) << "\"\n"; - ts << " xml:space=\"preserve\"\n"; - ts << " x=\"" << x << "\"\n"; - ts << " y=\"" << y << "\"\n"; - if (d->dc[d->level].style.baseline_shift.value) { - ts << " transform=\"" - << "rotate(-" << d->dc[d->level].style.baseline_shift.value - << " " << x << " " << y << ")" - << "\"\n"; - } - ts << " style=\"" - << "font-size:" << fabs(d->dc[d->level].style.font_size.computed) << "px;" - << tmp - << "font-style:" << (i ? "italic" : "normal") << ";" - << "font-weight:" << (b ? "bold" : "normal") << ";" - << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";" - << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";" - << "font-family:" << d->dc[d->level].tstyle.font_family.value << ";" - << "\"\n"; - ts << " >"; - ts << escaped_text; - ts << "</text>\n"; - - *(d->outsvg) += ts.str().c_str(); - - g_free(escaped_text); - g_free(ansi_text); - } - - break; - } - case EMR_POLYBEZIER16: - { - dbg_str << "<!-- EMR_POLYBEZIER16 -->\n"; - - PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i,j; - - if (pEmr->cpts<4) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYBEZIER16"); - - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << - pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; - - for (i=1; i<pEmr->cpts; ) { - tmp_str << "\n\tC "; - for (j=0; j<3 && i<pEmr->cpts; j++,i++) { - tmp_str << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYGON16: - { - dbg_str << "<!-- EMR_POLYGON16 -->\n"; - - PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - SVGOStringStream tmp_poly; - unsigned int i; - unsigned int first = 0; - - assert_empty_path(d, "EMR_POLYGON16"); - - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEANDFILLPATH); - *(d->outsvg) += "\n\td=\""; - - // skip the first point? - tmp_poly << "\n\tM " << - pix_to_x_point( d, apts[first].x, apts[first].y ) << " " << - pix_to_y_point( d, apts[first].x, apts[first].y ) << " "; - - for (i=first+1; i<pEmr->cpts; i++) { - tmp_poly << "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - - *(d->outsvg) += tmp_poly.str().c_str(); - *(d->outsvg) += " z \" /> \n"; - - break; - } - case EMR_POLYLINE16: - { - dbg_str << "<!-- EMR_POLYLINE16 -->\n"; - - EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i; - - if (pEmr->cpts<2) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYLINE16"); - - *(d->outsvg) += " <path "; - output_style(d, EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << - pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; - - for (i=1; i<pEmr->cpts; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYBEZIERTO16: - { - dbg_str << "<!-- EMR_POLYBEZIERTO16 -->\n"; - - PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i,j; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; i<pEmr->cpts;) { - tmp_path << "\n\tC "; - for (j=0; j<3 && i<pEmr->cpts; j++,i++) { - tmp_path << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - } - - break; - } - case EMR_POLYLINETO16: - { - dbg_str << "<!-- EMR_POLYLINETO16 -->\n"; - - PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; i<pEmr->cpts;i++) { - tmp_path << - "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - - break; - } - case EMR_POLYPOLYLINE16: - case EMR_POLYPOLYGON16: - { - if (lpEMFR->iType == EMR_POLYPOLYLINE16) - dbg_str << "<!-- EMR_POLYPOLYLINE16 -->\n"; - if (lpEMFR->iType == EMR_POLYPOLYGON16) - dbg_str << "<!-- EMR_POLYPOLYGON16 -->\n"; - - PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR; - unsigned int n, i, j; - - if (!d->inpath) { - assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16"); - - *(d->outsvg) += " <path "; - output_style(d, lpEMFR->iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys]; - - i = 0; - for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) { - SVGOStringStream poly_path; - - poly_path << "\n\tM " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - i++; - - for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) { - poly_path << "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - i++; - } - - tmp_str << poly_path.str().c_str(); - if (lpEMFR->iType == EMR_POLYPOLYGON16) - tmp_str << " z"; - tmp_str << " \n"; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYDRAW16: - dbg_str << "<!-- EMR_POLYDRAW16 -->\n"; - break; - case EMR_CREATEMONOBRUSH: - dbg_str << "<!-- EMR_CREATEMONOBRUSH -->\n"; - break; - case EMR_CREATEDIBPATTERNBRUSHPT: - { - dbg_str << "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n"; - - PEMRCREATEDIBPATTERNBRUSHPT pEmr = (PEMRCREATEDIBPATTERNBRUSHPT) lpEMFR; - int index = pEmr->ihBrush; - - EMRCREATEDIBPATTERNBRUSHPT *pBrush = - (EMRCREATEDIBPATTERNBRUSHPT *) malloc( sizeof(EMRCREATEDIBPATTERNBRUSHPT) ); - insert_object(d, index, EMR_CREATEDIBPATTERNBRUSHPT, (ENHMETARECORD *) pBrush); - break; - } - case EMR_EXTCREATEPEN: - { - dbg_str << "<!-- EMR_EXTCREATEPEN -->\n"; - - PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR; - int index = pEmr->ihPen; - - EMREXTCREATEPEN *pPen = - (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) + - sizeof(DWORD) * pEmr->elp.elpNumEntries ); - pPen->ihPen = pEmr->ihPen; - pPen->offBmi = pEmr->offBmi; - pPen->cbBmi = pEmr->cbBmi; - pPen->offBits = pEmr->offBits; - pPen->cbBits = pEmr->cbBits; - pPen->elp = pEmr->elp; - for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { - pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i]; - } - insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen); - - break; - } - case EMR_POLYTEXTOUTA: - dbg_str << "<!-- EMR_POLYTEXTOUTA -->\n"; - break; - case EMR_POLYTEXTOUTW: - dbg_str << "<!-- EMR_POLYTEXTOUTW -->\n"; - break; - case EMR_SETICMMODE: - dbg_str << "<!-- EMR_SETICMMODE -->\n"; - break; - case EMR_CREATECOLORSPACE: - dbg_str << "<!-- EMR_CREATECOLORSPACE -->\n"; - break; - case EMR_SETCOLORSPACE: - dbg_str << "<!-- EMR_SETCOLORSPACE -->\n"; - break; - case EMR_DELETECOLORSPACE: - dbg_str << "<!-- EMR_DELETECOLORSPACE -->\n"; - break; - case EMR_GLSRECORD: - dbg_str << "<!-- EMR_GLSRECORD -->\n"; - break; - case EMR_GLSBOUNDEDRECORD: - dbg_str << "<!-- EMR_GLSBOUNDEDRECORD -->\n"; - break; - case EMR_PIXELFORMAT: - dbg_str << "<!-- EMR_PIXELFORMAT -->\n"; - break; - default: - dbg_str << "<!-- EMR_??? -->\n"; - break; - } - -// *(d->outsvg) += dbg_str.str().c_str(); - *(d->outsvg) += tmp_outsvg.str().c_str(); - *(d->path) += tmp_path.str().c_str(); - - return 1; -} - -static int CALLBACK -myMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, METARECORD * /*lpMFR*/, int /*nObj*/, LPARAM /*lpData*/) -{ - g_warning("Unable to import Windows Meta File.\n"); - return 0; -} - -// Aldus Placeable Header =================================================== -// Since we are a 32bit app, we have to be sure this structure compiles to -// be identical to a 16 bit app's version. To do this, we use the #pragma -// to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT -// for the bbox rectangle. -#pragma pack( push ) -#pragma pack( 2 ) -typedef struct -{ - DWORD dwKey; - WORD hmf; - SMALL_RECT bbox; - WORD wInch; - DWORD dwReserved; - WORD wCheckSum; -} APMHEADER, *PAPMHEADER; -#pragma pack( pop ) - - -SPDocument * -EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) -{ - EMF_CALLBACK_DATA d; - - memset(&d, 0, sizeof(d)); - - d.dc[0].worldTransform.eM11 = 1.0; - d.dc[0].worldTransform.eM12 = 0.0; - d.dc[0].worldTransform.eM21 = 0.0; - d.dc[0].worldTransform.eM22 = 1.0; - d.dc[0].worldTransform.eDx = 0.0; - d.dc[0].worldTransform.eDy = 0.0; - - gsize bytesRead = 0; - gsize bytesWritten = 0; - GError* error = NULL; - gchar *local_fn = - g_filename_from_utf8( uri, -1, &bytesRead, &bytesWritten, &error ); - - if (local_fn == NULL) { - return NULL; - } - - d.outsvg = new Glib::ustring(""); - d.path = new Glib::ustring(""); - d.outdef = new Glib::ustring(""); - - CHAR *ansi_uri = (CHAR *) local_fn; - gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL ); - WCHAR *unicode_uri = (WCHAR *) unicode_fn; - - DWORD filesize = 0; - HANDLE fp = NULL; - - HMETAFILE hmf; - HENHMETAFILE hemf; - - fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if ( fp != INVALID_HANDLE_VALUE ) { - filesize = GetFileSize(fp, NULL); - CloseHandle(fp); - } - - // Try open as Enhanced Metafile - hemf = GetEnhMetaFileW(unicode_uri); - - if (!hemf) { - // Try open as Windows Metafile - hmf = GetMetaFileW(unicode_uri); - - METAFILEPICT mp; - HDC hDC; - - if (!hmf) { - WCHAR szTemp[MAX_PATH]; - - DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH ); - if (dw) { - hmf = GetMetaFileW( szTemp ); - } - } - - if (hmf) { - DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL ); - - if (!nSize) - nSize = filesize; - - if (nSize) { - BYTE *lpvData = new BYTE[nSize]; - if (lpvData) { - DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData ); - if (dw) { - // Fill out a METAFILEPICT structure - mp.mm = MM_ANISOTROPIC; - mp.xExt = 1000; - mp.yExt = 1000; - mp.hMF = NULL; - // Get a reference DC - hDC = GetDC( NULL ); - // Make an enhanced metafile from the windows metafile - hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp ); - // Clean up - ReleaseDC( NULL, hDC ); - DeleteMetaFile( hmf ); - hmf = NULL; - } - else { - // EnumMetaFile - } - delete[] lpvData; - } - else { - DeleteMetaFile( hmf ); - hmf = NULL; - } - } - else { - DeleteMetaFile( hmf ); - hmf = NULL; - } - } - else { - // Try open as Aldus Placeable Metafile - HANDLE hFile; - hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - - if (hFile != INVALID_HANDLE_VALUE) { - DWORD nSize = GetFileSize( hFile, NULL ); - if (nSize) { - BYTE *lpvData = new BYTE[nSize]; - if (lpvData) { - DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL ); - if (dw) { - if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) { - // Fill out a METAFILEPICT structure - mp.mm = MM_ANISOTROPIC; - mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left; - mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch); - mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top; - mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch); - mp.hMF = NULL; - // Get a reference DC - hDC = GetDC( NULL ); - // Create an enhanced metafile from the bits - hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp ); - // Clean up - ReleaseDC( NULL, hDC ); - } - } - delete[] lpvData; - } - } - CloseHandle( hFile ); - } - } - } - - if ((!hemf && !hmf) || !d.outsvg || !d.path) { - if (d.outsvg) - delete d.outsvg; - if (d.path) - delete d.path; - if (d.outdef) - delete d.outdef; - if (local_fn) - g_free(local_fn); - if (unicode_fn) - g_free(unicode_fn); - if (hemf) - DeleteEnhMetaFile(hemf); - if (hmf) - DeleteMetaFile(hmf); - return NULL; - } - - d.pDesc = NULL; - - if (hemf) { - DWORD dwNeeded = GetEnhMetaFileDescriptionA( hemf, 0, NULL ); - if ( dwNeeded > 0 ) { - d.pDesc = (CHAR *) malloc( dwNeeded + 1 ); - d.pDesc[dwNeeded] = 0; - if ( GetEnhMetaFileDescription( hemf, dwNeeded, d.pDesc ) == 0 ) - lstrcpy( d.pDesc, "" ); - if ((lstrlen(d.pDesc) > 1) && (lstrlen(d.pDesc) < dwNeeded)) - d.pDesc[lstrlen(d.pDesc)] = '#'; - } - - // This ugly reinterpret_cast is to prevent old versions of gcc from whining about a mismatch in the const-ness of the arguments - EnumEnhMetaFile(NULL, hemf, reinterpret_cast<ENHMFENUMPROC>(myEnhMetaFileProc), (LPVOID) &d, NULL); - DeleteEnhMetaFile(hemf); - } - else { - EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d); - DeleteMetaFile(hmf); - } - - if (d.pDesc) - free( d.pDesc ); - -// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; - - SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); - - delete d.outsvg; - delete d.path; - delete d.outdef; - - if (d.emf_obj) { - int i; - for (i=0; i<d.n_obj; i++) - delete_object(&d, i); - delete[] d.emf_obj; - } - - if (d.dc[0].style.stroke_dash.dash) - delete[] d.dc[0].style.stroke_dash.dash; - - if (local_fn) - g_free(local_fn); - if (unicode_fn) - g_free(unicode_fn); - - return doc; -} - - -void -EmfWin32::init (void) -{ - /* EMF in */ - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("EMF Input") "</name>\n" - "<id>org.inkscape.input.emf.win32</id>\n" - "<input>\n" - "<extension>.emf</extension>\n" - "<mimetype>image/x-emf</mimetype>\n" - "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n" - "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n" - "<output_extension>org.inkscape.output.emf.win32</output_extension>\n" - "</input>\n" - "</inkscape-extension>", new EmfWin32()); - - /* WMF in */ - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("WMF Input") "</name>\n" - "<id>org.inkscape.input.wmf.win32</id>\n" - "<input>\n" - "<extension>.wmf</extension>\n" - "<mimetype>image/x-wmf</mimetype>\n" - "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n" - "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n" - "<output_extension>org.inkscape.output.emf.win32</output_extension>\n" - "</input>\n" - "</inkscape-extension>", new EmfWin32()); - - /* EMF out */ - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("EMF Output") "</name>\n" - "<id>org.inkscape.output.emf.win32</id>\n" - "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n" - "<output>\n" - "<extension>.emf</extension>\n" - "<mimetype>image/x-emf</mimetype>\n" - "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n" - "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n" - "</output>\n" - "</inkscape-extension>", new EmfWin32()); - - return; -} - - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* WIN32 */ -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-inout.h b/src/extension/internal/emf-win32-inout.h deleted file mode 100644 index 4b975c8de..000000000 --- a/src/extension/internal/emf-win32-inout.h +++ /dev/null @@ -1,57 +0,0 @@ -/** @file - * @brief Enhanced Metafile Input/Output - */ -/* Authors: - * Ulf Erikson <ulferikson@users.sf.net> - * - * Copyright (C) 2006-2008 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifndef SEEN_EXTENSION_INTERNAL_EMF_WIN32_H -#define SEEN_EXTENSION_INTERNAL_EMF_WIN32_H -#ifdef WIN32 - -#include "extension/implementation/implementation.h" - -namespace Inkscape { -namespace Extension { -namespace Internal { - -class EmfWin32 : Inkscape::Extension::Implementation::Implementation { //This is a derived class - -public: - EmfWin32(); // Empty constructor - - virtual ~EmfWin32();//Destructor - - bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) - - void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename - SPDocument *doc, - gchar const *filename); - - virtual SPDocument *open( Inkscape::Extension::Input *mod, - const gchar *uri ); - - static void init(void);//Initialize the class - -private: -}; - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* WIN32 */ - -#endif /* EXTENSION_INTERNAL_EMF_WIN32_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp deleted file mode 100644 index 92f564078..000000000 --- a/src/extension/internal/emf-win32-print.cpp +++ /dev/null @@ -1,928 +0,0 @@ -/** @file - * @brief Enhanced Metafile printing - */ -/* Authors: - * Ulf Erikson <ulferikson@users.sf.net> - * Jon A. Cruz <jon@joncruz.org> - * Abhishek Sharma - * - * Copyright (C) 2006-2009 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -/* - * References: - * - How to Create & Play Enhanced Metafiles in Win32 - * http://support.microsoft.com/kb/q145999/ - * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles - * http://support.microsoft.com/kb/q66949/ - * - Metafile Functions - * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp - * - Metafile Structures - * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp - */ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - - -#include <2geom/pathvector.h> -#include <2geom/rect.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> -#include "helper/geom.h" -#include "helper/geom-curves.h" -#include "sp-item.h" -#include "util/units.h" - -#include "style.h" -#include "inkscape-version.h" -#include "sp-root.h" - -#include "emf-win32-print.h" - -#include "extension/system.h" -#include "extension/print.h" -#include "document.h" - - -namespace Inkscape { -namespace Extension { -namespace Internal { - -static float dwDPI = 2540; - - -PrintEmfWin32::PrintEmfWin32 (void): - _width(0), - _height(0), - hdc(NULL), - hbrush(NULL), - hbrushOld(NULL), - hpen(NULL), - stroke_and_fill(false), - fill_only(false), - simple_shape(false) -{ -} - - -PrintEmfWin32::~PrintEmfWin32 (void) -{ - if (hdc) { - HENHMETAFILE metafile = CloseEnhMetaFile( hdc ); - if ( metafile ) { - DeleteEnhMetaFile( metafile ); - } - DeleteDC( hdc ); - } - - /* restore default signal handling for SIGPIPE */ -#if !defined(_WIN32) && !defined(__WIN32__) - (void) signal(SIGPIPE, SIG_DFL); -#endif - return; -} - - -unsigned int PrintEmfWin32::setup (Inkscape::Extension::Print * /*mod*/) -{ - return TRUE; -} - - -unsigned int PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) -{ - gchar const *utf8_fn = mod->get_param_string("destination"); - - gsize bytesRead = 0; - gsize bytesWritten = 0; - GError* error = NULL; - gchar *local_fn = - g_filename_from_utf8( utf8_fn, -1, &bytesRead, &bytesWritten, &error ); - - if (local_fn == NULL) { - return 1; - } - - CHAR *ansi_uri = (CHAR *) local_fn; - gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL ); - WCHAR *unicode_uri = (WCHAR *) unicode_fn; - - // width and height in px - _width = doc->getWidth(); - _height = doc->getHeight(); - - bool pageBoundingBox; - pageBoundingBox = mod->get_param_bool("pageBoundingBox"); - - Geom::Rect d; - if (pageBoundingBox) { - d = Geom::Rect::from_xywh(0, 0, _width, _height); - } else { - SPItem* doc_item = doc->getRoot(); - Geom::OptRect bbox = doc_item->desktopVisualBounds(); - if (bbox) d = *bbox; - } - - d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in")); - - float dwInchesX = d.width(); - float dwInchesY = d.height(); - - // dwInchesX x dwInchesY in .01mm units - SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) ); - - // Get a Reference DC - HDC hScreenDC = GetDC( NULL ); - - // Get the physical characteristics of the reference DC - int PixelsX = GetDeviceCaps( hScreenDC, HORZRES ); - int PixelsY = GetDeviceCaps( hScreenDC, VERTRES ); - int MMX = GetDeviceCaps( hScreenDC, HORZSIZE ); - int MMY = GetDeviceCaps( hScreenDC, VERTSIZE ); - - CHAR buff[1024]; - ZeroMemory(buff, sizeof(buff)); - snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", Inkscape::version_string, __DATE__); - INT len = strlen(buff); - CHAR *p1 = strrchr(ansi_uri, '\\'); - CHAR *p2 = strrchr(ansi_uri, '/'); - CHAR *p = MAX(p1, p2); - if (p) - p++; - else - p = ansi_uri; - snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p); - - // Create the Metafile - { - WCHAR wbuff[1024]; - ZeroMemory(wbuff, sizeof(wbuff)); - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0])); - hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff ); - } - - // Release the reference DC - ReleaseDC( NULL, hScreenDC ); - - // Did we get a good metafile? - if (hdc == NULL) - { - g_free(local_fn); - g_free(unicode_fn); - return 1; - } - - // Anisotropic mapping mode - SetMapMode( hdc, MM_ANISOTROPIC ); - - // Set the Windows extent - int windowextX = (int) ceil(dwInchesX*dwDPI); - int windowextY = (int) ceil(dwInchesY*dwDPI); - SetWindowExtEx( hdc, windowextX, windowextY, NULL ); - - // Set the viewport extent to reflect - // dwInchesX" x dwInchesY" in device units - int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX); - int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY); - SetViewportExtEx( hdc, viewportextX, viewportextY, NULL ); - - if (1) { - snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY); - GdiComment(hdc, strlen(buff), (BYTE*) buff); - - snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * Inkscape::Util::Quantity::convert(1, "in", "mm"), dwInchesY * Inkscape::Util::Quantity::convert(1, "in", "mm")); - GdiComment(hdc, strlen(buff), (BYTE*) buff); - } - - SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) ); - - g_free(local_fn); - g_free(unicode_fn); - - m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight())); /// @fixme hardcoded doc2dt transform - - return 0; -} - - -unsigned int PrintEmfWin32::finish (Inkscape::Extension::Print * /*mod*/) -{ - if (!hdc) return 0; - - flush_fill(); // flush any pending fills - - HENHMETAFILE metafile = CloseEnhMetaFile( hdc ); - if ( metafile ) { - DeleteEnhMetaFile( metafile ); - } - DeleteDC( hdc ); - - hdc = NULL; - - return 0; -} - - -unsigned int PrintEmfWin32::comment (Inkscape::Extension::Print * /*module*/, - const char * /*comment*/) -{ - if (!hdc) return 0; - - flush_fill(); // flush any pending fills - - return 0; -} - - -int PrintEmfWin32::create_brush(SPStyle const *style) -{ - if (style) { - float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); - if (opacity <= 0.0) - return 1; - - float rgb[3]; - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) ); - hbrushOld = (HBRUSH) SelectObject( hdc, hbrush ); - - SetPolyFillMode( hdc, - style->fill_rule.computed == 0 ? WINDING : - style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE ); - } else { // if (!style) - hbrush = CreateSolidBrush( RGB(255, 255, 255) ); - hbrushOld = (HBRUSH) SelectObject( hdc, hbrush ); - SetPolyFillMode( hdc, ALTERNATE ); - } - - return 0; -} - - -void PrintEmfWin32::destroy_brush() -{ - SelectObject( hdc, hbrushOld ); - if (hbrush) - DeleteObject( hbrush ); - hbrush = NULL; - hbrushOld = NULL; -} - - -void PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Affine &transform) -{ - if (style) { - float rgb[3]; - - sp_color_get_rgb_floatv(&style->stroke.value.color, rgb); - - LOGBRUSH lb; - ZeroMemory(&lb, sizeof(lb)); - lb.lbStyle = BS_SOLID; - lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] ); - - int linestyle = PS_SOLID; - int linecap = 0; - int linejoin = 0; - DWORD n_dash = 0; - DWORD *dash = NULL; - - using Geom::X; - using Geom::Y; - - Geom::Point zero(0, 0); - Geom::Point one(1, 1); - Geom::Point p0(zero * transform); - Geom::Point p1(one * transform); - Geom::Point p(p1 - p0); - - double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); - - DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI) ); - - if (style->stroke_linecap.computed == 0) { - linecap = PS_ENDCAP_FLAT; - } - else if (style->stroke_linecap.computed == 1) { - linecap = PS_ENDCAP_ROUND; - } - else if (style->stroke_linecap.computed == 2) { - linecap = PS_ENDCAP_SQUARE; - } - - if (style->stroke_linejoin.computed == 0) { - linejoin = PS_JOIN_MITER; - } - else if (style->stroke_linejoin.computed == 1) { - linejoin = PS_JOIN_ROUND; - } - else if (style->stroke_linejoin.computed == 2) { - linejoin = PS_JOIN_BEVEL; - } - - if (style->stroke_dash.n_dash && - style->stroke_dash.dash ) - { - int i = 0; - while (linestyle != PS_USERSTYLE && - (i < style->stroke_dash.n_dash)) { - if (style->stroke_dash.dash[i] > 0.00000001) - linestyle = PS_USERSTYLE; - i++; - } - - if (linestyle == PS_USERSTYLE) { - n_dash = style->stroke_dash.n_dash; - dash = new DWORD[n_dash]; - for (i = 0; i < style->stroke_dash.n_dash; i++) { - dash[i] = (DWORD) (style->stroke_dash.dash[i] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - } - } - } - - hpen = ExtCreatePen( - PS_GEOMETRIC | linestyle | linecap | linejoin, - linewidth, - &lb, - n_dash, - dash ); - - if ( !hpen && linestyle == PS_USERSTYLE ) { - hpen = ExtCreatePen( - PS_GEOMETRIC | PS_SOLID | linecap | linejoin, - linewidth, - &lb, - 0, - NULL ); - } - - if ( !hpen ) { - hpen = CreatePen( - PS_SOLID, - linewidth, - lb.lbColor ); - } - - hpenOld = (HPEN) SelectObject( hdc, hpen ); - - if (linejoin == PS_JOIN_MITER) { - float oldmiterlimit; - float miterlimit = style->stroke_miterlimit.value; //ratio, not a pt size - - SetMiterLimit( - hdc, - miterlimit, - &oldmiterlimit ); - } - - if (n_dash) { - delete[] dash; - } - } - else { // if (!style) - hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) ); - hpenOld = (HPEN) SelectObject( hdc, hpen ); - } -} - - -void PrintEmfWin32::destroy_pen() -{ - SelectObject( hdc, hpenOld ); - if (hpen) - DeleteObject( hpen ); - hpen = NULL; -} - - -void PrintEmfWin32::flush_fill() -{ - if (!fill_pathv.empty()) { - stroke_and_fill = false; - fill_only = true; - print_pathv(fill_pathv, fill_transform); - fill_only = false; - if (!simple_shape) - FillPath( hdc ); - destroy_brush(); - fill_pathv.clear(); - } -} - -unsigned int PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) -{ - if (!m_tr_stack.empty()) { - Geom::Affine tr_top = m_tr_stack.top(); - m_tr_stack.push(transform * tr_top); - } else { - m_tr_stack.push(transform); - } - - return 1; -} - -unsigned int PrintEmfWin32::release(Inkscape::Extension::Print * /*mod*/) -{ - m_tr_stack.pop(); - return 1; -} - -unsigned int PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/, - Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, - Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) -{ - if (!hdc) return 0; - - Geom::Affine tf = m_tr_stack.top(); - - flush_fill(); // flush any pending fills - - if (style->fill.isColor()) { - if (create_brush(style)) - return 0; - } else { - // create_brush(NULL); - return 0; - } - - fill_pathv.clear(); - std::copy(pathv.begin(), pathv.end(), std::back_inserter(fill_pathv)); - fill_transform = tf; - - // postpone fill in case of stroke-and-fill - - return 0; -} - - -unsigned int PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/, - Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, - Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) -{ - if (!hdc) return 0; - - Geom::Affine tf = m_tr_stack.top(); - - stroke_and_fill = ( pathv == fill_pathv ); - - if (!stroke_and_fill) { - flush_fill(); // flush any pending fills - } - - if (style->stroke.isColor()) { - create_pen(style, tf); - } else { - // create_pen(NULL, tf); - return 0; - } - - print_pathv(pathv, tf); - - if (stroke_and_fill) { - if (!simple_shape) - StrokeAndFillPath( hdc ); - destroy_brush(); - fill_pathv.clear(); - } else { - if (!simple_shape) - StrokePath( hdc ); - } - - destroy_pen(); - - return 0; -} - - -bool PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) -{ - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); - - int nodes = 0; - int moves = 0; - int lines = 0; - int curves = 0; - - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { - moves++; - nodes++; - - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - nodes++; - - if ( is_straight_curve(*cit) ) { - lines++; - } - else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) { - cubic = cubic; - curves++; - } - } - } - - if (!nodes) - return false; - - POINT *lpPoints = new POINT[moves + lines + curves*3]; - int i = 0; - - /** - * For all Subpaths in the <path> - */ - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { - using Geom::X; - using Geom::Y; - - Geom::Point p0 = pit->initialPoint(); - - p0[X] = (p0[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p0[Y] = (p0[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - LONG const x0 = (LONG) round(p0[X]); - LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - - lpPoints[i].x = x0; - lpPoints[i].y = y0; - i = i + 1; - - /** - * For all segments in the subpath - */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { - //Geom::Point p0 = cit->initialPoint(); - Geom::Point p1 = cit->finalPoint(); - - //p0[X] = (p0[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[X] = (p1[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - //p0[Y] = (p0[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[Y] = (p1[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - - lpPoints[i].x = x1; - lpPoints[i].y = y1; - i = i + 1; - } - else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) - { - std::vector<Geom::Point> points = cubic->points(); - //Geom::Point p0 = points[0]; - Geom::Point p1 = points[1]; - Geom::Point p2 = points[2]; - Geom::Point p3 = points[3]; - - //p0[X] = (p0[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[X] = (p1[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p2[X] = (p2[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p3[X] = (p3[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - //p0[Y] = (p0[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[Y] = (p1[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p2[Y] = (p2[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p3[Y] = (p3[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - LONG const x2 = (LONG) round(p2[X]); - LONG const y2 = (LONG) round(rc.bottom-p2[Y]); - LONG const x3 = (LONG) round(p3[X]); - LONG const y3 = (LONG) round(rc.bottom-p3[Y]); - - POINT pt[3]; - pt[0].x = x1; - pt[0].y = y1; - pt[1].x = x2; - pt[1].y = y2; - pt[2].x = x3; - pt[2].y = y3; - - lpPoints[i].x = x1; - lpPoints[i].y = y1; - lpPoints[i+1].x = x2; - lpPoints[i+1].y = y2; - lpPoints[i+2].x = x3; - lpPoints[i+2].y = y3; - i = i + 3; - } - } - } - - bool done = false; - bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); - bool polygon = false; - bool rectangle = false; - bool ellipse = false; - - if (moves == 1 && moves+lines == nodes && closed) { - polygon = true; -// if (nodes==5) { // disable due to LP Bug 407394 -// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && -// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) -// { -// rectangle = true; -// } -// } - } - else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { -// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && -// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && -// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && -// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && -// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && -// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) -// { // disable due to LP Bug 407394 -// ellipse = true; -// } - } - - if (polygon || ellipse) { - HPEN hpenTmp = NULL; - HPEN hpenOld = NULL; - HBRUSH hbrushTmp = NULL; - HBRUSH hbrushOld = NULL; - - if (!stroke_and_fill) { - if (fill_only) { - hpenTmp = (HPEN) GetStockObject(NULL_PEN); - hpenOld = (HPEN) SelectObject( hdc, hpenTmp ); - } - else { // if (stroke_only) - hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH); - hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp ); - } - } - - if (polygon) { - if (rectangle) - Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y ); - else - Polygon( hdc, lpPoints, nodes ); - } - else if (ellipse) { - Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y); - } - - done = true; - - if (hpenOld) - SelectObject( hdc, hpenOld ); - if (hpenTmp) - DeleteObject( hpenTmp ); - if (hbrushOld) - SelectObject( hdc, hbrushOld ); - if (hbrushTmp) - DeleteObject( hbrushTmp ); - } - - delete[] lpPoints; - - return done; -} - -unsigned int PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) -{ - simple_shape = print_simple_shape(pathv, transform); - - if (simple_shape) - return TRUE; - - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); - - BeginPath( hdc ); - - /** - * For all Subpaths in the <path> - */ - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { - using Geom::X; - using Geom::Y; - - Geom::Point p0 = pit->initialPoint(); - - p0[X] = (p0[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p0[Y] = (p0[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - LONG const x0 = (LONG) round(p0[X]); - LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - - MoveToEx( hdc, x0, y0, NULL ); - - /** - * For all segments in the subpath - */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { - //Geom::Point p0 = cit->initialPoint(); - Geom::Point p1 = cit->finalPoint(); - - //p0[X] = (p0[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[X] = (p1[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - //p0[Y] = (p0[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[Y] = (p1[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - - LineTo( hdc, x1, y1 ); - } - else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) - { - std::vector<Geom::Point> points = cubic->points(); - //Geom::Point p0 = points[0]; - Geom::Point p1 = points[1]; - Geom::Point p2 = points[2]; - Geom::Point p3 = points[3]; - - //p0[X] = (p0[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[X] = (p1[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p2[X] = (p2[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p3[X] = (p3[X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - //p0[Y] = (p0[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p1[Y] = (p1[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p2[Y] = (p2[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p3[Y] = (p3[Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - LONG const x2 = (LONG) round(p2[X]); - LONG const y2 = (LONG) round(rc.bottom-p2[Y]); - LONG const x3 = (LONG) round(p3[X]); - LONG const y3 = (LONG) round(rc.bottom-p3[Y]); - - POINT pt[3]; - pt[0].x = x1; - pt[0].y = y1; - pt[1].x = x2; - pt[1].y = y2; - pt[2].x = x3; - pt[2].y = y3; - - PolyBezierTo( hdc, pt, 3 ); - } - else - { - g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used"); - } - } - - if (pit->end_default() == pit->end_closed()) { - CloseFigure( hdc ); - } - } - - EndPath( hdc ); - - return TRUE; -} - - -bool PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext) -{ - return ext->get_param_bool("textToPath"); -} - -unsigned int PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, - SPStyle const *const style) -{ - if (!hdc) return 0; - - HFONT hfont = NULL; - Geom::Affine tf = m_tr_stack.top(); - double rot = 1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation - -#ifdef USE_PANGO_WIN32 -/* - font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style)); - if (tf) { - LOGFONT *lf = pango_win32_font_logfont(tf->pFont); - tf->Unref(); - hfont = CreateFontIndirect(lf); - g_free(lf); - } -*/ -#endif - - if (!hfont) { - LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW)); - g_assert(lf != NULL); - - lf->lfHeight = -style->font_size.computed * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI; - lf->lfWidth = 0; - lf->lfEscapement = rot; - lf->lfOrientation = rot; - lf->lfWeight = - style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY : - FW_NORMAL; - lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC); - lf->lfUnderline = style->text_decoration.underline; - lf->lfStrikeOut = style->text_decoration.line_through; - lf->lfCharSet = DEFAULT_CHARSET; - lf->lfOutPrecision = OUT_DEFAULT_PRECIS; - lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf->lfQuality = DEFAULT_QUALITY; - lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - - gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL ); - wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1); - g_free(unicode_name); - - hfont = CreateFontIndirectW(lf); - - g_free(lf); - } - - HFONT hfontOld = (HFONT) SelectObject(hdc, hfont); - - float rgb[3]; - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); - - // Text alignment: - // - (x,y) coordinates received by this filter are those of the point where the text - // actually starts, and already takes into account the text object's alignment; - // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT. - SetTextAlign(hdc, TA_BASELINE | TA_LEFT); - - // Transparent text background - SetBkMode(hdc, TRANSPARENT); - - Geom::Point p2 = p * tf; - p2[Geom::X] = (p2[Geom::X] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - p2[Geom::Y] = (p2[Geom::Y] * Inkscape::Util::Quantity::convert(1, "px", "in") * dwDPI); - - LONG const xpos = (LONG) round(p2[Geom::X]); - LONG const ypos = (LONG) round(rc.bottom - p2[Geom::Y]); - - { - gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL ); - TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text)); - } - - SelectObject(hdc, hfontOld); - DeleteObject(hfont); - - return 0; -} - -void PrintEmfWin32::init (void) -{ - /* EMF print */ - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>Enhanced Metafile Print</name>\n" - "<id>org.inkscape.print.emf.win32</id>\n" - "<param name=\"destination\" type=\"string\"></param>\n" - "<param name=\"textToPath\" type=\"boolean\">true</param>\n" - "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n" - "<print/>\n" - "</inkscape-extension>", new PrintEmfWin32()); - - return; -} - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif /* WIN32 */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/emf-win32-print.h deleted file mode 100644 index bbeeeb051..000000000 --- a/src/extension/internal/emf-win32-print.h +++ /dev/null @@ -1,113 +0,0 @@ -/** @file - * @brief Enhanced Metafile printing - implementation - */ -/* Author: - * Ulf Erikson <ulferikson@users.sf.net> - * - * Copyright (C) 2006-2008 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ -#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -#include "extension/implementation/implementation.h" -//#include "extension/extension.h" - -#include <2geom/pathvector.h> - -#include <stack> - -namespace Inkscape { -namespace Extension { -namespace Internal { - -class PrintEmfWin32 : public Inkscape::Extension::Implementation::Implementation -{ - double _width; - double _height; - HDC hdc; - RECT rc; - - HBRUSH hbrush, hbrushOld; - HPEN hpen, hpenOld; - - std::stack<Geom::Affine> m_tr_stack; - Geom::PathVector fill_pathv; - Geom::Affine fill_transform; - bool stroke_and_fill; - bool fill_only; - bool simple_shape; - - unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); - bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); - -public: - PrintEmfWin32 (void); - virtual ~PrintEmfWin32 (void); - - /* Print functions */ - virtual unsigned int setup (Inkscape::Extension::Print * module); - - virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc); - virtual unsigned int finish (Inkscape::Extension::Print * module); - - /* Rendering methods */ - virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); - virtual unsigned int release(Inkscape::Extension::Print *module); - virtual unsigned int fill (Inkscape::Extension::Print *module, - Geom::PathVector const &pathv, - Geom::Affine const &ctm, SPStyle const *style, - Geom::OptRect const &pbox, Geom::OptRect const &dbox, - Geom::OptRect const &bbox); - virtual unsigned int stroke (Inkscape::Extension::Print * module, - Geom::PathVector const &pathv, - Geom::Affine const &ctm, SPStyle const *style, - Geom::OptRect const &pbox, Geom::OptRect const &dbox, - Geom::OptRect const &bbox); - virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); - virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, - Geom::Point const &p, SPStyle const *style); - bool textToPath (Inkscape::Extension::Print * ext); - - static void init (void); -protected: - int create_brush(SPStyle const *style); - - void destroy_brush(); - - void create_pen(SPStyle const *style, const Geom::Affine &transform); - - void destroy_pen(); - - void flush_fill(); - -}; - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif /* WIN32 */ - -#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c new file mode 100644 index 000000000..d16c060de --- /dev/null +++ b/src/extension/internal/text_reassemble.c @@ -0,0 +1,2884 @@ +/** + @file text_reassemble.c + +\verbatim +Method: + 1. For all ordered text objects which are sequential and share the same esc. + 2. For the first only pull x,y,esc and save, these define origin and rotation. + 3. Save the text object. + 4. Phase I: For all saved text objects construct lines. + 5. Check for allowed overlaps on sequential saved text object bounding rectangles. + 6 If found merge second with first, check next one. + 7. If not found, start a new complex (line). + 8. Phase II; for all lines construct paragraphs. + 9. Check alignment and line spacing of preceding line with current line. + 10. if alignment is the same, and line spacing is compatible merge current line into + current paragraph. Reaverage line spacing over all lines in paragraph. Check next one. + 11. If alignment does not match start a new paragraph. + (Test program) + 12. Over all phase II paragraphs + 13. Over all phase I lines in each paragraph. + 14. Over all text objects in each line. + Emit SVG corresponding to this construct to a file dump.svg. + (Conversion to other file types would be modeled on this example.) + 15. Clean up. + (General program) + Like for the Test program, but final representation may not be SVG. + Text object and bounding rectangle memory would all be released. If another set of + text will be processed then hang onto both Freetype and Fontconfig structures. If no + other text will be processed here, then also release Freetype structures. If the caller uses + Fontconfig elsewhere then do not release it, otherwise, do so. + +NOTE ON COORDINATES: x is positive to the right, y is positive down. So (0,0) is the upper left corner, and the +lower left corner of a rectangle has a LARGER Y coordinate than the upper left. Ie, LL=(10,10) UR=(30,5) is typical. +\endverbatim +*/ + +/* + +Compilation of test program (with all debugging output, but not loop testing): +On Windows use: + + gcc -Wall -DWIN32 -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT \ + -I. -I/c/progs/devlibs32/include -I/c/progs/devlibs32/include/freetype2\ + -o text_reassemble text_reassemble.c uemf_utf.c \ + -lfreetype6 -lfontconfig-1 -liconv -lm -L/c/progs/devlibs32/bin + +On Linux use: + + gcc -Wall -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT -I. -I/usr/include/freetype2 -o text_reassemble text_reassemble.c uemf_utf.c -lfreetype -lfontconfig -lm + +Compilation of object file only (Windows): + + gcc -Wall -DWIN32 -c \ + -I. -I/c/progs/devlibs32/include -I/c/progs/devlibs32/include/freetype2\ + text_reassemble.c + +Compilation of object file only (Linux): + gcc -Wall -c -I. -I/usr/include/freetype2 text_reassemble.c + + +Optional compiler switches for development: + -DDBG_TR_PARA draw bounding rectangles for paragraphs in SVG output + -DDBG_TR_INPUT draw input text and their bounding rectangles in SVG output + -DTEST build the test program + -DDBG_LOOP force the test program to cycle 5 times. Useful for finding + memory leaks. Ouput file is overwritten each time. + + +File: text_reassemble.c +Version: 0.0.10 +Date: 06-MAY-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "text_reassemble.h" +#include "uemf_utf.h" /* For a couple of text functions. Exact copy from libUEMF. */ +#include <float.h> + +/* Code generated by make_ucd_mn_table.c using: + cat mnlist.txt | ./make_ucd_mn_table >generated.c +*/ +#include <stdint.h> +int is_mn_unicode(int test){ +#define MN_TEST_LIMIT 921600 +#define N_SPAGES 225 +#define N_CPAGES 192 +#define N_CPDATA 344 +#define C_PER_S 16 + uint8_t superpages[N_SPAGES]={ + 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B}; + + uint8_t cpages[N_CPAGES]={ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x19, 0x00, 0x00, + 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x1C, 0x1D, 0x1E, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + uint32_t cpage_data[N_CPDATA]={ + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000F8, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFE0000, 0xBFFFFFFF, 0x000000B6, 0x00000000, + 0x07FF0000, 0x00000000, 0xFFFFF800, 0x00010000, 0x00000000, 0x00000000, 0x9FC00000, 0x00003D9F, + 0x00020000, 0xFFFF0000, 0x000007FF, 0x00000000, 0x00000000, 0x0001FFC0, 0x00000000, 0x000FF800, + 0xFBC00000, 0x00003EEF, 0x0E000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x7FFFFFF0, + 0x00000007, 0x14000000, 0x00FE21FE, 0x0000000C, 0x00000002, 0x10000000, 0x0000201E, 0x0000000C, + 0x00000006, 0x10000000, 0x00023986, 0x00230000, 0x00000006, 0x10000000, 0x000021BE, 0x0000000C, + 0x00000002, 0x90000000, 0x0040201E, 0x0000000C, 0x00000004, 0x00000000, 0x00002001, 0x00000000, + 0x00000000, 0xC0000000, 0x00603DC1, 0x0000000C, 0x00000000, 0x90000000, 0x00003040, 0x0000000C, + 0x00000000, 0x00000000, 0x0000201E, 0x0000000C, 0x00000000, 0x00000000, 0x005C0400, 0x00000000, + 0x00000000, 0x07F20000, 0x00007F80, 0x00000000, 0x00000000, 0x1BF20000, 0x00003F00, 0x00000000, + 0x03000000, 0x02A00000, 0x00000000, 0x7FFE0000, 0xFEFFE0DF, 0x1FFFFFFF, 0x00000040, 0x00000000, + 0x00000000, 0x66FDE000, 0xC3000000, 0x001E0001, 0x20002064, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xE0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x001C0000, 0x001C0000, 0x000C0000, 0x000C0000, 0x00000000, 0x3FB00000, 0x200FFE40, 0x00000000, + 0x00003800, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000, + 0x00000000, 0x0E040187, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x01800000, 0x00000000, 0x7F400000, 0x9FF81FE5, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000000F, 0x17D00000, 0x00000004, 0x000FF800, 0x00000003, 0x00000B3C, 0x00000000, 0x0003A340, + 0x00000000, 0x00CFF000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFF70000, 0x001021FD, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xF000007F, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1FFF0000, 0x0001FFE2, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00038000, + 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, + 0x00000000, 0x00003C00, 0x00000000, 0x00000000, 0x06000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x3FF08000, 0x80000000, 0x00000000, 0x00000000, 0x00030000, + 0x00000844, 0x00000060, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x0003FFFF, + 0x00000000, 0x00003FC0, 0x0003FF80, 0x00000000, 0x00000007, 0x13C80000, 0x00000000, 0x00000000, + 0x00000000, 0x00667E00, 0x00001008, 0x00000000, 0x00000000, 0xC19D0000, 0x00000002, 0x00403000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00002120, + 0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000FFFF, 0x0000007F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000, + 0x0000F06E, 0x87000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000002, 0xFF000000, 0x0000007F, 0x00000000, 0x00000003, 0x06780000, 0x00000000, 0x00000000, + 0x00000007, 0x001FEF80, 0x00000000, 0x00000000, 0x00000003, 0x7FC00000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00BF2800, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00078000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xF8000380, 0x00000FE7, 0x00003C00, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000001C, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF}; + + int result=0; + + int spage_idx; + int cpage_row, cpage_column, cpage_idx; + int cd_row, cd_column, cd_idx, cd_bit; + + if(test<MN_TEST_LIMIT){ + spage_idx = test >> 12; + cpage_row = superpages[spage_idx]; + cpage_column = (test>>8) & 15; + cpage_idx = C_PER_S*cpage_row + cpage_column; + cd_row = cpages[cpage_idx]; + cd_column = test>>5 & 7; + cd_idx = 8*cd_row + cd_column; + cd_bit = test & 31; + result = cpage_data[cd_idx] & (1 << cd_bit); + } + return(result); +} + + + +/** + \brief Find a (sub)string in a caseinvariant manner, used for locating "Narrow" in font name + \return Returns -1 if no match, else returns the position (numbered from 0) of the first character of the match. + \param string Text to search + \param sub Text to find +*/ +int TR_findcasesub(const char *string, const char *sub){ + int i,j; + int match=0; + for(i=0; string[i]; i++){ + for(match=1,j=0; sub[j] && string[i+j]; j++){ + if(toupper(sub[j]) != toupper(string[i+j])){ + match=0; + break; + } + } + if(match && !sub[j])break; /* matched over the entire substring */ + } + return((match ? i : -1)); +} + +/** + \brief Constrouct a fontspec from a TCHUNK_SPECS and a fontname + \return Returns NULL on error, new fontspec on success + \param tsp pointer to TCHUNK_SPECS to use for information + \param fontname Fontname to use in the new fontspec +*/ + /* construct a font name */ +char *TR_construct_fontspec(const TCHUNK_SPECS *tsp, const char *fontname){ + int newlen = 128 + strlen(fontname); /* too big, but not by much */ + char *newfs = NULL; + newfs = (char *) malloc(newlen); + sprintf(newfs,"%s:slant=%d:weight=%d:size=%lf:width=%d",fontname,tsp->italics,tsp->weight,tsp->fs,(tsp->co ? 75 : tsp->condensed)); + return(newfs); +} + + +/** + \brief Reconstrouct a fontspec by substituting a font name into an existing spec + \return Returns NULL on error, new fontspec on success + \param fontspec Original fontspec, only the name will be changed + \param fontname Fontname to substitute into the new fontspec +*/ + /* construct a font name */ +char *TR_reconstruct_fontspec(const char *fontspec, const char *fontname){ + int colon; + int newlen = strlen(fontspec) + strlen(fontname) + 1; /* too big, but not by much */ + char *newfs = NULL; + newfs = (char *) malloc(newlen); + colon = strcspn(fontspec,":"); + if(colon){ sprintf(newfs,"%s%s",fontname,&fontspec[colon]); } + return(newfs); +} + +/** + \brief Find a font in the list that has a glyph for this character, change alternate to match + \return Returns 0 if no match or an error, else returns the glyph index in the new alternate font + \param fti pointer to the FT_INFO structure, may be modified if alternate font is added + \param efsp Pointer to a Pointer to the original FNT_SPECS struct. On return contains the FNT_SPECS corresponding to the glyph_index.. + \param wc Current character (32 bit int) +*/ +int TR_find_alternate_font(FT_INFO *fti, FNT_SPECS **efsp, uint32_t wc){ + int glyph_index=0; /* this is the unknown character glyph */ + uint32_t i; + FcCharSet *cs; + FcResult result = FcResultMatch; + FcPattern *pattern, *fpat; + char *filename; + char *fontname; + char *newfontspec; + int fi_idx; + FNT_SPECS *fsp,*fsp2; + if(!fti || !efsp || !*efsp)return(0); + fsp = *efsp; + for(i=0;i<fsp->used;i++){ /* first check in alts */ + fsp2 = &fti->fonts[fsp->alts[i].fi_idx]; /* these are in order of descending previous usage */ + glyph_index = FT_Get_Char_Index( fsp2->face, wc); /* we have the face, might as well check that directly */ + if (glyph_index){ /* found a glyph for the character in this font */ + (void) fsp_alts_weight(fsp, i); + *efsp = fsp2; + return(glyph_index); + } + } + + /* it was not in alts, now go through fontset and see if it is in there */ + for(i=1; i< (unsigned int) fsp->fontset->nfont;i++){ /* already know the primary does not have this character */ + result = FcPatternGetCharSet(fsp->fontset->fonts[i], FC_CHARSET, 0, &cs); + if(result != FcResultMatch) return(0); /* some terrible problem, this should never happen */ + if (FcCharSetHasChar(cs, wc)){ /* found a glyph for the character in this font */ + glyph_index = i; + + /* Do a lot of work to find the filename corresponding to the fontset entry. + None of these should ever fail, but if one does, return 0 + */ + if( + !(pattern = FcNameParse((const FcChar8 *)&(fsp->fontspec))) || + !FcConfigSubstitute(NULL, pattern, FcMatchPattern) + )return(0); + FcDefaultSubstitute(pattern); + if( + !(fpat = FcFontRenderPrepare(NULL, pattern, fsp->fontset->fonts[i])) || + (FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch) || + (FcPatternGetString( fsp->fontset->fonts[i], FC_FULLNAME, 0, (FcChar8 **)&fontname) != FcResultMatch) + )return(0); + + /* find the font (added from an unrelated fontset, for instance) or insert it as new */ + fi_idx = ftinfo_find_loaded_by_src(fti, (uint8_t *) filename); + if(fi_idx < 0){ + newfontspec = TR_reconstruct_fontspec((char *) fsp->fontspec, fontname); + fi_idx = ftinfo_load_fontname(fti, newfontspec); + free(newfontspec); + if(fi_idx < 0)return(0); /* This could happen if we run out of memory*/ + } + + /* add the new font index to the alts list on the (current) fsp. */ + (void) fsp_alts_insert(fsp, fi_idx); + + /* release FC's own memory related to this call that does not need to be kept around so that face will work */ + FcPatternDestroy(pattern); + + *efsp = &(fti->fonts[fi_idx]); + return(glyph_index); + } + } + + return(0); +} + +/** + \brief Get the advance for the 32 bit character + + \return Returns -1 on error, or advance in units of 1/64th of a Point. + \param fti pointer to the FT_INFO structure, may be modified if alternate font is required + \param fsp Pointer to FNT_SPECS struct. + \param wc Current character (32 bit int) + \param pc Previous character + \param load_flags Controls internal advance: + FT_LOAD_NO_SCALE, internal advance is in 1/64th of a point. (kerning values are still scaled) + FT_LOAD_TARGET_NORMAL internal advance is in 1/64th of a point. The scale + factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi). + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. + \param ymin If the pointer is defined, the value is adjusted if ymin of wc character is less than the current value. + \param ymax If the pointer is defined, the value is adjusted if ymin of wc character is more than the current value. +*/ +int TR_getadvance(FT_INFO *fti, FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int load_flags, int kern_mode, int *ymin, int *ymax){ + FT_Glyph glyph; + int glyph_index; + int advance=-1; + FT_BBox bbox; + + if(is_mn_unicode(wc))return(0); /* no advance on Unicode Mn characters */ + + glyph_index = FT_Get_Char_Index( fsp->face, wc); + if(!glyph_index){ /* not in primary font, check alternates */ + glyph_index = TR_find_alternate_font(fti, &fsp, wc); + } + if(glyph_index){ + if (!FT_Load_Glyph( fsp->face, glyph_index, load_flags )){ + if ( !FT_Get_Glyph( fsp->face->glyph, &glyph ) ) { + advance = fsp->face->glyph->advance.x; + FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_UNSCALED, &bbox ); + if(ymin && (bbox.yMin < *ymin))*ymin=bbox.yMin; + if(ymax && (bbox.yMax > *ymax))*ymax=bbox.yMax; + if(pc)advance += TR_getkern2(fsp, wc, pc, kern_mode); + FT_Done_Glyph(glyph); + } + } + } + /* If there was no way to determine the width, this returns the error value */ + return(advance); +} + +/** + \brief Get the kerning for a pair of 32 bit characters + \return Returns 0 on error, or kerning value (which may be 0) for the pair in units of 1/64th of a point. + \param fsp Pointer to FNT_SPECS struct. + \param wc Current character (32 bit int) + \param pc Previous character + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. +*/ +int TR_getkern2(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int kern_mode){ + int this_glyph_index; + int prev_glyph_index; + int kern=0; + FT_Vector akerning; + + this_glyph_index = FT_Get_Char_Index( fsp->face, wc); + prev_glyph_index = FT_Get_Char_Index( fsp->face, pc); + if(!FT_Get_Kerning( fsp->face, + prev_glyph_index, + this_glyph_index, + kern_mode, + &akerning )){ + kern = akerning.x; /* Is sign correct? */ + } + return(kern); +} + +/** + \brief Get the kerning for a pair of 32 bit characters, where one is the last character in the previous text block, and the other is the first in the current text block. + \return Returns 0 on error, or kerning value (which may be 0) for the pair in units of 1/64th of a point. + \param fsp Pointer to FNT_SPECS struct. + \param tsp current text object + \param ptsp previous text object + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. +*/ +int TR_kern_gap(FNT_SPECS *fsp, TCHUNK_SPECS *tsp, TCHUNK_SPECS *ptsp, int kern_mode){ + int kern=0; + uint32_t *text32=NULL; + uint32_t *ptxt32=NULL; + size_t tlen,plen; + while(ptsp && tsp){ + text32 = U_Utf8ToUtf32le((char *) tsp->string, 0, &tlen); + if(!text32){ // LATIN1 encoded >128 are generally not valid UTF, so the first will fail + text32 = U_Latin1ToUtf32le((char *) tsp->string,0, &tlen); + if(!text32)break; + } + ptxt32 = U_Utf8ToUtf32le((char *) ptsp->string,0,&plen); + if(!ptxt32){ // LATIN1 encoded >128 are generally not valid UTF, so the first will fail + ptxt32 = U_Latin1ToUtf32le((char *) ptsp->string,0, &plen); + if(!ptxt32)break; + } + kern = TR_getkern2(fsp, *text32, ptxt32[plen-1], kern_mode); + break; + } + if(text32)free(text32); + if(ptxt32)free(ptxt32); + return(kern); +} + + + + +/** + \brief Find baseline on Y axis of a complex. + If the complex is a TR_TEXT or TR_LINE find its baseline. + If the complex is TR_PARA_[UCLR]J find the baseline of the last line. + If there are multiple text elements in a TR_LINE, the baseline is that of the + element that uses the largest font. This will definitely give the wrong + result if that line starts with a super or subscript that is full font size, but + they are usually smaller. + \return Returns 0 if it cannot determine a baseline, else returns the baseline Y coordinate. + \param tri pointer to the TR_INFO structure holding all TR data + \param src index of the current complex + \param ymax If the pointer is defined, the value is adjusted if ymax of current complex is more than the current value. + \param ymin If the pointer is defined, the value is adjusted if ymin of current complex is less than the current value. +*/ +double TR_baseline(TR_INFO *tri, int src, double *ymax, double *ymin){ + double baseline=0; + volatile double tmp=0.0; /* This MUST be volatile */ + double yheight; + int last; + int i; + int trec; + CX_INFO *cxi=tri->cxi; + BR_INFO *bri=tri->bri; + TP_INFO *tpi=tri->tpi; + FT_INFO *fti=tri->fti; + FNT_SPECS *fsp; + last = cxi->cx[src].kids.used - 1; + switch (cxi->cx[src].type){ + case TR_TEXT: + trec = cxi->cx[src].kids.members[0]; /* for this complex type there is only ever one member */ + baseline = bri->rects[trec].yll - tpi->chunks[trec].boff; + fsp = &(fti->fonts[tpi->chunks[trec].fi_idx]); + yheight = fsp->face->bbox.yMax - fsp->face->bbox.yMin; + if(ymax){ + tmp = tpi->chunks[trec].fs * ((double)fsp->face->bbox.yMax/yheight); + if(*ymax <= tmp)*ymax = tmp; + } + else if(ymin){ + tmp = tpi->chunks[trec].fs * ((double)-fsp->face->bbox.yMin/yheight); /* yMin in face is negative */ + if(*ymin <= tmp)*ymin = tmp; + } + break; + case TR_LINE: + for(i=last;i>=0;i--){ /* here last is the count of text objects in the complex */ + trec = cxi->cx[src].kids.members[i]; + fsp = &(fti->fonts[tpi->chunks[trec].fi_idx]); + yheight = fsp->face->bbox.yMax - fsp->face->bbox.yMin; + if(ymax){ + tmp = tpi->chunks[trec].fs * (((double)fsp->face->bbox.yMax)/yheight); + /* gcc 4.6.3 had a bizarre optimization error for -O2 and -O3 where *ymax <= tmp was + not true when *ymax == tmp, as verified by examining the binary representations. + This was apparently due to retained excess precision. Making tmp volatile + forces it to be stored into a 64 bit location, dropping the extra 12 bits from + the 80 bit register. */ + if(*ymax <= tmp){ + *ymax = tmp; + baseline = bri->rects[trec].yll - tpi->chunks[trec].boff; + } + } + else if(ymin){ + tmp = tpi->chunks[trec].fs * (((double)-fsp->face->bbox.yMin)/yheight); /* yMin in face is negative */ + if(*ymin <= tmp){ + *ymin = tmp; + baseline = bri->rects[trec].yll - tpi->chunks[trec].boff; + } + } + } + break; + case TR_PARA_UJ: + case TR_PARA_LJ: + case TR_PARA_CJ: + case TR_PARA_RJ: + trec = cxi->cx[src].kids.members[last]; + baseline = TR_baseline(tri, trec, ymax, ymin); + break; + } + return(baseline); +} + +/** + \brief Check or set vertical advance on the growing complex relative to the current complex. + Vadvance is a multiplicative factor like 1.25. + The distance between successive baselines is vadvance * max(font_size), where the maximum + is over all text elements in src. + The growing complex is always the last one in the CX_INFO section of the TR_INFO structure. + If an existing vadvance does not match the one which would be required to fit the next complex + to add to the growing one, it terminates a growing complex. (Ie, starts a new paragraph.) + Find baseline on Y axis of a complex. + If the complex is a TR_TEXT or TR_LINE find its baseline. + If the complex is TR_PARA+* find the baseline of the last line. + If there are multiple text elements in a TR_LINE, the baseline is that of the + element that uses the largest font. This will definitely give the wrong + result if that line starts with a super or subscript that is full font size, but + they are usually smaller. + \return Returns 0 on success, !0 on failure. + \param tri pointer to the TR_INFO structure holding all TR data + \param src index of the current complex, to be added to the growing complex. + This lets the value of "src - lines" determine the weight to give to each new vadvance value + as it is merged into the running weighted average. This improves the accuracy of the vertical advance, + since there can be some noise introduced when lines have different maximum font sizes. + \param lines index of the first text block that was added to the growing complex. +*/ +int TR_check_set_vadvance(TR_INFO *tri, int src, int lines){ + int status = 0; + CX_INFO *cxi = tri->cxi; + TP_INFO *tpi = tri->tpi; + double ymax = DBL_MIN; + double ymin = DBL_MIN; + double prevbase; + double thisbase; + double weight; + int trec; + double newV; + int dst; + + dst = cxi->used-1; /* complex being grown */ + + prevbase = TR_baseline(tri, dst, NULL, &ymin); + thisbase = TR_baseline(tri, src, &ymax, NULL); + newV = (thisbase - prevbase)/(ymax + ymin); + trec = cxi->cx[dst].kids.members[0]; /* complex whose first text record holds vadvance for this complex */ + trec = cxi->cx[trec].kids.members[0]; /* text record that halds vadvance for this complex */ + if(tpi->chunks[trec].vadvance){ + /* already set on the first text (only place it is stored.) + See if the line to be added is compatible. + All text fields in a complex have the same advance, so just set/check the first one. + vadvance must be within 1% or do not add a new line */ + if(fabs(1.0 - (tpi->chunks[trec].vadvance/newV) > 0.01)){ + status = 1; + } + else { /* recalculate the weighted vadvance */ + weight = (1.0 / (double) (src - lines)); + tpi->chunks[trec].vadvance = tpi->chunks[trec].vadvance*(1.0-weight) + newV*weight; + } + } + else { /* only happens when src = lines + 1*/ + tpi->chunks[trec].vadvance = newV; + } + return(status); +} + + +/** + \brief Initialize an FT_INFO structure. Sets up a freetype library to use in this context. + \returns a pointer to the FT_INFO structure created, or NULL on error. +*/ +FT_INFO *ftinfo_init(void){ + FT_INFO *fti = NULL; + if(FcInit()){ + fti = (FT_INFO *)calloc(1,sizeof(FT_INFO)); + if(fti){ + if(!FT_Init_FreeType( &(fti->library))){ + fti->space=0; + fti->used=0; + + if(ftinfo_make_insertable(fti)){ + FT_Done_FreeType(fti->library); + free(fti); + fti=NULL; + } + } + else { + free(fti); + fti=NULL; + } + } + if(!fti)FcFini(); + } + return(fti); +} + +/** + \brief Make an FT_INFO structure insertable. Adds storage as needed. + \param fti pointer to the FT_INFO structure + \returns 0 on success, !0 on error. +*/ +int ftinfo_make_insertable(FT_INFO *fti){ + int status=0; + if(!fti)return(2); + if(fti->used >= fti->space){ + fti->space += ALLOCINFO_CHUNK; + if((fti->fonts = (FNT_SPECS *) realloc(fti->fonts, fti->space * sizeof(FNT_SPECS) ))){ + memset(&fti->fonts[fti->used],0,(fti->space - fti->used)*sizeof(FNT_SPECS)); + } + else { + status=1; + } + } + return(status); +} + + +/** + \brief Insert a copy of a FNT_SPECS structure into the FT_INFO structure. + \param fti pointer to the FT_INFO structure. + \param fsp pointer to the FNT_SPECS structure. + \returns 0 on success, !0 on error. +*/ +int ftinfo_insert(FT_INFO *fti, FNT_SPECS *fsp){ + int status=1; + if(!fti)return(2); + if(!fsp)return(3); + if(!(status = ftinfo_make_insertable(fti))){ + memcpy(&(fti->fonts[fti->used]),fsp,sizeof(FNT_SPECS)); + fti->used++; + } + return(status); +} + + + +/** + \brief Release an FT_INFO structure. Release all associated memory. + Use like: fi_ptr = ftinfo_release(fi_ptr) + \param fti pointer to the FT_INFO structure. + \returns NULL. +*/ +FT_INFO *ftinfo_release(FT_INFO *fti){ + (void) ftinfo_clear(fti); + FcFini(); /* shut down FontConfig, release memory, patterns must have already been released or boom! */ + return NULL; +} + + +/** + \brief Clear an FT_INFO structure. Release all Freetype memory but does not release Fontconfig. + This would be called in preference to ftinfo_release() if some other part of the program needed + to continue using Fontconfig. + Use like: fi_ptr = ftinfo_clear(fi_ptr) + \param fti pointer to the FT_INFO structure. + \returns NULL. +*/ +FT_INFO *ftinfo_clear(FT_INFO *fti){ + uint32_t i; + FNT_SPECS *fsp; + if(fti){ + for(i=0;i<fti->used;i++){ + fsp = &(fti->fonts[i]); + FT_Done_Face(fsp->face); /* release memory for face controlled by FreeType */ + free(fsp->file); /* release memory holding copies of paths */ + free(fsp->fontspec); /* release memory holding copies of font names */ + FcPatternDestroy(fsp->fpat); /* release memory for FontConfig fpats */ + FcFontSetDestroy(fti->fonts[i].fontset); + if(fsp->alts){ free(fsp->alts); } + } + free(fti->fonts); + FT_Done_FreeType(fti->library); /* release all other FreeType memory */ + free(fti); + } + return NULL; +} + + +/** + \brief Find the loaded font matching fontspec + \returns index of font on success, -1 if not found + \param tri pointer to the TR_INFO structure. + \param fontspec UTF-8 description of the font, as constructed in trinfo_load_fontname +*/ + +int ftinfo_find_loaded_by_spec(const FT_INFO *fti, const uint8_t *fontspec){ + uint32_t i; + int status = -1; + /* If it is already loaded, do not load it again */ + for(i=0;i<fti->used;i++){ + if(0==strcmp((char *) fti->fonts[i].fontspec, (char *)fontspec)){ + status=i; + break; + } + } + return(status); +} + +/** + \brief Find the loaded font matching the source file + \returns index of font on success, -1 if not found + \param tri pointer to the TR_INFO structure. + \param filename UTF-8 file name for the font +*/ + +int ftinfo_find_loaded_by_src(const FT_INFO *fti, const uint8_t *filename){ + uint32_t i; + int status = -1; + /* If it is already loaded, do not load it again */ + for(i=0;i<fti->used;i++){ + if(0==strcmp((char *) fti->fonts[i].file, (char *) filename)){ + status=i; + break; + } + } + return(status); +} + + +/** + \brief Load a (new) font by name into a TR_INFO structure or find it if it is already loaded + \returns fi_idx of inserted (or found) font on success, <0 on error. + \param fti pointer to the FT_INFO structure. + \param fontname UTF-8 font name + \param fontspec UTF-8 font specification used for query string. +*/ + +int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){ + FcPattern *pattern, *fpat; + FcFontSet *fontset; + FcResult result = FcResultMatch; + char *filename; + double fd; + FNT_SPECS *fsp; + int status; + int fi_idx; + + if(!fti)return(-1); + + /* If it is already loaded, do not load it again */ + if((status = ftinfo_find_loaded_by_spec(fti, (uint8_t *) fontspec))>=0){ + return(status); + } + + ftinfo_make_insertable(fti); + fi_idx = fti->used; + + if(!(pattern = FcNameParse((const FcChar8 *)fontspec)) )return(2); + if(!FcConfigSubstitute(NULL, pattern, FcMatchPattern) )return(3); + FcDefaultSubstitute(pattern); + /* get a fontset, trimmed to only those with new glyphs as needed, so that missing glyph's may be handled */ + if(!(fontset = FcFontSort (NULL,pattern, FcTrue, NULL, &result)) + || result != FcResultMatch)return(4); + if(!(fpat = FcFontRenderPrepare(NULL, pattern, fontset->fonts[0])) )return(405); + if(FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch)return(5); + if(FcPatternGetDouble( fpat, FC_SIZE, 0, &fd) != FcResultMatch)return(6); + + /* copy these into memory for external use */ + fsp = &(fti->fonts[fti->used]); + fsp->fontset = fontset; + fsp->alts = NULL; /* Initially no links to alternate fonts */ + fsp->space = 0; + fsp->file = (uint8_t *) U_strdup((char *) filename); + fsp->fontspec = (uint8_t *) U_strdup((char *) fontspec); + fsp->fpat = fpat; + fsp->fsize = fd; + + /* release FC's own memory related to this call that does not need to be kept around so that face will work */ + FcPatternDestroy(pattern); + + /* get the current face */ + if(FT_New_Face( fti->library, (const char *) fsp->file, 0, &(fsp->face) )){ return(8); } + + if(FT_Set_Char_Size( + fsp->face, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + fd*64, /* char_height in 1/64th of points */ + 72, /* horizontal device resolution, DPI */ + 72) /* vebrical device resolution, DPI */ + ){ return(9); } + + /* The space advance is needed in various places. Get it now, and get it in the font units, + so that it can be scaled later with the text size */ + status = TR_getadvance(fti, fsp,' ',0,FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED, NULL, NULL); + if(status < 0)return(7); + fsp->spcadv = ((double) status)/(64.0); + + fti->used++; + +/* + char *fs; + int fb; + if(FcPatternGetBool( fpat, FC_OUTLINE, 0, &fb)== FcResultMatch){ printf("outline: %d\n",fb);fflush(stdout); } + if(FcPatternGetBool( fpat, FC_SCALABLE, 0, &fb)== FcResultMatch){ printf("scalable: %d\n",fb);fflush(stdout); } + if(FcPatternGetDouble( fpat, FC_DPI, 0, &fd)== FcResultMatch){ printf("DPI: %lf\n",fd);fflush(stdout); } + if(FcPatternGetInteger( fpat, FC_FONTVERSION, 0, &fb)== FcResultMatch){ printf("fontversion: %d\n",fb);fflush(stdout); } + if(FcPatternGetString( fpat, FC_FULLNAME , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FULLNAME : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_FAMILY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FAMILY : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_STYLE , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("STYLE : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_FOUNDRY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FOUNDRY : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_FAMILYLANG , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FAMILYLANG : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_STYLELANG , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("STYLELANG : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_FULLNAMELANG, 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FULLNAMELANG: %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_CAPABILITY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("CAPABILITY : %s\n",fs);fflush(stdout); } + if(FcPatternGetString( fpat, FC_FONTFORMAT , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FONTFORMAT : %s\n",fs);fflush(stdout); } +*/ + + return(fi_idx); +} + +/** + \brief Dump the contents of the TR_INFO structure to stdout. For debugging purposes,not used in production code. + \param tri pointer to the TR_INFO structure. +*/ +void ftinfo_dump(const FT_INFO *fti){ + uint32_t i,j; + FNT_SPECS *fsp; + printf("fti space: %d\n",fti->space); + printf("fti used: %d\n",fti->used); + for(i=0; i< fti->used; i++){ + fsp = &(fti->fonts[i]); + printf("fti font: %6d space: %6d used: %6d spcadv %8lf fsize %8lf \n",i,fsp->space,fsp->used,fsp->spcadv,fsp->fsize); + printf(" file: %s\n",fsp->file); + printf(" fspc: %s\n",fsp->fontspec); + for(j=0;j<fsp->used;j++){ + printf(" alts: %6d fi_idx: %6d wgt: %6d\n",j,fsp->alts[j].fi_idx,fsp->alts[j].weight); + } + } + +} + +/** + \brief Make the FNT_SPECS alts structure insertable. Adds storage as needed. + \param fti pointer to the FT_INFO structure + \returns 0 on success, !0 on error. +*/ +int fsp_alts_make_insertable(FNT_SPECS *fsp){ + int status=0; + if(!fsp)return(2); + if(fsp->used >= fsp->space){ + fsp->space += ALLOCINFO_CHUNK; + if((fsp->alts = (ALT_SPECS *) realloc(fsp->alts, fsp->space * sizeof(ALT_SPECS) ))){ + memset(&fsp->alts[fsp->used],0,(fsp->space - fsp->used)*sizeof(ALT_SPECS)); + } + else { + status=1; + } + } + return(status); +} + + +/** + \brief Insert a new ALT_SPECS into the FNT_SPECS alts list. + \param fsp pointer to the FNT_SPECS structure. + \param fi_idx font index to add to the alts list + \returns 0 on success, !0 on error. +*/ +int fsp_alts_insert(FNT_SPECS *fsp, uint32_t fi_idx){ + int status=1; + ALT_SPECS alt; + if(!fsp)return(3); + alt.fi_idx = fi_idx; + alt.weight = 1; /* new ones start with this weight, it can only go up */ + if(!(status = fsp_alts_make_insertable(fsp))){ + fsp->alts[fsp->used] = alt; + fsp->used++; + } + return(status); +} + +/** + \brief Increment the weight of an alts entry by 1, readjust order if necessary + \param fsp pointer to the FNT_SPECS structure. + \param idx index of the alts entry to increment + \returns 0 on success, !0 on error. +*/ +int fsp_alts_weight(FNT_SPECS *fsp, uint32_t a_idx){ + uint32_t i; + ALT_SPECS alt; + if(!fsp)return(1); + if(!fsp->used)return(2); + if(a_idx >= fsp->used)return(3); + /* If a counter hits the limit divide all counts in half. */ + if(fsp->alts[a_idx].weight == UINT32_MAX){ + for(i=0; i<fsp->used; i++){ fsp->alts[i].weight /= 2; } + } + fsp->alts[a_idx].weight++; + for(i=a_idx; i>0; i--){ + if(fsp->alts[i-1].weight >= fsp->alts[a_idx].weight)break; + alt = fsp->alts[i-1]; + fsp->alts[i-1] = fsp->alts[a_idx]; + fsp->alts[a_idx] = alt; + } + return(0); +} + + + +/** + \brief Make a CHILD_SPECS structure insertable. Adds storage as needed. + \param csp pointer to the CHILD_SPECS structure + \returns 0 on success, !0 on error. +*/ +int csp_make_insertable(CHILD_SPECS *csp){ + int status=0; + if(!csp)return(2); + if(csp->used >= csp->space){ + csp->space += ALLOCINFO_CHUNK; + if((csp->members = (int *) realloc(csp->members, csp->space * sizeof(int) ))){ + memset(&csp->members[csp->used],0,(csp->space - csp->used)*sizeof(int)); + } + else { + status=1; + } + } + return(status); +} + +/** + \brief Add a member to a CHILD_SPECS structure. (Member is an index for either a text object or a complex.) + \param dst pointer to the CHILD_SPECS structure. + \param src index of the member. + \returns 0 on success, !0 on error. +*/ +int csp_insert(CHILD_SPECS *dst, int src){ + int status=1; + if(!dst)return(2); + if(!(status=csp_make_insertable(dst))){ + dst->members[dst->used]=src; + dst->used++; + } + return(status); +} + +/** + \brief Append all the members of one CHILD_SPECS structure to another CHILD_SPECS structure. + Member is an index for either a text object or a complex. + The donor is not modified. + \param dst pointer to the recipient CHILD_SPECS structure. + \param src pointer to the donor CHILD_SPECS structure. + \returns 0 on success, !0 on error. +*/ +int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src){ + uint32_t i; + int status=1; + if(!dst)return(2); + if(!src)return(3); + for(i=0;i<src->used;i++){ + status = csp_insert(dst, src->members[i]); + if(status)break; + } + return(status); +} + +/** + \brief Release a CHILD_SPECS structure. Release all associated memory. + \param csp pointer to the CHILD_SPECS structure. + \returns NULL. +*/ +void csp_release(CHILD_SPECS *csp){ + if(csp){ + free(csp->members); + csp->space = 0; + csp->used = 0; + } +} + +/** + \brief Clear a CHILD_SPECS structure, making all allocated slots usable. Does not release associated memory. + \param csp pointer to the CHILD_SPECS structure. + \returns NULL. +*/ +void csp_clear(CHILD_SPECS *csp){ + csp->used = 0; +} + + +/** + \brief Initialize an CX_INFO structure. Holds complexes (multiple text objects in known positions and order.) + \returns a pointer to the CX_INFO structure created, or NULL on error. +*/ +CX_INFO *cxinfo_init(void){ + CX_INFO *cxi = NULL; + cxi = (CX_INFO *)calloc(1,sizeof(CX_INFO)); + if(cxi){ + if(cxinfo_make_insertable(cxi)){ + free(cxi); + cxi=NULL; + } + } + return(cxi); +} + +/** + \brief Make a CX_INFO structure insertable. Adds storage as needed. + \returns 0 on success, !0 on error. + \param cxi pointer to the CX_INFO structure +*/ +int cxinfo_make_insertable(CX_INFO *cxi){ + int status=0; + if(cxi->used >= cxi->space){ + cxi->space += ALLOCINFO_CHUNK; + if((cxi->cx = (CX_SPECS *) realloc(cxi->cx, cxi->space * sizeof(CX_SPECS) ))){ + memset(&cxi->cx[cxi->used],0,(cxi->space - cxi->used)*sizeof(CX_SPECS)); + } + else { + status=1; + } + } + return(status); +} + +/** + \brief Insert a complex into the CX_INFO structure. (Insert may be either TR_TEXT or TR_LINE.) + \returns 0 on success, !0 on error. + \param cxi pointer to the CX_INFO structure (complexes). + \param src index of the the complex to insert. + \param src_rt_tidx index of the bounding rectangle + \param type TR_TEXT (index is for tpi->chunks[]) or TR_LINE (index is for cxi->kids[]) +*/ +int cxinfo_insert(CX_INFO *cxi, int src, int src_rt_tidx, enum tr_classes type){ + int status=1; + if(!cxi)return(2); + if(!(status=cxinfo_make_insertable(cxi))){ + cxi->cx[cxi->used].rt_cidx = src_rt_tidx; + cxi->cx[cxi->used].type = type; + status = csp_insert(&(cxi->cx[cxi->used].kids), src); + cxi->used++; + } + return(status); +} + +/** + \brief Append a complex to the CX_INFO structure and give it a type. + \param cxi pointer to the CX_INFO structure (complexes). + \param src index of the complex to append. + \param type TR_LINE (src is an index for tpi->chunks[]) or TR_PARA (src is an index for cxi->kids[]). + \returns 0 on success, !0 on error. +*/ +int cxinfo_append(CX_INFO *cxi, int src, enum tr_classes type){ + int status=1; + if(!cxi)return(2); + if(!(status=cxinfo_make_insertable(cxi))){ + cxi->cx[cxi->used-1].type = type; + status = csp_insert(&(cxi->cx[cxi->used-1].kids), src); + } + return(status); +} + + +/** + \brief Merge a complex dst with N members (N>=1) by adding a second complex src, and change the type. + \param cxi pointer to the CX_INFO structure (complexes). + \param dst index of the complex to expand. + \param src index of the donor complex (which is not modified). + \param type TR_LINE (src is an index for tpi->chunks[]) or TR_PARA (src is an index for cxi->kids[]). + \returns 0 on success, !0 on error. +*/ +int cxinfo_merge(CX_INFO *cxi, int dst, int src, enum tr_classes type){ + int status =1; + if(!cxi)return(2); + if(!cxi->used)return(3); + if(dst < 0 || dst >= (int) cxi->used)return(4); + if(src < 0)return(5); + cxi->cx[dst].type = type; + status = csp_merge(&(cxi->cx[dst].kids), &(cxi->cx[src].kids)); + return(status); +} + +/** + \brief Trim the last complex from thelist of complexes. + \param cxi pointer to the CX_INFO structure (complexes). + \returns 0 on success, !0 on error. +*/ +int cxinfo_trim(CX_INFO *cxi){ + int status = 0; + int last ; + if(!cxi)return(1); + if(!cxi->used)return(2); + last = cxi->used - 1; + csp_clear(&(cxi->cx[last].kids)); + cxi->used--; + return(status); +} + + +/** + \brief Dump the contents of the TR_INFO structure to stdout. For debugging purposes,not used in production code. + \param tri pointer to the TR_INFO structure. +*/ +void cxinfo_dump(const TR_INFO *tri){ + uint32_t i,j,k; + CX_INFO *cxi = tri->cxi; + BR_INFO *bri = tri->bri; + TP_INFO *tpi = tri->tpi; + BRECT_SPECS *bsp; + CX_SPECS *csp; + if(cxi){ + printf("cxi space: %d\n",cxi->space); + printf("cxi used: %d\n",cxi->used); + printf("cxi phase1: %d\n",cxi->phase1); + printf("cxi lines: %d\n",cxi->lines); + printf("cxi paras: %d\n",cxi->paras); + printf("cxi xy: %lf , %lf\n",tri->x,tri->y); + + for(i=0;i<cxi->used;i++){ + csp = &(cxi->cx[i]); + bsp = &(bri->rects[csp->rt_cidx]); + printf("cxi cx[%d] type:%d rt_tidx:%d kids_used:%d kids_space:%d\n",i, csp->type, csp->rt_cidx, csp->kids.used, csp->kids.space); + printf("cxi cx[%d] br (LL,UR) (%lf,%lf),(%lf,%lf)\n",i,bsp->xll,bsp->yll,bsp->xur,bsp->yur); + for(j=0;j<csp->kids.used;j++){ + k = csp->kids.members[j]; + bsp = &(bri->rects[k]); + if(csp->type == TR_TEXT || csp->type == TR_LINE){ + printf("cxi cx[%d] member:%3d tp_idx:%3d ldir:%d rt_tidx:%3d br (LL,UR) (%8.3lf,%8.3lf),(%8.3lf,%8.3lf) xy (%8.3lf,%8.3lf) kern (%8.3lf,%8.3lf) text:<%s> decor:%5.5x\n", + i, j, k, tpi->chunks[k].ldir, tpi->chunks[k].rt_tidx, + bsp->xll,bsp->yll,bsp->xur,bsp->yur, + tpi->chunks[k].x, tpi->chunks[k].y, + tpi->chunks[k].xkern, tpi->chunks[k].ykern, + tpi->chunks[k].string, tpi->chunks[k].decoration ); + } + else { /* TR_PARA_* */ + printf("cxi cx[%d] member:%d cx_idx:%d\n",i, j, k); + } + } + } + } + return; +} + +/** + \brief Release a CX_INFO structure. Release all associated memory. + use like: cxi = cxiinfo_release(cxi); + \param cxi pointer to the CX_INFO structure. + \returns NULL. +*/ +CX_INFO *cxinfo_release(CX_INFO *cxi){ + uint32_t i; + if(cxi){ + for(i=0;i<cxi->used;i++){ csp_release(&cxi->cx[i].kids); } + free(cxi->cx); + free(cxi); /* release the overall cxinfo structure */ + } + return NULL; +} + + +/** + \brief Initialize an TP_INFO structure. Holds text objects from which complexes are built. + \returns a pointer to the TP_INFO structure created, or NULL on error. +*/ +TP_INFO *tpinfo_init(void){ + TP_INFO *tpi = NULL; + tpi = (TP_INFO *)calloc(1,sizeof(TP_INFO)); + if(tpi){ + if(tpinfo_make_insertable(tpi)){ + free(tpi); + tpi=NULL; + } + } + return(tpi); +} + + +/** + \brief Make a TP_INFO structure insertable. Adds storage as needed. + \returns 0 on success, !0 on error. + \param tpi pointer to the TP_INFO structure +*/ +int tpinfo_make_insertable(TP_INFO *tpi){ + int status=0; + if(tpi->used >= tpi->space){ + tpi->space += ALLOCINFO_CHUNK; + if((tpi->chunks = (TCHUNK_SPECS *) realloc(tpi->chunks, tpi->space * sizeof(TCHUNK_SPECS) ))){ + memset(&tpi->chunks[tpi->used],0,(tpi->space - tpi->used)*sizeof(TCHUNK_SPECS)); + } + else { + status=1; + } + } + return(status); +} + +/** + \brief Insert a copy of a TCHUNK_SPECS structure into a TP_INFO structure. (Insert a text object.) + \returns 0 on success, !0 on error. + \param tpi pointer to the TP_INFO structure + \param tsp pointer to the TCHUNK_SPECS structure +*/ +int tpinfo_insert(TP_INFO *tpi, const TCHUNK_SPECS *tsp){ + int status=1; + TCHUNK_SPECS *ltsp; + if(!tpi)return(2); + if(!tsp)return(3); + if(!(status = tpinfo_make_insertable(tpi))){ + ltsp = &(tpi->chunks[tpi->used]); + memcpy(ltsp,tsp,sizeof(TCHUNK_SPECS)); + if(tsp->co)ltsp->condensed = 75; /* Narrow was set in the font name */ + ltsp->xkern = ltsp->ykern = 0.0; /* kerning will be calculated from the derived layout */ + tpi->used++; + } + return(status); +} + +/** + \brief Release a TP_INFO structure. Release all associated memory. + use like: tpi = tpinfo_release(tpi); + \returns NULL. + \param tpi pointer to the TP_INFO structure. +*/ +TP_INFO *tpinfo_release(TP_INFO *tpi){ + uint32_t i; + if(tpi){ + for(i=0;i<tpi->used;i++){ + free(tpi->chunks[i].string); } + free(tpi->chunks); /* release the array */ + free(tpi); /* release the overall tpinfo structure */ + } + return NULL; +} + +/** + \brief Initialize an BR_INFO structure. Holds bounding rectangles, for both text objects and complexes. + \returns a pointer to the BR_INFO structure created, or NULL on error. +*/ +BR_INFO *brinfo_init(void){ + BR_INFO *bri = NULL; + bri = (BR_INFO *)calloc(1,sizeof(BR_INFO)); + if(bri){ + if(brinfo_make_insertable(bri)){ + free(bri); + bri=NULL; + } + } + return(bri); +} + +/** + \brief Make a BR_INFO structure insertable. Adds storage as needed. + \returns 0 on success, !0 on error. + \param bri pointer to the BR_INFO structure +*/ +int brinfo_make_insertable(BR_INFO *bri){ + int status=0; + if(!bri)return(2); + if(bri->used >= bri->space){ + bri->space += ALLOCINFO_CHUNK; + if(!(bri->rects = (BRECT_SPECS *) realloc(bri->rects, bri->space * sizeof(BRECT_SPECS) ))){ status = 1; } + } + return(status); +} + +/** + \brief Insert a copy of a BRECT_SPEC structure into a BR_INFO structure. (Insert a bounding rectangle.) + \returns 0 on success, !0 on error. + \param bri pointer to the BR_INFO structure + \param element pointer to the BRECT_SPECS structure +*/ +int brinfo_insert(BR_INFO *bri, const BRECT_SPECS *element){ + int status=1; + if(!bri)return(2); + if(!(status=brinfo_make_insertable(bri))){ + memcpy(&(bri->rects[bri->used]),element,sizeof(BRECT_SPECS)); + bri->used++; + } + return(status); +} + +/** + \brief Merge BRECT_SPEC element src into/with BRECT_SPEC element dst. src is unchanged. (Merge two bounding rectangles.) + \returns 0 on success, !0 on error. + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. +*/ +int brinfo_merge(BR_INFO *bri, int dst, int src){ + if(!bri)return(1); + if(!bri->used)return(2); + if(dst<0 || dst >= (int) bri->used)return(3); + if(src<0 || src >= (int) bri->used)return(4); + bri->rects[dst].xll = TEREMIN(bri->rects[dst].xll, bri->rects[src].xll); + bri->rects[dst].yll = TEREMAX(bri->rects[dst].yll, bri->rects[src].yll); /* MAX because Y is positive DOWN */ + bri->rects[dst].xur = TEREMAX(bri->rects[dst].xur, bri->rects[src].xur); + bri->rects[dst].yur = TEREMIN(bri->rects[dst].yur, bri->rects[src].yur); /* MIN because Y is positive DOWN */ +/* +printf("bri_Merge into rect:%d (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",dst, +(bri->rects[dst].xll), +(bri->rects[dst].yll), +(bri->rects[dst].xur), +(bri->rects[dst].yur), +(bri->rects[src].xll), +(bri->rects[src].yll), +(bri->rects[src].xur), +(bri->rects[src].yur)); +*/ + return(0); +} + +/** + \brief Check for an allowable overlap of two bounding rectangles. + Allowable overlap is any area overlap of src and dst bounding rectangles, after + they have been expanded (padded) by allowed edge expansions. (For instance, if + missing spaces must be accounted for.) + The method works backwards: look for all reasons they might not overlap, + if none are found, then the rectangles do overlap. + An overlap here does not count just a line or a point - area must be involved. + \returns 0 on success (overlap detected), 1 on no overlap, anything else is an error. + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. + \param rp_dst Pointer to edge padding values for dst. + \param rp_src Pointer to edge padding values for src. +*/ +int brinfo_overlap(const BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD *rp_src){ + int status; + BRECT_SPECS *br_dst; + BRECT_SPECS *br_src; + if(!bri || !rp_dst || !rp_src)return(2); + if(!bri->used)return(3); + if(dst<0 || dst>= (int) bri->used)return(4); + if(src<0 || src>= (int) bri->used)return(5); + br_dst=&bri->rects[dst]; + br_src=&bri->rects[src]; + if( /* Test all conditions that exclude overlap, if any are true, then no overlap */ + ((br_dst->xur + rp_dst->right) < (br_src->xll - rp_src->left) ) || /* dst fully to the left */ + ((br_dst->xll - rp_dst->left) > (br_src->xur + rp_src->right) ) || /* dst fully to the right */ + ((br_dst->yur - rp_dst->up) > (br_src->yll + rp_src->down) ) || /* dst fully below (Y is positive DOWN) */ + ((br_dst->yll + rp_dst->down) < (br_src->yur - rp_src->up) ) /* dst fully above (Y is positive DOWN) */ + ){ + status = 1; + } + else { + /* overlap not excluded, so it must occur. + Only accept overlaps that are mostly at one end or the other, not mostly top or bottom. + If the following condition is true then there is no more than a tiny bit of horizontal overlap of src + within dist, which suggests that the two pieces of text may be considered part of one line. + (For a vertical alphabet the same method could be used for up/down.) */ + if( + (br_src->xll >= br_dst->xur - rp_dst->right) || /* src overlaps just a little on the right (L->R language) */ + (br_src->xur <= br_dst->xll + rp_dst->left) /* src overlaps just a little on the left (R->L language) */ + ){ + status = 0; + } + else { /* Too much overlap, reject the overlap */ + status = 1; + } + } +/* +printf("Overlap status:%d\nOverlap trects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n", +status, +(br_dst->xll - rp_dst->left ), +(br_dst->yll - rp_dst->down ), +(br_dst->xur + rp_dst->right), +(br_dst->yur + rp_dst->up ), +(br_src->xll - rp_src->left ), +(br_src->yll - rp_src->down ), +(br_src->xur + rp_src->right), +(br_src->yur + rp_src->up )); +printf("Overlap brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n", +(br_dst->xll), +(br_dst->yll), +(br_dst->xur), +(br_dst->yur), +(br_src->xll), +(br_src->yll), +(br_src->xur), +(br_src->yur)); +printf("Overlap rprect (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n", +(rp_dst->left), +(rp_dst->down), +(rp_dst->right), +(rp_dst->up), +(rp_src->left), +(rp_src->down), +(rp_src->right), +(rp_src->up)); +*/ + return(status); +} + +/** + \brief Check for a text element upstream from the start element and in the reversed direction. + \returns 0 on success (not upstream), 1 if upstream, anything else is an error. + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. + \param ddir direction of dst + \param sdir direction of src +*/ + +int brinfo_upstream(BR_INFO *bri, int dst, int src, int ddir, int sdir){ + int status=0; + BRECT_SPECS *br_dst; + BRECT_SPECS *br_src; + if(!bri)return(2); + if(!bri->used)return(3); + if(dst<0 || dst>= (int) bri->used)return(4); + if(src<0 || src>= (int) bri->used)return(5); + br_dst=&bri->rects[dst]; + br_src=&bri->rects[src]; + if( ddir == LDIR_RL && sdir == LDIR_LR){ + if(br_dst->xur <= (br_src->xll + br_src->xur)/2.0){ status = 1; } + } + else if( ddir == LDIR_LR && sdir == LDIR_RL){ + if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; } + } + return(status); +} + + +/** + \brief Try to deduce justification of a paragraph from the bounding rectangles for two successive lines. + \returns one of TR_PARA_ UJ (unknown justified), LJ, CJ, or RJ (left, center, or right justified). + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. + \param slop allowed error in edge alignment. + \param type Preexisting justification for dst, if any. Justification of dst and src must match this or + TR_PARA_UJ is returned even if dst and src have some (other) alignment. +*/ +enum tr_classes brinfo_pp_alignment(const BR_INFO *bri, int dst, int src, double slop, enum tr_classes type){ + enum tr_classes newtype; + BRECT_SPECS *br_dst = & bri->rects[dst]; + BRECT_SPECS *br_src = & bri->rects[src]; + if((br_dst->yur >= br_src->yur) || (br_dst->yll >= br_src->yll)){ /* Y is positive DOWN */ + /* lines in the wrong vertical order, no paragraph possible (Y is positive down) */ + newtype = TR_PARA_UJ; + } + else if(fabs(br_dst->xll - br_src->xll) < slop){ + /* LJ (might also be CJ but LJ takes precedence) */ + newtype = TR_PARA_LJ; + } + else if(fabs(br_dst->xur - br_src->xur) < slop){ + /* RJ */ + newtype = TR_PARA_RJ; + } + else if(fabs( (br_dst->xur + br_dst->xll)/2.0 - (br_src->xur + br_src->xll)/2.0 ) < slop){ + /* CJ */ + newtype = TR_PARA_CJ; + } + else { + /* not aligned */ + newtype = TR_PARA_UJ; + } + /* within a paragraph type can change from unknown to known, but not from one known type to another*/ + if((type != TR_PARA_UJ) && (newtype != type)){ + newtype = TR_PARA_UJ; + } +/* +printf("pp_align newtype:%d brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n", +newtype, +(br_dst->xll), +(br_dst->yll), +(br_dst->xur), +(br_dst->yur), +(br_src->xll), +(br_src->yll), +(br_src->xur), +(br_src->yur)); +*/ + return(newtype); +} + +/** + \brief Release a BR_INFO structure. Release all associated memory. + use like: bri = brinfo_release(bri); + \param bri pointer to the BR_INFO structure. + \returns NULL. +*/ +BR_INFO *brinfo_release(BR_INFO *bri){ + if(bri){ + free(bri->rects); + free(bri); /* release the overall brinfo structure */ + } + return NULL; +} + + + +/** + \brief Initialize an TR_INFO structure. Holds all data for text reassembly. + \returns a pointer to the TR_INFO structure created, or NULL on error. +*/ +TR_INFO *trinfo_init(TR_INFO *tri){ + if(tri)return(tri); /* tri is already set, double initialization is not allowed */ + if(!(tri = (TR_INFO *)calloc(1,sizeof(TR_INFO))) || + !(tri->fti = ftinfo_init()) || + !(tri->tpi = tpinfo_init()) || + !(tri->bri = brinfo_init()) || + !(tri->cxi = cxinfo_init()) + ){ tri = trinfo_release(tri); } + tri->use_kern = 1; + tri->usebk = BKCLR_NONE; + tri->load_flags = FT_LOAD_NO_SCALE; + tri->kern_mode = FT_KERNING_UNSCALED; + tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */ + tri->outspace = 0; + tri->outused = 0; + return(tri); +} + +/** + \brief Release a TR_INFO structure completely. + Release all associated memory, including FontConfig. + See also trinfo_clear() and trinfo_release_except_FC(). + use like: tri = trinfo_release(tri); + \param tri pointer to the TR_INFO structure. + \returns NULL. +*/ +TR_INFO *trinfo_release(TR_INFO *tri){ + if(tri){ + if(tri->bri)tri->bri=brinfo_release(tri->bri); + if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi); + if(tri->fti)tri->fti=ftinfo_release(tri->fti); + if(tri->cxi)tri->cxi=cxinfo_release(tri->cxi); + if(tri->out){ free(tri->out); tri->out=NULL; }; + free(tri); + } + return(NULL); +} + +/** + \brief Release a TR_INFO structure mostly. + Release all associated memory EXCEPT Fontconfig. + Fontconfig may still be needed elsewhere in a program and there is no way to figure that out here. + See also trinfo_clear() and trinfo_release(). + use like: tri = trinfo_release_except_FC(tri); + \param tri pointer to the TR_INFO structure. + \returns NULL. +*/ +TR_INFO *trinfo_release_except_FC(TR_INFO *tri){ + if(tri){ + if(tri->bri)tri->bri=brinfo_release(tri->bri); + if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi); + if(tri->fti)tri->fti=ftinfo_clear(tri->fti); + if(tri->cxi)tri->cxi=cxinfo_release(tri->cxi); + if(tri->out){ free(tri->out); tri->out=NULL; }; + free(tri); + } + return(NULL); +} + +/** + \brief Clear a TR_INFO structure. + Releases text and rectangle information, but retains font information, both + Freetype information and Fontconfig information. + See also trinfo_release() and trinfo_release_except_FC(). + Use like: tri = trinfo_clear(tri); + \param tri pointer to the TR_INFO structure. + \returns NULL. +*/ +TR_INFO *trinfo_clear(TR_INFO *tri){ + if(tri){ + tri->dirty = 0; /* set these back to their defaults */ + tri->esc = 0.0; + /* Do NOT modify use_kern, usebk, load_flags, or kern_mode */ + + if(tri->bri)tri->bri=brinfo_release(tri->bri); + if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi); + if(tri->cxi)tri->cxi=cxinfo_release(tri->cxi); + if(tri->out){ + free(tri->out); + tri->out = NULL; + tri->outused = 0; + tri->outspace = 0; + }; + if(!(tri->tpi = tpinfo_init()) || /* re-init the pieces just released */ + !(tri->bri = brinfo_init()) || + !(tri->cxi = cxinfo_init()) + ){ + tri = trinfo_release(tri); /* something horrible happened, clean out tri and return NULL */ + } + } + return(tri); +} + + +/** + \brief Set the quantization error value for a TR_INFO structure. + If coordinates have passed through an integer form limits + in accuracy may have been imposed. For instance, if the X coordinate of a point in such a file + is 1000, and the conversion factor from those coordinates to points is .04, then eq is .04. This + just says that single coordinates are only good to within .04, and two coordinates may differ by as much + as .08, just due to quantization error. So if some calculation shows a difference of + .02 it may be interpreted as this sort of error and set to 0.0. + \returns 0 on success, !0 on error. + \param tri pointer to TR_INFO structure + \param qe quantization error. +*/ +int trinfo_load_qe(TR_INFO *tri, double qe){ + if(!tri)return(1); + if(qe<0.0)return(2); + tri->qe=qe; + return(0); +} + +/** + \brief Set the background color and whether or not to use it. + When background color is turned on each line of text is underwritten with a rectangle + of the specified color. The rectangle is the merged bounding rectangle for that line. + \returns 0 on success but nothing changed, >0 on error, <0 on success and a value changed. + \param tri pointer to TR_INFO structure + \param usebk 0 for no background, anything else uses background color + \param bkcolor background color to use +*/ +int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor){ + int status=0; + if(!tri){ status = 1; } + else { + if((usebk < BKCLR_NONE) || (usebk > BKCLR_ALL)){ status = 2; } + else { + status = trinfo_check_bk(tri, usebk, bkcolor); + tri->usebk = usebk; + tri->bkcolor = bkcolor; + } + } + return(status); +} + +/** + \brief Are the proposed new background and background color a change? + \returns 0 if they are the same, -1 if either is different + \param tri pointer to TR_INFO structure + \param usebk 0 for no background, anything else uses background color + \param bkcolor background color to use +*/ +int trinfo_check_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor){ + int status = 0; + if( (tri->usebk != usebk) || memcmp(&tri->bkcolor,&bkcolor,sizeof(TRCOLORREF))){ status = -1; } + return(status); +} + +/** + \brief Set Freetype parameters and kerning mode (if any) in a TRI_INFO structure. + \returns 0 on success, !0 on error. + \param tri pointer to a TR_INFO structure + \param use_kern 0 if kerning is to be employed, !0 otherwise. + \param load_flags Controls internal advance: + FT_LOAD_NO_SCALE, internal advance is in 1/64th of a point. (kerning values are still scaled) + FT_LOAD_TARGET_NORMAL internal advance is in 1/64th of a point. The scale + factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi). + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. +*/ +int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode){ + if(!tri)return(1); + tri->use_kern = use_kern; + tri->load_flags = load_flags; + tri->kern_mode = kern_mode; + return(0); +} + +/** + \brief Append text to a TR_INFO struct's output buffer, expanding it if necessary. + \returns 0 on success, !0 on error. + \param tri pointer to a TR_INFO structure + \param src Pointer to a text string. +*/ +int trinfo_append_out(TR_INFO *tri, const char *src){ + size_t slen; + if(!src)return(-1); + slen = strlen(src); + if(tri->outused + (int) slen + 1 >= tri->outspace){ + tri->outspace += TEREMAX(ALLOCOUT_CHUNK,slen+1); + if(!(tri->out = realloc(tri->out, tri->outspace )))return(-1); + } + memcpy(tri->out + tri->outused, src, slen+1); /* copy the terminator */ + tri->outused += slen; /* do not count the terminator in the length */ + return(0); +} + + +/** + \brief Load a text object into a TR_INFO struct. + \returns 0 on success, !0 on error. -1 means that the escapement is different from the objects already loaded. + \param tri pointer to a TR_INFO structure + \param tsp pointer to a TCHUNK_SPECS structure (text object to load) + \param escapement angle in degrees of the text object. + \param flags special processing flags: + TR_EMFBOT calculate Y coordinates of ALIBOT object compatible with EMF files TA_BOTTOM alignment. +*/ +int trinfo_load_textrec(TR_INFO *tri, const TCHUNK_SPECS *tsp, double escapement, int flags){ + + int status; + double x,y,xe; + double asc,dsc; /* these are the ascender/descender for the actual text */ + int ymin,ymax; + double fasc,fdsc; /* these are the ascender/descender for the font as a whole (text independent) */ + TP_INFO *tpi; + FT_INFO *fti; + BR_INFO *bri; + int current,idx,taln; + uint32_t prev; + uint32_t *text32,*tptr; + FNT_SPECS *fsp; + BRECT_SPECS bsp; + + /* check incoming parameters */ + if(!tri)return(1); + if(!tsp)return(2); + if(!tsp->string)return(3); + fti = tri->fti; + tpi = tri->tpi; + bri = tri->bri; + idx = tsp->fi_idx; + taln = tsp->taln; + if(!fti->used)return(4); + if(idx <0 || idx >= (int) fti->used)return(5); + fsp = &(fti->fonts[idx]); + + if(!tri->dirty){ + tri->x = tsp->x; + tri->y = tsp->y; + tri->esc = escapement; + tri->dirty = 1; + } + else { + if(tri->esc != escapement)return(-1); + } + + + tpinfo_insert(tpi,tsp); + current=tpi->used-1; + ymin = 64000; + ymax = -64000; + + /* The geometry model has origin Y at the top of screen, positive Y is down, maximum positive + Y is at the bottom of the screen. That makes "top" (by positive Y) actually the bottom + (as viewed on the screen.) */ + + escapement *= 2.0 * M_PI / 360.0; /* degrees to radians */ + x = tpi->chunks[current].x - tri->x; /* convert to internal orientation */ + y = tpi->chunks[current].y - tri->y; + tpi->chunks[current].x = x * cos(escapement) - y * sin(escapement); /* coordinate transformation */ + tpi->chunks[current].y = x * sin(escapement) + y * cos(escapement); + +/* Careful! face bbox does NOT scale with FT_Set_Char_Size +printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,%d height:%d size:%lf\n", + idx, + fsp->face->bbox.xMax,fsp->face->bbox.xMin, + fsp->face->bbox.yMax,fsp->face->bbox.yMin, + fsp->face->units_per_EM,fsp->face->ascender,fsp->face->descender,fsp->face->height,fsp->fsize); +*/ + + text32 = U_Utf8ToUtf32le((char *) tsp->string,0,NULL); + if(!text32){ // LATIN1 encoded >128 are generally not valid UTF, so the first will fail + text32 = U_Latin1ToUtf32le((char *) tsp->string,0,NULL); + if(!text32)return(5); + } + /* baseline advance is independent of character orientation */ + for(xe=0.0, prev=0, tptr=text32; *tptr; tptr++){ + status = TR_getadvance(fti, fsp, *tptr, (tri->use_kern ? prev: 0), tri->load_flags, tri->kern_mode, &ymin, &ymax); + if(status>=0){ + xe += ((double) status)/64.0; + } + else { return(6); } + prev=*tptr; + } + + /* Some glyphs in fonts have no vertical extent, for instance, Hebrew glyphs in Century Schoolbook L. + Use the 3/4 of the font size as a (very bad) approximation for the actual values. */ + if(ymin==0 && ymax==0){ + ymax = 0.75 * fsp->fsize * 64.0; + } + + asc = ((double) (ymax))/64.0; + dsc = ((double) (ymin))/64.0; /* This is negative */ +/* This did not work very well because the ascender/descender went well beyond the actual characters, causing + overlaps on lines that did not actually overlap (vertically). + asc = ((double) (fsp->face->ascender) )/64.0; + dsc = ((double) (fsp->face->descender))/64.0; +*/ + + free(text32); + + /* find the font ascender descender (general one, not specific for current text) */ + fasc = ((double) (fsp->face->ascender) )/64.0; + fdsc = ((double) (fsp->face->descender))/64.0; + + if(tri->load_flags & FT_LOAD_NO_SCALE) xe *= tsp->fs/32.0; + + /* now place the rectangle using ALN information */ + if( taln & ALIHORI & ALILEFT ){ + bsp.xll = tpi->chunks[current].x; + bsp.xur = tpi->chunks[current].x + xe; + } + else if( taln & ALIHORI & ALICENTER){ + bsp.xll = tpi->chunks[current].x - xe/2.0; + bsp.xur = tpi->chunks[current].x + xe/2.0; + } + else{ /* taln & ALIHORI & ALIRIGHT */ + bsp.xll = tpi->chunks[current].x - xe; + bsp.xur = tpi->chunks[current].x; + } + tpi->chunks[current].ldir = tsp->ldir; + + if(tri->load_flags & FT_LOAD_NO_SCALE){ + asc *= tsp->fs/32.0; + dsc *= tsp->fs/32.0; + fasc *= tsp->fs/32.0; + fdsc *= tsp->fs/32.0; + } + + + /* From this point forward y is on the baseline, so need to correct it in chunks. The asc/dsc are the general + ones for the font, else the text content will muck around with the baseline in BAD ways. */ + if( taln & ALIVERT & ALITOP ){ tpi->chunks[current].y += fasc; } + else if( taln & ALIVERT & ALIBASE){ } /* no correction required */ + else{ /* taln & ALIVERT & ALIBOT */ + if(flags & TR_EMFBOT){ tpi->chunks[current].y -= 0.35 * tsp->fs; } /* compatible with EMF implementations */ + else { tpi->chunks[current].y += fdsc; } + } + tpi->chunks[current].boff = -dsc; + + /* since y is always on the baseline, the lower left and upper right are easy. These use asc/dsc for the particular text, + so that the bounding box will fit it tightly. */ + bsp.yll = tpi->chunks[current].y - dsc; + bsp.yur = tpi->chunks[current].y - asc; + brinfo_insert(bri,&bsp); + tpi->chunks[current].rt_tidx = bri->used - 1; /* index of rectangle that contains it */ + + return(0); +} + +/** + \brief Fontweight conversion. Fontconfig units to SVG units. + Anything not recognized becomes "normal" == 400. + There is no interpolation because a value that mapped to 775, for instance, most + likely would not display properly because it is intermediate between 700 and 800, and + only those need be supported in SVG viewers. + \returns SVG font weight + \param weight Fontconfig font weight. +*/ +int TR_weight_FC_to_SVG(int weight){ + int ret=400; + if( weight == 0){ ret = 100; } + else if(weight == 40){ ret = 200; } + else if(weight == 50){ ret = 300; } + else if(weight == 80){ ret = 400; } + else if(weight == 100){ ret = 500; } + else if(weight == 180){ ret = 600; } + else if(weight == 200){ ret = 700; } + else if(weight == 205){ ret = 800; } + else if(weight == 210){ ret = 900; } + else { ret = 400; } + return(ret); +} + +/** + \brief Set the padding that will be added to bounding rectangles before checking for overlaps in brinfo_overlap(). + \returns void + \param rt_pad pointer to an RT_PAD structure. + \param up padding for the top of a bounding rectangle. + \param down padding for the bottom of a bounding rectangle. + \param left padding for the left of a bounding rectangle. + \param right padding for the right of a bounding rectangle. +*/ +void TR_rt_pad_set(RT_PAD *rt_pad, double up, double down, double left, double right){ + rt_pad->up = up; + rt_pad->down = down; + rt_pad->left = left; + rt_pad->right = right; +} + +/** + \brief Convert from analyzed complexes to SVG format. + \returns void + \param tri pointer to a TR_INFO struct which will be analyzed. Result is stored in its "out" buffer. +*/ +void TR_layout_2_svg(TR_INFO *tri){ + double x = tri->x; + double y = tri->y; + double dx,dy; + double esc; + double recenter; /* horizontal offset to set things up correctly for CJ and RJ text, is 0 for LJ*/ + double lineheight=1.25; + int cutat; + FT_INFO *fti=tri->fti; /* Font info storage */ + TP_INFO *tpi=tri->tpi; /* Text Info/Position Info storage */ + BR_INFO *bri=tri->bri; /* bounding Rectangle Info storage */ + CX_INFO *cxi=tri->cxi; /* Complexes deduced for this text */ + TCHUNK_SPECS *tsp; /* current text object */ + CX_SPECS *csp; + CX_SPECS *cline_sp; + unsigned int i,j,k,jdx,kdx; + int ldir; + char obuf[1024]; /* big enough for style and so forth */ + char cbuf[16]; /* big enough for one hex color */ + + char stransform[128]; + double newx,newy,tmpx; + uint32_t utmp; + +/* +#define DBG_TR_PARA 0 +#define DBG_TR_INPUT 1 +*/ + /* The debug section below is difficult to see if usebk is anything other than BKCLR_NONE */ +#if DBG_TR_PARA || DBG_TR_INPUT /* enable debugging code, writes extra information into SVG */ + /* put rectangles down for each text string - debugging!!! This will not work properly for any Narrow fonts */ + esc = tri->esc; + esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */ + sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y); + for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */ + csp = &(cxi->cx[i]); + for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */ + jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */ + for(k=0; k<cxi->cx[jdx].kids.used; k++){ /* over all members of the phase1 complex */ + kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi */ + tsp = &tpi->chunks[kdx]; + ldir = tsp->ldir; + if(!j && !k){ +#if DBG_TR_PARA + TRPRINT(tri, "<rect\n"); + TRPRINT(tri, "style=\"color:#0000FF;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#000000;stroke-width:0.8;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n"); + sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll)); + TRPRINT(tri, obuf); + sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur)); + TRPRINT(tri, obuf); + sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur)); + TRPRINT(tri, obuf); + TRPRINT(tri, stransform); + TRPRINT(tri, "/>\n"); +#endif /* DBG_TR_PARA */ + } +#if DBG_TR_INPUT /* debugging code, this section writes the original text objects */ + newx = 1.25*(ldir == LDIR_RL ? bri->rects[tsp->rt_tidx].xur : bri->rects[tsp->rt_tidx].xll); + newy = 1.25*(bri->rects[tsp->rt_tidx].yur); + TRPRINT(tri, "<rect\n"); + TRPRINT(tri, "style=\"color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#00FF00;stroke-width:0.3;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n"); + sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll)); + TRPRINT(tri, obuf); + sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur)); + TRPRINT(tri, obuf); + sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].xll),newy); + TRPRINT(tri, obuf); + TRPRINT(tri, stransform); + TRPRINT(tri, "/>\n"); + + newy = 1.25*(bri->rects[tsp->rt_tidx].yll - tsp->boff); + sprintf(obuf,"<text x=\"%lf\" y=\"%lf\"\n",newx, newy ); + TRPRINT(tri, obuf); + sprintf(obuf,"xml:space=\"preserve\"\n"); + TRPRINT(tri, obuf); + TRPRINT(tri, stransform); + TRPRINT(tri, "style=\"fill:#FF0000;"); + sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/ + TRPRINT(tri, obuf); + sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal")); + TRPRINT(tri, obuf); + TRPRINT(tri, "font-variant:normal;"); + sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight)); + TRPRINT(tri, obuf); + sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed")); + TRPRINT(tri, obuf); + sprintf(obuf,"text-anchor:%s;",(tsp->ldir == LDIR_RL ? "end" : "start")); + TRPRINT(tri, obuf); + cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":"); + sprintf(obuf,"font-family:%.*s;",cutat,fti->fonts[tsp->fi_idx].fontspec); + TRPRINT(tri, obuf); + sprintf(obuf,"\n\">%s</text>\n",tsp->string); + TRPRINT(tri, obuf); +#endif /* DBG_TR_INPUT debugging code, original text objects */ + } + } + } +#endif /* DBG_TR_PARA and/or DBG_TR_INPUT */ + + + if(tri->usebk){ + esc = tri->esc; + esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */ + sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y); + + for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */ + TRPRINT(tri, "<g>\n"); /* group backgrounds for each <text> object in the SVG */ + csp = &(cxi->cx[i]); + for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */ + jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */ + cline_sp = &(cxi->cx[jdx]); + if(tri->usebk == BKCLR_LINE){ + TRPRINT(tri, "<rect\n"); + sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue); + TRPRINT(tri, obuf); + sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[cline_sp->rt_cidx].xur - bri->rects[cline_sp->rt_cidx].xll)); + TRPRINT(tri, obuf); + sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].yll - bri->rects[cline_sp->rt_cidx].yur)); + TRPRINT(tri, obuf); + sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].xll),1.25*(bri->rects[cline_sp->rt_cidx].yur)); + TRPRINT(tri, obuf); + TRPRINT(tri, stransform); + TRPRINT(tri, "/>\n"); + } + + for(k=0; k<cxi->cx[jdx].kids.used; k++){ /* over all members of the phase1 complex */ + kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi */ + tsp = &tpi->chunks[kdx]; + ldir = tsp->ldir; + if(!j && !k){ + if(tri->usebk == BKCLR_ALL){ + TRPRINT(tri, "<rect\n"); + sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue); + TRPRINT(tri, obuf); + sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll)); + TRPRINT(tri, obuf); + sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur)); + TRPRINT(tri, obuf); + sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur)); + TRPRINT(tri, obuf); + TRPRINT(tri, stransform); + TRPRINT(tri, "/>\n"); + } + } + if(tri->usebk == BKCLR_FRAG){ + newx = 1.25*(ldir == LDIR_RL ? bri->rects[tsp->rt_tidx].xur : bri->rects[tsp->rt_tidx].xll); + newy = 1.25*(bri->rects[tsp->rt_tidx].yur); + TRPRINT(tri, "<rect\n"); + sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue); + TRPRINT(tri, obuf); + sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll)); + TRPRINT(tri, obuf); + sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur)); + TRPRINT(tri, obuf); + sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",newx,newy); + TRPRINT(tri, obuf); + TRPRINT(tri, stransform); + TRPRINT(tri, "/>\n"); + } + } + } + TRPRINT(tri, "</g>\n"); /* end of grouping for backgrounds for each <text> object in the SVG */ + } + } + + + tsp = tpi->chunks; + /* over all complex members from phase2. Paragraphs == TR_PARA_* */ + for(i=cxi->phase1; i<cxi->used;i++){ + csp = &(cxi->cx[i]); + esc = tri->esc; + esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */ + + /* over all members of the present Paragraph. Each of these is a line and a phase 1 complex. + It may be either TR_TEXT or TR_LINE */ + for(j=0; j<csp->kids.used; j++){ + if(j){ + sprintf(obuf,"</tspan>"); + TRPRINT(tri, obuf); + } + jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */ + recenter = 0; /* mostly to quiet a compiler warning, should always be set below */ + + + /* over all members of the present Line. These are the original text objects which were reassembled. + There will be one for TR_TEXT, more than one for TR_LINE */ + for(k=0; k<cxi->cx[jdx].kids.used; k++){ + kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi, for this k */ + tsp = &tpi->chunks[kdx]; /* text chunk for this k */ + ldir = tsp->ldir; /* language direction for this k */ + if(!k){ /* first iteration */ + switch(csp->type){ /* set up the alignment, if there is one */ + case TR_TEXT: + case TR_LINE: + /* these should never occur, this section quiets a compiler warning */ + break; + case TR_PARA_UJ: + case TR_PARA_LJ: + if(ldir == LDIR_RL){ recenter = -(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll); } + else { recenter = 0.0; } + break; + case TR_PARA_CJ: + if(ldir == LDIR_RL){ recenter = -(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll)/2.0; } + else { recenter = +(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll)/2.0; } + break; + case TR_PARA_RJ: + if(ldir == LDIR_RL){ recenter = 0.0; } + else { recenter = +(bri->rects[cxi->cx[jdx].rt_cidx].xur - bri->rects[cxi->cx[jdx].rt_cidx].xll); } + break; + } + if(!j){ + TRPRINT(tri, "<text\n"); + TRPRINT(tri, "xml:space=\"preserve\"\n"); + TRPRINT(tri, "style=\""); + sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/ + TRPRINT(tri, obuf); + sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal")); + TRPRINT(tri, obuf); + TRPRINT(tri, "font-variant:normal;"); + sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight)); + TRPRINT(tri, obuf); + sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed")); + TRPRINT(tri, obuf); + if(tsp->vadvance){ lineheight = tsp->vadvance *100.0; } + else { lineheight = 125.0; } + sprintf(obuf,"line-height:%lf%%;",lineheight); + TRPRINT(tri, obuf); + TRPRINT(tri, "letter-spacing:0px;"); + TRPRINT(tri, "word-spacing:0px;"); + TRPRINT(tri, "fill:#000000;"); + TRPRINT(tri, "fill-opacity:1;"); + TRPRINT(tri, "stroke:none;"); + cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":"); + sprintf(obuf,"font-family:%.*s;",cutat,fti->fonts[tsp->fi_idx].fontspec); + TRPRINT(tri, obuf); + switch(csp->type){ /* set up the alignment, if there is one */ + case TR_TEXT: + case TR_LINE: + /* these should never occur, this section quiets a compiler warning */ + break; + case TR_PARA_UJ: + case TR_PARA_LJ: + sprintf(obuf,"text-align:start;text-anchor:start;"); + break; + case TR_PARA_CJ: + sprintf(obuf,"text-align:center;text-anchor:middle;"); + break; + case TR_PARA_RJ: + sprintf(obuf,"text-align:end;text-anchor:end;"); + break; + } + TRPRINT(tri, obuf); + TRPRINT(tri, "\"\n"); /* End of style specification */ + sprintf(obuf,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),1.25*x,1.25*y); + TRPRINT(tri, obuf); + tmpx = 1.25*((ldir == LDIR_RL ? bri->rects[kdx].xur : bri->rects[kdx].xll) + recenter); + sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff)); + TRPRINT(tri, obuf); + } + tmpx = 1.25*((ldir == LDIR_RL ? bri->rects[kdx].xur : bri->rects[kdx].xll) + recenter); + sprintf(obuf,"<tspan sodipodi:role=\"line\"\nx=\"%lf\" y=\"%lf\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff)); + TRPRINT(tri, obuf); + } + TRPRINT(tri, "<tspan\n"); + + /* Scale kerning and make any other necessary adjustments + + */ + dx = 1.25 * tsp->xkern; + dy = 1.25 * tsp->ykern; + + sprintf(obuf,"dx=\"%lf\" dy=\"%lf\" ",dx, dy); + TRPRINT(tri, obuf); + sprintf(obuf,"style=\"fill:#%2.2X%2.2X%2.2X;",tsp->color.Red,tsp->color.Green,tsp->color.Blue); + TRPRINT(tri, obuf); + sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/ + TRPRINT(tri, obuf); + sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal")); + TRPRINT(tri, obuf); + if(tsp->decoration & TXTDECOR_TMASK){ + sprintf(obuf,"text-decoration:"); + /* multiple text decoration styles may be set */ + utmp = tsp->decoration & TXTDECOR_TMASK; + if(utmp & TXTDECOR_UNDER ){ strcat(obuf,"underline"); } + if(utmp & TXTDECOR_OVER ){ strcat(obuf,"overline"); } + if(utmp & TXTDECOR_BLINK ){ strcat(obuf,"blink"); } + if(utmp & TXTDECOR_STRIKE){ strcat(obuf,"line-through");} + if(*obuf){ + /* only a single text decoration line type may be set */ + switch(tsp->decoration & TXTDECOR_LMASK){ + case TXTDECOR_SOLID: break; // "solid" is the CSS 3 default, omitting it remains CSS 2 compatible + case TXTDECOR_DOUBLE: strcat(obuf," double"); break; // these are all CSS3 + case TXTDECOR_DOTTED: strcat(obuf," dotted"); break; + case TXTDECOR_DASHED: strcat(obuf," dashed"); break; + case TXTDECOR_WAVY: strcat(obuf," wavy" ); break; + default: break; + } + if((tsp->decoration & TXTDECOR_CLRSET) && memcmp(&(tsp->decColor),&(tsp->color),sizeof(TRCOLORREF))){ + /* CSS 3, CSS 2 implementations may choke on it. If the specified color matches text color omit, for better CSS 2 compatitiblity. */ + sprintf(cbuf," #%2.2X%2.2X%2.2X",tsp->decColor.Red,tsp->decColor.Green,tsp->decColor.Blue); + strcat(obuf,cbuf); + } + } + strcat(obuf,";"); + TRPRINT(tri,obuf); + } + TRPRINT(tri, "font-variant:normal;"); + sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight)); + TRPRINT(tri, obuf); + sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed")); + TRPRINT(tri, obuf); + cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":"); + sprintf(obuf,"font-family:%.*s;\"",cutat,fti->fonts[tsp->fi_idx].fontspec); + TRPRINT(tri, obuf); + TRPRINT(tri, "\n>"); + TRPRINT(tri, (char *) tsp->string); + TRPRINT(tri, "</tspan>"); + } /* end of k loop */ + } /* end of j loop */ + TRPRINT(tri,"</tspan></text>\n"); + } /* end of i loop */ +} + +/** + \brief Attempt to figure out the original organization, in lines and paragraphs, of the text objects. + The method is: + 1. Generate complexes from the text objects (strings) by overlaps (optionally allowing up to two spaces to be + added) to produce larger rectangles. Complexes that are more or less sequential and have 2 or more text objects + are TR_LINEs, therwise they are TR_TEXT. + 2. Group sequential complexes (TR_LINE or TR_TEXT) into TR_PARA_UJ (paragraphs,by smooth progression in vertical + position down page). + 3. Analyze the paragraphs to classify them as Left/Center/Right justified (possibly with indentation.) If + they do not fall into any of these categories break that one back down into TR_LINE/TR_TEXT. + 4. Return the number of complex text objects. + \returns Number of complexes. (>=1, <= number of text objects.) <0 is an error. + \param tri pointer to the TR_INFO structure holding the data, which will also hold the results. +*/ +int TR_layout_analyze(TR_INFO *tri){ + unsigned int i,j,k; + int ok; + int cxidx; + int src_rt; + int dst_rt; + TP_INFO *tpi; + BR_INFO *bri; + CX_INFO *cxi; + FT_INFO *fti; + BRECT_SPECS bsp; + RT_PAD rt_pad_i; + RT_PAD rt_pad_j; + double ratio; + double qsp,dx,dy; + double spcadv; + enum tr_classes type; + TCHUNK_SPECS *tspi; + TCHUNK_SPECS *tspj; + TCHUNK_SPECS *tspRevEnd=NULL; + TCHUNK_SPECS *tspRevStart=NULL; + CX_SPECS *csp; + CHILD_SPECS *kidp; /* used with preceding complex (see below) */ + CHILD_SPECS *kidc; /* used with current complex (see below) */ + int lastldir,ldir,rev; + + if(!tri)return(-1); + if(!tri->cxi)return(-2); + if(!tri->tpi)return(-3); + if(!tri->bri)return(-4); + if(!tri->fti)return(-5); + tpi=tri->tpi; + cxi=tri->cxi; + bri=tri->bri; + fti=tri->fti; + cxi->lines = 0; + cxi->paras = 0; + cxi->phase1 = 0; + +/* When debugging + ftinfo_dump(fti); +*/ + /* Phase 1. Working sequentially, insert text. Initially as TR_TEXT and then try to extend to TR_LINE by checking + overlaps. When done the complexes will contain a mix of TR_LINE and TR_TEXT. */ + + for(i=0; i<tpi->used; i++){ + tspi = &(tpi->chunks[i]); + memcpy(&bsp,&(bri->rects[tspi->rt_tidx]),sizeof(BRECT_SPECS)); /* Must make a copy as next call may reallocate rects! */ + (void) brinfo_insert(bri,&bsp); + dst_rt = bri->used-1; + (void) cxinfo_insert(cxi, i, dst_rt, TR_TEXT); + cxidx = cxi->used-1; + + spcadv = fti->fonts[tspi->fi_idx].spcadv * tspi->fs/32.0; /* spcadv was always FT_LOAD_NO_SCALE */ + /* for the leading text: pad with no leading and two trailing spaces, leading and trailing depend on direction */ + if(tspi->ldir == LDIR_RL){ TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, tri->qe + 2.0 * spcadv, 0.0); } + else { TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, 0.0, tri->qe + 2.0 * spcadv); } + + for(j=i+1; j<tpi->used; j++){ + tspj = &(tpi->chunks[j]); + /* Reject font size changes of greater than 50%, these are almost certainly not continuous text. These happen + in math formulas, for instance, where a sum or integral is much larger than the other symbols. */ + ratio = (double)(tspj->fs)/(double)(tspi->fs); + if(ratio >2.0 || ratio <0.5)break; + + spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0; /* spcadv was always FT_LOAD_NO_SCALE */ + /* for the trailing text: pad with one leading and trailing spaces (so it should work L->R and R->L) */ + TR_rt_pad_set(&rt_pad_j,tri->qe, tri->qe, spcadv, spcadv); + src_rt = tspj->rt_tidx; + + /* Reject direction changes like [1 <- Hebrew][2 -> English], that is where the direction changes AND the + next logical piece of text is "upstream" positionally of its logical predecessor. The meaning of such + a construct is at best ambiguous. The test is only applied with respect to the first text chunk. This sort + of construct may appear when a valid initial construct like [1->English][2<-Hebrew][3->English] is edited + and the leading chunk of text removed. + */ + if(brinfo_upstream(bri, + dst_rt, /* index into bri for dst */ + src_rt, /* index into bri for src */ + tspi->ldir,tspj->ldir))break; + + if(!brinfo_overlap(bri, + dst_rt, /* index into bri for dst */ + src_rt, /* index into bri for src */ + &rt_pad_i,&rt_pad_j)){ + (void) cxinfo_append(cxi,j,TR_LINE); + (void) brinfo_merge(bri,dst_rt,src_rt); + /* for the leading text: pad with two leading and trailing spaces (so it should work L->R and R->L */ + spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0; /* spcadv was always FT_LOAD_NO_SCALE */ + TR_rt_pad_set(&rt_pad_i, tri->qe, tri->qe, + tri->qe + 2.0 * spcadv, tri->qe + 2.0 * spcadv); + } + else { /* either alignment ge*/ + break; + } + } + + /* Bidirectional text will cause complexes to not assemble in one pass. + This happens whenever a change of direction occurs with 2 or more sequential elements in + the opposite direction, + + Let + = LR and - = RL. + + Reading left to right, this happens with +-- or -++. + For instance, the sequence ++-+ ---+ would break into the two complexes shown. + Not until the last element in the second complex is added will the bounding rectangles for the complexes overlap. + + Check for this effect now if there is a preceding complex and the first element of the current complex is + reversed from the last in the preceding. */ + if(cxidx >= 1){ + kidp = &(cxi->cx[cxidx-1].kids); + kidc = &(cxi->cx[cxidx ].kids); + tspi = &(tpi->chunks[ kidp->members[kidp->used - 1] ]); /* here, the last text element in preceding complex */ + tspj = &(tpi->chunks[ kidc->members[0 ] ]); /* here, tge first text element in current complex */ + if(tspi->ldir != tspj->ldir){ + spcadv = fti->fonts[tspi->fi_idx].spcadv * tspi->fs/32.0; + if(tspi->ldir == LDIR_RL){ TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, tri->qe + 2.0 * spcadv, 0.0); } + else { TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, 0.0, tri->qe + 2.0 * spcadv); } + spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0; + TR_rt_pad_set(&rt_pad_j,tri->qe, tri->qe, spcadv, spcadv); + if(!brinfo_overlap(bri, + cxi->cx[cxidx-1].rt_cidx, /* index into rt for dst cx */ + cxi->cx[cxidx].rt_cidx, /* index into rt for src cx */ + &rt_pad_i,&rt_pad_j)){ + /* Merge the current complex into the preceding one*/ + (void) cxinfo_merge(cxi, cxidx-1, cxidx, TR_LINE); + (void) brinfo_merge(bri,cxi->cx[cxidx-1].rt_cidx,cxi->cx[cxidx].rt_cidx); /* merge the bounding boxes*/ + (void) cxinfo_trim(cxi); + cxi->lines--; /* else the normal line count value is one too high */ + /* remove the current complex */ + } + } + } + + if(cxi->cx[cxidx].type == TR_LINE)cxi->lines++; + i=j-1; /* start up after the last merged entry (there may not be any) */ + } + cxi->phase1 = cxi->used; /* total complexes defined in this phase, all TR_LINE or TR_TEXT */ + + /* phase 1.5, calculate kerning. This is as good a place to do it as any. At this point all kern values + are zero. Each of these pieces is strictly unidirectional, but each piece can have a different direction. + The direction of the line is set by the first text element. The ends of runs of elements which are + reversed with respect to the line direction are special, everything else is simple: + Let: + == L->R, - == R->L, $ == end of text, the rules for kerning on B are: + A B others xkern + [+|$] + + [+|$] Bll - Aur + [-|$] - - [-|$] All - Bur (chs) + + - + [-|$] Bll - Aur (chs) + - + - [+|$] All - Bur + + - -...[-=C] [+|$] All - Cur (chs) + - + +...[+=C] [-|$] Cll - Aur + + chs = change sign, because dx is an absolute direction, and direction of text on RTL is in -x. + + Kerning calculations currently seems unstable for R->L if the kerning extends to the end of the line. If + the first and last characters are back in sync there are no issues. When things go south R->L left justified + text is not justified when read in. + */ + + for(i=0; i < cxi->phase1; i++){ /* over all lines */ + csp = &(cxi->cx[i]); + if(csp->kids.used < 2)continue; /* no kerning possible */ + tspi = &tpi->chunks[csp->kids.members[0]]; /* used here as last tsp. no kerning is applied to the first element */ + lastldir = ldir = tspi->ldir; + rev = 0; /* the first ldir defines forward and reverse */ + for(j=1; j<csp->kids.used; j++){ + tspj = &tpi->chunks[csp->kids.members[j]]; + ldir = tspj->ldir; + if(ldir != lastldir){ /* direction change */ + rev = !rev; /* reverse direction tracker */ + if(!rev){ /* back in original orientation */ + if(ldir == LDIR_RL){ tspj->xkern = bri->rects[tspj->rt_tidx].xur - bri->rects[tspRevStart->rt_tidx].xll; } + else { tspj->xkern = bri->rects[tspj->rt_tidx].xll - bri->rects[tspRevStart->rt_tidx].xur; } + tspj->ykern = (bri->rects[tspj->rt_tidx].yll - tspj->boff) - + (bri->rects[tspRevStart->rt_tidx].yll - tspRevStart->boff); + } + else { /* now in reversed orientation */ + tspRevStart = tspj; /* Save the beginning of this run (length >=1 ) */ + /* scan forward for the last text object in this orientation, include the first */ + for(k=j; k <csp->kids.used; k++){ + if(tpi->chunks[csp->kids.members[k]].ldir == ldir){ tspRevEnd = &tpi->chunks[csp->kids.members[k]]; } + else { break; } + } + if(lastldir == LDIR_RL){ tspj->xkern = bri->rects[tspRevEnd->rt_tidx].xur - bri->rects[tspi->rt_tidx].xll; } + else { tspj->xkern = bri->rects[tspRevEnd->rt_tidx].xll - bri->rects[tspi->rt_tidx].xur; } + tspj->ykern = (bri->rects[tspRevEnd->rt_tidx].yll - tspRevEnd->boff) - + (bri->rects[ tspi->rt_tidx].yll - tspi->boff ); + } + } + else { + if(ldir == LDIR_RL){ tspj->xkern = bri->rects[tspj->rt_tidx].xur - bri->rects[tspi->rt_tidx].xll; } + else { tspj->xkern = bri->rects[tspj->rt_tidx].xll - bri->rects[tspi->rt_tidx].xur; } + tspj->ykern = (bri->rects[tspj->rt_tidx].yll - tspj->boff) - + (bri->rects[tspi->rt_tidx].yll - tspi->boff); + } + + + /* + Sometimes a font substitution was absolutely terrible, for instance, for Arial Narrow on (most) Linux systems, + The resulting advance (xkern) may be much too large so that it overruns the next text chunk. Since + overlapping text on the same line is almost never encountered, this may be used to detect the bad + substitution so that a more appropriate offset can be used. + Detect this situation as a negative dx < 1/2 a space character's width while |dy| < an entire space width. + The y constraints allow super and subscripts, which overlap in x but are shifted above/below in y. + */ + spcadv = fti->fonts[tspj->fi_idx].spcadv * tspj->fs/32.0; + qsp = 0.25 * spcadv; + dx = tspj->xkern; + dy = tspj->ykern; + if(dy <=qsp && dy >= -qsp){ + if(ldir==LDIR_RL){ + if(dx > 2*qsp)tspj->xkern = 0.0; + } + else { + if(dx < -2*qsp)tspj->xkern = 0.0; + } + } + + /* if x or y kern is less than the quantization error it is probably noise, set it to zero */ + if(fabs(tspj->xkern)<tri->qe)tspj->xkern = 0.0; + if(fabs(tspj->ykern)<tri->qe)tspj->ykern = 0.0; + + + tspi = tspj; + lastldir = ldir; + } + } + + + /* Phase 2, try to group sequential lines. There may be "lines" that are still TR_TEXT, as in: + + ... this is a sentence that wraps by one + word. + + And some paragrahs might be single word lines (+ = bullet in the following) + + +verbs + +nouns + +adjectives + + Everything starts out as TR_PARA_UJ and if the next one can be lined up, the type changes to + an aligned paragraph and complexes are appended to the existing one. + */ + + for(i=0; i < cxi->phase1; i++){ + type = TR_PARA_UJ; /* any paragraph alignment will be acceptable */ + /* Must make a copy as next call may reallocate rects, so if we just passed a pointer to something in the structure + it would vaporize part way through the call. */ + memcpy(&bsp,&(bri->rects[cxi->cx[i].rt_cidx]),sizeof(BRECT_SPECS)); + (void) brinfo_insert(bri,&bsp); + dst_rt = bri->used-1; + (void) cxinfo_insert(cxi, i, dst_rt, type); + + cxi->paras++; + ok = 1; + for(j=i+1; ok && (j < cxi->phase1); j++){ + type = brinfo_pp_alignment(bri, cxi->cx[i].rt_cidx, cxi->cx[j].rt_cidx, 3*tri->qe, type); + switch (type){ + case TR_PARA_UJ: /* paragraph type was set and j line does not fit, or no paragraph alignment matched */ + ok = 0; /* force exit from j loop */ + j--; /* this will increment at loop bottom */ + break; + case TR_PARA_LJ: + case TR_PARA_CJ: + case TR_PARA_RJ: + /* two successive lines have been identified (possible following others already in the paragraph */ + if(TR_check_set_vadvance(tri,j,i)){ /* check for compatibility with vadvance if set, set it if it isn't. */ + ok = 0; /* force exit from j loop */ + j--; /* this will increment at loop bottom */ + } + else { + src_rt = cxi->cx[j].rt_cidx; + (void) cxinfo_append(cxi, j, type); + (void) brinfo_merge(bri, dst_rt, src_rt); + } + break; + default: + return(-6); /* programming error */ + } + } + if(j>=cxi->phase1)break; + i=j-1; + } + + +/* When debugging + cxinfo_dump(tri); +*/ + + return(cxi->used); +} + + +/* no doxygen documentation below this point, these pieces are for the text program, not the library. */ + +#if TEST +#define MAXLINE 2048 /* big enough for testing */ +enum OP_TYPES {OPCOM,OPOOPS,OPFONT,OPESC,OPORI,OPXY,OPFS,OPTEXT,OPALN,OPLDIR,OPMUL,OPITA,OPWGT,OPDEC,OPCND,OPBKG,OPCLR,OPDCLR,OPBCLR,OPFLAGS,OPEMIT,OPDONE}; + +int parseit(char *buffer,char **data){ + int pre; + pre = strcspn(buffer,":"); + if(!pre)return(OPOOPS); + *data=&buffer[pre+1]; + buffer[pre]='\0'; + if(*buffer=='#' )return(OPCOM ); + if(0==strcmp("FONT",buffer))return(OPFONT); + if(0==strcmp("ESC" ,buffer))return(OPESC ); + if(0==strcmp("ORI", buffer))return(OPORI ); + if(0==strcmp("XY", buffer))return(OPXY ); + if(0==strcmp("FS", buffer))return(OPFS ); + if(0==strcmp("TEXT",buffer))return(OPTEXT); + if(0==strcmp("ALN", buffer))return(OPALN ); + if(0==strcmp("LDIR",buffer))return(OPLDIR); + if(0==strcmp("MUL", buffer))return(OPMUL ); + if(0==strcmp("ITA", buffer))return(OPITA ); + if(0==strcmp("WGT", buffer))return(OPWGT ); + if(0==strcmp("DEC", buffer))return(OPDEC ); + if(0==strcmp("CND", buffer))return(OPCND ); + if(0==strcmp("BKG", buffer))return(OPBKG ); + if(0==strcmp("CLR", buffer))return(OPCLR ); + if(0==strcmp("DCLR", buffer))return(OPDCLR ); + if(0==strcmp("BCLR",buffer))return(OPBCLR ); + if(0==strcmp("FLAG",buffer))return(OPFLAGS); + if(0==strcmp("EMIT",buffer))return(OPEMIT); + if(0==strcmp("DONE",buffer))return(OPDONE); + return(OPOOPS); +} + +void boom(char *string,int lineno){ + fprintf(stderr,"Fatal error at line %d %s\n",lineno,string); + exit(EXIT_FAILURE); +} + + +void init_as_svg(TR_INFO *tri){ + TRPRINT(tri,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); + TRPRINT(tri,"<!-- Created with Inkscape (http://www.inkscape.org/) -->\n"); + TRPRINT(tri,"\n"); + TRPRINT(tri,"<svg\n"); + TRPRINT(tri," xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"); + TRPRINT(tri," xmlns:cc=\"http://creativecommons.org/ns#\"\n"); + TRPRINT(tri," xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"); + TRPRINT(tri," xmlns:svg=\"http://www.w3.org/2000/svg\"\n"); + TRPRINT(tri," xmlns=\"http://www.w3.org/2000/svg\"\n"); + TRPRINT(tri," xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"); + TRPRINT(tri," xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n"); + TRPRINT(tri," width=\"900\"\n"); + TRPRINT(tri," height=\"675\"\n"); + TRPRINT(tri," id=\"svg4122\"\n"); + TRPRINT(tri," version=\"1.1\"\n"); + TRPRINT(tri," inkscape:version=\"0.48+devel r11679 custom\"\n"); + TRPRINT(tri," sodipodi:docname=\"simplest_text.svg\">\n"); + TRPRINT(tri," <defs\n"); + TRPRINT(tri," id=\"defs4124\" />\n"); + TRPRINT(tri," <sodipodi:namedview\n"); + TRPRINT(tri," id=\"base\"\n"); + TRPRINT(tri," pagecolor=\"#ffffff\"\n"); + TRPRINT(tri," bordercolor=\"#666666\"\n"); + TRPRINT(tri," borderopacity=\"1.0\"\n"); + TRPRINT(tri," inkscape:pageopacity=\"0.0\"\n"); + TRPRINT(tri," inkscape:pageshadow=\"2\"\n"); + TRPRINT(tri," inkscape:zoom=\"0.98994949\"\n"); + TRPRINT(tri," inkscape:cx=\"309.88761\"\n"); + TRPRINT(tri," inkscape:cy=\"482.63995\"\n"); + TRPRINT(tri," inkscape:document-units=\"px\"\n"); + TRPRINT(tri," inkscape:current-layer=\"layer1\"\n"); + TRPRINT(tri," showgrid=\"false\"\n"); + TRPRINT(tri," width=\"0px\"\n"); + TRPRINT(tri," height=\"0px\"\n"); + TRPRINT(tri," fit-margin-top=\"0\"\n"); + TRPRINT(tri," fit-margin-left=\"0\"\n"); + TRPRINT(tri," fit-margin-right=\"0\"\n"); + TRPRINT(tri," fit-margin-bottom=\"0\"\n"); + TRPRINT(tri," units=\"in\"\n"); + TRPRINT(tri," inkscape:window-width=\"1200\"\n"); + TRPRINT(tri," inkscape:window-height=\"675\"\n"); + TRPRINT(tri," inkscape:window-x=\"26\"\n"); + TRPRINT(tri," inkscape:window-y=\"51\"\n"); + TRPRINT(tri," inkscape:window-maximized=\"0\" />\n"); + TRPRINT(tri," <metadata\n"); + TRPRINT(tri," id=\"metadata4127\">\n"); + TRPRINT(tri," <rdf:RDF>\n"); + TRPRINT(tri," <cc:Work\n"); + TRPRINT(tri," rdf:about=\"\">\n"); + TRPRINT(tri," <dc:format>image/svg+xml</dc:format>\n"); + TRPRINT(tri," <dc:type\n"); + TRPRINT(tri," rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n"); + TRPRINT(tri," <dc:title></dc:title>\n"); + TRPRINT(tri," </cc:Work>\n"); + TRPRINT(tri," </rdf:RDF>\n"); + TRPRINT(tri," </metadata>\n"); + TRPRINT(tri," <g\n"); + TRPRINT(tri," inkscape:label=\"Layer 1\"\n"); + TRPRINT(tri," inkscape:groupmode=\"layer\"\n"); + TRPRINT(tri," id=\"layer1\"\n"); + TRPRINT(tri," transform=\"translate(0,0)\">\n"); + TRPRINT(tri,"\n"); +} + + +void flush_as_svg(TR_INFO *tri, FILE *fp){ + fwrite(tri->out,tri->outused,1,fp); +} + +FILE *close_as_svg(TR_INFO *tri, FILE *fp){ + TRPRINT(tri, " </g>\n"); + TRPRINT(tri, "</svg>\n"); + flush_as_svg(tri,fp); + fclose(fp); + return(NULL); +} + + +int main(int argc, char *argv[]){ + char *data; + char inbuf[MAXLINE]; + FILE *fpi = NULL; + FILE *fpo = NULL; + int op; + double fact = 1.0; /* input units to points */ + double escapement = 0.0; /* degrees */ + int lineno = 0; + int ok = 1; + int status; + TCHUNK_SPECS tsp; + TR_INFO *tri=NULL; + int flags=0; + char *infile; + uint32_t utmp32; + TRCOLORREF bkcolor; + int bkmode; + char *fontspec; + + infile=malloc(strlen(argv[1])+1); + strcpy(infile,argv[1]); + + if(argc < 2 || !(fpi = fopen(infile,"r"))){ + printf("Usage: text_reassemble input_file\n"); + printf(" Test program reads an input file containing lines like:\n"); + printf(" FONT:(font for next text)\n"); + printf(" ESC:(escapement angle degrees of text line, up from X axis)\n"); + printf(" ORI:(angle degrees of character orientation, up from X axis)\n"); + printf(" FS:(font size, units)\n"); + printf(" XY:(x,y) X 0 is at left, N is at right, Y 0 is at top, N is at bottom, as page is viewed.\n"); + printf(" TEXT:(UTF8 text)\n"); + printf(" ALN:combination of {LCR}{BLT} = Text is placed on {X,Y} at Left/Center/Right of text, at Bottom,baseLine,Top of text.\n"); + printf(" LDIR:{LR|RL|TB) Left to Right, Right to Left, and Top to Bottom \n"); + printf(" MUL:(float, multiplicative factor to convert FS,XY units to points).\n"); + printf(" ITA:(Italics, 0=normal, 100=italics, 110=oblique).\n"); + printf(" WGT:(Weight, 0-215: 80=normal, 200=bold, 215=ultrablack, 0=thin)).\n"); + printf(" DEC:(this is a bit field. For color see DCLR\n"); + printf(" style: 000 none, 001 underline,002 overline, 004 blink, 008 strike-through\n"); + printf(" line: 000 solid, 010 double, 020 dotted, 040 dashed, 080 wavy)\n"); + printf(" CND:(Condensed 50-200: 100=normal, 50=ultracondensed, 75=condensed, 200=expanded).\n"); + printf(" BKG:(Background color: 0 none, 1 by input fragment, 2 by assembled line, 3 by entire assembly. Use BCLR, THEN BKG) \n"); + printf(" CLR:(Text RGB color, as 6 HEX digits, like: FF0000 (red) or 0000FF (blue)) \n"); + printf(" DCLR:(Decoration color, specify like CLR, except 1000000 or higher disables.)\n"); + printf(" BCLR:(Background RGB color, specify like CLR.) \n"); + printf(" FLAG: Special processing options. 1 EMF compatible text alignment.\n"); + printf(" EMIT:(Process everything up to this point, then start clean for remaining input).\n"); + printf(" DONE:(no more input, process it).\n"); + printf(" # comment\n"); + printf("\n"); + printf(" The output is a summary of how the pieces are to be assembled into complex text.\n"); + printf("\n"); + printf(" egrep pattern: '^LOAD:|^FONT:|^ESC:|^ORI:|^FS:|^XY:|^TEXT:|^ALN:|^LDIR:|^MUL:|^ITA:|^WGT:|^DEC:|^CND:|^BKG:|^CLR:|^BCLR:|^DCLR:|^FLAG:|^EMIT:^DONE:'\n"); + exit(EXIT_FAILURE); + } + + tri = trinfo_init(tri); /* If it loops the trinfo_clear at the end will reset tri to the proper state, do NOT call trinfo_init twice! */ + +#ifdef DBG_LOOP + int ldx; + for(ldx=0;ldx<5;ldx++){ + if(fpi)fclose(fpi); + fpi = fopen(infile,"r"); +#endif + tsp.string = NULL; + tsp.ori = 0.0; /* degrees */ + tsp.fs = 12.0; /* font size */ + tsp.x = 0.0; + tsp.y = 0.0; + tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/ + tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ + tsp.taln = ALILEFT + ALIBASE; + tsp.ldir = LDIR_LR; + tsp.color.Red = tsp.decColor.Red = 0; /* RGBA Black */ + tsp.color.Green = tsp.decColor.Green = 0; /* RGBA Black */ + tsp.color.Blue = tsp.decColor.Blue = 0; /* RGBA Black */ + tsp.color.Reserved = tsp.decColor.Reserved = 0; /* unused */ + tsp.italics = 0; + tsp.weight = 80; + tsp.condensed = 100; + tsp.decoration = 0; /* none */ + tsp.co = 0; + tsp.fi_idx = -1; /* set to an invalid */ + tsp.rt_tidx = -1; /* set to an invalid */ + tsp.xkern = tsp.ykern = 0.0; + /* no need to set rt_tidx */ + + + + if(!tri){ + fprintf(stderr,"Fatal error, could not initialize data structures\n"); + exit(EXIT_FAILURE); + } + (void) trinfo_load_ft_opts(tri, 1, + FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, + FT_KERNING_UNSCALED); + + fpo=fopen("dump.svg","wb"); + init_as_svg(tri); + + while(ok){ + lineno++; + if(!fgets(inbuf,MAXLINE,fpi))boom("Unexpected end of file - no DONE:",lineno); + inbuf[strlen(inbuf)-1]='\0'; /* step on the EOL character */ + op = parseit(inbuf,&data); + switch(op){ + case OPCOM: /* ignore comments*/ + break; + case OPFONT: + /* If the font name includes "Narrow" condensed may not have been set */ + if(0<= TR_findcasesub(data, "Narrow")){ + tsp.co=1; + } + else { + tsp.co=0; + } + fontspec = TR_construct_fontspec(&tsp, data); + if((tsp.fi_idx = ftinfo_load_fontname(tri->fti, fontspec)) < 0 )boom("Font load failed",lineno); + free(fontspec); + break; + case OPESC: + if(1 != sscanf(data,"%lf",&escapement))boom("Invalid ESC:",lineno); + break; + case OPORI: + if(1 != sscanf(data,"%lf",&tsp.ori))boom("Invalid ORI:",lineno); + break; + case OPFS: + if(1 != sscanf(data,"%lf",&tsp.fs) || tsp.fs <= 0.0)boom("Invalid FS:",lineno); + tsp.fs *= fact; + break; + case OPXY: + if(2 != sscanf(data,"%lf,%lf",&tsp.x,&tsp.y) )boom("Invalid XY:",lineno); + tsp.x *= fact; + tsp.y *= fact; + break; + case OPTEXT: + tsp.string = (uint8_t *) U_strdup(data); + /* FreeType parameters match inkscape*/ + status = trinfo_load_textrec(tri, &tsp, escapement,flags); + if(status==-1){ // change of escapement, emit what we have and reset + TR_layout_analyze(tri); + TR_layout_2_svg(tri); + flush_as_svg(tri, fpo); + tri = trinfo_clear(tri); + if(trinfo_load_textrec(tri, &tsp, escapement,flags)){ boom("Text load failed",lineno); } + } + else if(status){ boom("Text load failed",lineno); } + break; + case OPALN: + tsp.taln=0; + switch (*data++){ + case 'L': tsp.taln |= ALILEFT; break; + case 'C': tsp.taln |= ALICENTER; break; + case 'R': tsp.taln |= ALIRIGHT; break; + default: boom("Invalid ALN:",lineno); + } + switch (*data++){ + case 'T': tsp.taln |= ALITOP; break; + case 'L': tsp.taln |= ALIBASE; break; + case 'B': tsp.taln |= ALIBOT; break; + default: boom("Invalid ALN:",lineno); + } + break; + case OPLDIR: + tsp.ldir=0; + if(0==strcmp("LR",data)){ tsp.ldir=LDIR_LR; break;} + if(0==strcmp("RL",data)){ tsp.ldir=LDIR_RL; break;} + if(0==strcmp("TB",data)){ tsp.ldir=LDIR_TB; break;} + boom("Invalid LDIR:",lineno); + break; + case OPMUL: + if(1 != sscanf(data,"%lf",&fact) || fact <= 0.0)boom("Invalid MUL:",lineno); + (void) trinfo_load_qe(tri,fact); + break; + case OPITA: + if(1 != sscanf(data,"%d",&tsp.italics) || tsp.italics < 0 || tsp.italics>110)boom("Invalid ITA:",lineno); + break; + case OPWGT: + if(1 != sscanf(data,"%d",&tsp.weight) || tsp.weight < 0 || tsp.weight > 215)boom("Invalid WGT:",lineno); + break; + case OPDEC: + if(1 != sscanf(data,"%X",(unsigned int *) &tsp.decoration))boom("Invalid DEC:",lineno); + break; + case OPCND: + if(1 != sscanf(data,"%d",&tsp.condensed) || tsp.condensed < 50 || tsp.condensed > 200)boom("Invalid CND:",lineno); + break; + case OPBKG: + if(1 != sscanf(data,"%d",&bkmode) )boom("Invalid BKG:",lineno); + (void) trinfo_load_bk(tri,bkmode,bkcolor); + break; + case OPCLR: + if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid CLR:",lineno); + tsp.color.Red = (utmp32 >> 16) & 0xFF; + tsp.color.Green = (utmp32 >> 8) & 0xFF; + tsp.color.Blue = (utmp32 >> 0) & 0xFF; + tsp.color.Reserved = 0; + break; + case OPDCLR: + if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid DCLR:",lineno); + if(utmp32 >= 0x1000000){ + tsp.decColor.Red = tsp.decColor.Green = tsp.decColor.Blue = tsp.decColor.Reserved = 0; + tsp.decoration &= ~TXTDECOR_CLRSET; + } + else { + tsp.decColor.Red = (utmp32 >> 16) & 0xFF; + tsp.decColor.Green = (utmp32 >> 8) & 0xFF; + tsp.decColor.Blue = (utmp32 >> 0) & 0xFF; + tsp.decColor.Reserved = 0; + tsp.decoration |= TXTDECOR_CLRSET; + } + break; + case OPBCLR: + if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid BCLR:",lineno); + bkcolor.Red = (utmp32 >> 16) & 0xFF; + bkcolor.Green = (utmp32 >> 8) & 0xFF; + bkcolor.Blue = (utmp32 >> 0) & 0xFF; + bkcolor.Reserved = 0; + break; + case OPFLAGS: + if(1 != sscanf(data,"%d",&flags) )boom("Invalid FLAG:",lineno); + break; + case OPEMIT: + TR_layout_analyze(tri); + TR_layout_2_svg(tri); + flush_as_svg(tri, fpo); + tri = trinfo_clear(tri); + break; + case OPDONE: + TR_layout_analyze(tri); + TR_layout_2_svg(tri); + flush_as_svg(tri, fpo); + tri = trinfo_clear(tri); + ok = 0; + break; + case OPOOPS: + default: + boom("Input line cannot be parsed",lineno); + break; + } + + } + + if(fpo){ + fpo=close_as_svg(tri, fpo); + } + + +#ifdef DBG_LOOP + tri = trinfo_clear(tri); + ok = 1; + } +#endif /* DBG_LOOP */ + + fclose(fpi); + tri = trinfo_release(tri); + free(infile); + + exit(EXIT_SUCCESS); +} +#endif /* TEST */ + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/text_reassemble.h b/src/extension/internal/text_reassemble.h new file mode 100644 index 000000000..d85b233be --- /dev/null +++ b/src/extension/internal/text_reassemble.h @@ -0,0 +1,386 @@ +/** + @file text_reassemble.h libTERE headers. + +See text_reassemble.c for notes + +File: text_reassemble.h +Version: 0.0.12 +Date: 14-MAY-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _TEXT_REASSEMBLE_ +#define _TEXT_REASSEMBLE_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <stdint.h> +#include <ctype.h> +#include <fontconfig/fontconfig.h> +#include <ft2build.h> +#include <iconv.h> +#include FT_FREETYPE_H +#include FT_GLYPH_H + +/** \cond */ +#define TEREMIN(A,B) (A < B ? A : B) +#define TEREMAX(A,B) (A > B ? A : B) + +#ifndef M_PI +# define M_PI 3.14159265358979323846 /* pi */ +#endif +#define ALLOCINFO_CHUNK 32 +#define ALLOCOUT_CHUNK 8192 +#define TRPRINT trinfo_append_out +/** \endcond */ + +/** \defgroup color background options + Text is underwritten with the background color not at all, + by reassembled line, or by full assembly . + @{ +*/ +#define BKCLR_NONE 0x00 /**< text is not underwritten with background color (default) */ +#define BKCLR_FRAG 0x01 /**< each fragment of text is underwritten with background color */ +#define BKCLR_LINE 0x02 /**< each line of text is underwritten with background color */ +#define BKCLR_ALL 0x03 /**< entire assembly is underwritten with background color */ +/** @} */ + +/** \defgroup decoration options + One of these values may be present in the decoration field. + Unused bits may be used by end user code. + These values are SVG specific. Other applications could use the text + decoration field for a different set of bits, so long as it provided its own + output function. + @{ +*/ +#define TXTDECOR_NONE 0x000 /**< text is not decorated (default) */ +#define TXTDECOR_UNDER 0x001 /**< underlined */ +#define TXTDECOR_OVER 0x002 /**< overlined */ +#define TXTDECOR_BLINK 0x004 /**< blinking text */ +#define TXTDECOR_STRIKE 0x008 /**< strike through */ +#define TXTDECOR_TMASK 0x00F /**< Mask for selecting bits above */ + +#define TXTDECOR_SOLID 0x000 /**< draw as single solid line */ +#define TXTDECOR_DOUBLE 0x010 /**< draw as double solid line */ +#define TXTDECOR_DOTTED 0x020 /**< draw as single dotted line */ +#define TXTDECOR_DASHED 0x040 /**< draw as single dashed line */ +#define TXTDECOR_WAVY 0x080 /**< draw as single wavy line */ +#define TXTDECOR_LMASK 0x0F0 /**< Mask for selecting these bits */ + +#define TXTDECOR_CLRSET 0x100 /**< decoration has its own color */ + +/** @} */ + + + + + +/** \defgroup text alignment types + Location of text's {X,Y} coordinate on bounding rectangle. + Values are compatible with Fontconfig. + @{ +*/ +#define ALILEFT 0x01 /**< text object horizontal alignment = left */ +#define ALICENTER 0x02 /**< text object horizontal alignment = center */ +#define ALIRIGHT 0x04 /**< text object horizontal alignment = right */ +#define ALIHORI 0x07 /**< text object horizontal alignment mask */ +#define ALITOP 0x08 /**< text object vertical alignment = top */ +#define ALIBASE 0x10 /**< text object vertical alignment = baseline */ +#define ALIBOT 0x20 /**< text object vertical alignment = bottom */ +#define ALIVERT 0x38 /**< text object vertical alignment mask */ +/** @} */ + +/** \defgroup language direction types + @{ +*/ +#define LDIR_LR 0x00 /**< left to right */ +#define LDIR_RL 0x01 /**< right to left */ +#define LDIR_TB 0x02 /**< top to bottom */ +/** @} */ + +/** \defgroup special processing flags + @{ +*/ +#define TR_EMFBOT 0x01 /**< use an approximation compatible with EMF file's "BOTTOM" text orientation, which is not the "bottom" for Freetype fonts */ +/** @} */ + +/** \enum tr_classes +classification of complexes + @{ +*/ +enum tr_classes { + TR_TEXT, /**< simple text object */ + TR_LINE, /**< linear assembly of TR_TEXTs */ + TR_PARA_UJ, /**< sequential assembly of TR_LINEs and TR_TEXTs into a paragraph - + unknown justification properties */ + TR_PARA_LJ, /**< ditto, left justified */ + TR_PARA_CJ, /**< ditto, center justified */ + TR_PARA_RJ /**< ditto, right justified */ + }; +/** @} */ + +/** + \brief alt font entries. +*/ +typedef struct { + uint32_t fi_idx; /**< index into FT_INFO fonts, for fonts added for missing glyphs */ + uint32_t weight; /**< integer weight for alt fonts, kept sorted into descending order */ +} ALT_SPECS; + +/** + \brief Information for a font instance. +*/ +typedef struct { + FcFontSet *fontset; /**< all matching fonts (for fallback on missing glyphs) */ + ALT_SPECS *alts; /**< index into FT_INFO fonts, for fonts added for missing glyphs */ + uint32_t space; /**< alts storage slots allocated */ + uint32_t used; /**< alts storage slots in use */ + FT_Face face; /**< font face structures (FT_FACE is a pointer!) */ + uint8_t *file; /**< pointer to font paths to files */ + uint8_t *fontspec; /**< pointer to a font specification (name:italics, etc.) */ + FcPattern *fpat; /**< current font, must hang onto this or faces operations break */ + double spcadv; /**< advance equal to a space, in points at font's face size */ + double fsize; /**< font's face size in points */ +} FNT_SPECS; + +/** + \brief Information for all font instances. +*/ +typedef struct { + FT_Library library; /**< Fontconfig handle */ + FNT_SPECS *fonts; /**< Array of fontinfo structures */ + uint32_t space; /**< storage slots allocated */ + uint32_t used; /**< storage slots in use */ +} FT_INFO; + +typedef struct { + uint8_t Red; //!< Red color (0-255) + uint8_t Green; //!< Green color (0-255) + uint8_t Blue; //!< Blue color (0-255) + uint8_t Reserved; //!< Not used +} TRCOLORREF; + +/** + \brief Information for a single text object +*/ +typedef struct { + uint8_t *string; /**< UTF-8 text */ + double ori; /**< Orientation, angle of characters with respect to baseline in degrees */ + double fs; /**< font size of text */ + double x; /**< x coordinate, relative to TR_INFO x,y, in points */ + double y; /**< y coordinate, relative to TR_INFO x,y, in points */ + double xkern; /**< x kern relative to preceding text chunk in complex (if any) */ + double ykern; /**< y kern relative to preceding text chunk in complex (if any) */ + double boff; /**< Y LL corner - boff finds baseline */ + double vadvance; /**< Line spacing typically 1.25 or 1.2, only set on the first text + element in a complex */ + TRCOLORREF color; /**< RGB */ + int taln; /**< text alignment with respect to x,y */ + int ldir; /**< language diretion LDIR_* */ + int italics; /**< italics, as in FontConfig */ + int weight; /**< weight, as in FontConfig */ + int condensed; /**< condensed, as in FontConfig */ + int decoration; /**< text decorations, ignored during assembly, used during output */ + TRCOLORREF decColor; /**< text decoration color, ignored during assembly, used during output */ + int co; /**< condensed override, if set Font name included narrow */ + int rt_tidx; /**< index of rectangle that contains it */ + int fi_idx; /**< index of the font it uses */ +} TCHUNK_SPECS; + +/** + \brief Information for all text objects. + Coordinates here are INTERNAL, after offset/rotate using values in TR_INFO. +*/ +typedef struct { + TCHUNK_SPECS *chunks; /**< text chunks */ + uint32_t space; /**< storage slots allocated */ + uint32_t used; /**< storage slots in use */ +} TP_INFO; + +/** + \brief Information for a single bounding rectangle. + Coordinates here are INTERNAL, after offset/rotate using values in TR_INFO. +*/ +typedef struct { + double xll; /**< x rectangle lower left corner */ + double yll; /**< y " */ + double xur; /**< x upper right corner */ + double yur; /**< y " */ + double xbearing; /**< x bearing of the leftmost character */ +} BRECT_SPECS; + +/** + \brief Information for all bounding rectangles. +*/ +typedef struct { + BRECT_SPECS *rects; /**< bounding rectangles */ + uint32_t space; /**< storage slots allocated */ + uint32_t used; /**< storage slots in use */ +} BR_INFO; + +/** + \brief List of all members of a single complex. +*/ +typedef struct { + int *members; /**< array of immediate children (for TR_PARA_* these are indicies + for TR_TEXT or TR_LINE complexes also in cxi. For TR_TEXT + and TR_LINE these are indices to the actual text in tpi.) */ + uint32_t space; /**< storage slots allocated */ + uint32_t used; /**< storage slots in use */ +} CHILD_SPECS; + +/** + \brief Information for a single complex. +*/ +typedef struct { + int rt_cidx; /**< index of rectangle that contains all members */ + enum tr_classes type; /**< classification of the complex */ + CHILD_SPECS kids; /**< immediate child nodes of this complex, for type TR_TEXT the + idx refers to the tpi data. otherwise, cxi data */ +} CX_SPECS; + +/** + \brief Information for all complexes. +*/ +typedef struct { + CX_SPECS *cx; /**< complexes */ + uint32_t space; /**< storage slots allocated */ + uint32_t used; /**< storage slots in use */ + uint32_t phase1; /**< Number of complexes (lines + text fragments) entered in phase 1 */ + uint32_t lines; /**< Number of lines in phase 1 */ + uint32_t paras; /**< Number of complexes (paras) entered in phase 2 */ +} CX_INFO; + +/** + \brief Information for the entire text reassembly system. +*/ +typedef struct { + FT_INFO *fti; /**< Font info storage */ + TP_INFO *tpi; /**< Text Info/Position Info storage */ + BR_INFO *bri; /**< Bounding Rectangle Info storage */ + CX_INFO *cxi; /**< Complex Info storage */ + uint8_t *out; /**< buffer to hold formatted output */ + double qe; /**< quantization error in points. */ + double esc; /**< escapement angle in DEGREES */ + double x; /**< x coordinate of first text object, in points */ + double y; /**< y coordinate of first text object, in points */ + int dirty; /**< 1 if text records are loaded */ + int use_kern; /**< 1 if kerning is used, 0 if not */ + int load_flags; /**< FT_LOAD_NO_SCALE or FT_LOAD_TARGET_NORMAL */ + int kern_mode; /**< FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED */ + uint32_t outspace; /**< storage in output buffer allocated */ + uint32_t outused; /**< storage in output buffer in use */ + int usebk; /**< On output write the background color under the text */ + TRCOLORREF bkcolor; /**< RGB background color */ +} TR_INFO; + +/* padding added to rectangles before overlap test */ +/** + \brief Information for one padding record. (Padding is added to bounding rectangles before overlap tests.) +*/ +typedef struct { + double up; /**< to top */ + double down; /**< to bottom */ + double left; /**< to left */ + double right; /**< to right */ +} RT_PAD; + +/** \cond */ +/* + iconv() has a funny cast on some older systems, on most recent ones + it is just char **. This tries to work around the issue. If you build this + on another funky system this code may need to be modified, or define ICONV_CAST + on the compile line(but it may be tricky). +*/ +#ifdef SOL8 +#define ICONV_CAST (const char **) +#endif //SOL8 +#if !defined(ICONV_CAST) +#define ICONV_CAST (char **) +#endif //ICONV_CAST +/** \endcond */ + +/* Prototypes */ +int TR_findcasesub(const char *string, const char *sub); +char *TR_construct_fontspec(const TCHUNK_SPECS *tsp, const char *fontname); +char *TR_reconstruct_fontspec(const char *fontspec, const char *fontname); +int TR_find_alternate_font(FT_INFO *fti, FNT_SPECS **efsp, uint32_t wc); +int TR_getadvance(FT_INFO *fti, FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int load_flags, int kern_mode, int *ymin, int *ymax); +int TR_getkern2(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int kern_mode); +int TR_kern_gap(FNT_SPECS *fsp, TCHUNK_SPECS *tsp, TCHUNK_SPECS *ptsp, int kern_mode); +void TR_rt_pad_set(RT_PAD *rt_pad, double up, double down, double left, double right); +double TR_baseline(TR_INFO *tri, int src, double *AscMax, double *DscMax); +int TR_check_set_vadvance(TR_INFO *tri, int src, int lines); +int TR_layout_analyze(TR_INFO *tri); +void TR_layout_2_svg(TR_INFO *tri); +int TR_weight_FC_to_SVG(int weight); + +FT_INFO *ftinfo_init(void); +int ftinfo_make_insertable(FT_INFO *fti); +int ftinfo_insert(FT_INFO *fti, FNT_SPECS *fsp); +FT_INFO *ftinfo_release(FT_INFO *fti); +FT_INFO *ftinfo_clear(FT_INFO *fti); +int ftinfo_find_loaded_by_spec(const FT_INFO *fti, const uint8_t *fname); +int ftinfo_find_loaded_by_src(const FT_INFO *fti, const uint8_t *filename); +int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec); +void ftinfo_dump(const FT_INFO *fti); + +int fsp_alts_make_insertable(FNT_SPECS *fsp); +int fsp_alts_insert(FNT_SPECS *fsp, uint32_t fi_idx); +int fsp_alts_weight(FNT_SPECS *fsp, uint32_t a_idx); + +int csp_make_insertable(CHILD_SPECS *csp); +int csp_insert(CHILD_SPECS *csp, int src); +int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src); +void csp_release(CHILD_SPECS *csp); +void csp_clear(CHILD_SPECS *csp); + +CX_INFO *cxinfo_init(void); +int cxinfo_make_insertable(CX_INFO *cxi); +int cxinfo_insert(CX_INFO *cxi, int src, int src_rt_idx, enum tr_classes type); +int cxinfo_append(CX_INFO *cxi, int src, enum tr_classes type); +int cxinfo_merge(CX_INFO *cxi, int dst, int src, enum tr_classes type); +int cxinfo_trim(CX_INFO *cxi); +CX_INFO *cxinfo_release(CX_INFO *cxi); +void cxinfo_dump(const TR_INFO *tri); + +TP_INFO *tpinfo_init(void); +int tpinfo_make_insertable(TP_INFO *tpi); +int tpinfo_insert(TP_INFO *tpi, const TCHUNK_SPECS *tsp); +TP_INFO *tpinfo_release(TP_INFO *tpi); + +BR_INFO *brinfo_init(void); +int brinfo_make_insertable(BR_INFO *bri); +int brinfo_insert(BR_INFO *bri, const BRECT_SPECS *element); +int brinfo_merge(BR_INFO *bri, int dst, int src); +enum tr_classes + brinfo_pp_alignment(const BR_INFO *bri, int dst, int src, double slop, enum tr_classes type); +int brinfo_overlap(const BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD *rp_src); +BR_INFO *brinfo_release(BR_INFO *bri); + +TR_INFO *trinfo_init(TR_INFO *tri); +TR_INFO *trinfo_release(TR_INFO *tri); +TR_INFO *trinfo_release_except_FC(TR_INFO *tri); +TR_INFO *trinfo_clear(TR_INFO *tri); +int trinfo_load_qe(TR_INFO *tri, double qe); +int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor); +int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode); +int trinfo_load_textrec(TR_INFO *tri, const TCHUNK_SPECS *tsp, double escapement, int flags); +int trinfo_check_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor); +int trinfo_append_out(TR_INFO *tri, const char *src); + +int is_mn_unicode(int test); + + +#ifdef __cplusplus +} +#endif +#endif /* _TEXT_REASSEMBLE_ */ diff --git a/src/extension/internal/uemf.c b/src/extension/internal/uemf.c new file mode 100644 index 000000000..b06990dbd --- /dev/null +++ b/src/extension/internal/uemf.c @@ -0,0 +1,5523 @@ +/** + @file uemf.c Functions for manipulating EMF files and structures. + + [U_EMR*]_set all take data and return a pointer to memory holding the constructed record. + The size of that record is also returned in recsize. + It is also in the second int32 in the record, but may have been byte swapped and so not usable. + If something goes wrong a NULL pointer is returned and recsize is set to 0. + + Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for + uninitialized data. + + Compile with "SOL8" defined for Solaris 8 or 9 (Sparc). +*/ + +/* +File: uemf.c +Version: 0.0.21 +Date: 20-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <iconv.h> +#include <wchar.h> +#include <errno.h> +#include <string.h> +#include <limits.h> // for INT_MAX, INT_MIN +#include <math.h> // for U_ROUND() +#include <stddef.h> /* for offsetof() macro */ +#if 0 +#include <windef.h> //Not actually used, looking for collisions +#include <winnt.h> //Not actually used, looking for collisions +#include <wingdi.h> //Not actually used, looking for collisions +#endif +#include "uemf.h" +/* one prototype from uemf_endian. Put it here because end user should never need to see it, sno +not in uemf.h or uemf_endian.h */ +void U_swap2(void *ul, unsigned int count); + +/** + \brief Look up the name of the EMR record by type. Returns U_EMR_INVALID if out of range. + + \return name of the EMR record, "U_EMR_INVALID" if out of range. + \param idx EMR record type. + +*/ +char *U_emr_names(unsigned int idx){ + if(idx<U_EMR_MIN || idx > U_EMR_MAX){ idx = 0; } + static char *U_WMR_NAMES[U_EMR_MAX+1]={ + "U_EMR_INVALID", + "U_EMR_HEADER", + "U_EMR_POLYBEZIER", + "U_EMR_POLYGON", + "U_EMR_POLYLINE", + "U_EMR_POLYBEZIERTO", + "U_EMR_POLYLINETO", + "U_EMR_POLYPOLYLINE", + "U_EMR_POLYPOLYGON", + "U_EMR_SETWINDOWEXTEX", + "U_EMR_SETWINDOWORGEX", + "U_EMR_SETVIEWPORTEXTEX", + "U_EMR_SETVIEWPORTORGEX", + "U_EMR_SETBRUSHORGEX", + "U_EMR_EOF", + "U_EMR_SETPIXELV", + "U_EMR_SETMAPPERFLAGS", + "U_EMR_SETMAPMODE", + "U_EMR_SETBKMODE", + "U_EMR_SETPOLYFILLMODE", + "U_EMR_SETROP2", + "U_EMR_SETSTRETCHBLTMODE", + "U_EMR_SETTEXTALIGN", + "U_EMR_SETCOLORADJUSTMENT", + "U_EMR_SETTEXTCOLOR", + "U_EMR_SETBKCOLOR", + "U_EMR_OFFSETCLIPRGN", + "U_EMR_MOVETOEX", + "U_EMR_SETMETARGN", + "U_EMR_EXCLUDECLIPRECT", + "U_EMR_INTERSECTCLIPRECT", + "U_EMR_SCALEVIEWPORTEXTEX", + "U_EMR_SCALEWINDOWEXTEX", + "U_EMR_SAVEDC", + "U_EMR_RESTOREDC", + "U_EMR_SETWORLDTRANSFORM", + "U_EMR_MODIFYWORLDTRANSFORM", + "U_EMR_SELECTOBJECT", + "U_EMR_CREATEPEN", + "U_EMR_CREATEBRUSHINDIRECT", + "U_EMR_DELETEOBJECT", + "U_EMR_ANGLEARC", + "U_EMR_ELLIPSE", + "U_EMR_RECTANGLE", + "U_EMR_ROUNDRECT", + "U_EMR_ARC", + "U_EMR_CHORD", + "U_EMR_PIE", + "U_EMR_SELECTPALETTE", + "U_EMR_CREATEPALETTE", + "U_EMR_SETPALETTEENTRIES", + "U_EMR_RESIZEPALETTE", + "U_EMR_REALIZEPALETTE", + "U_EMR_EXTFLOODFILL", + "U_EMR_LINETO", + "U_EMR_ARCTO", + "U_EMR_POLYDRAW", + "U_EMR_SETARCDIRECTION", + "U_EMR_SETMITERLIMIT", + "U_EMR_BEGINPATH", + "U_EMR_ENDPATH", + "U_EMR_CLOSEFIGURE", + "U_EMR_FILLPATH", + "U_EMR_STROKEANDFILLPATH", + "U_EMR_STROKEPATH", + "U_EMR_FLATTENPATH", + "U_EMR_WIDENPATH", + "U_EMR_SELECTCLIPPATH", + "U_EMR_ABORTPATH", + "U_EMR_UNDEF69", + "U_EMR_COMMENT", + "U_EMR_FILLRGN", + "U_EMR_FRAMERGN", + "U_EMR_INVERTRGN", + "U_EMR_PAINTRGN", + "U_EMR_EXTSELECTCLIPRGN", + "U_EMR_BITBLT", + "U_EMR_STRETCHBLT", + "U_EMR_MASKBLT", + "U_EMR_PLGBLT", + "U_EMR_SETDIBITSTODEVICE", + "U_EMR_STRETCHDIBITS", + "U_EMR_EXTCREATEFONTINDIRECTW", + "U_EMR_EXTTEXTOUTA", + "U_EMR_EXTTEXTOUTW", + "U_EMR_POLYBEZIER16", + "U_EMR_POLYGON16", + "U_EMR_POLYLINE16", + "U_EMR_POLYBEZIERTO16", + "U_EMR_POLYLINETO16", + "U_EMR_POLYPOLYLINE16", + "U_EMR_POLYPOLYGON16", + "U_EMR_POLYDRAW16", + "U_EMR_CREATEMONOBRUSH", + "U_EMR_CREATEDIBPATTERNBRUSHPT", + "U_EMR_EXTCREATEPEN", + "U_EMR_POLYTEXTOUTA", + "U_EMR_POLYTEXTOUTW", + "U_EMR_SETICMMODE", + "U_EMR_CREATECOLORSPACE", + "U_EMR_SETCOLORSPACE", + "U_EMR_DELETECOLORSPACE", + "U_EMR_GLSRECORD", + "U_EMR_GLSBOUNDEDRECORD", + "U_EMR_PIXELFORMAT", + "U_EMR_DRAWESCAPE", + "U_EMR_EXTESCAPE", + "U_EMR_UNDEF107", + "U_EMR_SMALLTEXTOUT", + "U_EMR_FORCEUFIMAPPING", + "U_EMR_NAMEDESCAPE", + "U_EMR_COLORCORRECTPALETTE", + "U_EMR_SETICMPROFILEA", + "U_EMR_SETICMPROFILEW", + "U_EMR_ALPHABLEND", + "U_EMR_SETLAYOUT", + "U_EMR_TRANSPARENTBLT", + "U_EMR_UNDEF117", + "U_EMR_GRADIENTFILL", + "U_EMR_SETLINKEDUFIS", + "U_EMR_SETTEXTJUSTIFICATION", + "U_EMR_COLORMATCHTOTARGETW", + "U_EMR_CREATECOLORSPACEW" + }; + return(U_WMR_NAMES[idx]); +} + + + +/* ********************************************************************************************** +These definitions are for code pieces that are used many times in the following implementation. These +definitions are not needed in end user code, so they are here rather than in uemf.h. +*********************************************************************************************** */ + +//! @cond + +// this one may also be used A=Msk,B=MskBmi and F=cbMsk +#define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \ + if(A){\ + if(!B)return(NULL); /* size is derived from U_BIMAPINFO, but NOT from its size field, go figure*/ \ + C = F;\ + D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \ + E = sizeof(U_BITMAPINFOHEADER) + 4 * get_real_color_count((const char *) &(B->bmiHeader)); /* bmiheader + colortable*/ \ + }\ + else { C = 0; D = 0; E=0; } + +// variable "off" must be declared in the function + +#define APPEND_PXBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR,C=cbBmi, D=Bmi, E=Px, F=cbImage, G=cbImage4 */ \ + if(C){\ + memcpy(A + off, D, C);\ + ((B *) A)->offBmiSrc = off;\ + ((B *) A)->cbBmiSrc = C;\ + off += C;\ + memcpy(A + off, E, F);\ + ((B *) A)->offBitsSrc = off;\ + ((B *) A)->cbBitsSrc = F;\ + if(G - F){ \ + off += F;\ + memset(A + off, 0, G - F); \ + }\ + }\ + else {\ + ((B *) A)->offBmiSrc = 0;\ + ((B *) A)->cbBmiSrc = 0;\ + ((B *) A)->offBitsSrc = 0;\ + ((B *) A)->cbBitsSrc = 0;\ + } + +// variable "off" must be declared in the function + +#define APPEND_MSKBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR*,C=cbMskBmi, D=MskBmi, E=Msk, F=cbMskImage, G=cbMskImage4 */ \ + if(C){\ + memcpy(A + off, D, C);\ + ((B *) A)->offBmiMask = off;\ + ((B *) A)->cbBmiMask = C;\ + off += C;\ + memcpy(A + off, Msk, F);\ + ((B *) A)->offBitsMask = off;\ + ((B *) A)->cbBitsMask = F;\ + if(G - F){ memset(A + off, 0, G - F); }\ + }\ + else {\ + ((B *) A)->offBmiMask = 0;\ + ((B *) A)->cbBmiMask = 0;\ + ((B *) A)->offBitsMask = 0;\ + ((B *) A)->cbBitsMask = 0;\ + } + +//! @endcond + +/* ********************************************************************************************** +These functions are used for development and debugging and should be be includied in production code. +*********************************************************************************************** */ + +/** + \brief Debugging utility, used with valgrind to find uninitialized values. Not for use in production code. + \param buf memory area to examine ! + \param size length in bytes of buf! +*/ +int memprobe( + const void *buf, + size_t size + ){ + int sum=0; + char *ptr=(char *)buf; + for(;size;size--,ptr++){ sum += *ptr; } // read all bytes, trigger valgrind warning if any uninitialized + return(sum); +} + +/** + \brief Dump an EMFHANDLES structure. Not for use in production code. + \param string Text to output before dumping eht structure + \param handle Handle + \param eht EMFHANDLES structure to dump +*/ +void dumpeht( + char *string, + unsigned int *handle, + EMFHANDLES *eht + ){ + uint32_t i; + printf("%s\n",string); + printf("sptr: %d peak: %d top: %d\n",eht->sptr,eht->peak,eht->top); + if(handle){ + printf("handle: %d \n",*handle); + } + for(i=0;i<=5;i++){ + printf("table[%d]: %d\n",i,eht->table[i]); + } + for(i=1;i<=5;i++){ + printf("stack[%d]: %d\n",i,eht->stack[i]); + } +} + +/* ********************************************************************************************** +These functions are used for Image conversions and other +utility operations. Character type conversions are in uemf_utf.c +*********************************************************************************************** */ + +/** + \brief Make up an approximate dx array to pass to emrtext_set(), based on character height and weight. + + Take abs. value of character height, get width by multiplying by 0.6, and correct weight + approximately, with formula (measured on screen for one text line of Arial). + Caller is responsible for free() on the returned pointer. + + \return pointer to dx array + \param height character height (absolute value will be used) + \param weight LF_Weight Enumeration (character weight) + \param members Number of entries to put into dx + +*/ +uint32_t *dx_set( + int32_t height, + uint32_t weight, + uint32_t members + ){ + uint32_t i, width, *dx; + dx = (uint32_t *) malloc(members * sizeof(uint32_t)); + if(dx){ + if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL; + width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904)); + for ( i = 0; i < members; i++ ){ dx[i] = width; } + } + return(dx); +} + +/** + \brief Look up the properties (a bit map) of a type of EMR record. + Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc.. + + \return bitmap of EMR record properties, or U_EMR_INVALID on error or release of all memory + \param type EMR record type. If U_EMR_INVALID release memory. (There is no U_EMR_INVALID EMR record type) + +*/ +uint32_t emr_properties(uint32_t type){ + static uint32_t *table=NULL; + uint32_t result = U_EMR_INVALID; // initialized to indicate an error (on a lookup) or nothing (on a memory release) + if(type == U_EMR_INVALID){ + if(table)free(table); + table=NULL; + } + else if(type>=1 && type<U_EMR_MAX){ + if(!table){ + table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_EMR_MAX)); + if(!table)return(result); + // 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01 + // Path properties (U_DRAW_*) TEXT ALTERS ONLYTO VISIBLE + // PATH FORCE CLOSED NOTEMPTY + table[ 0] = 0x00; // Does not map to any EMR record + table[ 1] = 0x80; // U_EMRHEADER 1 0 0 0 0 0 0 0 + table[ 2] = 0x83; // U_EMRPOLYBEZIER 1 0 0 0 0 0 1 1 + table[ 3] = 0x87; // U_EMRPOLYGON 1 0 0 0 0 1 1 1 + table[ 4] = 0x83; // U_EMRPOLYLINE 1 0 0 0 0 0 1 1 + table[ 5] = 0x8B; // U_EMRPOLYBEZIERTO 1 0 0 0 1 0 1 1 + table[ 6] = 0x8B; // U_EMRPOLYLINETO 1 0 0 0 1 0 1 1 + table[ 7] = 0x83; // U_EMRPOLYPOLYLINE 1 0 0 0 0 0 1 1 + table[ 8] = 0x87; // U_EMRPOLYPOLYGON 1 0 0 0 0 1 1 1 + table[ 9] = 0xA0; // U_EMRSETWINDOWEXTEX 1 0 1 0 0 0 0 0 + table[ 10] = 0xA0; // U_EMRSETWINDOWORGEX 1 0 1 0 0 0 0 0 + table[ 11] = 0xA0; // U_EMRSETVIEWPORTEXTEX 1 0 1 0 0 0 0 0 + table[ 12] = 0xA0; // U_EMRSETVIEWPORTORGEX 1 0 1 0 0 0 0 0 + table[ 13] = 0xA0; // U_EMRSETBRUSHORGEX 1 0 1 0 0 0 0 0 + table[ 14] = 0x82; // U_EMREOF 1 0 1 0 0 0 0 0 Force out any pending draw + table[ 15] = 0x82; // U_EMRSETPIXELV 1 0 0 0 0 0 1 0 + table[ 16] = 0xA0; // U_EMRSETMAPPERFLAGS 1 0 1 0 0 0 0 0 + table[ 17] = 0xA0; // U_EMRSETMAPMODE 1 0 1 0 0 0 0 0 + table[ 18] = 0x20; // U_EMRSETBKMODE 0 0 1 0 0 0 0 0 + table[ 19] = 0xA0; // U_EMRSETPOLYFILLMODE 1 0 1 0 0 0 0 0 + table[ 20] = 0xA0; // U_EMRSETROP2 1 0 1 0 0 0 0 0 + table[ 21] = 0xA0; // U_EMRSETSTRETCHBLTMODE 1 0 1 0 0 0 0 0 + table[ 22] = 0x20; // U_EMRSETTEXTALIGN 0 0 1 0 0 0 0 0 + table[ 23] = 0xA0; // U_EMRSETCOLORADJUSTMENT 1 0 1 0 0 0 0 0 + table[ 24] = 0x20; // U_EMRSETTEXTCOLOR 0 0 1 0 0 0 0 0 + table[ 25] = 0x20; // U_EMRSETBKCOLOR 0 0 1 0 0 0 0 0 + table[ 26] = 0xA0; // U_EMROFFSETCLIPRGN 1 0 1 0 0 0 0 0 + table[ 27] = 0x89; // U_EMRMOVETOEX 1 0 0 0 1 0 0 1 + table[ 28] = 0xA0; // U_EMRSETMETARGN 1 0 1 0 0 0 0 0 + table[ 29] = 0xA0; // U_EMREXCLUDECLIPRECT 1 0 1 0 0 0 0 0 + table[ 30] = 0xA0; // U_EMRINTERSECTCLIPRECT 1 0 1 0 0 0 0 0 + table[ 31] = 0xA0; // U_EMRSCALEVIEWPORTEXTEX 1 0 1 0 0 0 0 0 + table[ 32] = 0xA0; // U_EMRSCALEWINDOWEXTEX 1 0 1 0 0 0 0 0 + table[ 33] = 0xA0; // U_EMRSAVEDC 1 0 1 0 0 0 0 0 + table[ 34] = 0xA0; // U_EMRRESTOREDC 1 0 1 0 0 0 0 0 + table[ 35] = 0xA0; // U_EMRSETWORLDTRANSFORM 1 0 1 0 0 0 0 0 + table[ 36] = 0xA0; // U_EMRMODIFYWORLDTRANSFORM 1 0 1 0 0 0 0 0 + table[ 37] = 0x20; // U_EMRSELECTOBJECT 0 0 1 0 0 0 0 0 + table[ 38] = 0x20; // U_EMRCREATEPEN 0 0 1 0 0 0 0 0 + table[ 39] = 0x20; // U_EMRCREATEBRUSHINDIRECT 0 0 1 0 0 0 0 0 + table[ 40] = 0x20; // U_EMRDELETEOBJECT 0 0 1 0 0 0 0 0 + table[ 41] = 0x83; // U_EMRANGLEARC 1 0 0 0 0 0 1 1 + table[ 42] = 0x87; // U_EMRELLIPSE 1 0 0 0 0 1 1 1 + table[ 43] = 0x87; // U_EMRRECTANGLE 1 0 0 0 0 1 1 1 + table[ 44] = 0x87; // U_EMRROUNDRECT 1 0 0 0 0 1 1 1 + table[ 45] = 0x83; // U_EMRARC 1 0 0 0 0 0 1 1 + table[ 46] = 0x87; // U_EMRCHORD 1 0 0 0 0 1 1 1 + table[ 47] = 0x87; // U_EMRPIE 1 0 0 0 0 1 1 1 + table[ 48] = 0xA0; // U_EMRSELECTPALETTE 1 0 1 0 0 0 0 0 + table[ 49] = 0xA0; // U_EMRCREATEPALETTE 1 0 1 0 0 0 0 0 + table[ 50] = 0xA0; // U_EMRSETPALETTEENTRIES 1 0 1 0 0 0 0 0 + table[ 51] = 0xA0; // U_EMRRESIZEPALETTE 1 0 1 0 0 0 0 0 + table[ 52] = 0xA0; // U_EMRREALIZEPALETTE 1 0 1 0 0 0 0 0 + table[ 53] = 0x82; // U_EMREXTFLOODFILL 1 0 0 0 0 0 1 0 + table[ 54] = 0x8B; // U_EMRLINETO 1 0 0 0 1 0 1 1 + table[ 55] = 0x8B; // U_EMRARCTO 1 0 0 0 1 0 1 1 + table[ 56] = 0x83; // U_EMRPOLYDRAW 1 0 0 0 0 0 1 1 + table[ 57] = 0xA0; // U_EMRSETARCDIRECTION 1 0 1 0 0 0 0 0 + table[ 58] = 0xA0; // U_EMRSETMITERLIMIT 1 0 1 0 0 0 0 0 + table[ 59] = 0xE0; // U_EMRBEGINPATH 1 1 1 0 0 0 0 0 + table[ 60] = 0x80; // U_EMRENDPATH 1 0 0 0 0 0 0 0 + table[ 61] = 0x84; // U_EMRCLOSEFIGURE 1 0 0 0 0 1 0 0 + table[ 62] = 0x94; // U_EMRFILLPATH 1 0 0 1 0 1 0 0 + table[ 63] = 0x94; // U_EMRSTROKEANDFILLPATH 1 0 0 1 0 1 0 0 + table[ 64] = 0x90; // U_EMRSTROKEPATH 1 0 0 1 0 0 0 0 + table[ 65] = 0xA0; // U_EMRFLATTENPATH 1 0 1 0 0 0 0 0 + table[ 66] = 0xA0; // U_EMRWIDENPATH 1 0 1 0 0 0 0 0 + table[ 67] = 0xA0; // U_EMRSELECTCLIPPATH 1 0 1 0 0 0 0 0 + table[ 68] = 0xA0; // U_EMRABORTPATH 1 0 1 0 0 0 0 0 + table[ 69] = 0xA0; // U_EMRUNDEF69 1 0 1 0 0 0 0 0 + table[ 70] = 0x00; // U_EMRCOMMENT 0 0 0 0 0 0 0 0 + table[ 71] = 0x82; // U_EMRFILLRGN 1 0 0 0 0 0 1 0 + table[ 72] = 0x82; // U_EMRFRAMERGN 1 0 0 0 0 0 1 0 + table[ 73] = 0x82; // U_EMRINVERTRGN 1 0 0 0 0 0 1 0 + table[ 74] = 0x82; // U_EMRPAINTRGN 1 0 0 0 0 0 1 0 + table[ 75] = 0xA0; // U_EMREXTSELECTCLIPRGN 1 0 1 0 0 0 0 0 + table[ 76] = 0x82; // U_EMRBITBLT 1 0 0 0 0 0 1 0 + table[ 77] = 0x82; // U_EMRSTRETCHBLT 1 0 0 0 0 0 1 0 + table[ 78] = 0x82; // U_EMRMASKBLT 1 0 0 0 0 0 1 0 + table[ 79] = 0x82; // U_EMRPLGBLT 1 0 0 0 0 0 1 0 + table[ 80] = 0xA0; // U_EMRSETDIBITSTODEVICE 1 0 1 0 0 0 0 0 + table[ 81] = 0xA0; // U_EMRSTRETCHDIBITS 1 0 1 0 0 0 0 0 + table[ 82] = 0x20; // U_EMREXTCREATEFONTINDIRECTW 0 0 1 0 0 0 0 0 + table[ 83] = 0x02; // U_EMREXTTEXTOUTA 0 0 0 0 0 0 1 0 + table[ 84] = 0x02; // U_EMREXTTEXTOUTW 0 0 0 0 0 0 1 0 + table[ 85] = 0x83; // U_EMRPOLYBEZIER16 1 0 0 0 0 0 1 1 + table[ 86] = 0x83; // U_EMRPOLYGON16 1 0 0 0 0 0 1 1 + table[ 87] = 0x83; // U_EMRPOLYLINE16 1 0 0 0 0 0 1 1 + table[ 88] = 0x8B; // U_EMRPOLYBEZIERTO16 1 0 0 0 1 0 1 1 + table[ 89] = 0x8B; // U_EMRPOLYLINETO16 1 0 0 0 1 0 1 1 + table[ 90] = 0x83; // U_EMRPOLYPOLYLINE16 1 0 0 0 0 0 1 1 + table[ 91] = 0x87; // U_EMRPOLYPOLYGON16 1 0 0 0 0 1 1 1 + table[ 92] = 0x83; // U_EMRPOLYDRAW16 1 0 0 0 0 0 1 1 + table[ 93] = 0x80; // U_EMRCREATEMONOBRUSH 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions + table[ 94] = 0x80; // U_EMRCREATEDIBPATTERNBRUSHPT 1 0 0 0 0 0 0 0 " + table[ 95] = 0x00; // U_EMREXTCREATEPEN 0 0 0 0 0 0 0 0 " + table[ 96] = 0x02; // U_EMRPOLYTEXTOUTA 0 0 0 0 0 0 1 0 + table[ 97] = 0x02; // U_EMRPOLYTEXTOUTW 0 0 0 0 0 0 1 0 + table[ 98] = 0xA0; // U_EMRSETICMMODE 1 0 1 0 0 0 0 0 + table[ 99] = 0xA0; // U_EMRCREATECOLORSPACE 1 0 1 0 0 0 0 0 + table[100] = 0xA0; // U_EMRSETCOLORSPACE 1 0 1 0 0 0 0 0 + table[101] = 0xA0; // U_EMRDELETECOLORSPACE 1 0 1 0 0 0 0 0 + table[102] = 0xA0; // U_EMRGLSRECORD 1 0 1 0 0 0 0 0 + table[103] = 0xA0; // U_EMRGLSBOUNDEDRECORD 1 0 1 0 0 0 0 0 + table[104] = 0xA0; // U_EMRPIXELFORMAT 1 0 1 0 0 0 0 0 + table[105] = 0xA0; // U_EMRDRAWESCAPE 1 0 1 0 0 0 0 0 + table[106] = 0xA0; // U_EMREXTESCAPE 1 0 1 0 0 0 0 0 + table[107] = 0xA0; // U_EMRUNDEF107 1 0 1 0 0 0 0 0 + table[108] = 0x02; // U_EMRSMALLTEXTOUT 0 0 0 0 0 0 1 0 + table[109] = 0xA0; // U_EMRFORCEUFIMAPPING 1 0 1 0 0 0 0 0 + table[110] = 0xA0; // U_EMRNAMEDESCAPE 1 0 1 0 0 0 0 0 + table[111] = 0xA0; // U_EMRCOLORCORRECTPALETTE 1 0 1 0 0 0 0 0 + table[112] = 0xA0; // U_EMRSETICMPROFILEA 1 0 1 0 0 0 0 0 + table[113] = 0xA0; // U_EMRSETICMPROFILEW 1 0 1 0 0 0 0 0 + table[114] = 0x82; // U_EMRALPHABLEND 1 0 0 0 0 0 1 0 + table[115] = 0xA0; // U_EMRSETLAYOUT 1 0 1 0 0 0 0 0 + table[116] = 0x82; // U_EMRTRANSPARENTBLT 1 0 0 0 0 0 1 0 + table[117] = 0xA0; // U_EMRUNDEF117 1 0 1 0 0 0 0 0 + table[118] = 0x82; // U_EMRGRADIENTFILL 1 0 0 0 0 0 1 0 + table[119] = 0xA0; // U_EMRSETLINKEDUFIS 1 0 1 0 0 0 0 0 + table[120] = 0x20; // U_EMRSETTEXTJUSTIFICATION 0 0 1 0 0 0 0 0 + table[121] = 0xA0; // U_EMRCOLORMATCHTOTARGETW 1 0 1 0 0 0 0 0 + table[122] = 0xA0; // U_EMRCREATECOLORSPACEW 1 0 1 0 0 0 0 0 + } + result = table[type]; + } + return(result); +} + +/** + \brief Derive from bounding rect, start and end radials, for arc, chord, or pie, the center, start, and end points, and the bounding rectangle. + + \return 0 on success, other values on errors. + \param rclBox bounding rectangle + \param ArcStart start of arc + \param ArcEnd end of arc + \param f1 1 if rotation angle >= 180, else 0 + \param f2 Rotation direction, 1 if counter clockwise, else 0 + \param center Center coordinates + \param start Start coordinates (point on the ellipse defined by rect) + \param end End coordinates (point on the ellipse defined by rect) + \param size W,H of the x,y axes of the bounding rectangle. +*/ +int emr_arc_points_common( + PU_RECTL rclBox, + PU_POINTL ArcStart, + PU_POINTL ArcEnd, + int *f1, + int f2, + PU_PAIRF center, + PU_PAIRF start, + PU_PAIRF end, + PU_PAIRF size + ){ + U_PAIRF estart; // EMF start position, defines a radial + U_PAIRF eend; // EMF end position, defines a radial + U_PAIRF vec_estart; // define a unit vector from the center to estart + U_PAIRF vec_eend; // define a unit vector from the center to eend + U_PAIRF radii; // x,y radii of ellipse + U_PAIRF ratio; // intermediate value + float scale, cross; + center->x = ((float)(rclBox->left + rclBox->right ))/2.0; + center->y = ((float)(rclBox->top + rclBox->bottom))/2.0; + size->x = (float)(rclBox->right - rclBox->left ); + size->y = (float)(rclBox->bottom - rclBox->top ); + estart.x = (float)(ArcStart->x); + estart.y = (float)(ArcStart->y); + eend.x = (float)(ArcEnd->x); + eend.y = (float)(ArcEnd->y); + radii.x = size->x/2.0; + radii.y = size->y/2.0; + + vec_estart.x = (estart.x - center->x); // initial vector, not unit length + vec_estart.y = (estart.y - center->y); + scale = sqrt(vec_estart.x*vec_estart.x + vec_estart.y*vec_estart.y); + if(!scale)return(1); // bogus record, has start at center + vec_estart.x /= scale; // now a unit vector + vec_estart.y /= scale; + + vec_eend.x = (eend.x - center->x); // initial vector, not unit length + vec_eend.y = (eend.y - center->y); + scale = sqrt(vec_eend.x*vec_eend.x + vec_eend.y*vec_eend.y); + if(!scale)return(2); // bogus record, has end at center + vec_eend.x /= scale; // now a unit vector + vec_eend.y /= scale; + + + // Find the intersection of the vectors with the ellipse. With no loss of generality + // we can translate the ellipse to the origin, then we just need to find tu (t a factor, u the unit vector) + // that also satisfies (x/Rx)^2 + (y/Ry)^2 = 1. x is t*(ux), y is t*(uy), where ux,uy are the x,y components + // of the unit vector. Substituting gives: + // (t*(ux)/Rx)^2 + (t*(uy)/Ry)^2 = 1 + // t^2 = 1/( (ux/Rx)^2 + (uy/Ry)^2 ) + // t = sqrt(1/( (ux/Rx)^2 + (uy/Ry)^2 )) + + ratio.x = vec_estart.x/radii.x; + ratio.y = vec_estart.y/radii.y; + ratio.x *= ratio.x; // we only use the square + ratio.y *= ratio.y; + scale = 1.0/sqrt(ratio.x + ratio.y); + start->x = center->x + scale * vec_estart.x; + start->y = center->y + scale * vec_estart.y; + + ratio.x = vec_eend.x/radii.x; + ratio.y = vec_eend.y/radii.y; + ratio.x *= ratio.x; // we only use the square + ratio.y *= ratio.y; + scale = 1.0/sqrt(ratio.x + ratio.y); + end->x = center->x + scale * vec_eend.x; + end->y = center->y + scale * vec_eend.y; + + //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation + //and the two unit vectors. + + cross = vec_estart.x * vec_eend.y - vec_estart.y * vec_eend.x; + if(!f2){ // counter clockwise rotation + if(cross >=0){ *f1 = 1; } + else { *f1 = 0; } + } + else { + if(cross >=0){ *f1 = 0; } + else { *f1 = 1; } + } + + + return(0); +} + +/** + \brief Derive from an EMF arc, chord, or pie the center, start, and end points, and the bounding rectangle. + + \return 0 on success, other values on errors. + \param record U_EMRPIE, U_EMRCHORD, or _EMRARC record + \param f1 1 if rotation angle >= 180, else 0 + \param f2 Rotation direction, 1 if counter clockwise, else 0 + \param center Center coordinates + \param start Start coordinates (point on the ellipse defined by rect) + \param end End coordinates (point on the ellipse defined by rect) + \param size W,H of the x,y axes of the bounding rectangle. +*/ +int emr_arc_points( + PU_ENHMETARECORD record, + int *f1, + int f2, + PU_PAIRF center, + PU_PAIRF start, + PU_PAIRF end, + PU_PAIRF size + ){ + PU_EMRARC pEmr = (PU_EMRARC) (record); + return emr_arc_points_common(&(pEmr->rclBox), &(pEmr->ptlStart), &(pEmr->ptlEnd), f1, f2, center, start, end, size ); +} + +/** + \brief Convert a U_RGBA 32 bit pixmap to one of many different types of DIB pixmaps. + + Conversions to formats using color tables assume that the color table can hold every color + in the input image. If that assumption is false then the conversion will fail. Conversion + from 8 bit color to N bit colors (N<8) do so by shifting the appropriate number of bits. + + \return 0 on success, other values on errors. + \param px DIB pixel array + \param cbPx DIB pixel array size in bytes + \param ct DIB color table + \param numCt DIB color table number of entries + \param rgba_px U_RGBA pixel array (32 bits) + \param w Width of pixel array + \param h Height of pixel array + \param stride Row stride of input pixel array in bytes + \param colortype DIB BitCount Enumeration + \param use_ct If true use color table (only for 1-16 bit DIBs) + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int RGBA_to_DIB( + char **px, + uint32_t *cbPx, + PU_RGBQUAD *ct, + int *numCt, + const char *rgba_px, + int w, + int h, + int stride, + uint32_t colortype, + int use_ct, + int invert + ){ + int bs; + int pad; + int i,j,k; + int istart, iend, iinc; + uint8_t r,g,b,a,tmp8; + char *pxptr; + const char *rptr; + int found; + int usedbytes; + U_RGBQUAD color; + PU_RGBQUAD lct; + int32_t index; + + *px=NULL; + *ct=NULL; + *numCt=0; + *cbPx=0; + // sanity checking + if(!w || !h || !stride || !colortype || !rgba_px)return(1); + if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels + if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit + + bs = colortype/8; + if(bs<1){ + bs=1; + usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = w*bs; + } + pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.; + *cbPx = h * (usedbytes + pad); // Rows must start on a 4 byte boundary! + *px = (char *) malloc(*cbPx); + if(!px)return(4); + if(use_ct){ + *numCt = 1<< colortype; + if(*numCt >w*h)*numCt=w*h; + lct = (PU_RGBQUAD) malloc(*numCt * sizeof(U_RGBQUAD)); + if(!lct)return(5); + *ct = lct; + } + + if(invert){ + istart = h-1; + iend = -1; + iinc = -1; + } + else { + istart = 0; + iend = h; + iinc = 1; + } + + found = 0; + tmp8 = 0; + pxptr = *px; + for(i=istart; i!=iend; i+=iinc){ + rptr= rgba_px + i*stride; + for(j=0; j<w; j++){ + r = *rptr++; + g = *rptr++; + b = *rptr++; + a = *rptr++; + if(use_ct){ + color = U_BGRA(r,g,b,a); // color has order in memory: b,g,r,a + index = -1; + for(lct = *ct, k=0; k<found; k++,lct++){ // Is this color in the table (VERY inefficient if there are a lot of colors!!!) + if(*(uint32_t *)lct != *(uint32_t *) &color)continue; + index =k; + break; + } + if(index==-1){ // add a color + found++; + if(found > *numCt){ // More colors found than are supported by the color table + free(*ct); + free(*px); + *numCt=0; + *cbPx=0; + return(6); + } + index = found - 1; + *lct = color; + } + switch(colortype){ + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + tmp8 = tmp8 >> 1; // This seems wrong, as it fills from the top of each byte. But it works. + tmp8 |= index << 7; + if(!((j+1) % 8)){ + *pxptr++ = tmp8; + tmp8 = 0; + } + break; + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + tmp8 = tmp8 << 4; + tmp8 |= index; + if(!((j+1) % 2)){ + *pxptr++ = tmp8; + tmp8 = 0; + } + break; + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + tmp8 = index; + *pxptr++ = tmp8; + break; + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + } + else { + switch(colortype){ + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + b /= 8; g /= 8; r /= 8; + // Do it in this way so that the bytes are always stored Little Endian + tmp8 = b; + tmp8 |= g<<5; // least significant 3 bits of green + *pxptr++ = tmp8; + tmp8 = g>>3; // most significant 2 bits of green (there are only 5 bits of data) + tmp8 |= r<<2; + *pxptr++ = tmp8; + break; + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + *pxptr++ = b; + *pxptr++ = g; + *pxptr++ = r; + break; + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + *pxptr++ = b; + *pxptr++ = g; + *pxptr++ = r; + *pxptr++ = a; + break; + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + } + } + if( use_ct && colortype == U_BCBM_MONOCHROME && (j % 8) ){ + *pxptr++ = tmp8; // Write last few indices + tmp8 = 0; + } + if( use_ct && colortype == U_BCBM_COLOR4 && (j % 2) ){ + *pxptr++ = tmp8; // Write last few indices + tmp8 = 0; + } + if(pad){ + memset(pxptr,0,pad); // not strictly necessary, but set all bytes so that we can find important unset ones with valgrind + pxptr += pad; + } + } + return(0); +} + +/** + \brief Get the actual number of colors in the color table from the BitMapInfoHeader. + BitmapInfoHeader may list 0 for some types which implies the maximum value. + If the image is big enough, that is set by the bit count, as in 256 for an 8 + bit image. + If the image is smaller it is set by width * height. + Note, this may be called by WMF code, so it is not safe to assume the data is aligned. + + \return Number of entries in the color table. + \param Bmih char * pointer to the U_BITMAPINFOHEADER +*/ +int get_real_color_count( + const char *Bmih + ){ + int Colors, BitCount, Width, Height; + uint32_t utmp4; + uint16_t utmp2; + int32_t tmp4; + char *cBmih = (char *) Bmih; + memcpy(&utmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); Colors = utmp4; + memcpy(&utmp2, cBmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2); BitCount = utmp2; + memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biWidth), 4); Width = tmp4; + memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); Height = tmp4; + return(get_real_color_icount(Colors, BitCount, Width, Height)); +} + +/** + \brief Get the actual number of colors in the color table from the ClrUsed, BitCount, Width, and Height. + BitmapInfoHeader may list 0 for some types which implies the maximum value. + If the image is big enough, that is set by the bit count, as in 256 for an 8 + bit image. + If the image is smaller it is set by width * height. + + \return Number of entries in the color table. + \param PU_BITMAPINFOHEADER pointer to to the U_BITMAPINFOHEADER +*/ +int get_real_color_icount( + int Colors, + int BitCount, + int Width, + int Height + ){ + int area = Width * Height; + if(area < 0){ area = -area; } /* Height might be negative */ + if(Colors == 0){ + if( BitCount == U_BCBM_MONOCHROME){ Colors = 2; } + else if(BitCount == U_BCBM_COLOR4 ){ Colors = 16; } + else if(BitCount == U_BCBM_COLOR8 ){ Colors = 256; } + if(Colors > area){ Colors = area; } + } + return(Colors); +} + + +/** + \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA() + + \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid. + \param pEmr pointer to EMR record that has a U_BITMAPINFO and bitmap + \param offBitsSrc Offset to the bitmap + \param offBmiSrc Offset to the U_BITMAPINFO + \param px pointer to DIB pixel array in pEmr + \param ct pointer to DIB color table in pEmr + \param numCt DIB color table number of entries, for PNG or JPG returns the number of bytes in the image + \param width Width of pixel array + \param height Height of pixel array (always returned as a positive number) + \param colortype DIB BitCount Enumeration + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int get_DIB_params( + void *pEmr, + uint32_t offBitsSrc, + uint32_t offBmiSrc, + const char **px, + const U_RGBQUAD **ct, + uint32_t *numCt, + uint32_t *width, + uint32_t *height, + uint32_t *colortype, + uint32_t *invert + ){ + uint32_t bic; + PU_BITMAPINFO Bmi = (PU_BITMAPINFO)((char *)pEmr + offBmiSrc); + PU_BITMAPINFOHEADER Bmih = &(Bmi->bmiHeader); + /* if biCompression is not U_BI_RGB some or all of the following might not hold real values */ + bic = Bmih->biCompression; + *width = Bmih->biWidth; + *colortype = Bmih->biBitCount; + if(Bmih->biHeight < 0){ + *height = -Bmih->biHeight; + *invert = 1; + } + else { + *height = Bmih->biHeight; + *invert = 0; + } + if(bic == U_BI_RGB){ + *numCt = get_real_color_count((const char *) Bmih); + if( numCt){ *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); } + else { *ct = NULL; } + } + else { + *numCt = Bmih->biSizeImage; + *ct = NULL; + } + *px = (char *)((char *)pEmr + offBitsSrc); + return(bic); +} + +/** + \brief Convert one of many different types of DIB pixmaps to an RGBA 32 bit pixmap. + + \return 0 on success, other values on errors. + \param px DIB pixel array + \param ct DIB color table + \param numCt DIB color table number of entries + \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free. + \param w Width of pixel array in the record + \param h Height of pixel array in the record + \param colortype DIB BitCount Enumeration + \param use_ct Kept for symmetry with RGBA_to_DIB, should be set to numCt + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int DIB_to_RGBA( + const char *px, + const U_RGBQUAD *ct, + int numCt, + char **rgba_px, + int w, + int h, + uint32_t colortype, + int use_ct, + int invert + ){ + uint32_t cbRgba_px; + int stride; + int bs; + int pad; + int i,j; + int istart, iend, iinc; + uint8_t r,g,b,a,tmp8; + const char *pxptr; + char *rptr; + int usedbytes; + U_RGBQUAD color; + int32_t index; + + // sanity checking + if(!w || !h || !colortype || !px)return(1); + if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels + if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit + if(use_ct && !numCt)return(4); //color table not adequately described + + stride = w * 4; + cbRgba_px = stride * h; + bs = colortype/8; + if(bs<1){ + bs=1; + usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = w*bs; + } + pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.; + *rgba_px = (char *) malloc(cbRgba_px); + if(!rgba_px)return(4); + + if(invert){ + istart = h-1; + iend = -1; + iinc = -1; + } + else { + istart = 0; + iend = h; + iinc = 1; + } + + pxptr = px; + tmp8 = 0; // silences a compiler warning, tmp8 always sets when j=0, so never used uninitialized + for(i=istart; i!=iend; i+=iinc){ + rptr= *rgba_px + i*stride; + for(j=0; j<w; j++){ + if(use_ct){ + switch(colortype){ + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + if(!(j % 8)){ tmp8 = *pxptr++; } + index = 0x80 & tmp8; // This seems wrong, as lowest position is top bit, but it works. + index = index >> 7; + tmp8 = tmp8 << 1; + break; + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + if(!(j % 2)){ tmp8 = *pxptr++; } + index = 0xF0 & tmp8; + index = index >> 4; + tmp8 = tmp8 << 4; + break; + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + index = (uint8_t) *pxptr++;; + break; + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + color = ct[index]; + b = U_BGRAGetB(color); + g = U_BGRAGetG(color); + r = U_BGRAGetR(color); + a = U_BGRAGetA(color); + } + else { + switch(colortype){ + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + // Do it in this way because the bytes are always stored Little Endian + tmp8 = *pxptr++; + b = (0x1F & tmp8) <<3; // 5 bits of b into the top 5 of 8 + g = tmp8 >> 5; // least significant 3 bits of green + tmp8 = *pxptr++; + r = (0x7C & tmp8) << 1; // 5 bits of r into the top 5 of 8 + g |= (0x3 & tmp8) << 3; // most significant 2 bits of green (there are only 5 bits of data) + g = g << 3; // restore intensity (have lost 3 bits of accuracy) + a = 0; + break; + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + b = *pxptr++; + g = *pxptr++; + r = *pxptr++; + a = 0; + break; + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + b = *pxptr++; + g = *pxptr++; + r = *pxptr++; + a = *pxptr++; + break; + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + } + *rptr++ = r; + *rptr++ = g; + *rptr++ = b; + *rptr++ = a; + } + for(j=0; j<pad; j++){ pxptr++; } // DIB rows are all 4 byte aligned + } + return(0); +} + +/** + \brief Extract a subset of an RGBA bitmap array. + Frees the incoming bitmap array IF a subset is extracted, otherwise it is left alone. + If the entire array is extracted it just returns the incoming pointer. + If the subset requested is partially outside of the bitmap the region is clipped to the + bitmap boundaries and extracted. This seems to be a (very) grey area in EMF files, and + even different Microsoft applications do not always do the same thing. For instance, + XP Preview gives some different images for EMR_BITBLT records than does the "import image" + (but not unpacked) view in PowerPoint. Since all of these states are probably best viewed + as undefined or errors we can only try to do something reasonable and not blow up when + encountering one. + + \return Pointer to the sub array on success, NULL otherwise. + \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free. + \param w Width of pixel array in the record + \param h Height of pixel array in the record + \param sl start left position in the pixel array in the record to start extracting + \param st start top position in the pixel array in the record to start extracting + \param eew Width of pixel array to extract + \param eeh Height of pixel array to extract +*/ +char *RGBA_to_RGBA( + char *rgba_px, + int w, + int h, + int sl, + int st, + int *eew, + int *eeh + ){ + int i; + char *sub; + char *sptr; + int ew = *eew; + int eh = *eeh; + + // sanity checking + if(w<=0 || h<=0 || ew<=0 || eh<=0 || !rgba_px)return(NULL); + + if(sl>w || st >h)return(NULL); // This is hopeless, the start point is outside of the array. + if(sl<0){ + if(sl+ew<=0)return(NULL); // This is hopeless, the start point is outside of the array. + ew += sl; + sl = 0; + } + if(st<0){ + if(st+eh<=0)return(NULL); // This is hopeless, the start point is outside of the array. + eh += st; + st = 0; + } + if(sl+ew > w)ew=w-sl; + if(st+eh > h)eh=h-st; + if(!sl && !st && (ew == w) && (eh == h)){ + sub = rgba_px; + } + else { + sptr = sub = malloc(ew*eh*4); + if(!sub)return(NULL); + for(i=st; i<st+eh; i++){ + memcpy(sptr,rgba_px + i*w*4 + sl*4,4*ew); + sptr += 4*ew; + } + free(rgba_px); + } + *eeh = eh; + *eew = ew; + return(sub); + } + + +/* ********************************************************************************************** +These functions are for setting up, appending to, and then tearing down an EMF structure, including +writing the final data structure out to a file. +*********************************************************************************************** */ + +/** + \brief Duplicate an EMR record. + \param emr record to duplicate +*/ +char *emr_dup( + const char *emr + ){ + char *dup; + int irecsize; + + if(!emr)return(NULL); + irecsize = ((PU_EMR)emr)->nSize; + dup=malloc(irecsize); + if(dup){ memcpy(dup,emr,irecsize); } + return(dup); +} + + +/** + \brief Start constructing an emf in memory. Supply the file name and initial size. + \return 0 for success, >=0 for failure. + \param name EMF filename (will be opened) + \param initsize Initialize EMF in memory to hold this many bytes + \param chunksize When needed increase EMF in memory by this number of bytes + \param et EMF in memory + + +*/ +int emf_start( + const char *name, + const uint32_t initsize, + const uint32_t chunksize, + EMFTRACK **et + ){ + FILE *fp; + EMFTRACK *etl=NULL; + + if(initsize < 1)return(1); + if(chunksize < 1)return(2); + if(!name)return(3); + etl = (EMFTRACK *) malloc(sizeof(EMFTRACK)); + if(!etl)return(4); + etl->buf = malloc(initsize); // no need to zero the memory + if(!etl->buf){ + free(etl); + return(5); + } + fp=emf_fopen(name,U_WRITE); + if(!fp){ + free(etl->buf); + free(etl); + return(6); + } + etl->fp = fp; + etl->allocated = initsize; + etl->used = 0; + etl->records = 0; + etl->PalEntries = 0; + etl->chunk = chunksize; + *et=etl; + return(0); +} + +/** + \brief Finalize the emf in memory and write it to the file. + \return 0 on success, >=1 on failure + \param et EMF in memory + \param eht EMF handle table (peak handle number needed) +*/ +int emf_finish( + EMFTRACK *et, + EMFHANDLES *eht + ){ + U_EMRHEADER *record; + + if(!et->fp)return(1); // This could happen if something stomps on memory, otherwise should be caught in emf_start + + // Set the header fields which were unknown up until this point + + record = (U_EMRHEADER *)et->buf; + record->nBytes = et->used; + record->nRecords = et->records; + record->nHandles = eht->peak + 1; + record->nPalEntries = et->PalEntries; + +#if U_BYTE_SWAP + //This is a Big Endian machine, EMF data must be Little Endian + U_emf_endian(et->buf,et->used,1); +#endif + + if(1 != fwrite(et->buf,et->used,1,et->fp))return(2); + (void) fclose(et->fp); + et->fp=NULL; + return(0); +} + +/** + \brief Release memory for an emf structure in memory. Call this after emf_finish(). + \return 0 on success, >=1 on failure + \param et EMF in memory +*/ +int emf_free( + EMFTRACK **et + ){ + EMFTRACK *etl; + if(!et)return(1); + etl=*et; + if(!etl)return(2); + free(etl->buf); + free(etl); + *et=NULL; + return(0); +} + +/** + \brief wrapper for fopen, works on any platform + \return 0 on success, >=1 on failure + \param filename file to open (either ASCII or UTF-8) + \param mode U_READ or U_WRITE (these map to "rb" and "wb") +*/ +FILE *emf_fopen( + const char *filename, + const int mode + ){ + FILE *fp = NULL; +#ifdef WIN32 + uint16_t *fn16; + uint16_t *md16; + if(mode == U_READ){ md16 = U_Utf8ToUtf16le("rb", 0, NULL); } + else { md16 = U_Utf8ToUtf16le("wb", 0, NULL); } + fn16 = U_Utf8ToUtf16le(filename, 0, NULL); + fp = _wfopen(fn16,md16); + free(fn16); + free(md16); +#else + if(mode == U_READ){ fp = fopen(filename,"rb"); } + else { fp = fopen(filename,"wb"); } +#endif + return(fp); +} + +/** + \brief Retrieve contents of an EMF file by name. + \return 0 on success, >=1 on failure + \param filename Name of file to open, including the path + \param contents Contents of the file. Buffer must be free()'d by caller. + \param length Number of bytes in Contents +*/ +int emf_readdata( + const char *filename, + char **contents, + size_t *length + ){ + FILE *fp; + int status=0; + + *contents=NULL; + fp=emf_fopen(filename,U_READ); + if(!fp){ status = 1; } + else { + // read the entire file into memory + fseek(fp, 0, SEEK_END); // move to end + *length = ftell(fp); + rewind(fp); + *contents = (char *) malloc(*length); + if(!*contents){ + status = 2; + } + else { + size_t inbytes = fread(*contents,*length,1,fp); + if(inbytes != 1){ + free(*contents); + status = 3; + } + else { +#if U_BYTE_SWAP + //This is a Big Endian machine, EMF data is Little Endian + U_emf_endian(*contents,*length,0); // LE to BE +#endif + } + } + fclose(fp); + } + return(status); +} + + +/** + \brief Append an EMF record to an emf in memory. This may reallocate buf memory. + \return 0 for success, >=1 for failure. + \param rec Record to append to EMF in memory + \param et EMF in memory + \param freerec If true, free rec after append +*/ +int emf_append( + U_ENHMETARECORD *rec, + EMFTRACK *et, + int freerec + ){ + size_t deficit; + +#ifdef U_VALGRIND + printf("\nbefore \n"); + printf(" probe %d\n",memprobe(rec, U_EMRSIZE(rec))); + printf("after \n"); +#endif + if(!rec)return(1); + if(!et)return(2); + if(rec->nSize + et->used > et->allocated){ + deficit = rec->nSize + et->used - et->allocated; + if(deficit < et->chunk)deficit = et->chunk; + et->allocated += deficit; + et->buf = realloc(et->buf,et->allocated); + if(!et->buf)return(3); + } + memcpy(et->buf + et->used, rec, rec->nSize); + et->used += rec->nSize; + et->records++; + if(rec->iType == U_EMR_EOF){ et->PalEntries = ((U_EMREOF *)rec)->cbPalEntries; } + if(freerec){ free(rec); } + return(0); +} + +/** + \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle. + \return 0 for success, >=1 for failure. + \param initsize Initialize with space for this number of handles + \param chunksize When needed increase space by this number of handles + \param eht EMF handle table +*/ +int emf_htable_create( + uint32_t initsize, + uint32_t chunksize, + EMFHANDLES **eht + ){ + EMFHANDLES *ehtl; + unsigned int i; + + if(initsize<1)return(1); + if(chunksize<1)return(2); + ehtl = (EMFHANDLES *) malloc(sizeof(EMFHANDLES)); + if(!ehtl)return(3); + ehtl->table = malloc(initsize * sizeof(uint32_t)); + if(!ehtl->table){ + free(ehtl); + return(4); + } + ehtl->stack = malloc(initsize * sizeof(uint32_t)); + if(!ehtl->stack){ + free(ehtl); + free(ehtl->table); + return(5); + } + memset(ehtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table + for(i=1; i<initsize; i++){ehtl->stack[i]=i;} // preset the stack + ehtl->allocated = initsize; + ehtl->chunk = chunksize; + ehtl->table[0] = 0; // This slot isn't actually ever used + ehtl->stack[0] = 0; // This stack position isn't actually ever used + ehtl->peak = 1; + ehtl->sptr = 1; + ehtl->top = 0; + *eht = ehtl; + return(0); +} + +/** + \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0. + \return 0 for success, >=1 for failure. + \param ih handle + \param eht EMF handle table + +*/ +int emf_htable_delete( + uint32_t *ih, + EMFHANDLES *eht + ){ + if(!eht)return(1); + if(!eht->table)return(2); + if(!eht->stack)return(3); + if(*ih < 1)return(4); // invalid handle + if(!eht->table[*ih])return(5); // requested table position was not in use + eht->table[*ih]=0; // remove handle from table + while(eht->top>0 && !eht->table[eht->top]){ // adjust top + eht->top--; + } + eht->sptr--; // adjust stack + eht->stack[eht->sptr]=*ih; // place handle on stack + *ih=0; // invalidate handle variable, so a second delete will of it is not possible + return(0); +} + +/** + \brief Returns the index of the first free slot. + Call realloc() if needed. The slot is set to handle (indicates occupied) and the peak value is adjusted. + \return 0 for success, >=1 for failure. + \param ih handle + \param eht EMF handle table +*/ +int emf_htable_insert( + uint32_t *ih, + EMFHANDLES *eht + ){ + unsigned int i; + size_t newsize; + + if(!eht)return(1); + if(!eht->table)return(2); + if(!eht->stack)return(3); + if(!ih)return(4); + if(eht->sptr >= eht->allocated - 1){ // need to reallocate + newsize=eht->allocated + eht->chunk; + eht->table = realloc(eht->table,newsize * sizeof(uint32_t)); + if(!eht->table)return(5); + memset(&eht->table[eht->allocated] , 0, eht->chunk * sizeof(uint32_t)); // zero all NEW slots in the table + + eht->stack = realloc(eht->stack,newsize * sizeof(uint32_t)); + if(!eht->stack)return(6); + for(i=eht->allocated; i<newsize;i++){ eht->stack[i] = i; } // init all NEW slots in the stack + eht->allocated = newsize; + } + *ih = eht->stack[eht->sptr]; // handle that is inserted + if(eht->table[*ih])return(7); + eht->table[*ih] = *ih; // handle goes into preexisting (but zero) slot in table + eht->stack[eht->sptr] = 0; + if(*ih > eht->top){ eht->top = *ih; } + if(eht->sptr > eht->peak){ eht->peak = eht->sptr; } + eht->sptr++; // next available handle + return(0); +} + +/** + \brief Free all memory in an htable. Sets the pointer to NULL. + \return 0 for success, >=1 for failure. + \param eht EMF handle table +*/ +int emf_htable_free( + EMFHANDLES **eht + ){ + EMFHANDLES *ehtl; + if(!eht)return(1); + ehtl = *eht; + if(!ehtl)return(2); + if(!ehtl->table)return(3); + if(!ehtl->stack)return(4); + free(ehtl->table); + free(ehtl->stack); + free(ehtl); + *eht=NULL; + return(0); +} + +/* ********************************************************************************************** +These functions create standard structures used in the EMR records. +*********************************************************************************************** */ + + +/** + \brief Set up fields for an EMR_HEADER from the physical device's width and height in mm and dots per millimeter. + Typically this is something like 216,279,47.244 (Letter paper, 1200 DPI = 47.244 DPmm) + \return 0 for success, >=1 for failure. + \param xmm Device width in millimeters + \param ymm Device height in millimeters + \param dpmm Dots per millimeter + \param szlDev Device size structure in pixels + \param szlMm Device size structure in mm +*/ +int device_size( + const int xmm, + const int ymm, + const float dpmm, + U_SIZEL *szlDev, + U_SIZEL *szlMm + ){ + if(xmm < 0 || ymm < 0 || dpmm < 0)return(1); + szlDev->cx = U_ROUND((float) xmm * dpmm); + szlDev->cy = U_ROUND((float) ymm * dpmm);; + szlMm->cx = xmm; + szlMm->cy = ymm; + return(0); +} + +/** + \brief Set up fields for an EMR_HEADER for drawing by physical size in mm and dots per millimeter. + Technically rclBounds is supposed to be the extent of the drawing within the EMF, but libUEMF has no way + of knowing this since it never actually draws anything. Instead this is set to the full drawing size. + Coordinates are inclusive inclusive, so 297 -> 0,29699. + \return 0 for success, >=1 for failure. + \param xmm Drawing width in millimeters + \param ymm Drawing height in millimeters + \param dpmm Dots per millimeter + \param rclBounds Drawing size structure in pixels + \param rclFrame Drawing size structure in mm +*/ +int drawing_size( + const int xmm, + const int ymm, + const float dpmm, + U_RECTL *rclBounds, + U_RECTL *rclFrame + ){ + if(xmm < 0 || ymm < 0 || dpmm < 0)return(1); + rclBounds->left = 0; + rclBounds->top = 0; + rclBounds->right = U_ROUND((float) xmm * dpmm) - 1; // because coordinate system is 0,0 in upper left, N,M in lower right + rclBounds->bottom = U_ROUND((float) ymm * dpmm) - 1; + rclFrame->left = 0; + rclFrame->top = 0; + rclFrame->right = U_ROUND((float) xmm * 100.) - 1; + rclFrame->bottom = U_ROUND((float) ymm * 100.) - 1; + return(0); +} + +/** + \brief Set a U_COLORREF value from separeate R,G,B values. + Or use macro directly: cr = U_RGB(r,g,b). + \param red Red component + \param green Green component + \param blue Blue component + +*/ +U_COLORREF colorref_set( + uint8_t red, + uint8_t green, + uint8_t blue + ){ + U_COLORREF cr = (U_COLORREF){red , green, blue, 0}; + return(cr); +} + +/** + \brief Set rect and rectl objects from Upper Left and Lower Right corner points. + \param ul upper left corner of rectangle + \param lr lower right corner of rectangle +*/ +U_RECTL rectl_set( + U_POINTL ul, + U_POINTL lr + ){ + U_RECTL rct; + rct.left = ul.x; + rct.top = ul.y; + rct.right = lr.x; + rct.bottom = lr.y; + return(rct); +} + +/** + \brief Set sizel objects with X,Y values. + \param x X coordinate + \param y Y coordinate +*/ +U_SIZEL sizel_set( + int32_t x, + int32_t y + ){ + U_SIZEL sz; + sz.cx = x; + sz.cy = y; + return(sz); +} + +/** + \brief Set pointl objects with X,Y values. + \param x X coordinate + \param y Y coordinate +*/ +U_POINTL point32_set( + int32_t x, + int32_t y + ){ + U_POINTL pt; + pt.x = x; + pt.y = y; + return(pt); +} + +/** + \brief Set point16 objects with 16 bit X,Y values. + \param x X coordinate + \param y Y coordinate +*/ +U_POINT16 point16_set( + int16_t x, + int16_t y + ){ + U_POINT16 pt; + pt.x = x; + pt.y = y; + return(pt); +} + +/** + \brief Find the bounding rectangle from a polyline of a given width. + \param count number of points in the polyline + \param pts the polyline + \param width width of drawn line + +*/ +U_RECT findbounds( + uint32_t count, + PU_POINT pts, + uint32_t width + ){ + U_RECT rect={INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN }; + unsigned int i; + + for(i=0; i<count;i++,pts++){ + if ( pts->x < rect.left ) rect.left = pts->x; + if ( pts->x > rect.right ) rect.right = pts->x; + if ( pts->y < rect.top ) rect.top = pts->y; + if ( pts->y > rect.bottom ) rect.bottom = pts->y; + } + if(width > 0){ + rect.left -= width; + rect.right += width; + rect.top += width; + rect.bottom -= width; + } + return(rect); +} + +/** + \brief Find the bounding rectangle from a polyline of a given width. + \param count number of points in the polyline + \param pts the polyline + \param width width of drawn line + +*/ +U_RECT findbounds16( + uint32_t count, + PU_POINT16 pts, + uint32_t width + ){ + U_RECT rect={INT16_MAX, INT16_MAX, INT16_MIN, INT16_MIN }; + unsigned int i; + + for(i=0; i<count;i++,pts++){ + if ( pts->x < rect.left ) rect.left = pts->x; + if ( pts->x > rect.right ) rect.right = pts->x; + if ( pts->y < rect.top ) rect.top = pts->y; + if ( pts->y > rect.bottom ) rect.bottom = pts->y; + } + if(width > 0){ + rect.left -= width; + rect.right += width; + rect.top += width; + rect.bottom -= width; + } + return(rect); +} +/** + \brief Construct a U_LOGBRUSH structure. + \return U_LOGBRUSH structure + \param lbStyle LB_Style Enumeration + \param lbColor Brush color + \param lbHatch HatchStyle Enumertaion +*/ +U_LOGBRUSH logbrush_set( + uint32_t lbStyle, + U_COLORREF lbColor, + int32_t lbHatch + ){ + U_LOGBRUSH lb; + lb.lbStyle = lbStyle; + lb.lbColor = lbColor; + lb.lbHatch = lbHatch; + return(lb); +} + +/** + \brief Construct a U_XFORM structure. + \return U_XFORM structure + \param eM11 Rotation Matrix element + \param eM12 Rotation Matrix element + \param eM21 Rotation Matrix element + \param eM22 Rotation Matrix element + \param eDx Translation element + \param eDy Translation element +*/ +U_XFORM xform_set( + U_FLOAT eM11, + U_FLOAT eM12, + U_FLOAT eM21, + U_FLOAT eM22, + U_FLOAT eDx, + U_FLOAT eDy + ){ + U_XFORM xform; + xform.eM11 = eM11; + xform.eM12 = eM12; + xform.eM21 = eM21; + xform.eM22 = eM22; + xform.eDx = eDx; + xform.eDy = eDy; + return(xform); +} + +/** + \brief Construct a U_XFORM structure. + \return U_XFORM structure + \param scale Scale factor + \param ratio Ratio of minor axis/major axis + \param rot Rotation angle in degrees, positive is counter clockwise from the x axis. + \param axisrot Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis. + \param eDx Translation element + \param eDy Translation element + + Operation is: + 1 Conformal map of points based on scale, axis rotation, and axis ratio, + 2. Apply rotation + 3. Apply offset +*/ +U_XFORM xform_alt_set( + U_FLOAT scale, + U_FLOAT ratio, + U_FLOAT rot, + U_FLOAT axisrot, + U_FLOAT eDx, + U_FLOAT eDy + ){ + U_XFORM xform; + U_MAT2X2 mat1, mat2; + // angles are in degrees, must be in radians + rot *= (2.0 * U_PI)/360.0; + axisrot *= -(2.0 * U_PI)/360.0; + mat1.M11 = cos(rot); // set up the rotation matrix + mat1.M12 = -sin(rot); + mat1.M21 = sin(rot); + mat1.M22 = cos(rot); + if(ratio!=1.0){ // set scale/ellipticity matrix + mat2.M11 = scale*( cos(axisrot)*cos(axisrot) + ratio*sin(axisrot)*sin(axisrot) ); + mat2.M12 = mat2.M21 = scale*( sin(axisrot)*cos(axisrot) * (1.0 - ratio) ); + mat2.M22 = scale*( sin(axisrot)*sin(axisrot) + ratio*cos(axisrot)*cos(axisrot) ); + } + else { // when the ratio is 1.0 then the major axis angle is ignored and only scale matters + mat2.M11 = scale; + mat2.M12 = 0.0; + mat2.M21 = 0.0; + mat2.M22 = scale; + } + xform.eM11 = mat2.M11 * mat1.M11 + mat2.M12 * mat1.M21; + xform.eM12 = mat2.M11 * mat1.M12 + mat2.M12 * mat1.M22;; + xform.eM21 = mat2.M21 * mat1.M11 + mat2.M22 * mat1.M21; + xform.eM22 = mat2.M21 * mat1.M12 + mat2.M22 * mat1.M22; + xform.eDx = eDx; + xform.eDy = eDy; + return(xform); +} + + +/** + \brief Construct a U_LOGCOLORSPACEA structure. + \return U_LOGCOLORSPACEA structure + \param lcsCSType LCS_CSType Enumeration + \param lcsIntent LCS_Intent Enumeration + \param lcsEndpoints CIE XYZ color space endpoints + \param lcsGammaRGB Gamma For RGB + \param lcsFilename Could name an external color profile file, otherwise empty string +*/ +U_LOGCOLORSPACEA logcolorspacea_set( + int32_t lcsCSType, + int32_t lcsIntent, + U_CIEXYZTRIPLE lcsEndpoints, + U_LCS_GAMMARGB lcsGammaRGB, + char *lcsFilename + ){ + U_LOGCOLORSPACEA lcsa; + lcsa.lcsSignature = U_LCS_SIGNATURE; + lcsa.lcsVersion = U_LCS_SIGNATURE; + lcsa.lcsSize = sizeof(U_LOGCOLORSPACEA); + lcsa.lcsCSType = lcsCSType; + lcsa.lcsIntent = lcsIntent; + lcsa.lcsEndpoints = lcsEndpoints; + lcsa.lcsGammaRGB = lcsGammaRGB; + memset(lcsa.lcsFilename,0,U_MAX_PATH); // zero out the Filename field + strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + return(lcsa); +} + +/** + + \brief Construct a U_LOGCOLORSPACEW structure. + \return U_LOGCOLORSPACEW structure + \param lcsCSType LCS_CSType Enumeration + \param lcsIntent LCS_Intent Enumeration + \param lcsEndpoints CIE XYZ color space endpoints + \param lcsGammaRGB Gamma For RGB + \param lcsFilename Could name an external color profile file, otherwise empty string +*/ +U_LOGCOLORSPACEW logcolorspacew_set( + int32_t lcsCSType, + int32_t lcsIntent, + U_CIEXYZTRIPLE lcsEndpoints, + U_LCS_GAMMARGB lcsGammaRGB, + uint16_t *lcsFilename + ){ + U_LOGCOLORSPACEW lcsa; + lcsa.lcsSignature = U_LCS_SIGNATURE; + lcsa.lcsVersion = U_LCS_SIGNATURE; + lcsa.lcsSize = sizeof(U_LOGCOLORSPACEW); + lcsa.lcsCSType = lcsCSType; + lcsa.lcsIntent = lcsIntent; + lcsa.lcsEndpoints = lcsEndpoints; + lcsa.lcsGammaRGB = lcsGammaRGB; + wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + return(lcsa); +} + +/** + + \brief Construct a U_PANOSE structure. + \return U_PANOSE structure + \param bFamilyType FamilyType Enumeration + \param bSerifStyle SerifType Enumeration + \param bWeight Weight Enumeration + \param bProportion Proportion Enumeration + \param bContrast Contrast Enumeration + \param bStrokeVariation StrokeVariation Enumeration + \param bArmStyle ArmStyle Enumeration + \param bLetterform Letterform Enumeration + \param bMidline Midline Enumeration + \param bXHeight XHeight Enumeration +*/ +U_PANOSE panose_set( + uint8_t bFamilyType, + uint8_t bSerifStyle, + uint8_t bWeight, + uint8_t bProportion, + uint8_t bContrast, + uint8_t bStrokeVariation, + uint8_t bArmStyle, + uint8_t bLetterform, + uint8_t bMidline, + uint8_t bXHeight + ){ + U_PANOSE panose; + panose.bFamilyType = bFamilyType; + panose.bSerifStyle = bSerifStyle; + panose.bWeight = bWeight; + panose.bProportion = bProportion; + panose.bContrast = bContrast; + panose.bStrokeVariation = bStrokeVariation; + panose.bArmStyle = bArmStyle; + panose.bLetterform = bLetterform; + panose.bMidline = bMidline; + panose.bXHeight = bXHeight; + return(panose); +} + +/** + \brief Construct a U_LOGFONT structure. + \return U_LOGFONT structure + \param lfHeight Height in Logical units + \param lfWidth Average Width in Logical units + \param lfEscapement Angle in 0.1 degrees betweem escapement vector and X axis + \param lfOrientation Angle in 0.1 degrees between baseline and X axis + \param lfWeight LF_Weight Enumeration + \param lfItalic Italics: 0 or 1 + \param lfUnderline Underline: 0 or 1 + \param lfStrikeOut Strikeout: 0 or 1 + \param lfCharSet LF_CharSet Enumeration + \param lfOutPrecision LF_OutPrecision Enumeration + \param lfClipPrecision LF_ClipPrecision Enumeration + \param lfQuality LF_Quality Enumeration + \param lfPitchAndFamily LF_PitchAndFamily Enumeration + \param lfFaceName Name of font. truncates at U_LF_FACESIZE, smaller must be null terminated + +*/ +U_LOGFONT logfont_set( + int32_t lfHeight, + int32_t lfWidth, + int32_t lfEscapement, + int32_t lfOrientation, + int32_t lfWeight, + uint8_t lfItalic, + uint8_t lfUnderline, + uint8_t lfStrikeOut, + uint8_t lfCharSet, + uint8_t lfOutPrecision, + uint8_t lfClipPrecision, + uint8_t lfQuality, + uint8_t lfPitchAndFamily, + uint16_t *lfFaceName + ){ + U_LOGFONT lf; + lf.lfHeight = lfHeight; + lf.lfWidth = lfWidth; + lf.lfEscapement = lfEscapement; + lf.lfOrientation = lfOrientation; + lf.lfWeight = lfWeight; + lf.lfItalic = lfItalic; + lf.lfUnderline = lfUnderline; + lf.lfStrikeOut = lfStrikeOut; + lf.lfCharSet = lfCharSet; + lf.lfOutPrecision = lfOutPrecision; + lf.lfClipPrecision = lfClipPrecision; + lf.lfQuality = lfQuality; + lf.lfPitchAndFamily = lfPitchAndFamily; + wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero + return(lf); +} + + +/** + \brief Construct a U_LOGFONT_PANOSE structure. + \return U_LOGFONT_PANOSE structure + \param elfLogFont Basic font attributes + \param elfFullName Font full name, truncates at U_LF_FULLFACESIZE, smaller must be null terminated + \param elfStyle Font style, truncates at U_LF_FULLFACESIZE, smaller must be null terminated + \param elfStyleSize Font hinting starting at this point size, if 0, starts at Height + \param elfPanose Panose Object. If all zero, it is ignored. +*/ +U_LOGFONT_PANOSE logfont_panose_set( + U_LOGFONT elfLogFont, + uint16_t *elfFullName, + uint16_t *elfStyle, + uint32_t elfStyleSize, + U_PANOSE elfPanose + ){ + U_LOGFONT_PANOSE lfp; + memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed. Many should be ignored or must be 0. + wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE); + wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE); + lfp.elfLogFont = elfLogFont; + lfp.elfStyleSize = elfStyleSize; + lfp.elfPanose = elfPanose; + return(lfp); +} + +/** + \brief Construct a U_BITMAPINFOHEADER structure. + \return U_BITMAPINFOHEADER structure + \param biWidth Bitmap width in pixels + \param biHeight Bitmap height in pixels + \param biPlanes Planes (must be 1) + \param biBitCount BitCount Enumeration + \param biCompression BI_Compression Enumeration + \param biSizeImage Size in bytes of image + \param biXPelsPerMeter X Resolution in pixels/meter + \param biYPelsPerMeter Y Resolution in pixels/meter + \param biClrUsed Number of bmciColors in U_BITMAPCOREINFO + \param biClrImportant Number of bmciColors needed (0 means all). +*/ +U_BITMAPINFOHEADER bitmapinfoheader_set( + int32_t biWidth, + int32_t biHeight, + uint16_t biPlanes, + uint16_t biBitCount, + uint32_t biCompression, + uint32_t biSizeImage, + int32_t biXPelsPerMeter, + int32_t biYPelsPerMeter, + U_NUM_RGBQUAD biClrUsed, + uint32_t biClrImportant + ){ + U_BITMAPINFOHEADER Bmi; + Bmi.biSize = sizeof(U_BITMAPINFOHEADER); + Bmi.biWidth = biWidth; + Bmi.biHeight = biHeight; + Bmi.biPlanes = biPlanes; + Bmi.biBitCount = biBitCount; + Bmi.biCompression = biCompression; + Bmi.biSizeImage = biSizeImage; + Bmi.biXPelsPerMeter = biXPelsPerMeter; + Bmi.biYPelsPerMeter = biYPelsPerMeter; + Bmi.biClrUsed = biClrUsed; + Bmi.biClrImportant = biClrImportant; + return(Bmi); +} + + +/** + \brief Allocate and construct a U_BITMAPINFO structure. + \return Pointer to a U_BITMAPINFO structure + \param BmiHeader Geometry and pixel properties + \param BmiColors Color table (must be NULL for some values of BmiHeader->biBitCount) +*/ +PU_BITMAPINFO bitmapinfo_set( + U_BITMAPINFOHEADER BmiHeader, + PU_RGBQUAD BmiColors + ){ + char *record; + int irecsize; + int cbColors, cbColors4, off; + + cbColors = 4*get_real_color_count((char *) &BmiHeader); + cbColors4 = UP4(cbColors); + irecsize = sizeof(U_BITMAPINFOHEADER) + cbColors4; + record = malloc(irecsize); + if(record){ + memcpy(record, &BmiHeader, sizeof(U_BITMAPINFOHEADER)); + if(cbColors){ + off = sizeof(U_BITMAPINFOHEADER); + memcpy(record + off, BmiColors, cbColors); + off += cbColors; + if(cbColors4 - cbColors){ memset(record + off, 0, cbColors4 - cbColors); } + } + } + return((PU_BITMAPINFO) record); +} + +/** + \brief Allocate and construct a U_EXTLOGPEN structure. + \return pointer to U_EXTLOGPEN structure, or NULL on error + \param elpPenStyle PenStyle Enumeration + \param elpWidth Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel) + \param elpBrushStyle LB_Style Enumeration + \param elpColor Pen color + \param elpHatch HatchStyle Enumeration + \param elpNumEntries Count of StyleEntry array + \param elpStyleEntry Array of StyleEntry (For user specified dot/dash patterns) +*/ +PU_EXTLOGPEN extlogpen_set( + uint32_t elpPenStyle, + uint32_t elpWidth, + uint32_t elpBrushStyle, + U_COLORREF elpColor, + int32_t elpHatch, + U_NUM_STYLEENTRY elpNumEntries, + U_STYLEENTRY *elpStyleEntry + ){ + int irecsize,szSyleArray; + char *record; + + if(elpNumEntries){ + if(!elpStyleEntry)return(NULL); + szSyleArray = elpNumEntries * sizeof(U_STYLEENTRY); + irecsize = sizeof(U_EXTLOGPEN) + szSyleArray - sizeof(U_STYLEENTRY); // first one is in the record + } + else { + szSyleArray = 0; + irecsize = sizeof(U_EXTLOGPEN); + } + record = malloc(irecsize); + if(record){ + ((PU_EXTLOGPEN) record)->elpPenStyle = elpPenStyle; + ((PU_EXTLOGPEN) record)->elpWidth = elpWidth; + ((PU_EXTLOGPEN) record)->elpBrushStyle = elpBrushStyle; + ((PU_EXTLOGPEN) record)->elpColor = elpColor; + ((PU_EXTLOGPEN) record)->elpHatch = elpHatch; + ((PU_EXTLOGPEN) record)->elpNumEntries = elpNumEntries; + if(elpNumEntries){ memcpy(((PU_EXTLOGPEN) record)->elpStyleEntry,elpStyleEntry,szSyleArray); } + else { memset(((PU_EXTLOGPEN) record)->elpStyleEntry,0,sizeof(U_STYLEENTRY)); } // not used, but this stops valgrind warnings + } + return((PU_EXTLOGPEN) record); +} + +/** + \brief Construct a U_LOGPEN structure. + \return U_LOGPEN structure + \param lopnStyle PenStyle Enumeration + \param lopnWidth Width of pen set by X, Y is ignored + \param lopnColor Pen color value + +*/ +U_LOGPEN logpen_set( + uint32_t lopnStyle, + U_POINT lopnWidth, + U_COLORREF lopnColor + ){ + U_LOGPEN lp; + lp.lopnStyle = lopnStyle; + lp.lopnWidth = lopnWidth; + lp.lopnColor = lopnColor; + return(lp); +} + +/** + \brief Construct a U_LOGPLTNTRY structure. + \return U_LOGPLTNTRY structure + \param peReserved Ignore + \param peRed Palette entry Red Intensity + \param peGreen Palette entry Green Intensity + \param peBlue Palette entry Blue Intensity +*/ +U_LOGPLTNTRY logpltntry_set( + uint8_t peReserved, + uint8_t peRed, + uint8_t peGreen, + uint8_t peBlue + ){ + U_LOGPLTNTRY lpny; + lpny.peReserved = peReserved; + lpny.peRed = peRed; + lpny.peGreen = peGreen; + lpny.peBlue = peBlue; + return(lpny); +} + +/** + \brief Allocate and construct a U_LOGPALETTE structure. + \return pointer to U_LOGPALETTE structure, or NULL on error. + \param palNumEntries Number of U_LOGPLTNTRY objects + \param palPalEntry array, PC_Entry Enumeration +*/ +PU_LOGPALETTE logpalette_set( + U_NUM_LOGPLTNTRY palNumEntries, + PU_LOGPLTNTRY *palPalEntry + ){ + PU_LOGPALETTE record; + int cbPalArray,irecsize; + + if(palNumEntries == 0 || !palPalEntry)return(NULL); + cbPalArray = palNumEntries * sizeof(U_LOGPLTNTRY); + irecsize = sizeof(U_LOGPALETTE) + cbPalArray - sizeof(U_LOGPLTNTRY); + record = (PU_LOGPALETTE) malloc(irecsize); + if(irecsize){ + record->palVersion = U_LP_VERSION; + record->palNumEntries = palNumEntries; + memcpy(record->palPalEntry,palPalEntry,cbPalArray); + } + return(record); +} + +/** + \brief Construct a U_RGNDATAHEADER structure. + \return U_RGNDATAHEADER structure + \param nCount Number of rectangles in region + \param rclBounds Region bounds +*/ +U_RGNDATAHEADER rgndataheader_set( + U_NUM_RECTL nCount, + U_RECTL rclBounds + ){ + U_RGNDATAHEADER rdh; + rdh.dwSize = U_RDH_OBJSIZE; + rdh.iType = U_RDH_RECTANGLES; + rdh.nCount = nCount; + rdh.nRgnSize = nCount * sizeof(U_RECTL); // Size in bytes of retangle array + rdh.rclBounds = rclBounds; + return(rdh); +} + +/** + \brief Allocate and construct a U_RGNDATA structure. + \return pointer to U_RGNDATA structure, or NULL on error. + \param rdh Data description + \param Buffer Array of U_RECTL elements +*/ +PU_RGNDATA rgndata_set( + U_RGNDATAHEADER rdh, + PU_RECTL Buffer + ){ + char *record; + int irecsize; + int szRgnArray,off; + + if(!Buffer || !rdh.nCount || !rdh.nRgnSize)return(NULL); + szRgnArray = rdh.nRgnSize; // size of the U_RECTL array + irecsize = sizeof(U_RGNDATA) + szRgnArray - sizeof(U_RECTL); // core + array - overlap + record = malloc(irecsize); + if(record){ + memcpy(record, &rdh, sizeof(U_RGNDATAHEADER)); + off = sizeof(U_RGNDATAHEADER); + memcpy(record + off, Buffer, szRgnArray); + } + return((PU_RGNDATA) record); +} + +/** + \brief Construct a U_COLORADJUSTMENT structure. + \return U_COLORADJUSTMENT structure + \param Size Size of this structure in bytes + \param Flags ColorAdjustment Enumeration + \param IlluminantIndex Illuminant Enumeration + \param RedGamma Red Gamma correction (range:2500:65000, 10000 is no correction) + \param GreenGamma Green Gamma correction (range:2500:65000, 10000 is no correction) + \param BlueGamma Blue Gamma correction (range:2500:65000, 10000 is no correction) + \param ReferenceBlack Values less than this are black (range:0:4000) + \param ReferenceWhite Values more than this are white (range:6000:10000) + \param Contrast Contrast adjustment (range:-100:100, 0 is no correction) + \param Brightness Brightness adjustment (range:-100:100, 0 is no correction) + \param Colorfulness Colorfulness adjustment (range:-100:100, 0 is no correction) + \param RedGreenTint Tine adjustment (range:-100:100, 0 is no correction) +*/ +U_COLORADJUSTMENT coloradjustment_set( + uint16_t Size, + uint16_t Flags, + uint16_t IlluminantIndex, + uint16_t RedGamma, + uint16_t GreenGamma, + uint16_t BlueGamma, + uint16_t ReferenceBlack, + uint16_t ReferenceWhite, + int16_t Contrast, + int16_t Brightness, + int16_t Colorfulness, + int16_t RedGreenTint + ){ + U_COLORADJUSTMENT ca; + ca.caSize = Size; + ca.caFlags = Flags; + ca.caIlluminantIndex = IlluminantIndex; + ca.caRedGamma = U_MNMX(RedGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX); + ca.caGreenGamma = U_MNMX(GreenGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX); + ca.caBlueGamma = U_MNMX(BlueGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX); + // Next one is different to eliminate compiler warning - U_R_B_MIN is 0 and unsigned + ca.caReferenceBlack = U_MAX( ReferenceBlack, U_REFERENCE_BLACK_MAX); + ca.caReferenceWhite = U_MNMX(ReferenceWhite, U_REFERENCE_WHITE_MIN, U_REFERENCE_WHITE_MAX); + ca.caContrast = U_MNMX(Contrast, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + ca.caBrightness = U_MNMX(Brightness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + ca.caColorfulness = U_MNMX(Colorfulness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + ca.caRedGreenTint = U_MNMX(RedGreenTint, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + return(ca); +} + +/** + \brief Construct a U_PIXELFORMATDESCRIPTOR structure. + \return U_PIXELFORMATDESCRIPTOR structure + \param dwFlags PFD_dwFlags Enumeration + \param iPixelType PFD_iPixelType Enumeration + \param cColorBits RGBA: total bits per pixel + \param cRedBits Red bits per pixel + \param cRedShift Red shift to data bits + \param cGreenBits Green bits per pixel + \param cGreenShift Green shift to data bits + \param cBlueBits Blue bits per pixel + \param cBlueShift Blue shift to data bits + \param cAlphaBits Alpha bits per pixel + \param cAlphaShift Alpha shift to data bits + \param cAccumBits Accumulator buffer, total bitplanes + \param cAccumRedBits Red accumulator buffer bitplanes + \param cAccumGreenBits Green accumulator buffer bitplanes + \param cAccumBlueBits Blue accumulator buffer bitplanes + \param cAccumAlphaBits Alpha accumulator buffer bitplanes + \param cDepthBits Depth of Z-buffer + \param cStencilBits Depth of stencil buffer + \param cAuxBuffers Depth of auxilliary buffers (not supported) + \param iLayerType PFD_iLayerType Enumeration, may be ignored + \param bReserved Bits 0:3/4:7 are number of Overlay/Underlay planes + \param dwLayerMask may be ignored + \param dwVisibleMask color or index of underlay plane + \param dwDamageMask may be ignored +*/ +U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set( + uint32_t dwFlags, + uint8_t iPixelType, + uint8_t cColorBits, + uint8_t cRedBits, + uint8_t cRedShift, + uint8_t cGreenBits, + uint8_t cGreenShift, + uint8_t cBlueBits, + uint8_t cBlueShift, + uint8_t cAlphaBits, + uint8_t cAlphaShift, + uint8_t cAccumBits, + uint8_t cAccumRedBits, + uint8_t cAccumGreenBits, + uint8_t cAccumBlueBits, + uint8_t cAccumAlphaBits, + uint8_t cDepthBits, + uint8_t cStencilBits, + uint8_t cAuxBuffers, + uint8_t iLayerType, + uint8_t bReserved, + uint32_t dwLayerMask, + uint32_t dwVisibleMask, + uint32_t dwDamageMask + ){ + U_PIXELFORMATDESCRIPTOR pfd; + pfd.nSize = sizeof(U_PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = dwFlags; + pfd.iPixelType = iPixelType; + pfd.cColorBits = cColorBits; + pfd.cRedBits = cRedBits; + pfd.cRedShift = cRedShift; + pfd.cGreenBits = cGreenBits; + pfd.cGreenShift = cGreenShift; + pfd.cBlueBits = cBlueBits; + pfd.cBlueShift = cBlueShift; + pfd.cAlphaBits = cAlphaBits; + pfd.cAlphaShift = cAlphaShift; + pfd.cAccumBits = cAccumBits; + pfd.cAccumRedBits = cAccumRedBits; + pfd.cAccumGreenBits = cAccumGreenBits; + pfd.cAccumBlueBits = cAccumBlueBits; + pfd.cAccumAlphaBits = cAccumAlphaBits; + pfd.cDepthBits = cDepthBits; + pfd.cStencilBits = cStencilBits; + pfd.cAuxBuffers = cAuxBuffers; + pfd.iLayerType = iLayerType; + pfd.bReserved = bReserved; + pfd.dwLayerMask = dwLayerMask; + pfd.dwVisibleMask = dwVisibleMask; + pfd.dwDamageMask = dwDamageMask; + return(pfd); +} + +/** + \brief Allocate and create a U_EMRTEXT structure followed by its variable pieces via a char* pointer. + Dx cannot be NULL, if the calling program has no appropriate values call dx_set() first. + \return char* pointer to U_EMRTEXT structure followed by its variable pieces, or NULL on error + \param ptlReference String start coordinates + \param NumString Number of characters in string, does NOT include a terminator + \param cbChar Number of bytes per character + \param String String to write + \param fOptions ExtTextOutOptions Enumeration + \param rcl (Optional, when fOptions & 7) grayed/clipping/opaque rectangle + \param Dx Character spacing array from the start of the RECORD +*/ +char *emrtext_set( + U_POINTL ptlReference, + U_NUM_STR NumString, + uint32_t cbChar, + void *String, + uint32_t fOptions, + U_RECTL rcl, + uint32_t *Dx + ){ + int irecsize,cbDxArray,cbString4,cbString,off; + char *record; + uint32_t *loffDx; + + if(!String)return(NULL); + if(!Dx)return(NULL); + cbString = cbChar * NumString; // size of the string in bytes + cbString4 = UP4(cbString); // size of the string buffer + cbDxArray = sizeof(uint32_t)*NumString; // size of Dx array storage + if(fOptions & U_ETO_PDY)cbDxArray += cbDxArray; // of the Dx buffer, here do both X and Y coordinates + irecsize = sizeof(U_EMRTEXT) + sizeof(uint32_t) + cbString4 + cbDxArray; // core structure + offDx + string buf + dx buf + if(!(fOptions & U_ETO_NO_RECT)){ irecsize += sizeof(U_RECTL); } // plus variable U_RECTL, when it is present + record = malloc(irecsize); + if(record){ + ((PU_EMRTEXT)record)->ptlReference = ptlReference; + ((PU_EMRTEXT)record)->nChars = NumString; + // pick up ((PU_EMRTEXT)record)->offString later + ((PU_EMRTEXT)record)->fOptions = fOptions; + off = sizeof(U_EMRTEXT); // location where variable pieces will start to be written + if(!(fOptions & U_ETO_NO_RECT)){ // variable field, may or may not be present + memcpy(record + off,&rcl, sizeof(U_RECTL)); + off += sizeof(U_RECTL); + } + loffDx = (uint32_t *)(record + off); // offDx will go here, but we do not know with what value yet + off += sizeof(uint32_t); + memcpy(record + off,String,cbString); // copy the string data to its buffer + ((PU_EMRTEXT)record)->offString = off; // now save offset in the structure + off += cbString; + if(cbString < cbString4){ + memset(record+off,0,cbString4-cbString); // keeps valgrind happy (initialize padding after string) + off += cbString4-cbString; + } + memcpy(record + off, Dx, cbDxArray); // copy the Dx data to its buffer + *loffDx = off; // now save offDx to the structure + } + return(record); +} + + + +/* ********************************************************************************************** +These functions are simpler or more convenient ways to generate the specified types of EMR records. +Each should be called in preference to the underlying "base" EMR function. +*********************************************************************************************** */ + + +/** + \brief Allocate and construct a U_EMRCOMMENT structure with a UTF8 string. + A U_EMRCOMMENT contains application specific data, and that may include contain null characters. This function may be used when the + comment only incluces UT8 text. + \return pointer to U_EMRCOMMENT structure, or NULL on error. + \param string UTF8 string to store in the comment + + +*/ +char *textcomment_set( + const char *string + ){ + if(!string)return(NULL); + return(U_EMRCOMMENT_set(1 + strlen(string),string)); +} + +/** + \brief Allocate and construct a U_EMRDELETEOBJECT structure and also delete the requested object from the table. + Use this function instead of calling U_EMRDELETEOBJECT_set() directly. + \return pointer to U_EMRDELETEOBJECT structure, or NULL on error. + \param ihObject Pointer to handle to delete. This value is set to 0 if the function succeeds. + \param eht EMF handle table + + Note that calling this function should always be conditional on the specifed object being defined. It is easy to + write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined. + Then a later modification, possibly quite far away in the code, causes it to be undefined. That distant change will + result in a failure when this function reutrns. That problem cannot be handled here because the only values which + may be returned are a valid U_EMRDELETEOBJECT record or a NULL, and other errors could result in the NULL. + So the object must be checked before the call. +*/ +char *deleteobject_set( + uint32_t *ihObject, + EMFHANDLES *eht + ){ + uint32_t saveObject=*ihObject; + if(emf_htable_delete(ihObject,eht))return(NULL); // invalid handle or other problem, cannot be deleted + return(U_EMRDELETEOBJECT_set(saveObject)); +} + +/** + \brief Allocate and construct a U_EMRSELECTOBJECT structure, checks that the handle specified is one that can actually be selected. + Use this function instead of calling U_EMRSELECTOBJECT_set() directly. + \return pointer to U_EMRSELECTOBJECT structure, or NULL on error. + \param ihObject handle to select + \param eht EMF handle table +*/ +char *selectobject_set( + uint32_t ihObject, + EMFHANDLES *eht + ){ + if(!(U_STOCK_OBJECT & ihObject)){ // not a stock object, those go straight through + if(ihObject > eht->top)return(NULL); // handle this high is not in the table + if(!eht->table[ihObject])return(NULL); // handle is not in the table, so not active, so cannot be selected + } + return(U_EMRSELECTOBJECT_set(ihObject)); +} + +/** + \brief Allocate and construct a U_EMREXTCREATEPEN structure, create a handle and return it. + Use this function instead of calling U_EMREXTCREATEPEN_set() directly. + \return pointer to U_EMREXTCREATEPEN structure, or NULL on error. + \param ihPen handle to be used by new object + \param eht EMF handle table + \param Bmi bitmapbuffer + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px pixel array (NULL if cbPx == 0) + \param elp Pen parameters (Size is Variable!!!!) +*/ +char *extcreatepen_set( + uint32_t *ihPen, + EMFHANDLES *eht, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px, + PU_EXTLOGPEN elp + ){ + if(emf_htable_insert(ihPen, eht))return(NULL); + return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp )); +} + +/** + \brief Allocate and construct a U_EMRCREATEPEN structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEPEN_set() directly. + \return pointer to U_EMRCREATEPEN structure, or NULL on error. + \param ihPen handle to be used by new object + \param eht EMF handle table + \param lopn Pen parameters +*/ +char *createpen_set( + uint32_t *ihPen, + EMFHANDLES *eht, + U_LOGPEN lopn + ){ + if(emf_htable_insert(ihPen, eht))return(NULL); + return(U_EMRCREATEPEN_set(*ihPen, lopn)); +} + +/** + \brief Allocate and construct a U_EMRCREATEBRUSHINDIRECT structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEBRUSHINDIRECT_set() directly. + \return pointer to U_EMRCREATEBRUSHINDIRECT structure, or NULL on error. + \param ihBrush handle to be used by new object + \param eht EMF handle table + \param lb Brush parameters +*/ +char *createbrushindirect_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + U_LOGBRUSH lb + ){ + if(emf_htable_insert(ihBrush, eht))return(NULL); + return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb)); +} + +/** + \brief Allocate and construct a U_EMRCREATEDIBPATTERNBRUSHPT_set structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEDIBPATTERNBRUSHPT_set() directly. + \return pointer to U_EMRCREATEDIBPATTERNBRUSHPT_set structure, or NULL on error. + \param ihBrush handle to be used by new object + \param eht EMF handle table + \param iUsage DIBColors enumeration + \param Bmi Bitmap info + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *createdibpatternbrushpt_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const uint32_t iUsage, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + + ){ + if(emf_htable_insert(ihBrush, eht))return(NULL); + return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px)); +} + +/** + \brief Allocate and construct a U_EMRCREATEMONOBRUSH_set structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEMONOBRUSH_set() directly. + \return pointer to U_EMRCREATEMONOBRUSH_set structure, or NULL on error. + \param ihBrush handle to be used by new object + \param eht EMF handle table + \param iUsage DIBColors enumeration + \param Bmi Bitmap info + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *createmonobrush_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const uint32_t iUsage, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + + ){ + if(emf_htable_insert(ihBrush, eht))return(NULL); + return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px)); +} + + +/** + \brief Allocate and construct a U_EMRCREATECOLORSPACE structure, create a handle and returns it + Use this function instead of calling U_EMRCREATECOLORSPACE_set() directly. + \return pointer to U_EMRCREATECOLORSPACE structure, or NULL on error. + \param ihCS ColorSpace handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param lcs ColorSpace parameters +*/ +char *createcolorspace_set( + uint32_t *ihCS, + EMFHANDLES *eht, + U_LOGCOLORSPACEA lcs + ){ + if(emf_htable_insert(ihCS, eht))return(NULL); + return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs)); +} + +/** + \brief Allocate and construct a U_EMRCREATECOLORSPACEW structure, create a handle and returns it + Use this function instead of calling U_EMRCREATECOLORSPACEW_set() directly. + \return pointer to U_EMRCREATECOLORSPACEW structure, or NULL on error. + \param ihCS ColorSpace handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param lcs ColorSpace parameters + \param dwFlags If low bit set Data is present + \param cbData Number of bytes of theData field. + \param Data (Optional, dwFlags & 1) color profile data +*/ +char *createcolorspacew_set( + uint32_t *ihCS, + EMFHANDLES *eht, + U_LOGCOLORSPACEW lcs, + uint32_t dwFlags, + U_CBDATA cbData, + uint8_t *Data + ){ + if(emf_htable_insert(ihCS, eht))return(NULL); + return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data)); +} + +/** + \brief Allocate and construct a U_EMREXTCREATEFONTINDIRECTW structure, create a handle and returns it + Use this function instead of calling U_EMREXTCREATEFONTINDIRECTW_set() directly. + \return pointer to U_EMREXTCREATEFONTINDIRECTW structure, or NULL on error. + \param ihFont Font handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param elf Pointer to Font parameters asPU_LOGFONT + \param elfw Pointer to Font parameters as U_LOGFONT_PANOSE +*/ +char *extcreatefontindirectw_set( + uint32_t *ihFont, + EMFHANDLES *eht, + const char *elf, + const char *elfw + ){ + if(emf_htable_insert(ihFont, eht))return(NULL); + return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw)); +} + +/** + \brief Allocate and construct a U_EMRCREATEPALETTE structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEPALETTE_set() directly. + \return pointer to U_EMRCREATEPALETTE structure, or NULL on error. + \param ihPal Palette handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param lgpl PaletteFont parameters +*/ +char *createpalette_set( + uint32_t *ihPal, + EMFHANDLES *eht, + U_LOGPALETTE lgpl + ){ + if(emf_htable_insert(ihPal, eht))return(NULL); + return(U_EMRCREATEPALETTE_set(*ihPal, lgpl)); +} + +/** + \brief Allocate and construct a U_EMRSETPALETTEENTRIES structure, create a handle and returns it + Use this function instead of calling U_EMRSETPALETTEENTRIES_set() directly. + \return pointer to U_EMRSETPALETTEENTRIES structure, or NULL on error. + \param ihPal Palette handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param iStart First Palette entry in selected object to set + \param cEntries Number of Palette entries in selected object to set + \param aPalEntries Values to set with +*/ +char *setpaletteentries_set( + uint32_t *ihPal, + EMFHANDLES *eht, + const uint32_t iStart, + const U_NUM_LOGPLTNTRY cEntries, + const PU_LOGPLTNTRY aPalEntries + ){ + if(emf_htable_insert(ihPal, eht))return(NULL); + return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries)); +} + +/** + \brief Allocate and construct a U_EMRFILLRGN structure, create a handle and returns it + Use this function instead of calling U_EMRFILLRGN_set() directly. + \return pointer to U_EMRFILLRGN structure, or NULL on error. + \param ihBrush Brush handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param rclBounds Bounding rectangle in device units + \param RgnData Pointer to a U_RGNDATA structure +*/ +char *fillrgn_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const U_RECTL rclBounds, + const PU_RGNDATA RgnData + ){ + if(emf_htable_insert(ihBrush, eht))return(NULL); + return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData)); +} + +/** + \brief Allocate and construct a U_EMRFRAMERGN structure, create a handle and returns it + Use this function instead of calling U_EMRFRAMERGN_set() directly. + \return pointer to U_EMRFRAMERGN structure, or NULL on error. + \param ihBrush Brush handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param rclBounds Bounding rectangle in device units + \param szlStroke W & H of Brush stroke + \param RgnData Pointer to a U_RGNDATA structure +*/ +char *framergn_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const U_RECTL rclBounds, + const U_SIZEL szlStroke, + const PU_RGNDATA RgnData + ){ + if(emf_htable_insert(ihBrush, eht))return(NULL); + return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData)); +} + +/** + \brief Allocate and construct an array of U_POINT objects which has been subjected to a U_XFORM + \returns pointer to an array of U_POINT structures. + \param points pointer to the source U_POINT structures + \param count number of members in points + \param xform U_XFORM to apply + + May also be used to modify U_RECT by doubling the count and casting the pointer. +*/ +PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform){ + PU_POINT newpts; + int i; + float x,y; + newpts = (PU_POINT) malloc(count * sizeof(U_POINT)); + for(i=0; i<count; i++){ + x = (float) points[i].x; + y = (float) points[i].y; + newpts[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx); + newpts[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy); + } + return(newpts); +} + +/** + \brief Allocate and construct an array of U_POINT16 objects which has been subjected to a U_XFORM + \returns pointer to an array of U_POINT16 structures. + \param points pointer to the source U_POINT16 structures + \param count number of members in points + \param xform U_XFORM to apply + + Transformed src points {x0,y0} appear at {x0*xscale + x, y0*yscale + y} +*/ +PU_POINT16 point16_transform(PU_POINT16 points, int count, U_XFORM xform){ + PU_POINT16 newpts; + int i; + float x,y; + newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16)); + for(i=0; i<count; i++){ + x = (float) points[i].x; + y = (float) points[i].y; + newpts[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx); + newpts[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy); + } + return(newpts); +} + +/** + \brief Allocate and construct an array of U_TRIVERTEX objects which has been subjected to a U_XFORM + \returns pointer to an array of U_TRIVERTEX structures. + \param tv pointer to the source U_TRIVERTEX structures + \param count number of members in points + \param xform U_XFORM to apply + + Transformed Trivertex points {x0,y0} appear at {x0*xscale + x, y0*yscale + y} +*/ +PU_TRIVERTEX trivertex_transform(PU_TRIVERTEX tv, int count, U_XFORM xform){ + PU_TRIVERTEX newtvs; + int i; + float x,y; + newtvs = (PU_TRIVERTEX) malloc(count * sizeof(U_TRIVERTEX)); + for(i=0; i<count; i++){ + x = (float) tv[i].x; + y = (float) tv[i].y; + newtvs[i] = tv[i]; + newtvs[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx); + newtvs[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy); + } + return(newtvs); +} + +/** + \brief Allocate and construct an array of U_POINT objects from a set of U_POINT16 objects + \returns pointer to an array of U_POINT structures. + \param points pointer to the source U_POINT16 structures + \param count number of members in points + +*/ +PU_POINT point16_to_point(PU_POINT16 points, int count){ + PU_POINT newpts; + int i; + newpts = (PU_POINT) malloc(count * sizeof(U_POINT)); + for(i=0; i<count; i++){ + newpts[i].x = points[i].x; + newpts[i].y = points[i].y; + } + return(newpts); +} + +/** + \brief Allocate and construct an array of U_POINT16 objects from a set of U_POINT objects + \returns pointer to an array of U_POINT16 structures. + \param points pointer to the source U_POINT structures + \param count number of members in points + + If a coordinate is out of range it saturates at boundary. +*/ +PU_POINT16 point_to_point16(PU_POINT points, int count){ + PU_POINT16 newpts; + int i; + newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16)); + for(i=0; i<count; i++){ + newpts[i].x = U_MNMX(points[i].x, INT16_MIN, INT16_MAX); + newpts[i].y = U_MNMX(points[i].y, INT16_MIN, INT16_MAX); + } + return(newpts); +} + +// hide these from Doxygen +//! @cond +/* ********************************************************************************************** +These functions contain shared code used by various U_EMR*_set functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. + + + These are (mostly) ordered by U_EMR_* index number. + For all _set functions the caller must eventually call free() on the returned pointer. + + CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){ + CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){ + CORE3(uint32_t iType, uint32_t iMode){ (generic 1 uint) + CORE4(uint32_t iType, U_RECTL rclBox){ + CORE5(uint32_t iType){ (generic noargs) + CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE1) + CORE7(uint32_t iType, U_PAIR pair){ + CORE8(uint32_t iType, U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext){ + CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){ + CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE2) + CORE11(uint32_t iType, PU_RGNDATA RgnData){ + CORE12(uint32_t iType, uint32_t ihBrush, uint32_t iUsage, PU_BITMAPINFO Bmi){ + CORE13(uint32_t iType, U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest, + U_POINTL Src, U_POINTL cSrc, U_XFORM xformSrc, U_COLORREF crBkColorSrc, uint32_t iUsageSrc, + uint32_t Data, PU_BITMAPINFO Bmi); +*********************************************************************************************** */ + + +// Functions with the same form starting with U_EMRPOLYBEZIER_set +char *U_EMR_CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){ + char *record; + int cbPoints; + int irecsize; + + cbPoints = sizeof(U_POINTL)*cptl; + irecsize = sizeof(U_EMRPOLYBEZIER) + cbPoints - sizeof(U_POINTL); // First instance is in struct + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPOLYBEZIER) record)->rclBounds = rclBounds; + ((PU_EMRPOLYBEZIER) record)->cptl = cptl; + memcpy(((PU_EMRPOLYBEZIER) record)->aptl,points,cbPoints); + } + return(record); +} + +// Functions with the same form starting with U_EMR_POLYPOLYLINE +char *U_EMR_CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){ + char *record; + int cbPolys,cbPoints,off; + int irecsize; + + cbPoints = sizeof(U_POINTL)*cptl; + cbPolys = sizeof(uint32_t)*nPolys; + irecsize = sizeof(U_EMRPOLYPOLYLINE) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPOLYPOLYLINE) record)->rclBounds = rclBounds; + ((PU_EMRPOLYPOLYLINE) record)->nPolys = nPolys; + ((PU_EMRPOLYPOLYLINE) record)->cptl = cptl; + memcpy(((PU_EMRPOLYPOLYLINE) record)->aPolyCounts,aPolyCounts,cbPolys); + off = sizeof(U_EMRPOLYPOLYLINE) - 4 + cbPolys; + memcpy(record + off,points,cbPoints); + } + return(record); +} + +// Functions with the same form starting with U_EMR_SETMAPMODE_set +char *U_EMR_CORE3(uint32_t iType, uint32_t iMode){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRSETMAPMODE); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETMAPMODE)record)->iMode = iMode; + } + return(record); +} + +// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_set, also U_EMRFILLPATH, +char *U_EMR_CORE4(uint32_t iType, U_RECTL rclBox){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRELLIPSE); + record = malloc(irecsize); + memset(record,0,irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRELLIPSE)record)->rclBox = rclBox; // bounding rectangle in logical units + } + return(record); +} + +// Functions with the same form starting with U_EMRSETMETARGN_set +char *U_EMR_CORE5(uint32_t iType){ + char *record; + int irecsize = 8; + + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + } + return(record); +} + +// Functions with the same form starting with U_EMRPOLYBEZIER16_set +char *U_EMR_CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){ + char *record; + int cbPoints,cbPoints4,off; + int irecsize; + + cbPoints = sizeof(U_POINT16)*cpts; + cbPoints4 = UP4(cbPoints); + off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16); // offset to the start of the variable region + irecsize = off + cbPoints4; // First instance is in struct + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPOLYBEZIER16) record)->rclBounds = rclBounds; + ((PU_EMRPOLYBEZIER16) record)->cpts = cpts; + memcpy(record + off, points, cbPoints); + if(cbPoints < cbPoints4){ + off += cbPoints; + memset(record + off, 0, cbPoints4 - cbPoints); + } + } + return(record); +} + + +// Functions that take a single struct argument which contains two uint32_t, starting with U_EMRSETWINDOWEXTEX_set +// these all pass two 32 bit ints and are cast by the caller to U_PAIR +char *U_EMR_CORE7(uint32_t iType, U_PAIR pair){ + char *record; + int irecsize = sizeof(U_EMRGENERICPAIR); + + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRGENERICPAIR)record)->pair = pair; + } + return(record); +} + +// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW +char *U_EMR_CORE8( + uint32_t iType, + U_RECTL rclBounds, // Bounding rectangle in device units + uint32_t iGraphicsMode, // Graphics mode Enumeration + U_FLOAT exScale, // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE) + U_FLOAT eyScale, // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE) + PU_EMRTEXT emrtext // Text parameters + ){ + char *record; + int irecsize,cbString,cbString4,cbDx,cbEmrtext,cbEmrtextAll; + uint32_t *loffDx; + int csize; + + if( iType == U_EMR_EXTTEXTOUTA){ csize = 1; } // how many bytes per character + else if(iType == U_EMR_EXTTEXTOUTW){ csize = 2; } + else { return(NULL); } + + cbString = csize * emrtext->nChars; + cbString4 = UP4(cbString); // size of the string buffer + cbEmrtext = sizeof(U_EMRTEXT); // size of the constant part of the U_EMRTEXT structure + if(!(emrtext->fOptions & U_ETO_NO_RECT)){ cbEmrtext += sizeof(U_RECTL); } // plus the variable U_RECTL, when it is present + cbDx = emrtext->nChars * sizeof(int32_t); // size of Dx buffer + if(emrtext->fOptions & U_ETO_PDY)cbDx += cbDx; // size of Dx buffer when both x and y offsets are used + cbEmrtextAll = cbEmrtext + sizeof(uint32_t) + cbString4 + cbDx; // structure (+- rect) + offDx + string buf + dx buf + offDx + + /* adjust offset fields in emrtext to match the EMRTEXTOUT* field, currently they match EMRTEXT. + This works because the variable pieces have all been moved outside of the U_EMRTEXT and U_EMRTEXTOUTA strutures. + */ + ((PU_EMRTEXT)emrtext)->offString += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT); // adjust offString + loffDx = (uint32_t *)((char *)emrtext + cbEmrtext); + *loffDx += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT); + + // final record size is: U_EMREXTTEXTOUTA (includes constant part of U_EMRTEXT) + U_RECTL (if present) + offDx + dx buffer + string buffer + irecsize = sizeof(U_EMREXTTEXTOUTA) + cbEmrtextAll - sizeof(U_EMRTEXT); // do not count core emrtext strcture twice + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMREXTTEXTOUTA) record)->iGraphicsMode = iGraphicsMode; + ((PU_EMREXTTEXTOUTA) record)->rclBounds = rclBounds; + ((PU_EMREXTTEXTOUTA) record)->exScale = exScale; + ((PU_EMREXTTEXTOUTA) record)->eyScale = eyScale; + // copy the adjusted U_EMRTEXT into the emrtext part of the full record.. + memcpy(&(((PU_EMREXTTEXTOUTA) record)->emrtext), emrtext, cbEmrtextAll); + } + return(record); +} + +// Functions that take a rect and a pair of points, starting with U_EMRARC_set +char *U_EMR_CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){ + char *record; + int irecsize = sizeof(U_EMRARC); + + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRARC) record)->rclBox = rclBox; + ((PU_EMRARC) record)->ptlStart = ptlStart; + ((PU_EMRARC) record)->ptlEnd = ptlEnd; + } + return(record); +} + +// Functions with the same form starting with U_EMR_POLYPOLYLINE16 +char *U_EMR_CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ + char *record; + int cbPoints,cbPolys,off; + int irecsize; + + cbPolys = sizeof(uint32_t)*nPolys; + cbPoints = sizeof(U_POINT16)*cpts; + irecsize = sizeof(U_EMRPOLYPOLYLINE16) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPOLYPOLYLINE16) record)->rclBounds = rclBounds; + ((PU_EMRPOLYPOLYLINE16) record)->nPolys = nPolys; + ((PU_EMRPOLYPOLYLINE16) record)->cpts = cpts; + memcpy(((PU_EMRPOLYPOLYLINE16) record)->aPolyCounts,aPolyCounts,cbPolys); + off = sizeof(U_EMRPOLYPOLYLINE16) - 4 + cbPolys; + memcpy(record + off,points,cbPoints); + } + return(record); +} + +// common code for U_EMRINVERTRGN and U_EMRPAINTRGN, +char *U_EMR_CORE11(uint32_t iType, PU_RGNDATA RgnData){ + char *record; + int irecsize; + int cbRgns,cbRgns4,off; + + if(!RgnData)return(NULL); + cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; + cbRgns4 = UP4(cbRgns); + irecsize = sizeof(U_EMRINVERTRGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRINVERTRGN) record)->rclBounds = ((PU_RGNDATAHEADER) RgnData)->rclBounds; + ((PU_EMRINVERTRGN) record)->cbRgnData = cbRgns; + off = irecsize - cbRgns4; + memcpy(record + off, RgnData, cbRgns); + off += cbRgns; + if(cbRgns < cbRgns4){ memset(record + off,0, cbRgns4 - cbRgns); } // clear any unused bytes + } + return(record); +} + + +// common code for U_EMRCREATEMONOBRUSH_set and U_EMRCREATEDIBPATTERNBRUSHPT_set, +char *U_EMR_CORE12_set( + uint32_t iType, + uint32_t ihBrush, // Index to place object in EMF object table (this entry must not yet exist) + uint32_t iUsage, // DIBcolors Enumeration + PU_BITMAPINFO Bmi, // (Optional) bitmapbuffer (U_BITMAPINFO + pixel array) + const uint32_t cbPx, // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + const char *Px // (Optional) bitmapbuffer (pixel array section ) + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = sizeof(U_EMRCREATEMONOBRUSH) + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCREATEMONOBRUSH) record)->ihBrush = ihBrush; + ((PU_EMRCREATEMONOBRUSH) record)->iUsage = iUsage; + if(cbBmi){ + off = sizeof(U_EMRCREATEMONOBRUSH); + memcpy(record + off, Bmi, cbBmi); + ((PU_EMRCREATEMONOBRUSH) record)->offBmi = off; + ((PU_EMRCREATEMONOBRUSH) record)->cbBmi = cbBmi; + off += cbBmi; + memcpy(record + off, Px, cbPx); + ((PU_EMRCREATEMONOBRUSH) record)->offBits = off; + ((PU_EMRCREATEMONOBRUSH) record)->cbBits = cbImage; + } + else { + ((PU_EMRCREATEMONOBRUSH) record)->offBmi = 0; + ((PU_EMRCREATEMONOBRUSH) record)->cbBmi = 0; + ((PU_EMRCREATEMONOBRUSH) record)->offBits = 0; + ((PU_EMRCREATEMONOBRUSH) record)->cbBits = 0; + } + } + return(record); +} + +// common code for U_EMRBLEND_set and U_EMRTRANSPARENTBLT_set, +char *U_EMR_CORE13_set( + uint32_t iType, + U_RECTL rclBounds, // Bounding rectangle in device units + U_POINTL Dest, // Destination UL corner in logical units + U_POINTL cDest, // Destination width in logical units + U_POINTL Src, // Source UL corner in logical units + U_POINTL cSrc, // Src W & H in logical units + U_XFORM xformSrc, // Transform to apply to source + U_COLORREF crBkColorSrc, // Background color + uint32_t iUsageSrc, // DIBcolors Enumeration + uint32_t Data, // The meaning and type of this field varies, but it is always 4 bytes + const PU_BITMAPINFO Bmi, // (Optional) bitmapbuffer (U_BITMAPINFO section) + const uint32_t cbPx, // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + char *Px // (Optional) bitmapbuffer (pixel array section ) + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = sizeof(U_EMRALPHABLEND) + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = iType; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRALPHABLEND) record)->rclBounds = rclBounds; + ((PU_EMRALPHABLEND) record)->Dest = Dest; + ((PU_EMRALPHABLEND) record)->cDest = cDest; + ((PU_EMRALPHABLEND) record)->Blend = *((PU_BLEND)&Data); + ((PU_EMRALPHABLEND) record)->Src = Src; + ((PU_EMRALPHABLEND) record)->xformSrc = xformSrc; + ((PU_EMRALPHABLEND) record)->crBkColorSrc = crBkColorSrc; + ((PU_EMRALPHABLEND) record)->iUsageSrc = iUsageSrc; + off = sizeof(U_EMRALPHABLEND); + APPEND_PXBMISRC(record, U_EMRALPHABLEND, cbBmi, Bmi, Px, cbImage, cbImage4); + ((PU_EMRALPHABLEND) record)->cSrc = cSrc; + } + return(record); +} +//! @endcond + +/* ********************************************************************************************** +These are the core EMR functions, each creates a particular type of record. +All return these records via a char* pointer, which is NULL if the call failed. +They are listed in order by the corresponding U_EMR_* index number. +*********************************************************************************************** */ + +// U_EMRHEADER_set 1 + +/** + \brief Allocate and construct a U_EMRHEADER record. + \return pointer to U_EMRHEADER record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param rclFrame Bounding rectangle in 0.01 mm units + \param pfmtDesc Pointer to a PixelFormatDescriptor + \param nDesc number of characters in Description, will include first three '\0' + \param Description Description, formatted like: text1\0text2\0\0 + \param szlDevice Reference device size in pixels + \param szlMillimeters Reference device size in 0.01 mm + \param bOpenGL nonZero if OpenGL commands are included +*/ +char *U_EMRHEADER_set( + const U_RECTL rclBounds, + const U_RECTL rclFrame, + U_PIXELFORMATDESCRIPTOR* const pfmtDesc, + U_CBSTR nDesc, + uint16_t* const Description, + const U_SIZEL szlDevice, + const U_SIZEL szlMillimeters, + const uint32_t bOpenGL + ){ + + char *record; + int cbPFD,cbDesc,cbDesc4; + uint32_t off; + int irecsize; + + if(pfmtDesc){ cbPFD = sizeof(U_PIXELFORMATDESCRIPTOR); } + else { cbPFD = 0; } + if(Description){ cbDesc = 2*nDesc; } // also copy the terminator. Size is in bytes + else { cbDesc = 0; } + cbDesc4 = UP4(cbDesc); + irecsize = sizeof(U_EMRHEADER) + cbPFD + cbDesc4; + record = malloc(irecsize); + if(record){ + off = sizeof(U_EMRHEADER); + ((PU_EMR) record)->iType = U_EMR_HEADER; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRHEADER) record)->rclBounds = rclBounds; + ((PU_EMRHEADER) record)->rclFrame = rclFrame; + ((PU_EMRHEADER) record)->dSignature = U_ENHMETA_SIGNATURE; + ((PU_EMRHEADER) record)->nVersion = U_ENHMETA_VERSION; + ((PU_EMRHEADER) record)->nBytes = 0; // Not known yet + ((PU_EMRHEADER) record)->nRecords = 0; // Not known yet + ((PU_EMRHEADER) record)->nHandles = 0; // Not known yet + ((PU_EMRHEADER) record)->sReserved = 0; // Must be 0 + ((PU_EMRHEADER) record)->nDescription = nDesc; + ((PU_EMRHEADER) record)->offDescription = 0; // may change below + ((PU_EMRHEADER) record)->nPalEntries = 0; // Not known yet + ((PU_EMRHEADER) record)->szlDevice = szlDevice; + ((PU_EMRHEADER) record)->szlMillimeters = szlMillimeters; + ((PU_EMRHEADER) record)->cbPixelFormat = cbPFD; + ((PU_EMRHEADER) record)->offPixelFormat = 0; // may change below + ((PU_EMRHEADER) record)->bOpenGL = bOpenGL; + ((PU_EMRHEADER) record)->szlMicrometers.cx = szlMillimeters.cx*1000; + ((PU_EMRHEADER) record)->szlMicrometers.cy = szlMillimeters.cy*1000; + if(cbDesc4){ + ((PU_EMRHEADER) record)->offDescription = off; + memcpy(record + off, Description, cbDesc); + off += cbDesc; + if(cbDesc < cbDesc4)memset(record + off,0,cbDesc4-cbDesc); // clear any unused bytes + off += cbDesc4 - cbDesc; + } + if(cbPFD){ + ((PU_EMRHEADER) record)->offPixelFormat = off; + memcpy(record+off,pfmtDesc,cbPFD); + } + } + return(record); +} + +// U_EMRPOLYBEZIER_set 2 +/** + \brief Allocate and construct a U_EMR_POLYBEZIER record. + \return pointer to U_EMR_POLYBEZIER record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param cptl Number of points to draw + \param points array of points +*/ +char *U_EMRPOLYBEZIER_set( + const U_RECTL rclBounds, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE1(U_EMR_POLYBEZIER, rclBounds, cptl, points)); +} + +// U_EMRPOLYGON_set 3 +/** + \brief Allocate and construct a U_EMR_POLYGON record. + \return pointer to U_EMR_POLYGON record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param cptl Number of points to draw + \param points array of points +*/ +char *U_EMRPOLYGON_set( + const U_RECTL rclBounds, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE1(U_EMR_POLYGON, rclBounds, cptl, points)); +} + +// U_EMRPOLYLINE_set 4 +/** + \brief Allocate and construct a U_EMR_POLYLINE record. + \return pointer to U_EMR_POLYLINE record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param cptl Number of points to draw + \param points array of points +*/ +char *U_EMRPOLYLINE_set( + const U_RECTL rclBounds, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE1(U_EMR_POLYLINE, rclBounds, cptl, points)); +} + +// U_EMRPOLYBEZIERTO_set 5 +/** + \brief Allocate and construct a U_EMR_POLYBEZIERTO record. + \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param cptl Number of points to draw + \param points array of points +*/ +char *U_EMRPOLYBEZIERTO_set( + const U_RECTL rclBounds, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE1(U_EMR_POLYBEZIERTO, rclBounds, cptl, points)); +} + +// U_EMRPOLYLINETO_set 6 +/** + \brief Allocate and construct a U_EMR_POLYLINETO record. + \return pointer to U_EMR_POLYLINETO record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param cptl Number of points to draw + \param points array of points +*/ +char *U_EMRPOLYLINETO_set( + const U_RECTL rclBounds, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE1(U_EMR_POLYLINETO, rclBounds, cptl, points)); +} + +// U_EMRPOLYPOLYLINE_set 7 +/** + \brief Allocate and construct a U_EMR_POLYPOLYLINE record. + \return pointer to U_EMR_POLYPOLYLINE record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param cptl Total number of points (over all poly) + \param points array of points +*/ +char *U_EMRPOLYPOLYLINE_set( + const U_RECTL rclBounds, + const uint32_t nPolys, + const uint32_t *aPolyCounts, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE2(U_EMR_POLYPOLYLINE, rclBounds, nPolys, aPolyCounts,cptl, points)); +} + +// U_EMRPOLYPOLYGON_set 8 +/** + \brief Allocate and construct a U_EMR_POLYPOLYGON record. + \return pointer to U_EMR_POLYPOLYGON record, or NULL on error. + \param rclBounds bounding rectangle in device units + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param cptl Total number of points (over all poly) + \param points array of points +*/ +char *U_EMRPOLYPOLYGON_set( + const U_RECTL rclBounds, + const uint32_t nPolys, + const uint32_t *aPolyCounts, + const uint32_t cptl, + const U_POINTL *points + ){ + return(U_EMR_CORE2(U_EMR_POLYPOLYGON, rclBounds, nPolys, aPolyCounts,cptl, points)); +} + +// U_EMRSETWINDOWEXTEX_set 9 +/** + \brief Allocate and construct a U_EMR_SETWINDOWEXTEX record. + \return pointer to U_EMR_SETWINDOWEXTEX record, or NULL on error. + \param szlExtent H & V extent in logical units +*/ +char *U_EMRSETWINDOWEXTEX_set( + const U_SIZEL szlExtent + ){ + U_PAIR temp; + temp.x = szlExtent.cx; + temp.y = szlExtent.cy; + return(U_EMR_CORE7(U_EMR_SETWINDOWEXTEX, temp)); +} + +// U_EMRSETWINDOWORGEX_set 10 +/** + \brief Allocate and construct a U_EMR_SETWINDOWORGEX record. + \return pointer to U_EMR_SETWINDOWORGEX record, or NULL on error. + \param ptlOrigin H & V origin in logical units +*/ +char *U_EMRSETWINDOWORGEX_set( + const U_POINTL ptlOrigin + ){ + return(U_EMR_CORE7(U_EMR_SETWINDOWORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing +} + +// U_EMRSETVIEWPORTEXTEX_set 11 +/** + \brief Allocate and construct a U_EMR_SETVIEWPORTEXTEX record. + \return pointer to U_EMR_SETVIEWPORTEXTEX record, or NULL on error. + \param szlExtent H & V extent in logical units +*/ +char *U_EMRSETVIEWPORTEXTEX_set( + const U_SIZEL szlExtent + ){ + U_PAIR temp; + temp.x = szlExtent.cx; + temp.y = szlExtent.cy; + return(U_EMR_CORE7(U_EMR_SETVIEWPORTEXTEX, temp)); +} + +// U_EMRSETVIEWPORTORGEX_set 12 +/** + \brief Allocate and construct a U_EMR_SETVIEWPORTORGEX record. + \return pointer to U_EMR_SETVIEWPORTORGEX record, or NULL on error. + \param ptlOrigin H & V origin in logical units +*/ +char *U_EMRSETVIEWPORTORGEX_set( + const U_POINTL ptlOrigin + ){ + return(U_EMR_CORE7(U_EMR_SETVIEWPORTORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing +} + +// U_EMRSETBRUSHORGEX_set 13 +/** + \brief Allocate and construct a U_EMR_SETBRUSHORGEX record. + \return pointer to U_EMR_SETBRUSHORGEX record, or NULL on error. + \param ptlOrigin H & V origin in logical units +*/ +char *U_EMRSETBRUSHORGEX_set( + const U_POINTL ptlOrigin + ){ + return(U_EMR_CORE7(U_EMR_SETBRUSHORGEX, *((PU_PAIR) & ptlOrigin))); +} + +// U_EMREOF_set 14 +/** + \brief Allocate and construct a U_EMR_EOF record. + \return pointer to U_EMR_EOF record, or NULL on error. + \param cbPalEntries Number of palette entries + \param PalEntries (optional) array of PalEntries + \param et tracking information, needed for nSizeLast calculation +*/ +char *U_EMREOF_set( + const U_CBPLENTRIES cbPalEntries, + const PU_LOGPLTNTRY PalEntries, + EMFTRACK *et + ){ + char *record; + char *ptr; + int irecsize; + int cbPals; // space allocated for Palette Entries + uint32_t off; + + if(cbPalEntries && !PalEntries)return(NULL); + if(!et)return(NULL); + cbPals = cbPalEntries * sizeof(U_LOGPLTNTRY); + irecsize = sizeof(U_EMREOF) + cbPals + sizeof(uint32_t); //invariant core, variable palette, palette byte count + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_EOF; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMREOF) record)->cbPalEntries = cbPalEntries; + ((PU_EMREOF) record)->offPalEntries = 0; // May be changed below + off = sizeof(U_EMREOF); //start of the variable region + if(cbPals){ + ((PU_EMREOF) record)->offPalEntries = off; + memcpy(record+off,PalEntries,cbPals); + off += cbPals; + } + ptr = record + off; + *(uint32_t *)ptr = irecsize + et->used; // EMREOF nSizeLast field, not at a fixed position, cannot be accessed by field name + } + et->PalEntries = cbPalEntries; + return(record); +} + + +// U_EMRSETPIXELV_set 15 +/** + \brief Allocate and construct a U_EMR_SETPIXELV record. + \return pointer to U_EMR_SETPIXELV record, or NULL on error. + \param ptlPixel Pixel coordinates (logical) + \param crColor Pixel color +*/ +char *U_EMRSETPIXELV_set( + const U_POINTL ptlPixel, + const U_COLORREF crColor + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRSETPIXELV); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SETPIXELV; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETPIXELV)record)->ptlPixel = ptlPixel; + ((PU_EMRSETPIXELV)record)->crColor = crColor; + } + return(record); +} + + +// U_EMRSETMAPPERFLAGS_set 16 +/** + \brief Allocate and construct a U_EMR_SETMAPPERFLAGS record. + \return pointer to U_EMR_SETMAPPERFLAGS record, or NULL on error. +*/ +char *U_EMRSETMAPPERFLAGS_set(void){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRSETMAPPERFLAGS); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SETMAPPERFLAGS; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETMAPPERFLAGS)record)->dwFlags = 1; + } + return(record); +} + +// U_EMRSETMAPMODE_set 17 +/** + \brief Allocate and construct a U_EMR_SETMAPMODE record. + \return pointer to U_EMR_SETMAPMODE record, or NULL on error. + \param iMode MapMode Enumeration +*/ +char *U_EMRSETMAPMODE_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETMAPMODE, iMode)); +} + +// U_EMRSETBKMODE_set 18 +/** + \brief Allocate and construct a U_EMR_SETBKMODE record. + \return pointer to U_EMR_SETBKMODE record, or NULL on error. + \param iMode BackgroundMode Enumeration +*/ +char *U_EMRSETBKMODE_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETBKMODE, iMode)); +} + +// U_EMRSETPOLYFILLMODE_set 19 +/** + \brief Allocate and construct a U_EMR_SETPOLYFILLMODE record. + \return pointer to U_EMR_SETPOLYFILLMODE record, or NULL on error. + \param iMode PolygonFillMode Enumeration +*/ +char *U_EMRSETPOLYFILLMODE_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETPOLYFILLMODE, iMode)); +} + +// U_EMRSETROP2_set 20 +/** + \brief Allocate and construct a U_EMR_SETROP2 record. + \return pointer to U_EMR_SETROP2 record, or NULL on error. + \param iMode RasterOperation2 Enumeration +*/ +char *U_EMRSETROP2_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETROP2, iMode)); +} + +// U_EMRSETSTRETCHBLTMODE_set 21 +/** + \brief Allocate and construct a U_EMR_SETSTRETCHBLTMODE record. + \return pointer to U_EMR_SETSTRETCHBLTMODE record, or NULL on error. + \param iMode StretchMode Enumeration +*/ +char *U_EMRSETSTRETCHBLTMODE_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETSTRETCHBLTMODE, iMode)); +} + +// U_EMRSETTEXTALIGN_set 22 +/** + \brief Allocate and construct a U_EMR_SETTEXTALIGN record. + \return pointer to U_EMR_SETTEXTALIGN record, or NULL on error. + \param iMode TextAlignment Enumeration +*/ +char *U_EMRSETTEXTALIGN_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETTEXTALIGN, iMode)); +} + +// U_EMRSETCOLORADJUSTMENT_set 23 +/** + \brief Allocate and construct a U_EMR_SETCOLORADJUSTMENT record. + \return pointer to U_EMR_SETCOLORADJUSTMENT record, or NULL on error. + \param ColorAdjustment Color Adjustment +*/ +char *U_EMRSETCOLORADJUSTMENT_set( + const U_COLORADJUSTMENT ColorAdjustment + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRSETCOLORADJUSTMENT); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SETCOLORADJUSTMENT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETCOLORADJUSTMENT) record)->ColorAdjustment = ColorAdjustment; + } + return(record); +} + +// U_EMRSETTEXTCOLOR_set 24 +/** + \brief Allocate and construct a U_EMR_SETTEXTCOLOR record. + \return pointer to U_EMR_SETTEXTCOLOR record, or NULL on error. + \param crColor Text Color +*/ +char *U_EMRSETTEXTCOLOR_set( + const U_COLORREF crColor + ){ + return(U_EMR_CORE3(U_EMR_SETTEXTCOLOR, *(uint32_t *) &crColor)); +} + +// U_EMRSETBKCOLOR_set 25 +/** + \brief Allocate and construct a U_EMR_SETBKCOLOR record. + \return pointer to U_EMR_SETBKCOLOR record, or NULL on error. + \param crColor Background Color +*/ +char *U_EMRSETBKCOLOR_set( + const U_COLORREF crColor + ){ + return(U_EMR_CORE3(U_EMR_SETBKCOLOR, *(uint32_t *) &crColor)); +} + +// U_EMROFFSETCLIPRGN_set 26 +/** + \brief Allocate and construct a U_EMR_OFFSETCLIPRGN record. + \return pointer to U_EMR_OFFSETCLIPRGN record, or NULL on error. + \param ptl Clipping region +*/ +char *U_EMROFFSETCLIPRGN_set( + const U_POINTL ptl + ){ + return(U_EMR_CORE7(U_EMR_OFFSETCLIPRGN, ptl)); +} + +// U_EMRMOVETOEX_set 27 +/** + \brief Allocate and construct a U_EMR_MOVETOEX record. + \return pointer to U_EMR_MOVETOEX record, or NULL on error. + \param ptl Point coordinates +*/ +char *U_EMRMOVETOEX_set( + const U_POINTL ptl + ){ + return(U_EMR_CORE7(U_EMR_MOVETOEX, ptl)); +} + +// U_EMRSETMETARGN_set 28 +/** + \brief Allocate and construct a U_EMR_SETMETARGN record. + \return pointer to U_EMR_SETMETARGN record, or NULL on error. +*/ +char *U_EMRSETMETARGN_set(void){ + return(U_EMR_CORE5(U_EMR_SETMETARGN)); +} + +// U_EMREXCLUDECLIPRECT_set 29 +/** + \brief Allocate and construct a U_EMR_EXCLUDECLIPRECT record. + \return pointer to U_EMR_EXCLUDECLIPRECT record, or NULL on error. + \param rclClip Clipping Region +*/ +char *U_EMREXCLUDECLIPRECT_set( + const U_RECTL rclClip + ){ + return(U_EMR_CORE4(U_EMR_EXCLUDECLIPRECT,rclClip)); +} + +// U_EMRINTERSECTCLIPRECT_set 30 +/** + \brief Allocate and construct a U_EMR_INTERSECTCLIPRECT record. + \return pointer to U_EMR_INTERSECTCLIPRECT record, or NULL on error. + \param rclClip Clipping Region +*/ +char *U_EMRINTERSECTCLIPRECT_set( + const U_RECTL rclClip + ){ + return(U_EMR_CORE4(U_EMR_INTERSECTCLIPRECT,rclClip)); +} + +// U_EMRSCALEVIEWPORTEXTEX_set 31 +/** + \brief Allocate and construct a U_EMR_SCALEVIEWPORTEXTEX record. + \return pointer to U_EMR_SCALEVIEWPORTEXTEX record, or NULL on error. + \param xNum Horizontal multiplier (!=0) + \param xDenom Horizontal divisor (!=0) + \param yNum Vertical multiplier (!=0) + \param yDenom Vertical divisor (!=0) +*/ +char *U_EMRSCALEVIEWPORTEXTEX_set( + const int32_t xNum, + const int32_t xDenom, + const int32_t yNum, + const int32_t yDenom + ){ + return(U_EMR_CORE4(U_EMR_SCALEVIEWPORTEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom})); +} + + +// U_EMRSCALEWINDOWEXTEX_set 32 +/** + \brief Allocate and construct a U_EMR_SCALEWINDOWEXTEX record. + \return pointer to U_EMR_SCALEWINDOWEXTEX record, or NULL on error. + \param xNum Horizontal multiplier (!=0) + \param xDenom Horizontal divisor (!=0) + \param yNum Vertical multiplier (!=0) + \param yDenom Vertical divisor (!=0) +*/ +char *U_EMRSCALEWINDOWEXTEX_set( + const int32_t xNum, + const int32_t xDenom, + const int32_t yNum, + const int32_t yDenom + ){ + return(U_EMR_CORE4(U_EMR_SCALEWINDOWEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom})); +} + +// U_EMRSAVEDC_set 33 +/** + \brief Allocate and construct a U_EMR_SAVEDC record. + \return pointer to U_EMR_SAVEDC record, or NULL on error. +*/ +char *U_EMRSAVEDC_set(void){ + return(U_EMR_CORE5(U_EMR_SAVEDC)); +} + +// U_EMRRESTOREDC_set 34 +/** + \brief Allocate and construct a U_EMR_RESTOREDC record. + \return pointer to U_EMR_RESTOREDC record, or NULL on error. + \param iRelative DC to restore. -1 is preceding +*/ +char *U_EMRRESTOREDC_set( + const int32_t iRelative + ){ + return(U_EMR_CORE3(U_EMR_RESTOREDC, (uint32_t) iRelative)); +} + +// U_EMRSETWORLDTRANSFORM_set 35 +/** + \brief Allocate and construct a U_EMR_SETWORLDTRANSFORM record. + \return pointer to U_EMR_SETWORLDTRANSFORM record, or NULL on error. + \param xform Transform to use +*/ +char *U_EMRSETWORLDTRANSFORM_set( + const U_XFORM xform + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRSETWORLDTRANSFORM); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SETWORLDTRANSFORM; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETWORLDTRANSFORM) record)->xform = xform; + } + return(record); +} + +// U_EMRMODIFYWORLDTRANSFORM_set 36 +/** + \brief Allocate and construct a U_EMR_MODIFYWORLDTRANSFORM record. + \return pointer to U_EMR_MODIFYWORLDTRANSFORM record, or NULL on error. + \param xform Transform to use + \param iMode ModifyWorldTransformMode Enumeration +*/ +char *U_EMRMODIFYWORLDTRANSFORM_set( + const U_XFORM xform, + const uint32_t iMode + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRMODIFYWORLDTRANSFORM); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_MODIFYWORLDTRANSFORM; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRMODIFYWORLDTRANSFORM) record)->xform = xform; + ((PU_EMRMODIFYWORLDTRANSFORM) record)->iMode = iMode; + } + return(record); +} + +// U_EMRSELECTOBJECT_set 37 +/** + \brief Allocate and construct a U_EMR_SELECTOBJECT record. + Use selectobject_set() instead of calling this function directly. + \return pointer to U_EMR_SELECTOBJECT record, or NULL on error. + \param ihObject Number of a stock or created object +*/ +char *U_EMRSELECTOBJECT_set( + const uint32_t ihObject + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRSELECTOBJECT); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SELECTOBJECT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSELECTOBJECT) record)->ihObject = ihObject; // Index of object to SELECT + } + return(record); +} + +// U_EMRCREATEPEN_set 38 +/** + \brief Allocate and construct a U_EMR_CREATEPEN record. + Use createpen_set() instead of calling this function directly. + \return pointer to U_EMR_CREATEPEN record, or NULL on error. + \param ihPen Handle of created pen + \param lopn U_LOGPEN structure describing this pen +*/ +char *U_EMRCREATEPEN_set( + const uint32_t ihPen, + const U_LOGPEN lopn + ){ + char *record; + int irecsize=sizeof(U_EMRCREATEPEN); + + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_CREATEPEN; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCREATEPEN) record)->ihPen = ihPen; + ((PU_EMRCREATEPEN) record)->lopn = lopn; + } + return(record); +} + +// U_EMRCREATEBRUSHINDIRECT_set 39 +/** + \brief Allocate and construct a U_EMR_CREATEBRUSHINDIRECT record. + Use createbrushindirect_set() instead of calling this function directly. + \return pointer to U_EMR_CREATEBRUSHINDIRECT record, or NULL on error. + \param ihBrush Index to place object in EMF object table (this entry must not yet exist) + \param lb Brush properties +*/ +char *U_EMRCREATEBRUSHINDIRECT_set( + const uint32_t ihBrush, + const U_LOGBRUSH lb + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRCREATEBRUSHINDIRECT); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_CREATEBRUSHINDIRECT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCREATEBRUSHINDIRECT) record)->ihBrush = ihBrush; // Index to place object in EMF object table (this entry must not yet exist) + ((PU_EMRCREATEBRUSHINDIRECT) record)->lb = lb; + } + return(record); +} + +// U_EMRDELETEOBJECT_set 40 +/** + \brief Allocate and construct a U_EMR_DELETEOBJECT record. + Use deleteobject_set() instead of calling this function directly. + \return pointer to U_EMR_DELETEOBJECT record, or NULL on error. + \param ihObject Number of a stock or created object +*/ +char *U_EMRDELETEOBJECT_set( + const uint32_t ihObject + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRDELETEOBJECT); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_DELETEOBJECT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRDELETEOBJECT) record)->ihObject = ihObject; // Index of object to DELETE + } + return(record); +} + +// U_EMRANGLEARC_set 41 +/** + \brief Allocate and construct a U_EMR_ANGLEARC record. + \return pointer to U_EMR_ANGLEARC record, or NULL on error. + \param ptlCenter Center in logical units + \param nRadius Radius in logical units + \param eStartAngle Starting angle in degrees (counter clockwise from x axis) + \param eSweepAngle Sweep angle in degrees +*/ +char *U_EMRANGLEARC_set( + const U_POINTL ptlCenter, + const uint32_t nRadius, + const U_FLOAT eStartAngle, + const U_FLOAT eSweepAngle + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRANGLEARC); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_ANGLEARC; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRANGLEARC) record)->ptlCenter = ptlCenter; + ((PU_EMRANGLEARC) record)->nRadius = nRadius; + ((PU_EMRANGLEARC) record)->eStartAngle = eStartAngle; + ((PU_EMRANGLEARC) record)->eSweepAngle = eSweepAngle; + } + return(record); +} + +// U_EMRELLIPSE_set 42 +/** + \brief Allocate and construct a U_EMR_ELLIPSE record. + \return pointer to U_EMR_ELLIPSE record, or NULL on error. + \param rclBox bounding rectangle in logical units +*/ +char *U_EMRELLIPSE_set( + const U_RECTL rclBox + ){ + return(U_EMR_CORE4(U_EMR_ELLIPSE,rclBox)); +} + +// U_EMRRECTANGLE_set 43 +/** + \brief Allocate and construct a U_EMR_RECTANGLE record. + \return pointer to U_EMR_RECTANGLE record, or NULL on error. + \param rclBox bounding rectangle in logical units +*/ +char *U_EMRRECTANGLE_set( + const U_RECTL rclBox + ){ + return(U_EMR_CORE4(U_EMR_RECTANGLE,rclBox)); +} + +// U_EMRROUNDRECT_set 44 +/** + \brief Allocate and construct a U_EMR_ROUNDRECT record. + \return pointer to U_EMR_ROUNDRECT record, or NULL on error. + \param rclBox bounding rectangle in logical units + \param szlCorner W & H in logical units of ellipse used to round corner +*/ +char *U_EMRROUNDRECT_set( + const U_RECTL rclBox, + const U_SIZEL szlCorner + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRROUNDRECT); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_ROUNDRECT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRROUNDRECT) record)->rclBox = rclBox; + ((PU_EMRROUNDRECT) record)->szlCorner = szlCorner; + } + return(record); +} + +// U_EMRARC_set 45 +/** + \brief Allocate and construct a U_EMR_ARC record. + \return pointer to U_EMR_ARC record, or NULL on error. + \param rclBox bounding rectangle in logical units + \param ptlStart Start point in logical units + \param ptlEnd End point in logical units +*/ +char *U_EMRARC_set( + const U_RECTL rclBox, + const U_POINTL ptlStart, + const U_POINTL ptlEnd + ){ + return(U_EMR_CORE9(U_EMR_ARC,rclBox, ptlStart, ptlEnd)); +} + +// U_EMRCHORD_set 46 +/** + \brief Allocate and construct a U_EMR_CHORD record. + \return pointer to U_EMR_CHORD record, or NULL on error. + \param rclBox bounding rectangle in logical units + \param ptlStart Start point in logical units + \param ptlEnd End point in logical units +*/ +char *U_EMRCHORD_set( + const U_RECTL rclBox, + const U_POINTL ptlStart, + const U_POINTL ptlEnd + ){ + return(U_EMR_CORE9(U_EMR_CHORD,rclBox, ptlStart, ptlEnd)); +} + +// U_EMRPIE_set 47 +/** + \brief Allocate and construct a U_EMR_PIE record. + \return pointer to U_EMR_PIE record, or NULL on error. + \param rclBox bounding rectangle in logical units + \param ptlStart Start point in logical units + \param ptlEnd End point in logical units +*/ +char *U_EMRPIE_set( + const U_RECTL rclBox, + const U_POINTL ptlStart, + const U_POINTL ptlEnd + ){ + return(U_EMR_CORE9(U_EMR_PIE,rclBox, ptlStart, ptlEnd)); +} + +// U_EMRSELECTPALETTE_set 48 +/** + \brief Allocate and construct a U_EMR_SELECTPALETTE record. + \return pointer to U_EMR_SELECTPALETTE record, or NULL on error. + \param ihPal Index of a Palette object in the EMF object table +*/ +char *U_EMRSELECTPALETTE_set( + const uint32_t ihPal + ){ + return(U_EMR_CORE3(U_EMR_SELECTPALETTE, ihPal)); +} + +// U_EMRCREATEPALETTE_set 49 +/** + \brief Allocate and construct a U_EMR_CREATEPALETTE record. + Use createpalette_set() instead of calling this function directly. + \return pointer to U_EMR_CREATEPALETTE record, or NULL on error. + \param ihPal Index to place object in EMF object table (this entry must not yet exist) + \param lgpl Palette properties +*/ +char *U_EMRCREATEPALETTE_set( + const uint32_t ihPal, + const U_LOGPALETTE lgpl + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRCREATEPALETTE); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_CREATEPALETTE; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCREATEPALETTE) record)->ihPal = ihPal; + ((PU_EMRCREATEPALETTE) record)->lgpl = lgpl; + } + return(record); +} + +// U_EMRSETPALETTEENTRIES_set 50 +/** + \brief Allocate and construct a U_EMR_SETPALETTEENTRIES record. + Use setpaletteentries_set() instead of calling this function directly. + \return pointer to U_EMR_SETPALETTEENTRIES record, or NULL on error. + \param ihPal Index of a Palette object in the EMF object table + \param iStart First Palette entry in selected object to set + \param cEntries Number of Palette entries in selected object to set + \param aPalEntries Values to set with +*/ +char *U_EMRSETPALETTEENTRIES_set( + const uint32_t ihPal, + const uint32_t iStart, + const U_NUM_LOGPLTNTRY cEntries, + const PU_LOGPLTNTRY aPalEntries + ){ + char *record; + int irecsize; + int cbPals; + + if(!aPalEntries)return(NULL); + cbPals = cEntries * sizeof(U_LOGPLTNTRY); + irecsize = sizeof(U_EMRSETPALETTEENTRIES) + cbPals - sizeof(U_LOGPLTNTRY); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SETPALETTEENTRIES; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETPALETTEENTRIES) record)->ihPal = ihPal; + ((PU_EMRSETPALETTEENTRIES) record)->iStart = iStart; + ((PU_EMRSETPALETTEENTRIES) record)->cEntries = cEntries; + memcpy(((PU_EMRSETPALETTEENTRIES) record)->aPalEntries, aPalEntries,cbPals); + } + return(record); +} + +// U_EMRRESIZEPALETTE_set 51 +/** + \brief Allocate and construct a U_EMR_RESIZEPALETTE record. + \return pointer to U_EMR_RESIZEPALETTE record, or NULL on error. + \param ihPal Index of a Palette object in the EMF object table + \param cEntries Number to expand or truncate the Palette entry list to +*/ +char *U_EMRRESIZEPALETTE_set( + const uint32_t ihPal, + const uint32_t cEntries + ){ + return(U_EMR_CORE7(U_EMR_RESIZEPALETTE, (U_PAIR){ihPal,cEntries})); +} + +// U_EMRREALIZEPALETTE_set 52 +/** + \brief Allocate and construct a U_EMR_REALIZEPALETTE record. + \return pointer to U_EMR_REALIZEPALETTE record, or NULL on error. +*/ +char *U_EMRREALIZEPALETTE_set(void){ + return(U_EMR_CORE5(U_EMR_REALIZEPALETTE)); +} + +// U_EMREXTFLOODFILL_set 53 +/** + \brief Allocate and construct a U_EMR_EXTFLOODFILL record. + \return pointer to U_EMR_EXTFLOODFILL record, or NULL on error. + \param ptlStart Start point in logical units + \param crColor Color to fill with + \param iMode FloodFill Enumeration +*/ +char *U_EMREXTFLOODFILL_set( + const U_POINTL ptlStart, + const U_COLORREF crColor, + const uint32_t iMode + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMREXTFLOODFILL); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_EXTFLOODFILL; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMREXTFLOODFILL) record)->ptlStart = ptlStart; + ((PU_EMREXTFLOODFILL) record)->crColor = crColor; + ((PU_EMREXTFLOODFILL) record)->iMode = iMode; + } + return(record); +} + +// U_EMRLINETO_set 54 +/** + \brief Allocate and construct a U_EMR_LINETO record. + \return pointer to U_EMR_LINETO record, or NULL on error. + \param ptl Point coordinates +*/ +char *U_EMRLINETO_set( + const U_POINTL ptl + ){ + return(U_EMR_CORE7(U_EMR_LINETO, ptl)); +} + +// U_EMRARCTO_set 55 +/** + \brief Allocate and construct a U_EMR_ARCTO record. + \return pointer to U_EMR_ARCTO record, or NULL on error. + \param rclBox bounding rectangle in logical units + \param ptlStart Start point in logical units + \param ptlEnd End point in logical units + + Note that the draw begins with a line from the current point to ptlStart, which is + not indicated in the Microsoft EMF documentation for this record. +*/ +char *U_EMRARCTO_set( + U_RECTL rclBox, + U_POINTL ptlStart, + U_POINTL ptlEnd + ){ + return(U_EMR_CORE9(U_EMR_ARCTO,rclBox, ptlStart, ptlEnd)); +} + +// U_EMRPOLYDRAW_set 56 +/** + \brief Allocate and construct a U_EMR_POLYDRAW record. + \return pointer to U_EMR_POLYDRAW record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cptl Number of U_POINTL objects + \param aptl Array of U_POINTL objects + \param abTypes Array of Point Enumeration +*/ +char *U_EMRPOLYDRAW_set( + const U_RECTL rclBounds, + const U_NUM_POINTL cptl, + const U_POINTL *aptl, + const uint8_t *abTypes + ){ + char *record; + int irecsize; + int cbPoints, cbAbTypes, cbAbTypes4, off; + + if(!cptl || !aptl || !abTypes)return(NULL); + cbPoints = cptl * sizeof(U_POINTL); // space for aptl + cbAbTypes = cptl; // number of abTypes (also size, 1 byte each) + cbAbTypes4 = UP4(cbAbTypes); // space for abTypes + irecsize = sizeof(U_EMRPOLYDRAW) + cbPoints + cbAbTypes4 - sizeof(U_POINTL) - 1; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_POLYDRAW; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPOLYDRAW) record)->rclBounds = rclBounds; + ((PU_EMRPOLYDRAW) record)->cptl = cptl; + off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t); // offset to first variable part + memcpy(record+off,aptl,cbPoints); + off += cbPoints; + memcpy(record+off,abTypes,cbAbTypes); + off += cbAbTypes; + if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array) + } + return(record); +} + +// U_EMRSETARCDIRECTION_set 57 +/** + \brief Allocate and construct a U_EMR_SETARCDIRECTION record. + \return pointer to U_EMR_SETARCDIRECTION record, or NULL on error. + \param iArcDirection ArcDirection Enumeration +*/ +char *U_EMRSETARCDIRECTION_set( + const uint32_t iArcDirection + ){ + return(U_EMR_CORE3(U_EMR_SETARCDIRECTION, iArcDirection)); +} + +// U_EMRSETMITERLIMIT_set 58 +/** + \brief Allocate and construct a U_EMR_SETMITERLIMIT record. + \return pointer to U_EMR_SETMITERLIMIT record, or NULL on error. + \param eMiterLimit MapMode Enumeration +*/ +char *U_EMRSETMITERLIMIT_set( + const uint32_t eMiterLimit + ){ + return(U_EMR_CORE3(U_EMR_SETMITERLIMIT, eMiterLimit)); +} + + +// U_EMRBEGINPATH_set 59 +/** + \brief Allocate and construct a U_EMR_BEGINPATH record. + \return pointer to U_EMR_BEGINPATH record, or NULL on error. +*/ +char *U_EMRBEGINPATH_set(void){ + return(U_EMR_CORE5(U_EMR_BEGINPATH)); +} + +// U_EMRENDPATH_set 60 +/** + \brief Allocate and construct a U_EMR_ENDPATH record. + \return pointer to U_EMR_ENDPATH record, or NULL on error. +*/ +char *U_EMRENDPATH_set(void){ + return(U_EMR_CORE5(U_EMR_ENDPATH)); +} + +// U_EMRCLOSEFIGURE_set 61 +/** + \brief Allocate and construct a U_EMR_CLOSEFIGURE record. + \return pointer to U_EMR_CLOSEFIGURE record, or NULL on error. +*/ +char *U_EMRCLOSEFIGURE_set(void){ + return(U_EMR_CORE5(U_EMR_CLOSEFIGURE)); +} + +// U_EMRFILLPATH_set 62 +/** + \brief Allocate and construct a U_EMR_FILLPATH record. + \return pointer to U_EMR_FILLPATH record, or NULL on error. + \param rclBox Bounding rectangle in device units + + U_EMR_FILLPATH closes the open figure before filling. +*/ +char *U_EMRFILLPATH_set( + const U_RECTL rclBox + ){ + return(U_EMR_CORE4(U_EMR_FILLPATH,rclBox)); +} + +// U_EMRSTROKEANDFILLPATH_set 63 +/** + \brief Allocate and construct a U_EMR_STROKEANDFILLPATH record. + \return pointer to U_EMR_STROKEANDFILLPATH record, or NULL on error. + \param rclBox Bounding rectangle in device units + + U_EMR_STROKEANDFILLPATH closes the open figure before filling and stroking. + There appears to be no way to fill an open path while stroking it, as any one + of U_EMRFILLPATH, U_EMRSTROKEPATH, or U_EMRSTROKEANDFILEPATH will "use up" the path, +*/ +char *U_EMRSTROKEANDFILLPATH_set( + const U_RECTL rclBox + ){ + return(U_EMR_CORE4(U_EMR_STROKEANDFILLPATH,rclBox)); +} + +// U_EMRSTROKEPATH_set 64 +/** + \brief Allocate and construct a U_EMR_STROKEPATH record. + \return pointer to U_EMR_STROKEPATH record, or NULL on error. + \param rclBox Bounding rectangle in device units + + U_EMR_STROKEPATH does NOT close the open figure before stroking it. +*/ +char *U_EMRSTROKEPATH_set( + const U_RECTL rclBox + ){ + return(U_EMR_CORE4(U_EMR_STROKEPATH,rclBox)); +} + +// U_EMRFLATTENPATH_set 65 +/** + \brief Allocate and construct a U_EMR_FLATTENPATH record. + \return pointer to U_EMR_FLATTENPATH record, or NULL on error. +*/ +char *U_EMRFLATTENPATH_set(void){ + return(U_EMR_CORE5(U_EMR_FLATTENPATH)); +} + +// U_EMRWIDENPATH_set 66 +/** + \brief Allocate and construct a U_EMR_WIDENPATH record. + \return pointer to U_EMR_WIDENPATH record, or NULL on error. +*/ +char *U_EMRWIDENPATH_set(void){ + return(U_EMR_CORE5(U_EMR_WIDENPATH)); +} + +// U_EMRSELECTCLIPPATH_set 67 +/** + \brief Allocate and construct a U_EMR_SELECTCLIPPATH record. + \return pointer to U_EMR_SELECTCLIPPATH record, or NULL on error. + \param iMode RegionMode Enumeration +*/ +char *U_EMRSELECTCLIPPATH_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SELECTCLIPPATH, iMode)); +} + +// U_EMRABORTPATH_set 68 +/** + \brief Allocate and construct a U_EMR_ABORTPATH record. + \return pointer to U_EMR_ABORTPATH record, or NULL on error. +*/ +char *U_EMRABORTPATH_set(void){ + return(U_EMR_CORE5(U_EMR_ABORTPATH)); +} + +// U_EMRUNDEF69 69 + +// U_EMRCOMMENT_set 70 Comment (any binary data, interpretation is program specific) +/** + \brief Allocate and construct a U_EMR_COMMENT record. + \return pointer to U_EMR_COMMENT record, or NULL on error. + \param cbData Number of bytes in comment + \param Data Comment (any binary data, interpretation is program specific) +*/ +char *U_EMRCOMMENT_set( + const U_CBDATA cbData, + const char *Data + ){ + char *record; + unsigned int cbData4; + int irecsize; + + cbData4 = UP4(cbData); + irecsize = sizeof(U_EMR) + sizeof(U_CBDATA) + cbData4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_COMMENT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCOMMENT) record)->cbData = cbData; + memcpy(record + irecsize - cbData4,Data,cbData); + if(cbData4 > cbData)memset(record + irecsize - cbData4 + cbData,0,cbData4-cbData); // clear any unused bytes + } + return(record); +} + +// U_EMRFILLRGN_set 71 +/** + \brief Allocate and construct a U_EMR_FILLRGN record. + Use fillrgn_set() instead of calling this function directly. + \return pointer to U_EMR_FILLRGN record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param ihBrush Index of a Brush object in the EMF object table + \param RgnData Pointer to a U_RGNDATA structure +*/ +char *U_EMRFILLRGN_set( + const U_RECTL rclBounds, + const uint32_t ihBrush, + const PU_RGNDATA RgnData + ){ + char *record; + int irecsize; + int cbRgns,cbRgns4,off; + + if(!RgnData)return(NULL); + cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; + cbRgns4 = UP4(cbRgns); + irecsize = sizeof(U_EMRFILLRGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_FILLRGN; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRFILLRGN) record)->rclBounds = rclBounds; // or ??? ((PU_RGNDATAHEADER) RgnData)->rclBounds; + ((PU_EMRFILLRGN) record)->cbRgnData = cbRgns; + ((PU_EMRFILLRGN) record)->ihBrush = ihBrush; + off = irecsize - cbRgns4; + memcpy(record + off, RgnData, cbRgns); + off += cbRgns; + if(cbRgns4 > cbRgns){ memset(record + off,0,cbRgns4-cbRgns); } // clear any unused bytes + } + return(record); +} + +// U_EMRFRAMERGN_set 72 +/** + \brief Allocate and construct a U_EMR_FRAMERGN record. + Use framegrn_set() instead of calling this function directly. + \return pointer to U_EMR_FRAMERGN record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param ihBrush Index of a Brush object in the EMF object table + \param szlStroke W & H of Brush stroke + \param RgnData Pointer to a U_RGNDATA structure +*/ +char *U_EMRFRAMERGN_set( + const U_RECTL rclBounds, + const uint32_t ihBrush, + const U_SIZEL szlStroke, + const PU_RGNDATA RgnData + ){ + char *record; + int irecsize; + int cbRgns,cbRgns4,off; + + if(!RgnData)return(NULL); + cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; + cbRgns4 = UP4(cbRgns); + irecsize = sizeof(U_EMRFRAMERGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_FRAMERGN; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRFRAMERGN) record)->rclBounds = rclBounds; // or ??? ((PU_RGNDATAHEADER) RgnData)->rclBounds; + ((PU_EMRFRAMERGN) record)->cbRgnData = cbRgns; + ((PU_EMRFRAMERGN) record)->ihBrush = ihBrush; + ((PU_EMRFRAMERGN) record)->szlStroke = szlStroke; + off = irecsize - cbRgns4; + memcpy(record + off, RgnData, cbRgns); + off += cbRgns; + if(cbRgns4 > cbRgns){ memset(record + off,0,cbRgns4-cbRgns); } // clear any unused bytes + } + return(record); +} + +// U_EMRINVERTRGN_set 73 +/** + \brief Allocate and construct a U_EMR_INVERTRGN record. + \return pointer to U_EMR_INVERTRGN record, or NULL on error. + \param RgnData Variable size U_RGNDATA structure +*/ +char *U_EMRINVERTRGN_set( + const PU_RGNDATA RgnData + ){ + return(U_EMR_CORE11(U_EMR_INVERTRGN, RgnData)); +} + +// U_EMRPAINTRGN_set 74 +/** + \brief Allocate and construct a U_EMR_PAINTRGN record. + \return pointer to U_EMR_PAINTRGN record, or NULL on error. + \param RgnData Variable size U_RGNDATA structure +*/ +char *U_EMRPAINTRGN_set( + const PU_RGNDATA RgnData + ){ + return(U_EMR_CORE11(U_EMR_PAINTRGN, RgnData)); +} + +// U_EMREXTSELECTCLIPRGN_set 75 +/** + \brief Allocate and construct a U_EMR_EXTSELECTCLIPRGN record. + \return pointer to U_EMR_EXTSELECTCLIPRGN or NULL on error. + \param iMode RegionMode Enumeration + \param RgnData Variable size U_RGNDATA structure +*/ +char *U_EMREXTSELECTCLIPRGN_set( + const uint32_t iMode, + const PU_RGNDATA RgnData + ){ + char *record; + int irecsize; + int cbRgns,cbRgns4,off; + + if(!RgnData)return(NULL); + cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; + cbRgns4 = UP4(cbRgns); + irecsize = sizeof(U_EMREXTSELECTCLIPRGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_EXTSELECTCLIPRGN; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMREXTSELECTCLIPRGN) record)->cbRgnData = cbRgns; + ((PU_EMREXTSELECTCLIPRGN) record)->iMode = iMode; + off = irecsize - cbRgns4; + memcpy(record + off, RgnData, cbRgns); + off += cbRgns; + if(cbRgns4 > cbRgns){ memset(record + off,0,cbRgns4-cbRgns); } // clear any unused bytes + } + return(record); +} + +// U_EMRBITBLT_set 76 +/** + \brief Allocate and construct a U_EMR_BITBLT record. + \return pointer to U_EMR_BITBLT record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param cDest Destination width in logical units + \param Src Source rectangle UL corner in logical units + \param xformSrc Source bitmap transform (world to page coordinates) + \param crBkColorSrc Source bitmap background color + \param iUsageSrc DIBcolors Enumeration + \param dwRop Ternary Raster Operation enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRBITBLT_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL cDest, + const U_POINTL Src, + const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = sizeof(U_EMRBITBLT) + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_BITBLT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRBITBLT) record)->rclBounds = rclBounds; + ((PU_EMRBITBLT) record)->Dest = Dest; + ((PU_EMRBITBLT) record)->cDest = cDest; + ((PU_EMRBITBLT) record)->dwRop = dwRop; + ((PU_EMRBITBLT) record)->Src = Src; + ((PU_EMRBITBLT) record)->xformSrc = xformSrc; + ((PU_EMRBITBLT) record)->crBkColorSrc = crBkColorSrc; + ((PU_EMRBITBLT) record)->iUsageSrc = iUsageSrc; + off = sizeof(U_EMRBITBLT); + APPEND_PXBMISRC(record, U_EMRBITBLT, cbBmi, Bmi, Px, cbImage, cbImage4); + } + return(record); +} + +// U_EMRSTRETCHBLT_set 77 +/** + \brief Allocate and construct a U_EMR_STRETCHBLT record. + \return pointer to U_EMR_STRETCHBLT record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param cDest Destination width in logical units + \param Src Source UL corner in logical units + \param cSrc Src W & H in logical units + \param xformSrc Transform to apply to source + \param crBkColorSrc Background color + \param iUsageSrc DIBcolors Enumeration + \param dwRop Ternary Raster Operation enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRSTRETCHBLT_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL cDest, + const U_POINTL Src, + const U_POINTL cSrc, + const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = sizeof(U_EMRSTRETCHBLT) + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_STRETCHBLT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSTRETCHBLT) record)->rclBounds = rclBounds; + ((PU_EMRSTRETCHBLT) record)->Dest = Dest; + ((PU_EMRSTRETCHBLT) record)->cDest = cDest; + ((PU_EMRSTRETCHBLT) record)->dwRop = dwRop; + ((PU_EMRSTRETCHBLT) record)->Src = Src; + ((PU_EMRSTRETCHBLT) record)->xformSrc = xformSrc; + ((PU_EMRSTRETCHBLT) record)->crBkColorSrc = crBkColorSrc; + ((PU_EMRSTRETCHBLT) record)->iUsageSrc = iUsageSrc; + off = sizeof(U_EMRSTRETCHBLT); + APPEND_PXBMISRC(record, U_EMRSTRETCHBLT, cbBmi, Bmi, Px, cbImage, cbImage4); + ((PU_EMRSTRETCHBLT) record)->cSrc = cSrc; + } + return(record); +} + +// U_EMRMASKBLT_set 78 +/** + \brief Allocate and construct a U_EMR_MASKBLT record. + \return pointer to U_EMR_MASKBLT record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param cDest Destination width in logical units + \param Src Source UL corner in logical units + \param xformSrc Transform to apply to source + \param crBkColorSrc Background color + \param iUsageSrc DIBcolors Enumeration + \param Mask Mask UL corner in logical units + \param iUsageMask DIBcolors Enumeration + \param dwRop Ternary Raster Operation enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) + \param MskBmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbMsk Size in bytes of mask array (row stride * height, there may be some padding at the end of each row) + \param Msk (Optional) bitmapbuffer (mask section ) +*/ +char *U_EMRMASKBLT_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL cDest, + const U_POINTL Src, + const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, + const U_POINTL Mask, + const uint32_t iUsageMask, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px, + const PU_BITMAPINFO MskBmi, + const uint32_t cbMsk, + char *Msk + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk); + + irecsize = sizeof(U_EMRMASKBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_MASKBLT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRMASKBLT) record)->rclBounds = rclBounds; + ((PU_EMRMASKBLT) record)->Dest = Dest; + ((PU_EMRMASKBLT) record)->cDest = cDest; + ((PU_EMRMASKBLT) record)->dwRop = dwRop; + ((PU_EMRMASKBLT) record)->Src = Src; + ((PU_EMRMASKBLT) record)->xformSrc = xformSrc; + ((PU_EMRMASKBLT) record)->crBkColorSrc = crBkColorSrc; + ((PU_EMRMASKBLT) record)->iUsageSrc = iUsageSrc; + ((PU_EMRMASKBLT) record)->Mask = Mask; + ((PU_EMRMASKBLT) record)->iUsageMask = iUsageMask; + off = sizeof(U_EMRMASKBLT); + APPEND_PXBMISRC(record, U_EMRMASKBLT, cbBmi, Bmi, Px, cbImage, cbImage4); + APPEND_MSKBMISRC(record, U_EMRMASKBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4); + } + return(record); +} + +// U_EMRPLGBLT_set 79 + +/** + \brief Allocate and construct a U_EMRPLGBLT record. + \return U_EMRPLGBLT record. + \param rclBounds Bounding rectangle in device units + \param aptlDst Defines parallelogram, UL, UR, LL corners, LR is derived (3 points) + \param Src Source UL corner in logical units + \param cSrc Source width in logical units + \param xformSrc Transform to apply to source + \param crBkColorSrc Background color + \param iUsageSrc DIBcolors Enumeration + \param Mask Mask UL corner in logical units + \param iUsageMask DIBcolors Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) + \param MskBmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbMsk Size in bytes of mask array (row stride * height, there may be some padding at the end of each row) + \param Msk (Optional) bitmapbuffer (mask section ) +*/ +char *U_EMRPLGBLT_set( + const U_RECTL rclBounds, + const PU_POINTL aptlDst, + const U_POINTL Src, + const U_POINTL cSrc, + const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, + const U_POINTL Mask, + const uint32_t iUsageMask, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px, + const PU_BITMAPINFO MskBmi, + const uint32_t cbMsk, + char *Msk + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk); + + irecsize = sizeof(U_EMRPLGBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_PLGBLT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPLGBLT) record)->rclBounds = rclBounds; + memcpy(((PU_EMRPLGBLT) record)->aptlDst,aptlDst,3*sizeof(U_POINTL)); + ((PU_EMRPLGBLT) record)->Src = Src; + ((PU_EMRPLGBLT) record)->cSrc = cSrc; + ((PU_EMRPLGBLT) record)->xformSrc = xformSrc; + ((PU_EMRPLGBLT) record)->crBkColorSrc = crBkColorSrc; + ((PU_EMRPLGBLT) record)->iUsageSrc = iUsageSrc; + ((PU_EMRPLGBLT) record)->Mask = Mask; + ((PU_EMRPLGBLT) record)->iUsageMask = iUsageMask; + off = sizeof(U_EMRPLGBLT); + APPEND_PXBMISRC(record, U_EMRPLGBLT, cbBmi, Bmi, Px, cbImage, cbImage4); + APPEND_MSKBMISRC(record, U_EMRPLGBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4); + } + return(record); +} + +// U_EMRSETDIBITSTODEVICE_set 80 +/** + \brief Allocate and construct a U_EMR_SETDIBITSTODEVICE record. + \return pointer to U_EMR_SETDIBITSTODEVICE record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param iUsageSrc DIBColors Enumeration + \param iStartScan First scan line + \param cScans Number of scan lines + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRSETDIBITSTODEVICE_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL Src, + const U_POINTL cSrc, + const uint32_t iUsageSrc, + const uint32_t iStartScan, + const uint32_t cScans, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = sizeof(U_EMRSETDIBITSTODEVICE) + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SETDIBITSTODEVICE; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSETDIBITSTODEVICE) record)->rclBounds = rclBounds; + ((PU_EMRSETDIBITSTODEVICE) record)->Dest = Dest; + ((PU_EMRSETDIBITSTODEVICE) record)->Src = Src; + ((PU_EMRSETDIBITSTODEVICE) record)->cSrc = cSrc; + ((PU_EMRSETDIBITSTODEVICE) record)->iUsageSrc = iUsageSrc; + ((PU_EMRSETDIBITSTODEVICE) record)->iStartScan = iStartScan; + ((PU_EMRSETDIBITSTODEVICE) record)->cScans = cScans; + off = sizeof(U_EMRSETDIBITSTODEVICE); + APPEND_PXBMISRC(record, U_EMRSETDIBITSTODEVICE, cbBmi, Bmi, Px, cbImage, cbImage4); + } + return(record); +} + +// U_EMRSTRETCHDIBITS_set 81 +/** + \brief Allocate and construct a U_EMR_EMRSTRETCHDIBITS record. + \return pointer to U_EMR_EMRSTRETCHDIBITS record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param cDest Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param iUsageSrc DIBColors Enumeration + \param dwRop RasterOPeration Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRSTRETCHDIBITS_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL cDest, + const U_POINTL Src, + const U_POINTL cSrc, + const uint32_t iUsageSrc, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px + ){ + char *record; + int irecsize; + int cbImage,cbImage4,cbBmi,off; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = sizeof(U_EMRSTRETCHDIBITS) + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_STRETCHDIBITS; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSTRETCHDIBITS) record)->rclBounds = rclBounds; + ((PU_EMRSTRETCHDIBITS) record)->Dest = Dest; + ((PU_EMRSTRETCHDIBITS) record)->Src = Src; + ((PU_EMRSTRETCHDIBITS) record)->cSrc = cSrc; + ((PU_EMRSTRETCHDIBITS) record)->iUsageSrc = iUsageSrc; + ((PU_EMRSTRETCHDIBITS) record)->dwRop = dwRop; + ((PU_EMRSTRETCHDIBITS) record)->cDest = cDest; + off = sizeof(U_EMRSTRETCHDIBITS); + APPEND_PXBMISRC(record, U_EMRSTRETCHDIBITS, cbBmi, Bmi, Px, cbImage, cbImage4); + } + return(record); +} + +// U_EMREXTCREATEFONTINDIRECTW_set 82 +/** + \brief Allocate and construct a U_EMR_EXTCREATEFONTINDIRECTW record. + Use extcreatefontindirectw_set() instead of calling this function directly. + \return pointer to U_EMR_EXTCREATEFONTINDIRECTW record, or NULL on error. + \param ihFont Index of the font in the EMF object table + \param elf Font parameters as U_LOGFONT + \param elfw Font parameters as U_LOGFONT_PANOSE +*/ +char *U_EMREXTCREATEFONTINDIRECTW_set( + const uint32_t ihFont, + const char * elf, + const char * elfw + ){ + char *record; + const char *cptr; + int irecsize; + int cbLf,off; + + if((elf && elfw) || (!elf && !elfw))return(NULL); // ONE only must be passed + if(elf){ cbLf = sizeof(U_LOGFONT); cptr = elf; } + else { cbLf = sizeof(U_LOGFONT_PANOSE); cptr = elfw; } + + irecsize = sizeof(U_EMR) + sizeof(uint32_t) + cbLf; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_EXTCREATEFONTINDIRECTW; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMREXTCREATEFONTINDIRECTW) record)->ihFont = ihFont; + off = sizeof(U_EMR) + sizeof(uint32_t); + memcpy(record + off, cptr, cbLf); // No need to add padding for either structure + } + return(record); +} + +// U_EMREXTTEXTOUTA_set 83 +/** + \brief Allocate and construct a U_EMR_EXTTEXTOUTA record. + \return pointer to U_EMR_EXTTEXTOUTA record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param iGraphicsMode Graphics mode Enumeration + \param exScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE) + \param eyScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE) + \param emrtext Text parameters +*/ +char *U_EMREXTTEXTOUTA_set( + const U_RECTL rclBounds, + const uint32_t iGraphicsMode, + const U_FLOAT exScale, + const U_FLOAT eyScale, + const PU_EMRTEXT emrtext + ){ + return(U_EMR_CORE8(U_EMR_EXTTEXTOUTA,rclBounds, iGraphicsMode, exScale, eyScale,emrtext)); +} + +// U_EMREXTTEXTOUTW_set 84 +/** + \brief Allocate and construct a U_EMR_EXTTEXTOUTW record. + \return pointer to U_EMR_EXTTEXTOUTW record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param iGraphicsMode Graphics mode Enumeration + \param exScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE) + \param eyScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE) + \param emrtext Text parameters +*/ +char *U_EMREXTTEXTOUTW_set( + const U_RECTL rclBounds, + const uint32_t iGraphicsMode, + const U_FLOAT exScale, + const U_FLOAT eyScale, + const PU_EMRTEXT emrtext + ){ + return(U_EMR_CORE8(U_EMR_EXTTEXTOUTW,rclBounds, iGraphicsMode, exScale, eyScale,emrtext)); +} + +// U_EMRPOLYBEZIER16_set 85 +/** + \brief Allocate and construct a U_EMR_POLYBEZIER16 record. + \return pointer to U_EMR_POLYBEZIER16 record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYBEZIER16_set( + const U_RECTL rclBounds, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE6(U_EMR_POLYBEZIER16, rclBounds, cpts, points)); +} + +// U_EMRPOLYGON16_set 86 +/** + \brief Allocate and construct a U_EMR_POLYGON16 record. + \return pointer to U_EMR_POLYGON16 record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYGON16_set( + const U_RECTL rclBounds, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE6(U_EMR_POLYGON16, rclBounds, cpts, points)); +} + +// U_EMRPOLYLINE16_set 87 +/** + \brief Allocate and construct a U_EMR_POLYLINE16 record. + \return pointer to U_EMR_POLYLINE16 record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYLINE16_set( + const U_RECTL rclBounds, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE6(U_EMR_POLYLINE16, rclBounds, cpts, points)); +} + +// U_EMRPOLYBEZIERTO16_set 88 +/** + \brief Allocate and construct a U_EMR_POLYBEZIERTO record. + \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYBEZIERTO16_set( + const U_RECTL rclBounds, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE6(U_EMR_POLYBEZIERTO16, rclBounds, cpts, points)); +} + +// U_EMRPOLYLINETO16_set 89 +/** + \brief Allocate and construct a U_EMR_POLYLINETO record. + \return pointer to U_EMR_POLYLINETO record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYLINETO16_set( + const U_RECTL rclBounds, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE6(U_EMR_POLYLINETO16, rclBounds, cpts, points)); +} + +// U_EMRPOLYPOLYLINE16_set 90 +/** + \brief Allocate and construct a U_EMR_POLYPOLYLINE16 record. + \return pointer to U_EMR_POLYPOLYLINE16 record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYPOLYLINE16_set( + const U_RECTL rclBounds, + const uint32_t nPolys, + const uint32_t *aPolyCounts, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE10(U_EMR_POLYPOLYLINE16, rclBounds, nPolys, aPolyCounts,cpts, points)); +} + +// U_EMRPOLYPOLYGON16_set 91 +/** + \brief Allocate and construct a U_EMR_POLYPOLYGON16 record. + \return pointer to U_EMR_POLYPOLYGON16 record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param cpts Number of POINT16 in array + \param points Array of POINT16 +*/ +char *U_EMRPOLYPOLYGON16_set( + const U_RECTL rclBounds, + const uint32_t nPolys, + const uint32_t *aPolyCounts, + const uint32_t cpts, + const U_POINT16 *points + ){ + return(U_EMR_CORE10(U_EMR_POLYPOLYGON16, rclBounds, nPolys, aPolyCounts,cpts, points)); +} + + +// U_EMRPOLYDRAW16_set 92 +/** + \brief Allocate and construct a U_EMR_POLYDRAW16 record. + \return pointer to U_EMR_POLYDRAW16 record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param cpts Number of U_POINTL objects + \param aptl Array of U_POINTL objects + \param abTypes Array of Point Enumeration +*/ +char *U_EMRPOLYDRAW16_set( + const U_RECTL rclBounds, + const U_NUM_POINT16 cpts, + const U_POINT16 *aptl, + const uint8_t *abTypes + ){ + char *record; + int irecsize; + int cbPoints, cbAbTypes, cbAbTypes4, off; + + if(!cpts || !aptl || !abTypes)return(NULL); + cbPoints = cpts * sizeof(U_POINT16); // space for aptl + cbAbTypes = cpts; // number of abTypes (also size, 1 byte each) + cbAbTypes4 = UP4(cbAbTypes); // space for abTypes + irecsize = sizeof(U_EMRPOLYDRAW16) + cbPoints + cbAbTypes4 - sizeof(U_POINT16) - 1; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_POLYDRAW16; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPOLYDRAW16) record)->rclBounds = rclBounds; + ((PU_EMRPOLYDRAW16) record)->cpts = cpts; + off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t); // offset to first variable part + memcpy(record+off,aptl,cbPoints); + off += cbPoints; + memcpy(record+off,abTypes,cbAbTypes); + off += cbAbTypes; + if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array) + } + return(record); +} + +// U_EMRCREATEMONOBRUSH_set 93 +/** + \brief Allocate and construct a U_EMR_CREATEMONOBRUSH record. + \return pointer to U_EMR_CREATEMONOBRUSH record, or NULL on error. + \param ihBrush Index to place object in EMF object table (this entry must not yet exist) + \param iUsage DIBcolors Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO + pixel array) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRCREATEMONOBRUSH_set( + const uint32_t ihBrush, + const uint32_t iUsage, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + ){ + return(U_EMR_CORE12_set(U_EMR_CREATEMONOBRUSH,ihBrush,iUsage,Bmi,cbPx,Px)); +} + +// U_EMRCREATEDIBPATTERNBRUSHPT_set 94 +/** + \brief Allocate and construct a U_EMR_CREATEDIBPATTERNBRUSHPT record. + Use createdibpatternbrushpt_set() instead of calling this function directly. + \return pointer to U_EMR_CREATEDIBPATTERNBRUSHPT record, or NULL on error. + \param ihBrush Index to place object in EMF object table (this entry must not yet exist) + \param iUsage DIBcolors Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO + pixel array) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRCREATEDIBPATTERNBRUSHPT_set( + const uint32_t ihBrush, + const uint32_t iUsage, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + ){ + return(U_EMR_CORE12_set(U_EMR_CREATEDIBPATTERNBRUSHPT,ihBrush,iUsage,Bmi,cbPx,Px)); +} + + +// U_EMREXTCREATEPEN_set 95 +/** + \brief Allocate and construct a U_EMR_EXTCREATEPEN record. + Use extcreatepen_set() instead of calling this function directly. + \return pointer to U_EMR_EXTCREATEPEN record, or NULL on error. + \param ihPen ihPen Index to place object in EMF object table (this entry must not yet exist) + \param Bmi Bmi bitmapbuffer + \param cbPx cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px Px pixel array (NULL if cbPx == 0) + \param elp elp Pen parameters (Size is Variable!!!!) +*/ +char *U_EMREXTCREATEPEN_set( + const uint32_t ihPen, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px, + const PU_EXTLOGPEN elp + ){ + char *record; + int cbImage,cbImage4,cbBmi,off; + int irecsize,cbStyleArray,cbElp; + + if(!elp)return(NULL); + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + cbStyleArray = elp->elpNumEntries * sizeof(U_STYLEENTRY); // space actually used by penstyle entries + // EXTLOGPEN is already included in EMREXTCREATEPEN, including the possibly unused first penstyle entry + if(cbStyleArray){ + cbElp = sizeof(U_EXTLOGPEN) + cbStyleArray - sizeof(U_STYLEENTRY); // space actually used by elp + irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4 + cbStyleArray - sizeof(U_STYLEENTRY); + } + else { + cbElp = sizeof(U_EXTLOGPEN); // first U_STYLEENTRY is present but unused + irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4; + } + record = malloc(irecsize); + + if(record){ + ((PU_EMR) record)->iType = U_EMR_EXTCREATEPEN; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMREXTCREATEPEN) record)->ihPen = ihPen; + memcpy(&(((PU_EMREXTCREATEPEN) record)->elp),elp,cbElp); + if(cbStyleArray){ + off = sizeof(U_EMREXTCREATEPEN) + cbStyleArray - sizeof(U_STYLEENTRY); + } + else { + off = sizeof(U_EMREXTCREATEPEN); + } + // Cannot use APPEND_PXBMISRC here because there is no "Src" in the field names + if(cbBmi){ + memcpy(record + off, Bmi, cbBmi); + ((PU_EMREXTCREATEPEN) record)->offBmi = off; + ((PU_EMREXTCREATEPEN) record)->cbBmi = cbBmi; + off += cbBmi; + memcpy(record + off, Px, cbImage); + ((PU_EMREXTCREATEPEN) record)->offBits = off; + ((PU_EMREXTCREATEPEN) record)->cbBits = cbImage; + off += cbImage; + if(cbImage4 - cbImage){ memset(record + off, 0, cbImage4 - cbImage); } + } + else { + ((PU_EMREXTCREATEPEN) record)->cbBmi = 0; + ((PU_EMREXTCREATEPEN) record)->offBmi = 0; + ((PU_EMREXTCREATEPEN) record)->cbBits = 0; + ((PU_EMREXTCREATEPEN) record)->offBits = 0; + } + } + return(record); +} + +// U_EMRPOLYTEXTOUTA_set 96 NOT IMPLEMENTED, denigrated after Windows NT +// U_EMRPOLYTEXTOUTW_set 97 NOT IMPLEMENTED, denigrated after Windows NT + +// U_EMRSETICMMODE_set 98 +/** + \brief Allocate and construct a U_EMR_SETICMMODE record. + \return pointer to U_EMR_SETICMMODE record, or NULL on error. + \param iMode ICMMode Enumeration +*/ +char *U_EMRSETICMMODE_set( + const uint32_t iMode + ){ + return(U_EMR_CORE3(U_EMR_SETICMMODE, iMode)); +} + +// U_EMRCREATECOLORSPACE_set 99 +/** + \brief Allocate and construct a U_EMR_CREATECOLORSPACE record. + Use createcolorspace_set() instead of calling this function directly. + \return pointer to U_EMR_CREATECOLORSPACE record, or NULL on error. + \param ihCS Index to place object in EMF object table (this entry must not yet exist) + \param lcs ColorSpace parameters +*/ +char *U_EMRCREATECOLORSPACE_set( + const uint32_t ihCS, + const U_LOGCOLORSPACEA lcs + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRCREATECOLORSPACE); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_CREATECOLORSPACE; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCREATECOLORSPACE) record)->ihCS = ihCS; + ((PU_EMRCREATECOLORSPACE) record)->lcs = lcs; + } + return(record); +} + +// U_EMRSETCOLORSPACE_set 100 +/** + \brief Allocate and construct a U_EMR_SETCOLORSPACE record. + \return pointer to U_EMR_SETCOLORSPACE record, or NULL on error. + \param ihCS Index of object in EMF object table +*/ +char *U_EMRSETCOLORSPACE_set( + const uint32_t ihCS + ){ + return(U_EMR_CORE3(U_EMR_SETCOLORSPACE, ihCS)); +} + +// U_EMRDELETECOLORSPACE_set 101 +/** + \brief Allocate and construct a U_EMR_DELETECOLORSPACE record. + \return pointer to U_EMR_DELETECOLORSPACE record, or NULL on error. + \param ihCS Index of object in EMF object table +*/ +char *U_EMRDELETECOLORSPACE_set( + const uint32_t ihCS + ){ + return(U_EMR_CORE3(U_EMR_DELETECOLORSPACE, ihCS)); +} + +// U_EMRGLSRECORD_set 102 Not implemented +// U_EMRGLSBOUNDEDRECORD_set 103 Not implemented +// U_EMRPIXELFORMAT_set 104 +/** + \brief Allocate and construct a U_EMR_PIXELFORMAT record. + \return pointer to U_EMR_PIXELFORMAT record, or NULL on error. + \param pfd PixelFormatDescriptor +*/ +char *U_EMRPIXELFORMAT_set( + const U_PIXELFORMATDESCRIPTOR pfd + ){ + char *record; + int irecsize; + + irecsize = sizeof(U_EMRPIXELFORMAT); + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_PIXELFORMAT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRPIXELFORMAT) record)->pfd = pfd; + } + return(record); +} +// U_EMRDRAWESCAPE_set 105 Not implemented +// U_EMREXTESCAPE_set 106 Not implemented +// U_EMRUNDEF107_set 107 Not implemented + +// U_EMRSMALLTEXTOUT_set 108 +/** + \brief Allocate and construct a U_EMR_SMALLTEXTOUT record. + \return pointer to U_EMR_SMALLTEXTOUT record, or NULL on error. + \param Dest Where to draw the text + \param cChars Characters in TextString (not null terminated) + \param fuOptions ExtTextOutOptions Enumeration + \param iGraphicsMode GraphicsMode Enumeration + \param exScale scale on X axis + \param eyScale scale on Y axis + \param rclBounds OPTIONAL Bounding rectangle (absent when: fuOPtions & ETO_NO_U_RECT) + \param TextString text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit) +*/ +char *U_EMRSMALLTEXTOUT_set( + const U_POINTL Dest, + const U_NUM_STR cChars, + const uint32_t fuOptions, + const uint32_t iGraphicsMode, + const U_FLOAT exScale, + const U_FLOAT eyScale, + const U_RECTL rclBounds, + const char *TextString + ){ + char *record; + int irecsize,cbString,cbString4,cbRectl,off; + int csize; + + if( fuOptions & U_ETO_SMALL_CHARS ){ csize = 1; } // how many bytes per character + else { csize = 2; } + cbString = csize * cChars; // filled contents of the string buffer + cbString4 = UP4(cbString); // size of the variable string buffer + if(fuOptions & U_ETO_NO_RECT){ cbRectl = 0; } // size of the optional U_RECTL field + else { cbRectl = sizeof(U_RECTL); } + + irecsize = sizeof(U_EMRSMALLTEXTOUT) + cbString4 + cbRectl; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_SMALLTEXTOUT; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRSMALLTEXTOUT) record)->Dest = Dest; + ((PU_EMRSMALLTEXTOUT) record)->cChars = cChars; + ((PU_EMRSMALLTEXTOUT) record)->fuOptions = fuOptions; + ((PU_EMRSMALLTEXTOUT) record)->iGraphicsMode = iGraphicsMode; + ((PU_EMRSMALLTEXTOUT) record)->exScale = exScale; + ((PU_EMRSMALLTEXTOUT) record)->eyScale = eyScale; + off = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields + if(cbRectl){ + memcpy(record + off, &rclBounds, cbRectl); + off += cbRectl; + } + memcpy(record + off, TextString, cbString); + if(cbString < cbString4){ + off += cbString; + memset(record + off, 0, cbString4 - cbString); + } + } + return(record); +} + +// U_EMRFORCEUFIMAPPING_set 109 Not implemented +// U_EMRNAMEDESCAPE_set 110 Not implemented +// U_EMRCOLORCORRECTPALETTE_set 111 Not implemented +// U_EMRSETICMPROFILEA_set 112 Not implemented +// U_EMRSETICMPROFILEW_set 113 Not implemented + +// U_EMRALPHABLEND_set 114 +/** + \brief Allocate and construct a U_EMR_ALPHABLEND record. + \return pointer to U_EMR_ALPHABLEND record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param cDest Destination width in logical units + \param Src Source UL corner in logical units + \param cSrc Src W & H in logical units + \param xformSrc Transform to apply to source + \param crBkColorSrc Background color + \param iUsageSrc DIBcolors Enumeration + \param Blend Blend function + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRALPHABLEND_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL cDest, + const U_POINTL Src, + const U_POINTL cSrc, + const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, + const U_BLEND Blend, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px + ){ + return(U_EMR_CORE13_set(U_EMR_ALPHABLEND,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,*((uint32_t *) &Blend),Bmi,cbPx,Px)); +} + +// U_EMRSETLAYOUT_set 115 +/** + \brief Allocate and construct a U_EMR_SETLAYOUT record. + \return pointer to U_EMR_SETLAYOUT record, or NULL on error. + \param iMode Mirroring Enumeration +*/ +char *U_EMRSETLAYOUT_set(uint32_t iMode){ + return(U_EMR_CORE3(U_EMR_SETLAYOUT, iMode)); +} + +// U_EMRTRANSPARENTBLT_set 116 +/** + \brief Allocate and construct a U_EMR_TRANSPARENTBLT record. + \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param Dest Destination UL corner in logical units + \param cDest Destination width in logical units + \param Src Source UL corner in logical units + \param cSrc Src W & H in logical units + \param xformSrc Transform to apply to source + \param crBkColorSrc Background color + \param iUsageSrc DIBcolors Enumeration + \param TColor Bitmap color to be treated as transparent + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_EMRTRANSPARENTBLT_set( + const U_RECTL rclBounds, + const U_POINTL Dest, + const U_POINTL cDest, + const U_POINTL Src, + const U_POINTL cSrc, + const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, + const uint32_t TColor, + const PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px + ){ + return(U_EMR_CORE13_set(U_EMR_TRANSPARENTBLT,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,TColor,Bmi,cbPx,Px)); +} +// U_EMRUNDEF117_set 117 Not implemented +// U_EMRGRADIENTFILL_set 118 +/** + \brief Allocate and construct a U_EMR_TRANSPARENTBLT record. + \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error. + \param rclBounds Bounding rectangle in device units + \param nTriVert Number of TriVertex objects in TriVert + \param nGradObj Number of gradient triangle/rectangle objects + \param ulMode Gradientfill Enumeration (determines Triangle/Rectangle) + \param TriVert Array of TriVertex objects + \param GradObj Array of gradient objects (each has 2 [rect] or 3 [triangle] indices into TriVert array) +*/ +char *U_EMRGRADIENTFILL_set( + const U_RECTL rclBounds, + const U_NUM_TRIVERTEX nTriVert, + const U_NUM_GRADOBJ nGradObj, + const uint32_t ulMode, + const PU_TRIVERTEX TriVert, + const uint32_t *GradObj + ){ + char *record; + unsigned int cbTriVert,cbGradObj,off; + int irecsize; + + cbTriVert = sizeof(U_TRIVERTEX) * nTriVert; // all of the cb's will be a multiple of 4 bytes + if( ulMode == U_GRADIENT_FILL_TRIANGLE){ cbGradObj = sizeof(U_GRADIENT3) * nGradObj; } + else if(ulMode == U_GRADIENT_FILL_RECT_H || + ulMode == U_GRADIENT_FILL_RECT_V){ cbGradObj = sizeof(U_GRADIENT4) * nGradObj; } + else { return(NULL); } + + irecsize = sizeof(U_EMRGRADIENTFILL) + cbTriVert + cbGradObj; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_GRADIENTFILL; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRGRADIENTFILL) record)->rclBounds = rclBounds; + ((PU_EMRGRADIENTFILL) record)->nTriVert = nTriVert; + ((PU_EMRGRADIENTFILL) record)->nGradObj = nGradObj; + ((PU_EMRGRADIENTFILL) record)->ulMode = ulMode; + off = sizeof(U_EMRGRADIENTFILL); // offset to TriVert field + memcpy(record + off, TriVert, cbTriVert); + off += cbTriVert; + memcpy(record + off, GradObj, cbGradObj); + } + return(record); +} + +// U_EMRSETLINKEDUFIS_set 119 Not implemented +// U_EMRSETTEXTJUSTIFICATION_set 120 Not implemented (denigrated) +// U_EMRCOLORMATCHTOTARGETW_set 121 Not implemented + +// U_EMRCREATECOLORSPACEW_set 122 +/** + \brief Allocate and construct a U_EMR_CREATECOLORSPACEW record. + Use createcolorspacew_set() instead of calling this function directly. + \return pointer to U_EMR_CREATECOLORSPACEW record, or NULL on error. + \param ihCS Index to place object in EMF object table (this entry must not yet exist) + \param lcs ColorSpace parameters + \param dwFlags If low bit set Data is present + \param cbData Number of bytes of theData field. + \param Data (Optional, dwFlags & 1) color profile data +*/ +char *U_EMRCREATECOLORSPACEW_set( + const uint32_t ihCS, + const U_LOGCOLORSPACEW lcs, + const uint32_t dwFlags, + const U_CBDATA cbData, + const uint8_t *Data + ){ + char *record; + unsigned int cbData4,off; + int irecsize; + + cbData4 = UP4(cbData); // buffer to hold Data + irecsize = sizeof(U_EMRCREATECOLORSPACEW) + cbData4; + record = malloc(irecsize); + if(record){ + ((PU_EMR) record)->iType = U_EMR_CREATECOLORSPACEW; + ((PU_EMR) record)->nSize = irecsize; + ((PU_EMRCREATECOLORSPACEW) record)->ihCS = ihCS; + ((PU_EMRCREATECOLORSPACEW) record)->lcs = lcs; + ((PU_EMRCREATECOLORSPACEW) record)->dwFlags = dwFlags; + ((PU_EMRCREATECOLORSPACEW) record)->cbData = cbData; + off = sizeof(U_EMR) + sizeof(uint32_t) + sizeof(U_LOGCOLORSPACEW) + sizeof(uint32_t) + sizeof(U_CBDATA); // offset to Data field + memcpy(record + off, Data, cbData); + if(cbData < cbData4){ + off += cbData; + memset(record + off,0,cbData4-cbData); + } + } + return(record); +} + + + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uemf.h b/src/extension/internal/uemf.h new file mode 100644 index 000000000..4d620b424 --- /dev/null +++ b/src/extension/internal/uemf.h @@ -0,0 +1,2889 @@ +/** + @file uemf.h Structures and functions prototypes for EMF files. + + EMF file Record structure information has been derived from Mingw, Wine, and libEMF header files, and from + Microsoft's EMF Information pdf, release date March 28,2012, link from here: + + http://msdn2.microsoft.com/en-us/library/cc230514.aspx + + If the direct link fails the document may be found + by searching for: "[MS-EMF]: Enhanced Metafile Format" + +*/ + +/* +File: uemf.h +Version: 0.0.19 +Date: 20-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UEMF_ +#define _UEMF_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> +#include "uemf_utf.h" +#include "uemf_endian.h" + + + +// *********************************************************************************** +// defines not placed yet + +#define U_PAN_CULTURE_LATIN 0 + +#define U_SYSPAL_ERROR 0 +#define U_SYSPAL_STATIC 1 +#define U_SYSPAL_NOSTATIC 2 + +#define U_ELF_VENDOR_SIZE 4 + + +// *********************************************************************************** +// Value enumerations and other predefined constants, alphabetical order by group + + +/** \defgroup Font_struct_widths Font name and style widths in characters + For U_LOGFONT and U_LOGFONT_PANOSE, + @{ +*/ +#define U_LF_FACESIZE 32 //!< U_LOGFONT lfFaceName and U_LOGFONT_PANOSE elfStyle fields maximum width +#define U_LF_FULLFACESIZE 64 //!< U_LOGFONT_PANOSE elfFullName field maximum width +/** @} */ + +/** \defgroup U_EMR_Qualifiers RecordType Enumeration + (RecordType Enumeration) + For U_EMR iType field + @{ +*/ +#define U_EMR_HEADER 1 //!< U_EMRHEADER record +#define U_EMR_POLYBEZIER 2 //!< U_EMRPOLYBEZIER record +#define U_EMR_POLYGON 3 //!< U_EMRPOLYGON record +#define U_EMR_POLYLINE 4 //!< U_EMRPOLYLINE record +#define U_EMR_POLYBEZIERTO 5 //!< U_EMRPOLYBEZIERTO record +#define U_EMR_POLYLINETO 6 //!< U_EMRPOLYLINETO record +#define U_EMR_POLYPOLYLINE 7 //!< U_EMRPOLYPOLYLINE record +#define U_EMR_POLYPOLYGON 8 //!< U_EMRPOLYPOLYGON record +#define U_EMR_SETWINDOWEXTEX 9 //!< U_EMRSETWINDOWEXTEX record +#define U_EMR_SETWINDOWORGEX 10 //!< U_EMRSETWINDOWORGEX record +#define U_EMR_SETVIEWPORTEXTEX 11 //!< U_EMRSETVIEWPORTEXTEX record +#define U_EMR_SETVIEWPORTORGEX 12 //!< U_EMRSETVIEWPORTORGEX record +#define U_EMR_SETBRUSHORGEX 13 //!< U_EMRSETBRUSHORGEX record +#define U_EMR_EOF 14 //!< U_EMREOF record +#define U_EMR_SETPIXELV 15 //!< U_EMRSETPIXELV record +#define U_EMR_SETMAPPERFLAGS 16 //!< U_EMRSETMAPPERFLAGS record +#define U_EMR_SETMAPMODE 17 //!< U_EMRSETMAPMODE record +#define U_EMR_SETBKMODE 18 //!< U_EMRSETBKMODE record +#define U_EMR_SETPOLYFILLMODE 19 //!< U_EMRSETPOLYFILLMODE record +#define U_EMR_SETROP2 20 //!< U_EMRSETROP2 record +#define U_EMR_SETSTRETCHBLTMODE 21 //!< U_EMRSETSTRETCHBLTMODE record +#define U_EMR_SETTEXTALIGN 22 //!< U_EMRSETTEXTALIGN record +#define U_EMR_SETCOLORADJUSTMENT 23 //!< U_EMRSETCOLORADJUSTMENT record +#define U_EMR_SETTEXTCOLOR 24 //!< U_EMRSETTEXTCOLOR record +#define U_EMR_SETBKCOLOR 25 //!< U_EMRSETBKCOLOR record +#define U_EMR_OFFSETCLIPRGN 26 //!< U_EMROFFSETCLIPRGN record +#define U_EMR_MOVETOEX 27 //!< U_EMRMOVETOEX record +#define U_EMR_SETMETARGN 28 //!< U_EMRSETMETARGN record +#define U_EMR_EXCLUDECLIPRECT 29 //!< U_EMREXCLUDECLIPRECT record +#define U_EMR_INTERSECTCLIPRECT 30 //!< U_EMRINTERSECTCLIPRECT record +#define U_EMR_SCALEVIEWPORTEXTEX 31 //!< U_EMRSCALEVIEWPORTEXTEX record +#define U_EMR_SCALEWINDOWEXTEX 32 //!< U_EMRSCALEWINDOWEXTEX record +#define U_EMR_SAVEDC 33 //!< U_EMRSAVEDC record +#define U_EMR_RESTOREDC 34 //!< U_EMRRESTOREDC record +#define U_EMR_SETWORLDTRANSFORM 35 //!< U_EMRSETWORLDTRANSFORM record +#define U_EMR_MODIFYWORLDTRANSFORM 36 //!< U_EMRMODIFYWORLDTRANSFORM record +#define U_EMR_SELECTOBJECT 37 //!< U_EMRSELECTOBJECT record +#define U_EMR_CREATEPEN 38 //!< U_EMRCREATEPEN record +#define U_EMR_CREATEBRUSHINDIRECT 39 //!< U_EMRCREATEBRUSHINDIRECT record +#define U_EMR_DELETEOBJECT 40 //!< U_EMRDELETEOBJECT record +#define U_EMR_ANGLEARC 41 //!< U_EMRANGLEARC record +#define U_EMR_ELLIPSE 42 //!< U_EMRELLIPSE record +#define U_EMR_RECTANGLE 43 //!< U_EMRRECTANGLE record +#define U_EMR_ROUNDRECT 44 //!< U_EMRROUNDRECT record +#define U_EMR_ARC 45 //!< U_EMRARC record +#define U_EMR_CHORD 46 //!< U_EMRCHORD record +#define U_EMR_PIE 47 //!< U_EMRPIE record +#define U_EMR_SELECTPALETTE 48 //!< U_EMRSELECTPALETTE record +#define U_EMR_CREATEPALETTE 49 //!< U_EMRCREATEPALETTE record +#define U_EMR_SETPALETTEENTRIES 50 //!< U_EMRSETPALETTEENTRIES record +#define U_EMR_RESIZEPALETTE 51 //!< U_EMRRESIZEPALETTE record +#define U_EMR_REALIZEPALETTE 52 //!< U_EMRREALIZEPALETTE record +#define U_EMR_EXTFLOODFILL 53 //!< U_EMREXTFLOODFILL record +#define U_EMR_LINETO 54 //!< U_EMRLINETO record +#define U_EMR_ARCTO 55 //!< U_EMRARCTO record +#define U_EMR_POLYDRAW 56 //!< U_EMRPOLYDRAW record +#define U_EMR_SETARCDIRECTION 57 //!< U_EMRSETARCDIRECTION record +#define U_EMR_SETMITERLIMIT 58 //!< U_EMRSETMITERLIMIT record +#define U_EMR_BEGINPATH 59 //!< U_EMRBEGINPATH record +#define U_EMR_ENDPATH 60 //!< U_EMRENDPATH record +#define U_EMR_CLOSEFIGURE 61 //!< U_EMRCLOSEFIGURE record +#define U_EMR_FILLPATH 62 //!< U_EMRFILLPATH record +#define U_EMR_STROKEANDFILLPATH 63 //!< U_EMRSTROKEANDFILLPATH record +#define U_EMR_STROKEPATH 64 //!< U_EMRSTROKEPATH record +#define U_EMR_FLATTENPATH 65 //!< U_EMRFLATTENPATH record +#define U_EMR_WIDENPATH 66 //!< U_EMRWIDENPATH record +#define U_EMR_SELECTCLIPPATH 67 //!< U_EMRSELECTCLIPPATH record +#define U_EMR_ABORTPATH 68 //!< U_EMRABORTPATH record +#define U_EMR_UNDEF69 69 //!< U_EMRUNDEF69 record +#define U_EMR_COMMENT 70 //!< U_EMRCOMMENT record +#define U_EMR_FILLRGN 71 //!< U_EMRFILLRGN record +#define U_EMR_FRAMERGN 72 //!< U_EMRFRAMERGN record +#define U_EMR_INVERTRGN 73 //!< U_EMRINVERTRGN record +#define U_EMR_PAINTRGN 74 //!< U_EMRPAINTRGN record +#define U_EMR_EXTSELECTCLIPRGN 75 //!< U_EMREXTSELECTCLIPRGN record +#define U_EMR_BITBLT 76 //!< U_EMRBITBLT record +#define U_EMR_STRETCHBLT 77 //!< U_EMRSTRETCHBLT record +#define U_EMR_MASKBLT 78 //!< U_EMRMASKBLT record +#define U_EMR_PLGBLT 79 //!< U_EMRPLGBLT record +#define U_EMR_SETDIBITSTODEVICE 80 //!< U_EMRSETDIBITSTODEVICE record +#define U_EMR_STRETCHDIBITS 81 //!< U_EMRSTRETCHDIBITS record +#define U_EMR_EXTCREATEFONTINDIRECTW 82 //!< U_EMREXTCREATEFONTINDIRECTW record +#define U_EMR_EXTTEXTOUTA 83 //!< U_EMREXTTEXTOUTA record +#define U_EMR_EXTTEXTOUTW 84 //!< U_EMREXTTEXTOUTW record +#define U_EMR_POLYBEZIER16 85 //!< U_EMRPOLYBEZIER16 record +#define U_EMR_POLYGON16 86 //!< U_EMRPOLYGON16 record +#define U_EMR_POLYLINE16 87 //!< U_EMRPOLYLINE16 record +#define U_EMR_POLYBEZIERTO16 88 //!< U_EMRPOLYBEZIERTO16 record +#define U_EMR_POLYLINETO16 89 //!< U_EMRPOLYLINETO16 record +#define U_EMR_POLYPOLYLINE16 90 //!< U_EMRPOLYPOLYLINE16 record +#define U_EMR_POLYPOLYGON16 91 //!< U_EMRPOLYPOLYGON16 record +#define U_EMR_POLYDRAW16 92 //!< U_EMRPOLYDRAW16 record +#define U_EMR_CREATEMONOBRUSH 93 //!< U_EMRCREATEMONOBRUSH record +#define U_EMR_CREATEDIBPATTERNBRUSHPT 94 //!< U_EMRCREATEDIBPATTERNBRUSHPT record +#define U_EMR_EXTCREATEPEN 95 //!< U_EMREXTCREATEPEN record +#define U_EMR_POLYTEXTOUTA 96 //!< U_EMRPOLYTEXTOUTA record +#define U_EMR_POLYTEXTOUTW 97 //!< U_EMRPOLYTEXTOUTW record +#define U_EMR_SETICMMODE 98 //!< U_EMRSETICMMODE record +#define U_EMR_CREATECOLORSPACE 99 //!< U_EMRCREATECOLORSPACE record +#define U_EMR_SETCOLORSPACE 100 //!< U_EMRSETCOLORSPACE record +#define U_EMR_DELETECOLORSPACE 101 //!< U_EMRDELETECOLORSPACE record +#define U_EMR_GLSRECORD 102 //!< U_EMRGLSRECORD record +#define U_EMR_GLSBOUNDEDRECORD 103 //!< U_EMRGLSBOUNDEDRECORD record +#define U_EMR_PIXELFORMAT 104 //!< U_EMRPIXELFORMAT record +#define U_EMR_DRAWESCAPE 105 //!< U_EMRDRAWESCAPE record +#define U_EMR_EXTESCAPE 106 //!< U_EMREXTESCAPE record +#define U_EMR_UNDEF107 107 //!< U_EMRUNDEF107 record +#define U_EMR_SMALLTEXTOUT 108 //!< U_EMRSMALLTEXTOUT record +#define U_EMR_FORCEUFIMAPPING 109 //!< U_EMRFORCEUFIMAPPING record +#define U_EMR_NAMEDESCAPE 110 //!< U_EMRNAMEDESCAPE record +#define U_EMR_COLORCORRECTPALETTE 111 //!< U_EMRCOLORCORRECTPALETTE record +#define U_EMR_SETICMPROFILEA 112 //!< U_EMRSETICMPROFILEA record +#define U_EMR_SETICMPROFILEW 113 //!< U_EMRSETICMPROFILEW record +#define U_EMR_ALPHABLEND 114 //!< U_EMRALPHABLEND record +#define U_EMR_SETLAYOUT 115 //!< U_EMRSETLAYOUT record +#define U_EMR_TRANSPARENTBLT 116 //!< U_EMRTRANSPARENTBLT record +#define U_EMR_UNDEF117 117 //!< U_EMRUNDEF117 record +#define U_EMR_GRADIENTFILL 118 //!< U_EMRGRADIENTFILL record +#define U_EMR_SETLINKEDUFIS 119 //!< U_EMRSETLINKEDUFIS record +#define U_EMR_SETTEXTJUSTIFICATION 120 //!< U_EMRSETTEXTJUSTIFICATION record +#define U_EMR_COLORMATCHTOTARGETW 121 //!< U_EMRCOLORMATCHTOTARGETW record +#define U_EMR_CREATECOLORSPACEW 122 //!< U_EMRCREATECOLORSPACEW record + +#define U_EMR_MIN 1 //!< Minimum U_EMR_ value. +#define U_EMR_MAX 122 //!< Maximum U_EMR_ value. Not much beyond 104 is implemented + +#define U_EMR_INVALID 0xFFFFFFFF //!< Not any valid U_EMF_ value +/** @} */ + +/** \defgroup U_DRAW_PROPERTIES draw properties + Used in emr_properties() and wmr_properties. These are the bit definitions. + @{ +*/ +#define U_DRAW_NOTEMPTY 0x001 //!< Path has at least a MOVETO in it +#define U_DRAW_VISIBLE 0x002 //!< Path has at least a LINE in it +#define U_DRAW_CLOSED 0x004 //!< Path has been closed +#define U_DRAW_ONLYTO 0x008 //!< Path so far contains only *TO operations +#define U_DRAW_FORCE 0x010 //!< Path MUST be drawn +#define U_DRAW_ALTERS 0x020 //!< Alters draw parameters (pen, brush, coordinates...) +#define U_DRAW_PATH 0x040 //!< An explicit path is being used (with a BEGIN and END) +#define U_DRAW_TEXT 0x080 //!< Current record forces all pending text to be drawn first. +#define U_DRAW_OBJECT 0x100 //!< Creates an Object (only used in WMF) +#define U_DRAW_NOFILL 0x200 //!< Object is not fillable (lines and arc, only used in WMF) + +/** @} */ +/** \defgroup U_EMRSETARCDIRECTION_Qualifiers ArcDirection Enumeration + For U_EMRSETARCDIRECTION iArcDirection field + @{ +*/ +#define U_AD_COUNTERCLOCKWISE 1 +#define U_AD_CLOCKWISE 2 +/** @} */ + +/** \defgroup U_PANOSE_bArmStyle_Qualifiers ArmStyle Enumeration + For U_PANOSE bArmStyle field + @{ +*/ +#define U_PAN_STRAIGHT_ARMS_HORZ 2 +#define U_PAN_STRAIGHT_ARMS_WEDGE 3 +#define U_PAN_STRAIGHT_ARMS_VERT 4 +#define U_PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 +#define U_PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 +#define U_PAN_BENT_ARMS_HORZ 7 +#define U_PAN_BENT_ARMS_WEDGE 8 +#define U_PAN_BENT_ARMS_VERT 9 +#define U_PAN_BENT_ARMS_SINGLE_SERIF 10 +#define U_PAN_BENT_ARMS_DOUBLE_SERIF 11 +/** @} */ + +/** \defgroup U_EMRSETBKMODE_iMode_Qualifiers BackgroundMode enumeration + For U_EMRSETBKMODE iMode field + @{ +*/ +#define U_TRANSPARENT 1 +#define U_OPAQUE 2 +/** @} */ + +/** \defgroup U_BITMAPINFOHEADER_biBitCount_Qualifiers BitCount Enumeration + For U_BITMAPINFOHEADER biBitCount field. + @{ +*/ +#define U_BCBM_EXPLICIT 0 //!< Derived from JPG or PNG compressed image or ? +#define U_BCBM_MONOCHROME 1 //!< 2 colors. bmiColors array has two entries +#define U_BCBM_COLOR4 4 //!< 2^4 colors. bmiColors array has 16 entries +#define U_BCBM_COLOR8 8 //!< 2^8 colors. bmiColors array has 256 entries +#define U_BCBM_COLOR16 16 //!< 2^16 colors. bmiColors is not used. Pixels are 5 bits B,G,R with 1 unused bit +#define U_BCBM_COLOR24 24 //!< 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. +#define U_BCBM_COLOR32 32 //!< 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. +/** @} */ + +/** \defgroup U_BITMAPINFOHEADER_biCompression_Qualifiers BI_Compression Enumeration + For U_BITMAPINFOHEADER biCompression field + @{ +*/ +#define U_BI_RGB 0 //!< This is the only one supported by UEMF at present +#define U_BI_RLE8 1 +#define U_BI_RLE4 2 +#define U_BI_BITFIELDS 3 +#define U_BI_JPEG 4 +#define U_BI_PNG 5 +/** @} */ + +/** \defgroup U_COLORADJUSTMENT_caFlags_Qualifiers ColorAdjustment Enumeration + For U_COLORADJUSTMENT caFlags field + @{ +*/ +#define U_CA_NEGATIVE 0x0001 +#define U_CA_LOG_FILTER 0x0002 +/** @} */ + +/** \defgroup U_EMRCOLORMATCHTOTARGETW_dwFlags_Qualifiers ColorMatchToTarget Enumeration + For U_EMRCOLORMATCHTOTARGETW dwFlags field + @{ +*/ +#define U_COLORMATCHTOTARGET_NOTEMBEDDED 0 +#define U_COLORMATCHTOTARGET_EMBEDDED 1 +/** @} */ + +/** \defgroup U_EMRCOLORMATCHTOTARGETW_dwAction_Qualifiers ColorSpace Enumeration + For U_EMRCOLORMATCHTOTARGETW dwAction field + @{ +*/ +#define U_CS_ENABLE 1 +#define U_CS_DISABLE 2 +#define U_CS_DELETE_TRANSFORM 3 +/** @} */ + +/** \defgroup U_PANOSE_bContrast_Qualifiers Contrast Enumeration + For U_PANOSE bContrast field + @{ +*/ +#define U_PAN_CONTRAST_NONE 2 +#define U_PAN_CONTRAST_VERY_LOW 3 +#define U_PAN_CONTRAST_LOW 4 +#define U_PAN_CONTRAST_MEDIUM_LOW 5 +#define U_PAN_CONTRAST_MEDIUM 6 +#define U_PAN_CONTRAST_MEDIUM_HIGH 7 +#define U_PAN_CONTRAST_HIGH 8 +#define U_PAN_CONTRAST_VERY_HIGH 9 +/** @} */ + +/** \defgroup U_DIBITS_iUsageSrc_Qualifiers DIBColors Enumeration + For U_EMRSETDIBITSTODEIVCE and U_EMRSTRETCHDIBITS iUsageSrc fields. + @{ +*/ +#define U_DIB_RGB_COLORS 0 +#define U_DIB_PAL_COLORS 1 +/** @} */ + +/** \defgroup U_EMRCOMMENT_TYPES Comment record types + For U_EMRCOMMENT_* cIdent fields + @{ +*/ +#define U_EMR_COMMENT_PUBLIC 0x43494447 +#define U_EMR_COMMENT_SPOOL 0x00000000 +#define U_EMR_COMMENT_SPOOLFONTDEF 0x544F4E46 +#define U_EMR_COMMENT_EMFPLUSRECORD 0x2B464D45 +/** @} */ + +/** \defgroup U_EMR_COMMENT_PUBLIC EMRComment Enumeration + For U_EMRCOMMENT_PUBLIC pcIdent fields + @{ +*/ +#define U_EMR_COMMENT_WINDOWS_METAFILE 0x80000001 +#define U_EMR_COMMENT_BEGINGROUP 0x00000002 +#define U_EMR_COMMENT_ENDGROUP 0x00000003 +#define U_EMR_COMMENT_MULTIFORMATS 0x40000004 +#define U_EMR_COMMENT_UNICODE_STRING 0x00000040 +#define U_EMR_COMMENT_UNICODE_END 0x00000080 +/** @} */ + +/** \defgroup U_EMRTEXT_foptions_Qualifiers ExtTextOutOptions Enumeration + For U_EMRTEXT foptions field + @{ +*/ +#define U_ETO_NONE 0x00000000 +#define U_ETO_GRAYED 0x00000001 +#define U_ETO_OPAQUE 0x00000002 +#define U_ETO_CLIPPED 0x00000004 +#define U_ETO_GLYPH_INDEX 0x00000010 +#define U_ETO_RTLREADING 0x00000080 +#define U_ETO_NO_RECT 0x00000100 +#define U_ETO_SMALL_CHARS 0x00000200 // For EMRSMALLTEXTOUT ONLY, does not affect EMRTEXTOUTA or EMRTEXTOUTW +#define U_ETO_NUMERICSLOCAL 0x00000400 +#define U_ETO_NUMERICSLATIN 0x00000800 +#define U_ETO_IGNORELANGUAGE 0x00001000 +#define U_ETO_PDY 0x00002000 +#define U_ETO_REVERSE_INDEX_MAP 0x00010000 +/** @} */ + +/** \defgroup U_PANOSE_bFamilyType_Qualifiers FamilyType Enumeration + For U_PANOSE bFamilyType field + @{ +*/ +#define U_PAN_FAMILY_TEXT_DISPLAY 2 +#define U_PAN_FAMILY_SCRIPT 3 +#define U_PAN_FAMILY_DECORATIVE 4 +#define U_PAN_FAMILY_PICTORIAL 5 +/** @} */ + +/** \defgroup U_EMREXTFLOODFILL_iMode_Qualifiers FloodFill Enumeration + For U_EMREXTFLOODFILL iMode field + @{ +*/ +#define U_FLOODFILLBORDER 0x00000000 /* Color specified must be the same as the border - brush fill stops at this color */ +#define U_FLOODFILLSURFACE 0x00000001 /* Color specified must be different from the border - brush fills only this color */ +/** @} */ + +/** \defgroup U_DESIGNVECTOR_Signature_Qualifiers Signature Enumeration + For U_DESIGNVECTOR Signature field + @{ +*/ +#define U_ENHMETA_SIGNATURE 0x464D4520 //!< also for U_EMRHEADER dSignature field +#define U_EPS_SIGNATURE 0x46535045 +/** @} */ + +/** \defgroup U_EMRGRADIENTFILL_ulMode_Qualifiers GradientFill Enumeration + For U_EMRGRADIENTFILL ulMode field + @{ +*/ +#define U_GRADIENT_FILL_RECT_H 0x00000000 +#define U_GRADIENT_FILL_RECT_V 0x00000001 +#define U_GRADIENT_FILL_TRIANGLE 0x00000002 +/** @} */ + +/** \defgroup U_EMREXTTEXTOUT_iGraphicsMode_Qualifiers GraphicsMode Enumeration + For U_EMREXTTEXTOUTA/U_EMREXTTEXTOUTW and all other iGraphicsMode fields + @{ +*/ +#define U_GM_COMPATIBLE 1 +#define U_GM_ADVANCED 2 +#define U_GM_LAST 2 +/** @} */ + +/** \defgroup U_LOGBRUSH_lbHatch_Qualifiers HatchStyle Enumeration + For U_LOGBRUSH lbHatch field + @{ +*/ +#define U_HS_HORIZONTAL 0 +#define U_HS_VERTICAL 1 +#define U_HS_FDIAGONAL 2 +#define U_HS_BDIAGONAL 3 +#define U_HS_CROSS 4 +#define U_HS_DIAGCROSS 5 +#define U_HS_SOLIDCLR 6 +#define U_HS_DITHEREDCLR 7 +#define U_HS_SOLIDTEXTCLR 8 +#define U_HS_DITHEREDTEXTCLR 9 +#define U_HS_SOLIDBKCLR 10 +#define U_HS_DITHEREDBKCLR 11 +/** @} */ + +/** \defgroup U_EMRSETICMMODE_iMode_Qualifiers ICMMode Enumeration + For EMF U_EMR_SETICMMODE iMode field + @{ +*/ +#define U_ICM_OFF 1 +#define U_ICM_ON 2 +#define U_ICM_QUERY 3 +/** @} */ + +/** \defgroup U_COLORADJUSTMENT_caIlluminantIndex_Qualifiers Illuminant Enumeration + For U_COLORADJUSTMENT caIlluminantIndex field + @{ +*/ +#define U_ILLUMINANT_DEVICE_DEFAULT 0 +#define U_ILLUMINANT_A 1 +#define U_ILLUMINANT_B 2 +#define U_ILLUMINANT_C 3 +#define U_ILLUMINANT_D50 4 +#define U_ILLUMINANT_D55 5 +#define U_ILLUMINANT_D65 6 +#define U_ILLUMINANT_D75 7 +#define U_ILLUMINANT_F2 8 +#define U_ILLUMINANT_MAX_INDEX ILLUMINANT_F2 +#define U_ILLUMINANT_TUNGSTEN ILLUMINANT_A +#define U_ILLUMINANT_DAYLIGHT ILLUMINANT_C +#define U_ILLUMINANT_FLUORESCENT ILLUMINANT_F2 +#define U_ILLUMINANT_NTSC ILLUMINANT_C +/** @} */ + +/** \defgroup U_LOGBRUSH_lbStyle_Qualifiers LB_Style Enumeration + For U_LOGBRUSH lbStyle field + @{ +*/ +#define U_BS_SOLID 0 +#define U_BS_NULL 1 +#define U_BS_HOLLOW 1 +#define U_BS_HATCHED 2 +#define U_BS_PATTERN 3 +#define U_BS_INDEXED 4 +#define U_BS_DIBPATTERN 5 +#define U_BS_DIBPATTERNPT 6 +#define U_BS_PATTERN8X8 7 +#define U_BS_DIBPATTERN8X8 8 +#define U_BS_MONOPATTERN 9 +/** @} */ + +/** \defgroup _LOGCOLORSPACE_lcsCSType_Qualifiers LCS_CSType Enumeration + For U_LOGCOLORSPACEA/U_LOGCOLORSPACEW lcsCSType field + @{ +*/ +#define U_LCS_CALIBRATED_RGB 0x00000000L +#define U_LCS_DEVICE_RGB 0x00000001L +#define U_LCS_DEVICE_CMYK 0x00000002L +/** @} */ + +/** \defgroup U_LOGCOLORSPACE_lcsIntent_Qualifiers LCS_Intent Enumeration + For U_LOGCOLORSPACEA/U_LOGCOLORSPACEW lcsIntent field + @{ +*/ +#define U_LCS_GM_BUSINESS 0x00000001L +#define U_LCS_GM_GRAPHICS 0x00000002L +#define U_LCS_GM_IMAGES 0x00000004L +#define U_LCS_GM_ABS_COLORIMETRIC 0x00000008L +/** @} */ + +/** \defgroup U_PANOSE_bLetterForm_Qualifiers Letterform Enumeration + For U_PANOSE bLetterForm field + @{ +*/ +#define U_PAN_LETT_NORMAL_COMPACT 2 +#define U_PAN_LETT_NORMAL_WEIGHTED 3 +#define U_PAN_LETT_NORMAL_BOXED 4 +#define U_PAN_LETT_NORMAL_FLATTENED 5 +#define U_PAN_LETT_NORMAL_ROUNDED 6 +#define U_PAN_LETT_NORMAL_OFF_CENTER 7 +#define U_PAN_LETT_NORMAL_SQUARE 8 +#define U_PAN_LETT_OBLIQUE_COMPACT 9 +#define U_PAN_LETT_OBLIQUE_WEIGHTED 10 +#define U_PAN_LETT_OBLIQUE_BOXED 11 +#define U_PAN_LETT_OBLIQUE_FLATTENED 12 +#define U_PAN_LETT_OBLIQUE_ROUNDED 13 +#define U_PAN_LETT_OBLIQUE_OFF_CENTER 14 +#define U_PAN_LETT_OBLIQUE_SQUARE 15 +/** @} */ + +/** \defgroup U_LOGFONT_lfWeight_Qualifiers LF_Weight Enumeration + For U_LOGFONT lfWeight field + @{ +*/ +#define U_FW_DONTCARE 0 +#define U_FW_THIN 100 +#define U_FW_EXTRALIGHT 200 +#define U_FW_ULTRALIGHT 200 +#define U_FW_LIGHT 300 +#define U_FW_NORMAL 400 +#define U_FW_REGULAR 400 +#define U_FW_MEDIUM 500 +#define U_FW_SEMIBOLD 600 +#define U_FW_DEMIBOLD 600 +#define U_FW_BOLD 700 +#define U_FW_EXTRABOLD 800 +#define U_FW_ULTRABOLD 800 +#define U_FW_HEAVY 900 +#define U_FW_BLACK 900 +/** @} */ + +/** \defgroup U_LOGFONT_lfItalic_Qualifiers LF_Italic Enumeration + For U_LOGFONT lfItalic field + @{ +*/ +#define U_FW_NOITALIC 0 +#define U_FW_ITALIC 1 +/** @} */ + +/** \defgroup U_LOGFONT_lfunderline_Qualifiers LF_Underline Enumeration + For U_LOGFONT lfunderline field + @{ +*/ +#define U_FW_NOUNDERLINE 0 +#define U_FW_UNDERLINE 1 +/** @} */ + +/** \defgroup U_LOGFONT_lfStrikeOut_Qualifiers LF_StrikeOut Enumeration + For U_LOGFONT lfStrikeOut field + @{ +*/ +#define U_FW_NOSTRIKEOUT 0 +#define U_FW_STRIKEOUT 1 +/** @} */ + +/** \defgroup U_LOGFONT_lfCharSet_Qualifiers LF_CharSet Enumeration + For U_LOGFONT lfCharSet field + @{ +*/ +#define U_ANSI_CHARSET (uint8_t)0 /* CP1252, ansi-0, iso8859-{1,15} */ +#define U_DEFAULT_CHARSET (uint8_t)1 +#define U_SYMBOL_CHARSET (uint8_t)2 +#define U_SHIFTJIS_CHARSET (uint8_t)128 /* CP932 */ +#define U_HANGEUL_CHARSET (uint8_t)129 /* CP949, ksc5601.1987-0 */ +#define U_HANGUL_CHARSET U_HANGEUL_CHARSET +#define U_GB2312_CHARSET (uint8_t)134 /* CP936, gb2312.1980-0 */ +#define U_CHINESEBIG5_CHARSET (uint8_t)136 /* CP950, big5.et-0 */ +#define U_GREEK_CHARSET (uint8_t)161 /* CP1253 */ +#define U_TURKISH_CHARSET (uint8_t)162 /* CP1254, -iso8859-9 */ +#define U_HEBREW_CHARSET (uint8_t)177 /* CP1255, -iso8859-8 */ +#define U_ARABIC_CHARSET (uint8_t)178 /* CP1256, -iso8859-6 */ +#define U_BALTIC_CHARSET (uint8_t)186 /* CP1257, -iso8859-13 */ +#define U_RUSSIAN_CHARSET (uint8_t)204 /* CP1251, -iso8859-5 */ +#define U_EE_CHARSET (uint8_t)238 /* CP1250, -iso8859-2 */ +#define U_EASTEUROPE_CHARSET U_EE_CHARSET +#define U_THAI_CHARSET (uint8_t)222 /* CP874, iso8859-11, tis620 */ +#define U_JOHAB_CHARSET (uint8_t)130 /* korean (johab) CP1361 */ +#define U_MAC_CHARSET (uint8_t)77 +#define U_OEM_CHARSET (uint8_t)255 +/* I don't know if the values of *_CHARSET macros are defined in Windows + * or if we can choose them as we want. -- srtxg + */ +#define U_VISCII_CHARSET (uint8_t)240 /* viscii1.1-1 */ +#define U_TCVN_CHARSET (uint8_t)241 /* tcvn-0 */ +#define U_KOI8_CHARSET (uint8_t)242 /* koi8-{r,u,ru} */ +#define U_ISO3_CHARSET (uint8_t)243 /* iso8859-3 */ +#define U_ISO4_CHARSET (uint8_t)244 /* iso8859-4 */ +#define U_ISO10_CHARSET (uint8_t)245 /* iso8859-10 */ +#define U_CELTIC_CHARSET (uint8_t)246 /* iso8859-14 */ +/** @} */ + +/** \defgroup U_LOGFONT_lfOutPrecision_Qualifiers LF_OutPrecision Enumeration + For U_LOGFONT lfOutPrecision field + @{ +*/ +#define U_OUT_DEFAULT_PRECIS 0 +#define U_OUT_STRING_PRECIS 1 +#define U_OUT_CHARACTER_PRECIS 2 +#define U_OUT_STROKE_PRECIS 3 +#define U_OUT_TT_PRECIS 4 +#define U_OUT_DEVICE_PRECIS 5 +#define U_OUT_RASTER_PRECIS 6 +#define U_OUT_TT_ONLY_PRECIS 7 +#define U_OUT_OUTLINE_PRECIS 8 +/** @} */ + +/** \defgroup U_LOGFONT_lfClipPrecision_Qualifiers LF_ClipPrecision Enumeration + For U_LOGFONT lfClipPrecision field + @{ +*/ +#define U_CLIP_DEFAULT_PRECIS 0x00 +#define U_CLIP_CHARACTER_PRECIS 0x01 +#define U_CLIP_STROKE_PRECIS 0x02 +#define U_CLIP_MASK 0x0F +#define U_CLIP_LH_ANGLES 0x10 +#define U_CLIP_TT_ALWAYS 0x20 +#define U_CLIP_EMBEDDED 0x80 +/** @} */ + +/** \defgroup U_LOGFONT_lfQuality_Qualifiers LF_Quality Enumeration + For For U_LOGFONT lfQuality field + @{ +*/ +#define U_DEFAULT_QUALITY 0 +#define U_DRAFT_QUALITY 1 +#define U_PROOF_QUALITY 2 +#define U_NONANTIALIASED_QUALITY 3 +#define U_ANTIALIASED_QUALITY 4 +/** @} */ + +/** \defgroup U_LOGFONT_lfPitchAndFamily_Qualifiers LF_PitchAndFamily Enumeration + For U_LOGFONT lfPitchAndFamily field + @{ +*/ +#define U_DEFAULT_PITCH 0x00 +#define U_FIXED_PITCH 0x01 +#define U_VARIABLE_PITCH 0x02 +#define U_MONO_FONT 0x08 +#define U_FF_DONTCARE 0x00 +#define U_FF_ROMAN 0x10 +#define U_FF_SWISS 0x20 +#define U_FF_MODERN 0x30 +#define U_FF_SCRIPT 0x40 +#define U_FF_DECORATIVE 0x50 +/** @} */ + +/** \defgroup U_EMRSETMAPMODE_iMode_Qualifiers MapMode Enumeration + For U_EMRSETMAPMODE iMode field + @{ +*/ +#define U_MM_TEXT 1 +#define U_MM_LOMETRIC 2 +#define U_MM_HIMETRIC 3 +#define U_MM_LOENGLISH 4 +#define U_MM_HIENGLISH 5 +#define U_MM_TWIPS 6 +#define U_MM_ISOTROPIC 7 +#define U_MM_ANISOTROPIC 8 +#define U_MM_MIN U_MM_TEXT +#define U_MM_MAX U_MM_ANISOTROPIC +#define U_MM_MAX_FIXEDSCALE U_MM_TWIPS +/** @} */ + + +/** \defgroup U_PANOSE_bMidline_Qualifiers MidLine Enumeration + For U_PANOSE bMidline field + @{ +*/ +#define U_PAN_MIDLINE_STANDARD_TRIMMED 2 +#define U_PAN_MIDLINE_STANDARD_POINTED 3 +#define U_PAN_MIDLINE_STANDARD_SERIFED 4 +#define U_PAN_MIDLINE_HIGH_TRIMMED 5 +#define U_PAN_MIDLINE_HIGH_POINTED 6 +#define U_PAN_MIDLINE_HIGH_SERIFED 7 +#define U_PAN_MIDLINE_CONSTANT_TRIMMED 8 +#define U_PAN_MIDLINE_CONSTANT_POINTED 9 +#define U_PAN_MIDLINE_CONSTANT_SERIFED 10 +#define U_PAN_MIDLINE_LOW_TRIMMED 11 +#define U_PAN_MIDLINE_LOW_POINTED 12 +#define U_PAN_MIDLINE_LOW_SERIFED 13 +/** @} */ + +/** \defgroup U_EMRSETLAYOUT_iMode_Qualifiers Mirroring Enumeration + For U_EMRSETLAYOUT iMode field + @{ +*/ +#define U_LAYOUT_LTR 0x00000000 +#define U_LAYOUT_RTL 0x00000001 +#define U_LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 +#define U_NOMIRRORBITMAP 0x80000000 +/** @} */ + +/** \defgroup U_EMRMODIFYWORLDTRANSFORM_iMode_Qualifiers ModifyWorldTransformMode Enumeration + For U_EMRMODIFYWORLDTRANSFORM iMode + @{ +*/ +#define U_MWT_IDENTITY 1 +#define U_MWT_LEFTMULTIPLY 2 +#define U_MWT_RIGHTMULTIPLY 3 +#define U_MWT_MIN U_MWT_IDENTITY +#define U_MWT_MAX U_MWT_RIGHTMULTIPLY +/** @} */ + +/** \defgroup U_PANOSE_common_Qualifiers PanoseCommon Enumeration + Used by all PAN_* enumerations, but only defined once here. + See also U_PAN_ALL1 after the U_PANOSE structure + @{ +*/ +#define U_PAN_ANY 0 +#define U_PAN_NO_FIT 1 +/** @} */ + +/** \defgroup U_PANOSE_index PanoseIndex Enumeration + Fositions of each field in U_PANOSE structure. + @{ +*/ +#define U_PANOSE_COUNT 10 +#define U_PANOSE_FAMILYTYPE_INDEX 0 +#define U_PAN_SERIFSTYLE_INDEX 1 +#define U_PAN_WEIGHT_INDEX 2 +#define U_PAN_PROPORTION_INDEX 3 +#define U_PAN_CONTRAST_INDEX 4 +#define U_PAN_STROKEVARIATION_INDEX 5 +#define U_PAN_ARMSTYLE_INDEX 6 +#define U_PAN_LETTERFORM_INDEX 7 +#define U_PAN_MIDLINE_INDEX 8 +#define U_PAN_XHEIGHT_INDEX 9 +/** @} */ + +/** \defgroup U_*LOGPEN_elpPenStyle_Qualifiers PenStyle Enumeration + For U_LOGPEN lopnStyle and U_EXTLOGPEN elpPenStyle fields + @{ +*/ +#define U_PS_SOLID 0x00000000 +#define U_PS_DASH 0x00000001 //!< This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to. +#define U_PS_DOT 0x00000002 //!< This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to. +#define U_PS_DASHDOT 0x00000003 //!< This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to. +#define U_PS_DASHDOTDOT 0x00000004 //!< This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to. +#define U_PS_NULL 0x00000005 +#define U_PS_INSIDEFRAME 0x00000006 +#define U_PS_USERSTYLE 0x00000007 +#define U_PS_ALTERNATE 0x00000008 +#define U_PS_STYLE_MASK 0x0000000f + +#define U_PS_ENDCAP_ROUND 0x00000000 //!< These are only with U_PS_GEOMETRIC +#define U_PS_ENDCAP_SQUARE 0x00000100 +#define U_PS_ENDCAP_FLAT 0x00000200 +#define U_PS_ENDCAP_MASK 0x00000f00 + +#define U_PS_JOIN_ROUND 0x00000000 //!< These are only with U_PS_GEOMETRIC +#define U_PS_JOIN_BEVEL 0x00001000 +#define U_PS_JOIN_MITER 0x00002000 +#define U_PS_JOIN_MASK 0x0000f000 + +#define U_PS_COSMETIC 0x00000000 //!< width may only be 1 pixel. (If set higher it is still drawn as 1). +#define U_PS_GEOMETRIC 0x00010000 //!< width may be >1 pixel, but style may only be U_PS_SOLID or U_PS_NULL. +#define U_PS_TYPE_MASK 0x000f0000 +/** @} */ + +/** \defgroup U_PIXELFORMATDESCRIPTOR_dwFlags_Qualifiers PFD_dwFlags Enumeration + For U_PIXELFORMATDESCRIPTOR dwFlags field + @{ +*/ +#define U_PFD_DOUBLEBUFFER 0x00000001 +#define U_PFD_STEREO 0x00000002 +#define U_PFD_DRAW_TO_WINDOW 0x00000004 +#define U_PFD_DRAW_TO_BITMAP 0x00000008 +#define U_PFD_SUPPORT_GDI 0x00000010 +#define U_PFD_SUPPORT_OPENGL 0x00000020 +#define U_PFD_GENERIC_FORMAT 0x00000040 +#define U_PFD_NEED_PALETTE 0x00000080 +#define U_PFD_NEED_SYSTEM_PALETTE 0x00000100 +#define U_PFD_SWAP_EXCHANGE 0x00000200 +#define U_PFD_SWAP_COPY 0x00000400 +#define U_PFD_SWAP_LAYER_BUFFERS 0x00000800 +#define U_PFD_GENERIC_ACCELERATED 0x00001000 +/** @} */ + +/** \defgroup U_PIXELFORMATDESCRIPTOR_iLayerType_Qualifiers PFD_iLayerType Enumeration + For U_PIXELFORMATDESCRIPTOR iLayerType field + @{ +*/ +#define U_PFD_MAIN_PLANE 0 +#define U_PFD_OVERLAY_PLANE 1 +#define U_PFD_UNDERLAY_PLANE (-1) +/** @} */ + +/** \defgroup U_PIXELFORMATDESCRIPTOR_iPixelType_Qualifiers PFD_iPixelType Enumeration + For U_PIXELFORMATDESCRIPTOR iPixelType field + @{ +*/ +#define U_PFD_TYPE_RGBA 0 +#define U_PFD_TYPE_COLORINDEX 1 +/** @} */ + +/** \defgroup U_EMRPOLY_iMode_Qualifiers Point Enumeration + For U_EMRPOLYDRAW and U_EMRPOLAYDRAW16 abTypes fields. + @{ +*/ +#define U_PT_CLOSEFIGURE 0x0001 +#define U_PT_LINETO 0x0002 +#define U_PT_BEZIERTO 0x0004 +#define U_PT_MOVETO 0x0006 +/** @} */ + +/** \defgroup U_EMRSETPOLYFILLMODE_iMode_Qualifiers PolygonFillMode Enumeration + For U_EMRSETPOLYFILLMODE iMode field + @{ +*/ +#define U_ALTERNATE 1 +#define U_WINDING 2 +#define U_POLYFILL_LAST 2 +/** @} */ + +/** \defgroup U_BITMAPV5HEADER_bV5CSType_Qualifiers Profile Enumeration + For U_BITMAPV5HEADER bV5CSType field + @{ +*/ +#define U_PROFILE_LINKED 'LINK' +#define U_PROFILE_EMBEDDED 'MBED' +/** @} */ + +/** \defgroup U_PANOSE_bProportion_Qualifiers Proportion Enumeration + For U_PANOSE bProportion field + @{ +*/ +#define U_PAN_PROP_OLD_STYLE 2 +#define U_PAN_PROP_MODERN 3 +#define U_PAN_PROP_EVEN_WIDTH 4 +#define U_PAN_PROP_EXPANDED 5 +#define U_PAN_PROP_CONDENSED 6 +#define U_PAN_PROP_VERY_EXPANDED 7 +#define U_PAN_PROP_VERY_CONDENSED 8 +#define U_PAN_PROP_MONOSPACED 9 +/** @} */ + +/** \defgroup U_EMR_dwROP_Qualifiers Ternary Raster Operation enumeration + For U_EMR* dwROP fields. + + These codes specify: + 1. an order of operands (composed of various orders and combinations of: Dest, Src, Pen) + (There are 3, hence "Ternary Raster Operation") + 2. an order of operators to apply to the operands (composed of Not, Xor, Or, And) + Only a few of the more common operations are provided here. + When the Operation does not use a Src operand the corresponding source bitmap may be + omitted from the record. + + For more details see: + http://wiki.winehq.org/TernaryRasterOps + @{ +*/ +#define U_SRCCOPY 0xcc0020 +#define U_SRCPAINT 0xee0086 +#define U_SRCAND 0x8800c6 +#define U_SRCINVERT 0x660046 +#define U_SRCERASE 0x440328 +#define U_NOTSRCCOPY 0x330008 +#define U_NOTSRCERASE 0x1100a6 +#define U_MERGECOPY 0xc000ca +#define U_MERGEPAINT 0xbb0226 +#define U_PATCOPY 0xf00021 +#define U_PATPAINT 0xfb0a09 +#define U_PATINVERT 0x5a0049 +#define U_DSTINVERT 0x550009 +#define U_BLACKNESS 0x000042 +#define U_WHITENESS 0xff0062 +/** @} */ + +/** \defgroup U_EMRSETROP2_iMode_Qualifiers Binary Raster Operation Enumeration + For U_EMRSETROP2 iMode field + + These codes specify: + 1. an order of operands (composed of various orders and combinations of: Dest, Pen) + (There are 2, hence "Binary Raster Operation") + 2. an order of operators to apply to the operands (composed of Not, Xor, Or, And) + Only a few of the more common operations are provided here. + + The default is U_R2_COPYPEN. If this value is changed to something else all subsequenty + draw operations will use the altered logic. For instance, if it is set to U_R2_BLACK and + a red rectangle is drawn it will appear as a black rectangle. + + @{ +*/ +#define U_R2_BLACK 1 +#define U_R2_NOTMERGEPEN 2 +#define U_R2_MASKNOTPEN 3 +#define U_R2_NOTCOPYPEN 4 +#define U_R2_MASKPENNOT 5 +#define U_R2_NOT 6 +#define U_R2_XORPEN 7 +#define U_R2_NOTMASKPEN 8 +#define U_R2_MASKPEN 9 +#define U_R2_NOTXORPEN 10 +#define U_R2_NOP 11 +#define U_R2_MERGENOTPEN 12 +#define U_R2_COPYPEN 13 +#define U_R2_MERGEPENNOT 14 +#define U_R2_MERGEPEN 15 +#define U_R2_WHITE 16 +#define U_R2_LAST 16 +/** @} */ + +/** \defgroup U_EMRSELECTCLIP_iMode_Qualifiers RegionMode Enumeration + For U_EMRSELECTCLIPPATH and U_EMREXTSELECTCLIPRGN iMode field + @{ +*/ +#define U_RGN_AND 1 +#define U_RGN_OR 2 +#define U_RGN_XOR 3 +#define U_RGN_DIFF 4 +#define U_RGN_COPY 5 +#define U_RGN_MIN U_RGN_AND +#define U_RGN_MAX U_RGN_COPY +/** @} */ + +/** \defgroup U_PANOSE_bSerifStyle_Qualifiers SerifType Enumeration + For U_PANOSE bSerifStyle field + @{ +*/ +#define U_PAN_SERIF_COVE 2 +#define U_PAN_SERIF_OBTUSE_COVE 3 +#define U_PAN_SERIF_SQUARE_COVE 4 +#define U_PAN_SERIF_OBTUSE_SQUARE_COVE 5 +#define U_PAN_SERIF_SQUARE 6 +#define U_PAN_SERIF_THIN 7 +#define U_PAN_SERIF_BONE 8 +#define U_PAN_SERIF_EXAGGERATED 9 +#define U_PAN_SERIF_TRIANGLE 10 +#define U_PAN_SERIF_NORMAL_SANS 11 +#define U_PAN_SERIF_OBTUSE_SANS 12 +#define U_PAN_SERIF_PERP_SANS 13 +#define U_PAN_SERIF_FLARED 14 +#define U_PAN_SERIF_ROUNDED 15 +/** @} */ + +/** \defgroup U_EMRSELECTOBJECT_ihObject_Qualifiers StockObject Enumeration + For U_EMRSELECTOBJECT ihObject field. + @{ +*/ +#define U_STOCK_OBJECT 0x80000000 +#define U_WHITE_BRUSH 0x80000000 +#define U_LTGRAY_BRUSH 0x80000001 +#define U_GRAY_BRUSH 0x80000002 +#define U_DKGRAY_BRUSH 0x80000003 +#define U_BLACK_BRUSH 0x80000004 +#define U_NULL_BRUSH 0x80000005 +#define U_HOLLOW_BRUSH 0x80000005 +#define U_WHITE_PEN 0x80000006 +#define U_BLACK_PEN 0x80000007 +#define U_NULL_PEN 0x80000008 +#define U_OEM_FIXED_FONT 0x8000000A +#define U_ANSI_FIXED_FONT 0x8000000B +#define U_ANSI_VAR_FONT 0x8000000C +#define U_SYSTEM_FONT 0x8000000D +#define U_DEVICE_DEFAULT_FONT 0x8000000E +#define U_DEFAULT_PALETTE 0x8000000F +#define U_SYSTEM_FIXED_FONT 0x80000010 +#define U_DEFAULT_GUI_FONT 0x80000011 +#define U_STOCK_LAST 0x80000011 +/** @} */ + +/** \defgroup U_EMRSETSTRETCHBLTMODE_iMode_Qualifiers StretchMode Enumeration + For EMF U_EMRSETSTRETCHBLTMODE iMode field + @{ +*/ +#define U_BLACKONWHITE 1 +#define U_WHITEONBLACK 2 +#define U_COLORONCOLOR 3 +#define U_HALFTONE 4 +#define U_MAXSTRETCHBLTMODE 4 +#define U_STRETCH_ANDSCANS 1 +#define U_STRETCH_ORSCANS 2 +#define U_STRETCH_DELETESCANS 3 +#define U_STRETCH_HALFTONE 4 +/** @} */ + +/** \defgroup U_PANOSE_bStrokeVariation_Qualifiers StrokeVariation Enumeration + For U_PANOSE bStrokeVariation field + @{ +*/ +#define U_PAN_STROKE_GRADUAL_DIAG 2 +#define U_PAN_STROKE_GRADUAL_TRAN 3 +#define U_PAN_STROKE_GRADUAL_VERT 4 +#define U_PAN_STROKE_GRADUAL_HORZ 5 +#define U_PAN_STROKE_RAPID_VERT 6 +#define U_PAN_STROKE_RAPID_HORZ 7 +#define U_PAN_STROKE_INSTANT_VERT 8 +/** @} */ + +/** \defgroup U_EMRSETTEXTALIGN_iMode_Qualifiers TextAlignment Enumeration + For U_EMRSETTEXTALIGN iMode field + + Recall that EMF coordinates have UL closest to {0,0}, LR is below and to the right of UL and so has LARGER + {x,y} coordinates. In the following "TOP" is on the horizontal line defined by LR, as it has larger y coordinates, + which when viewing the EMF file, would actually be on the BOTTOM of the bounding rectangle. Similarly, left and right + are reversed. + + Microsoft documentation (WMF manual, section 2.1.2.3) says that the text starts on certain edges of the bounding rectangle. + That is apparently not true, whether the bounding rectangle is {0,0,-1,-1}, which is effectively no bounding rectangle, + or if a valid bounding rectangle is specified. In all cases the text (in Windows XP Preview) starts, has center at, or ends + at the center point. Vertical offsets seem to be defined analogously, but with respect to the height of the font. The bounding + rectangle defined for the U_EMRTEXT record appears to be ignored. + + Microsoft documentation (EMF manual,section 2.2.5) says that the same rectangle is used for "clipping or opaquing" by ExtTextOutA/W. + That does not seem to occur either. + + @{ +*/ +// Horizontal text flags +#define U_TA_DEFAULT 0x00 // default alignment +#define U_TA_NOUPDATECP 0x00 // Reference point does not move +#define U_TA_UPDATECP 0x01 // Reference point moves to end of next text drawn. +#define U_TA_LEFT 0x00 // Reference point is on left edge of bounding rectangle +#define U_TA_RIGHT 0x02 // Reference point is on right edge of bounding rectangle +#define U_TA_CENTER 0x06 // Reference point is on center vertical line of bounding rectangle +#define U_TA_TOP 0x00 // Reference point is on top edge of bounding rectangle +#define U_TA_BOTTOM 0x08 // Reference point is on bottom edge of bounding rectangle +#define U_TA_BASEBIT 0x10 // Reference point is on baseline of text if this bit is set, for 0x10 <-> 0x18 +#define U_TA_BASELINE 0x18 // Reference point is on baseline of text +#define U_TA_RTLREADING 0x100 // Set for Right to Left languages like Hebrew and Arabic +#define U_TA_MASK U_TA_BASELINE+U_TA_CENTER+U_TA_UPDATECP+U_TA_RTLREADING +// Vertical text flags +#define U_VTA_BASELINE U_TA_BASELINE // for vertical text +#define U_VTA_LEFT U_TA_BOTTOM +#define U_VTA_RIGHT U_TA_TOP +#define U_VTA_CENTER U_TA_CENTER +#define U_VTA_BOTTOM U_TA_RIGHT +#define U_VTA_TOP U_TA_LEFT +/** @} */ + +/** \defgroup U_PANOSE_bWeight_Qualifiers Weight Enumeration + For U_PANOSE bWeight field + @{ +*/ +#define U_PAN_WEIGHT_VERY_LIGHT 2 +#define U_PAN_WEIGHT_LIGHT 3 +#define U_PAN_WEIGHT_THIN 4 +#define U_PAN_WEIGHT_BOOK 5 +#define U_PAN_WEIGHT_MEDIUM 6 +#define U_PAN_WEIGHT_DEMI 7 +#define U_PAN_WEIGHT_BOLD 8 +#define U_PAN_WEIGHT_HEAVY 9 +#define U_PAN_WEIGHT_BLACK 10 +#define U_PAN_WEIGHT_NORD 11 +/** @} */ + +/** \defgroup U_PANOSE_bXHeight_Qualifiers XHeight Enumeration + For U_PANOSE bXHeight field + @{ +*/ +#define U_PAN_XHEIGHT_CONSTANT_SMALL 2 +#define U_PAN_XHEIGHT_CONSTANT_STANDARD 3 +#define U_PAN_XHEIGHT_CONSTANT_LARGE 4 +#define U_PAN_XHEIGHT_DUCKING_SMALL 5 +#define U_PAN_XHEIGHT_DUCKING_STANDARD 6 +#define U_PAN_XHEIGHT_DUCKING_LARGE 7 +/** @} */ + +/** \defgroup U_BLEND_Op_Qualifiers Blend Enumeration + For U_BLEND Op field + @{ +*/ +#define U_AC_SRC_GLOBAL 0 +#define U_AC_SRC_CONST 0 +#define U_AC_SRC_ALPHA 1 +/** @} */ + + +// *************************************************************************** +/** \defgroup Miscellaneous_values Miscellaneous Values + @{ +*/ +#define U_NONE 0 //!< Generic for nothing selected for all flag fields +#define U_PI 3.14159265358979323846 //!< pi +#define U_READ 1 +#define U_WRITE 0 +#define U_ENHMETA_VERSION 0x00010000 //!< U_EMRHEADER nVersion field +#define U_DV_SGNTR 0x08007664 //!< For U_DESIGNVECTOR Signature field +#define U_LP_VERSION 0x0300 //!< For U_LOGPALETTE palVersion field +#define U_RDH_RECTANGLES 1 //!< For U_RGNDATAHEADER iType field +#define U_RDH_OBJSIZE 0x20 //!< For U_RGNDATAHEADER dwSIze field +#define U_RGB_GAMMA_MIN (uint16_t)02500 //!< For U_COLORADJUSTMENT ca[Red|Green|Blue]Gamma fields +#define U_RGB_GAMMA_MAX (uint16_t)65000 //!< For U_COLORADJUSTMENT ca[Red|Green|Blue]Gamma fields +#define U_REFERENCE_WHITE_MIN (uint16_t)6000 //!< For U_COLORADJUSTMENT caReferenceWhite field +#define U_REFERENCE_WHITE_MAX (uint16_t)10000 //!< For U_COLORADJUSTMENT caReferenceWhite field +#define U_REFERENCE_BLACK_MIN (uint16_t)0 //!< For U_COLORADJUSTMENT caReferenceBlack field +#define U_REFERENCE_BLACK_MAX (uint16_t)4000 //!< For U_COLORADJUSTMENT caReferenceBlack field +#define U_COLOR_ADJ_MIN ((int16_t)-100) //!< For U_COLORADJUSTMENT ca[Contrast|Brightness|Colorfulness|RedGreenTint] fields +#define U_COLOR_ADJ_MAX (int16_t) 100 //!< For U_COLORADJUSTMENT ca[Contrast|Brightness|Colorfulness|RedGreenTint] fields +#define U_MAX_PATH 1024 //!< longest path name for a file +#define U_LCS_SIGNATURE 0x50534F43 //!< logColorSpace Signature +#define U_LCS_VERSION 0x400 //!< logColorSpace Version +#define U_REC_FREE 1 //!< used with emf_append +#define U_REC_KEEP 0 //!< used with emf_append +/** Solaris 8 has problems with round/roundf, just use this everywhere */ +#define U_ROUND(A) ( (A) > 0 ? floor((A)+0.5) : ( (A) < 0 ? -floor(-(A)+0.5) : (A) ) ) + +/** @} */ + +// *************************************************************************** +// Macros + +/** \defgroup Common_macros Common Macros + @{ +*/ +// Color U_BGR(A), byte order lo to hi: {B,G,R,A} corresponding to U_RGBQUAD. Set/Get Macros. +// These are used in EMF structures and the byte order must be the same in memory or on disk. +#define U_BGR(r,g,b) (U_RGBQUAD){b,g,r,0} //!< Set any BGR color with an {r,g,b} triplet +#define U_BGRA(r,g,b,a) (U_RGBQUAD){b,g,r,a} //!< Set any BGRA color with an {r,g,b,a} quad +#define U_WHITE U_BGR(255,255,255) //!< Set BGR white. +#define U_BLACK U_BGR(0,0,0) //!< Set BGR black. +#define U_BGRAGetR(rgb) (rgb.Red ) //!< Color BGR Get Red Macro. +#define U_BGRAGetG(rgb) (rgb.Green ) //!< Color BGR Get Green Macro. +#define U_BGRAGetB(rgb) (rgb.Blue ) //!< Color BGR Get Blue Macro. +#define U_BGRAGetA(rgb) (rgb.Reserved) //!< Color BGR Get A/reserved Macro. + +#define U_PALETTERGB(r,g,b) U_RGB(r,g,b,0x02)) //!< Set any Palette RGB color. +#define U_PALETTEINDEX(i) ((U_COLORREF)(0x01000000 | (uint16_t)(i)))\ + //!< Get RGB from Palette by index. + +// Color U_RGB(A), byte order lo to hi: {R,G,B,A} corresponding to U_COLORREF. Set/Get Macros. +// These are used in EMF structures and the byte order must be the same in memory or on disk. +// These MAY be used in PNG and other libraries if these enforce byte order in memory,otherwise +// U_swap4 may need to also be employed. +#define U_RGB(r,g,b) (U_COLORREF){r,g,b,0} //!< Set any RGB color with an {r,g,b} triplet +#define U_RGBA(r,g,b,a) (U_COLORREF){r,g,b,a} //!< Set any RGBA color with an {r,g,b,a} quad +#define U_RGBAGetR(rgb) ((U_COLORREF)rgb).Red //!< Color RGB Get Red Macro. +#define U_RGBAGetG(rgb) ((U_COLORREF)rgb).Green //!< Color RGB Get Green Macro. +#define U_RGBAGetB(rgb) ((U_COLORREF)rgb).Blue //!< Color RGB Get Blue Macro. +#define U_RGBAGetA(rgb) ((U_COLORREF)rgb).Reserved //!< Color RGBA Get A/reserved Macro. + +// color type conversions +#define U_RGB2BGR(rgb) (U_RGBQUAD){ U_RGBAGetB(rgb),U_RGBAGetG(rgb),U_RGBAGetR(rgb),0} //!< Set any BGR color from an RGB color +#define U_BGR2RGB(rgb) (U_COLORREF){U_BGRAGetR(rgb),U_BGRAGetG(rgb),U_BGRAGetB(rgb),0} //!< Set any RGB color from an BGR color +#define U_RGBA2BGRA(rgb) (U_RGBQUAD){ U_RGBAGetB(rgb),U_RGBAGetG(rgb),U_RGBAGetR(rgb),U_RGBAGetA(rgb)} //!< Set any BGRA color from an RGBA color +#define U_BGRA2RGBA(rgb) (U_COLORREF){U_BGRAGetR(rgb),U_BGRAGetG(rgb),U_BGRAGetB(rgb),U_BGRAGetA(rgb)} //!< Set any RGBA color from an BGRA color + +// Color CMYK Get/Set Macros +#define U_CMYK(c,m,y,k)\ + ((COLOREF)((((uint8_t)(k)|((uint16_t)((uint8_t)(y))<<8))|(((uint32_t)(uint8_t)(m))<<16))|(((uint32_t)(uint8_t)(c))<<24))) \ + //!< Color CMYK Set Macro. +#define U_GetKValue(cmyk) ((uint8_t) (cmyk) ) //!< Color CMYK Get K Macro. +#define U_GetYValue(cmyk) ((uint8_t) ((cymk) >> 8)) //!< Color CMYK Get Y Macro. +#define U_GetMValue(cmyk) ((uint8_t) ((cymk) >> 16)) //!< Color CMYK Get M Macro. +#define U_GetCValue(cmyk) ((uint8_t) ((cymk) >> 24)) //!< Color CMYK Get C Macro. + +// Other macros +#define U_Gamma(A) (A < U_RGB_GAMMA_MIN ? U_RGB_GAMMA_MIN : (A > U_RGB_GAMMA_MAX ? U_RGB_GAMMA_MAX: A)) \ + //!< Gamma set Macro (enforce range). +#define U_PM(A,B) ((A)<-(B)?-(B):((A)>(B)?(B):(A))) //!< Plus/Minus Range Macro (B must be postitive!). +#define U_MNMX(A,B,C) ((A)<(B)?(B):((A)>(C)?(C):(A))) //!< Min/Max Range Macro (B <= A <= C). +#define U_MIN(A,B) ((A)>(B)?(B):(A)) //!< Minimum of A,B +#define U_MAX(A,B) ((A)>(B)?(A):(B)) //!< Maximum of A,B + +// basic EMR macros. +#define U_EMRTYPE(A) (((PU_EMR)A)->iType) //!< Get iType from U_EMR* record +#define U_EMRSIZE(A) (((PU_EMR)A)->nSize) //!< Get nSize from U_EMR* record + +// Utility macros +#define UP4(A) (4 * ((A + 3 ) / 4)) //!< Round up to nearest multiple of 4 + +/** @} */ + +typedef float U_FLOAT; + +typedef uint32_t U_CBBITS; // Describes byte count of TYPE +typedef uint32_t U_CBBITSMSK; +typedef uint32_t U_CBBITSSRC; +typedef uint32_t U_CBBMI; +typedef uint32_t U_CBBMIMSK; +typedef uint32_t U_CBBMISRC; +typedef uint32_t U_CBDATA; +typedef uint32_t U_CBNAME; +typedef uint32_t U_CBPLENTRIES; +typedef uint32_t U_CBPXLFMT; +typedef uint32_t U_CBRGNDATA; +typedef uint32_t U_CBSTR; // bytes in an 8 or 16 bit string + +typedef uint32_t U_OFFBITS; // Describes byte offset to TYPE, always measured from the start of the RECORD (not the struct) +typedef uint32_t U_OFFBITSMSK; +typedef uint32_t U_OFFBITSSRC; +typedef uint32_t U_OFFBMI; +typedef uint32_t U_OFFBMIMSK; +typedef uint32_t U_OFFBMISRC; +typedef uint32_t U_OFFDATA; +typedef uint32_t U_OFFDESC; +typedef uint32_t U_OFFDX; +typedef uint32_t U_OFFPLENTRIES; +typedef uint32_t U_OFFPXLFMT; +typedef uint32_t U_OFFSTR; // String of either 8 or 16 bit characters +typedef uint8_t U_DATA; // any binary sort of data, not otherwise classified. + +// "Types" For array components in structures, where not otherwise defined as a structure +typedef uint32_t U_FNTAXES; // Font Axes For U_DESIGNVECTOR +typedef uint32_t U_STYLEENTRY; // StyleEntry For U_EXTLOGPEN +typedef uint32_t U_POLYCOUNTS; // aPolyCounts For U_EMRPOLYPOLYLINE etc. + +// "Counts" for array components in structures +typedef uint32_t U_NUM_FNTAXES; // Number of U_FNTAXES +typedef uint32_t U_NUM_LOGPLTNTRY; // Number of U_LOGPLTENTRY +typedef uint32_t U_NUM_RECTL; // Number of U_RECTL +typedef uint32_t U_NUM_POINTL; // Number of U_POINTL +typedef uint32_t U_NUM_POINT16; // Number of U_POINT16 +typedef uint32_t U_NUM_STYLEENTRY; // Number of U_STYLEENTRY +typedef uint32_t U_NUM_POLYCOUNTS; // Number of U_POLYCOUNTS +typedef uint32_t U_NUM_EMRTEXT; // Number of U_EMRTEXT +typedef uint32_t U_NUM_STR; // Number of 8 or 16 bit characters in string +typedef uint32_t U_NUM_TRIVERTEX; // Number of U_TRIVERTEX +typedef uint32_t U_NUM_GRADOBJ; // Number of U_GRADIENT4 OR U_GRADIENT3 (determined at run time) +typedef uint32_t U_NUM_RGBQUAD; // Number of U_RGBQUAD (in bmciColors in U_BITMAPCOREINFO) + + +/** + \brief Pair of values indicating x and y sizes. + Microsoft name: SIZE Object + Microsoft name: SIZEL Object +*/ +typedef struct { + int32_t cx; //!< X size + int32_t cy; //!< Y size +} U_SIZE, U_SIZEL, *PU_SIZE, *PU_SIZEL; + +/** + \brief Used for any generic pair of floats + Microsoft name: (none) +*/ +typedef struct { + float x; //!< X value + float y; //!< Y value +} U_PAIRF, *PU_PAIRF; + +/** + \brief Used for any generic pair of uint32_t + Microsoft name: POINT Object +*/ +typedef struct { + int32_t x; //!< X value + int32_t y; //!< Y value +} U_PAIR, *PU_PAIR, U_POINT, *PU_POINT, U_POINTL, *PU_POINTL; + +/** + \brief Point type for 16 bit EMR drawing functions. + Microsoft name: POINTS Object + Microsoft name: POINTS16 Object +*/ +typedef struct { + int16_t x; //!< X size (16 bit) + int16_t y; //!< Y size (16 bit) +} U_POINT16, *PU_POINT16; + +/** + \brief Coordinates of the upper left, lower right corner. + Note that the coordinate system is 0,0 in the upper left corner + of the screen an N,M in the lower right corner. + Microsoft name: RECT Object +*/ +typedef struct { + int32_t left; //!< left coordinate + int32_t top; //!< top coordinate + int32_t right; //!< right coordinate + int32_t bottom; //!< bottom coordinate +} U_RECT, *PU_RECT, + U_RECTL, *PU_RECTL; + +#define U_RCL_DEF (U_RECTL){0,0,-1,-1} //!< Use this when no bounds are needed. + +/* ************************************************************ + EMF structures OTHER than those corresponding to complete U_EMR_* records + ************************************************************ */ + +/** + \brief For U_BITMAPINFO bmiColors field + NOTE that the color order is BGR, even though the name is RGB! + Microsoft name: RGBQUAD Object +*/ +typedef struct { + uint8_t Blue; //!< Blue color (0-255) + uint8_t Green; //!< Green color (0-255) + uint8_t Red; //!< Red color (0-255) + uint8_t Reserved; //!< Not used +} U_RGBQUAD, *PU_RGBQUAD; + +/** + \brief For U_BITMAPINFO crColor field + NOTE that the color order is RGB reserved, flipped around from the preceding. + Microsoft name: COLORREF Object +*/ +typedef struct { + uint8_t Red; //!< Red color (0-255) + uint8_t Green; //!< Green color (0-255) + uint8_t Blue; //!< Blue color (0-255) + uint8_t Reserved; //!< Not used +} U_COLORREF, *PU_COLORREF; + +/** + \brief For U_POINT28_4 x and y fields. + Microsoft name: BitFIX28_4 Object. +*/ +typedef struct { + signed IntValue :28; //!< Signed integral bit field + unsigned FracValue :4; //!< Unsigned integral bit field +} U_BITFIX28_4, *PU_BITFIX28_4; + +/** + \brief For U_LCS_GAMMARGB lcsGamma* fields + Microsoft name:(unknown) Object +*/ +typedef struct { + unsigned ignoreHi :8; //!< not used + unsigned intPart :8; //!< integer part + unsigned fracPart :8; //!< fraction part + unsigned ignoreLo :8; //!< not used +} U_LCS_GAMMA, *PU_LCS_GAMMA; + +/** + \brief For U_LOGCOLORSPACEA and U_LOGCOLORSPACEW lcsGammaRGB field + Microsoft name:(unknown) Object +*/ +typedef struct { + U_LCS_GAMMA lcsGammaRed; //!< Red Gamma + U_LCS_GAMMA lcsGammaGreen; //!< Green Gamma + U_LCS_GAMMA lcsGammaBlue; //!< Blue Gamma +} U_LCS_GAMMARGB, *PU_LCS_GAMMARGB; + +/** + \brief For U_EMRSETOLORADJUSTMENT ColorAdjustment field + Note, range constants are: RGB_GAMMA_[MIN|MAX],REFERENCE_[WHITE|BLACK]_[MIN|MAX],COLOR_ADJ_[MIN|MAX] + Microsoft name: ColorAdjustment Object +*/ +typedef struct { + uint16_t caSize; //!< Size of this structure in bytes + uint16_t caFlags; //!< ColorAdjustment Enumeration + uint16_t caIlluminantIndex; //!< Illuminant Enumeration + uint16_t caRedGamma; //!< Red Gamma correction (range:2500:65000, 10000 is no correction) + uint16_t caGreenGamma; //!< Green Gamma correction (range:2500:65000, 10000 is no correction) + uint16_t caBlueGamma; //!< Blue Gamma correction (range:2500:65000, 10000 is no correction) + uint16_t caReferenceBlack; //!< Values less than this are black (range:0:4000) + uint16_t caReferenceWhite; //!< Values more than this are white (range:6000:10000) + int16_t caContrast; //!< Contrast adjustment (range:-100:100, 0 is no correction) + int16_t caBrightness; //!< Brightness adjustment (range:-100:100, 0 is no correction) + int16_t caColorfulness; //!< Colorfulness adjustment (range:-100:100, 0 is no correction) + int16_t caRedGreenTint; //!< Tine adjustment (range:-100:100, 0 is no correction) +} U_COLORADJUSTMENT, *PU_COLORADJUSTMENT; + +/** + \brief For ? (not implemented yet) + Microsoft name: DesignVector Object +*/ +typedef struct { + uint32_t Signature; //!< Must be 0x08007664 (AKA: DV_SGNTR) + U_NUM_FNTAXES NumAxes; //!< Number of elements in Values, 0-16 + U_FNTAXES Values[1]; //!< Optional. Array of font axes for opentype font +} U_DESIGNVECTOR,*PU_DESIGNVECTOR; + +/** + \brief For U_EMR_COMMENT_MULTIFORMATS record, where an array of these is used + Microsoft name: EmrFormat Object +*/ +typedef struct { + uint32_t signature; //!< FormatSignature Enumeration + uint32_t nVersion; //!< Must be 1 if signature is EPS, else ignored + U_CBDATA cbData; //!< Data size in bytes + U_OFFDATA offData; //!< Offset in bytes to the Data from the start of the RECORD +} U_EMRFORMAT, *PU_EMRFORMAT; + +/** + \brief For U_EMR[POLY]EXTTEXTOUT[A|W] emrtext field + Differs from implementation in Mingw and Wine in that the core struct has a fixed size. + Optional and movable components must be handled with offsets. + Microsoft name: EmrText Object + Following invariant core there may/must be: + U_RECTL rcl; (Optional, absent when fOptions & U_ETO_NO_RECT) grayed/clipping/opaque rectangle + + U_OFFDX offDx; (required) but position isn't static. Offset in bytes to the character spacing array measured + from the start of the RECORD, NOT from the start of this structure. + + The order of the next two may be reversed, they are found from their offsets. + + char string (required) String buffer holding nChars (padded to a multiple of 4 bytes in length). + + uint32_t Dx[1] (required) character spacing, array with one entry per glyph. + +*/ +typedef struct { + U_POINTL ptlReference; //!< String start coordinates + U_NUM_STR nChars; //!< Number of characters in the string + U_OFFSTR offString; //!< Offset in bytes to the string from the start of the RECORD + uint32_t fOptions; //!< ExtTextOutOptions Enumeration +} U_EMRTEXT, *PU_EMRTEXT; + +/** + \brief For U_EPS_DATA Points field + Microsoft name: Point28_4 Object +*/ +typedef struct { + U_BITFIX28_4 x; //!< X coordinate + U_BITFIX28_4 y; //!< Y coordinate +} U_POINT28_4, *PU_POINT28_4; + +/** + \brief For embedding EPS in EMF via U_EMRFORMAT offData array in U_EMR_COMMENT_MULTIFORMATS + Microsoft name: EpsData Object +*/ +typedef struct { + uint32_t sizeData; //!< Size in bytes of this object + uint32_t version; //!< Must be 1 + U_POINT28_4 Points[3]; //!< Defines parallelogram, UL, UR, LL corners, LR is derived. + U_RECTL PostScriptData; //!< Record may include optional clipping/opaque rectangle +} U_EPS_DATA, *PU_EPS_DATA; + +/** + \brief For GRADIENT_[TRIANGLE|U_RECT] + Microsoft name: TriVertex Object +*/ +typedef struct { + int32_t x; //!< X coord + int32_t y; //!< Y coord + uint16_t Red; //!< Red component + uint16_t Green; //!< Green component + uint16_t Blue; //!< Bule component + uint16_t Alpha; //!< Alpha Transparency +} U_TRIVERTEX, *PU_TRIVERTEX; + + +/** + \brief For U_EMRGRADIENTFILL GradObj field + + Gradient object notes. The next two structures are used to define the shape with reference to an existing array + of points stored in an array of TriVertex objects in the U_EMRGRADIENTFILL record. The tricky part + is that these two structures are different sizes. In some implementations (MingW) the array is cast to uint32_t + and basically the cast is then ignored. For libUEMF we leave this out of the structure entirely and get to it with offsets. + + Microsoft name: GradientTriangle Object +*/ +typedef struct { + uint32_t Vertex1; //!< Index of Vertex1 in an array of U_TRIVERTEX objects + uint32_t Vertex2; //!< Index of Vertex2 in an array of U_TRIVERTEX objects + uint32_t Vertex3; //!< Index of Vertex3 in an array of U_TRIVERTEX objects +} U_GRADIENT3, *PU_GRADIENT3; + +/** + \brief For U_EMRGRADIENTFILL GradObj field + Microsoft name: GradientRectangle Object +*/ +typedef struct { + uint32_t UpperLeft; //!< Index of UL corner in an array of U_TRIVERTEX objects + uint32_t LowerRight; //!< Index of LR corner in an array of U_TRIVERTEX objects +} U_GRADIENT4, *PU_GRADIENT4; + +/** + \brief For U_EMRCREATEBRUSHINDIRECT lb field + Microsoft name: LogBrushEx Object +*/ +typedef struct { //!< In MS documentation this is LogBrushEx Object + uint32_t lbStyle; //!< LB_Style Enumeration + U_COLORREF lbColor; //!< Brush color + uint32_t lbHatch; //!< HatchStyle Enumeration +} U_LOGBRUSH, *PU_LOGBRUSH; +typedef U_LOGBRUSH U_PATTERN, *PU_PATTERN; + +/** + \brief For U_LOGFONT_PANOSE elfLogFont field + Microsoft name: LogFont Object +*/ +typedef struct { + int32_t lfHeight; //!< Height in Logical units + int32_t lfWidth; //!< Average Width in Logical units + int32_t lfEscapement; //!< Angle in 0.1 degrees betweem escapement vector and X axis + int32_t lfOrientation; //!< Angle in 0.1 degrees between baseline and X axis + int32_t lfWeight; //!< LF_Weight Enumeration + uint8_t lfItalic; //!< LF_Italic Enumeration + uint8_t lfUnderline; //!< LF_Underline Enumeration + uint8_t lfStrikeOut; //!< LF_StrikeOut Enumeration + uint8_t lfCharSet; //!< LF_CharSet Enumeration + uint8_t lfOutPrecision; //!< LF_OutPrecision Enumeration + uint8_t lfClipPrecision; //!< LF_ClipPrecision Enumeration + uint8_t lfQuality; //!< LF_Quality Enumeration + uint8_t lfPitchAndFamily; //!< LF_PitchAndFamily Enumeration + uint16_t lfFaceName[U_LF_FACESIZE]; //!< Name of font. If <U_LF_FACESIZE chars must be null terminated +} U_LOGFONT, *PU_LOGFONT; + +/** + \brief For U_LOGFONT_PANOSE elfPanose field + Microsoft name: Panose Object +*/ +typedef struct { + uint8_t bFamilyType; //!< FamilyType Enumeration + uint8_t bSerifStyle; //!< SerifType Enumeration + uint8_t bWeight; //!< Weight Enumeration + uint8_t bProportion; //!< Proportion Enumeration + uint8_t bContrast; //!< Contrast Enumeration + uint8_t bStrokeVariation; //!< StrokeVariation Enumeration + uint8_t bArmStyle; //!< ArmStyle Enumeration + uint8_t bLetterform; //!< Letterform Enumeration + uint8_t bMidline; //!< Midline Enumeration + uint8_t bXHeight; //!< XHeight Enumeration +} U_PANOSE, *PU_PANOSE; + +#define U_PAN_ALL0 (U_PANOSE){0,0,0,0,0,0,0,0,0,0} // all U_PAN_ANY, have not seen this in an EMF file +#define U_PAN_ALL1 (U_PANOSE){1,1,1,1,1,1,1,1,1,1} // all U_PAN_NO_FIT, this is what createfont() would have made + +// Microsoft name: LogFontEx Object (not implemented) +// Microsoft name: LogFontExDv Object (not implemented) + +/** + \brief For U_EMREXTCREATEFONTINDIRECTW elfw field + Microsoft name: LogFont_Panose Object +*/ +typedef struct { + U_LOGFONT elfLogFont; //!< Basic font attributes + uint16_t elfFullName[U_LF_FULLFACESIZE]; //!< Font full name + uint16_t elfStyle[U_LF_FACESIZE]; //!< Font style (if <U_LF_FACESIZE characters, null terminate string) + uint32_t elfVersion; //!< Ignore + uint32_t elfStyleSize; //!< Font hinting starting at this point size, if 0, starts at Height + uint32_t elfMatch; //!< Ignore + uint32_t elfReserved; //!< Must be 0, Ignore + uint8_t elfVendorId[U_ELF_VENDOR_SIZE]; //!< Ignore + uint32_t elfCulture; //!< Must be 0, Ignore + U_PANOSE elfPanose; //!< Panose Object. If all zero, it is ignored. + uint16_t elfPadding; //!< Ignore +} U_LOGFONT_PANOSE, *PU_LOGFONT_PANOSE; + +/** + \brief For U_LOGPALETTE palPalEntry field(s) + Microsoft name: LogPaletteEntry Object +*/ +typedef struct { + uint8_t peReserved; //!< Ignore + uint8_t peRed; //!< Palette entry Red Intensity + uint8_t peGreen; //!< Palette entry Green Intensity + uint8_t peBlue; //!< Palette entry Blue Intensity +} U_LOGPLTNTRY, *PU_LOGPLTNTRY; + +/** + \brief For U_EMRCREATEPALETTE lgpl field + Microsoft name: LogPalette Object +*/ +typedef struct { + uint16_t palVersion; //!< Must be 0x0300 (AKA: U_LP_VERSION) + uint16_t palNumEntries; //!< Number of U_LOGPLTNTRY objects + U_LOGPLTNTRY palPalEntry[1]; //!< PC_Entry Enumeration +} U_LOGPALETTE, *PU_LOGPALETTE; + +/** + \brief For U_EMRCREATEPEN lopn field + Microsoft name: LogPen Object +*/ +typedef struct { + uint32_t lopnStyle; //!< PenStyle Enumeration + U_POINT lopnWidth; //!< Width of pen set by X, Y is ignored + U_COLORREF lopnColor; //!< Pen color value +} U_LOGPEN, *PU_LOGPEN; + +// Microsoft name: LogPenEx Object (not implemented) + +/** + \brief For U_EMRPIXELFORMAT pfd field + Microsoft name: PixelFormatDescriptor Object +*/ +typedef struct { + uint16_t nSize; //!< Structure size in bytes + uint16_t nVersion; //!< must be 1 + uint32_t dwFlags; //!< PFD_dwFlags Enumeration + uint8_t iPixelType; //!< PFD_iPixelType Enumeration + uint8_t cColorBits; //!< RGBA: total bits per pixel + uint8_t cRedBits; //!< Red bits per pixel + uint8_t cRedShift; //!< Red shift to data bits + uint8_t cGreenBits; //!< Green bits per pixel + uint8_t cGreenShift; //!< Green shift to data bits + uint8_t cBlueBits; //!< Blue bits per pixel + uint8_t cBlueShift; //!< Blue shift to data bits + uint8_t cAlphaBits; //!< Alpha bits per pixel + uint8_t cAlphaShift; //!< Alpha shift to data bits + uint8_t cAccumBits; //!< Accumulator buffer, total bitplanes + uint8_t cAccumRedBits; //!< Red accumulator buffer bitplanes + uint8_t cAccumGreenBits; //!< Green accumulator buffer bitplanes + uint8_t cAccumBlueBits; //!< Blue accumulator buffer bitplanes + uint8_t cAccumAlphaBits; //!< Alpha accumulator buffer bitplanes + uint8_t cDepthBits; //!< Depth of Z-buffer + uint8_t cStencilBits; //!< Depth of stencil buffer + uint8_t cAuxBuffers; //!< Depth of auxilliary buffers (not supported) + uint8_t iLayerType; //!< PFD_iLayerType Enumeration, may be ignored + uint8_t bReserved; //!< Bits 0:3/4:7 are number of Overlay/Underlay planes + uint32_t dwLayerMask; //!< may be ignored + uint32_t dwVisibleMask; //!< color or index of underlay plane + uint32_t dwDamageMask; //!< may be ignored +} U_PIXELFORMATDESCRIPTOR, *PU_PIXELFORMATDESCRIPTOR; + +/** + \brief For U_RGNDATA rdb field + Microsoft name: RegionDataHeader Object (RGNDATAHEADER) +*/ +typedef struct { + uint32_t dwSize; //!< Size in bytes, must be 0x20 (AKA: U_RDH_OBJSIZE) + uint32_t iType; //!< Must be 1 (AKA: U_RDH_RECTANGLES) + U_NUM_RECTL nCount; //!< Number of rectangles in region + uint32_t nRgnSize; //!< Size in bytes of rectangle buffer + U_RECTL rclBounds; //!< Region bounds +} U_RGNDATAHEADER,*PU_RGNDATAHEADER; + +/** + \brief For U_EMRFILLRGN RgnData field(s) + Microsoft name: RegionData Object +*/ +typedef struct { + U_RGNDATAHEADER rdh; //!< Data description + U_RECTL Buffer[1]; //!< Array of U_RECTL elements +} U_RGNDATA,*PU_RGNDATA; + +// Microsoft name: UniversalFontId Object (not implemented) + +/** + \brief For U_EMR[FILLRGN|STRETCHBLT|MASKBLT|PLGBLT] xformSrc field + Microsoft name: Xform Object +*/ +typedef struct { + U_FLOAT eM11; //!< Matrix element M11 + U_FLOAT eM12; //!< Matrix element M12 + U_FLOAT eM21; //!< Matrix element M21 + U_FLOAT eM22; //!< Matrix element M22 + U_FLOAT eDx; //!< X offset in logical units + U_FLOAT eDy; //!< Y offset in logical units +} U_XFORM , *PU_XFORM; + +/** + \brief For U_CIEXYZTRIPLE (all) fields + Microsoft name: CIEXYZ Object +*/ +typedef struct { + int32_t ciexyzX; //!< CIE color space X component + int32_t ciexyzY; //!< CIE color space Y component + int32_t ciexyzZ; //!< CIE color space Z component +} U_CIEXYZ, *PU_CIEXYZ; + +/** + \brief For U_LOGCOLORSPACEA and U_LOGCOLORSPACEW lcsEndpints field + defines a CIE colorspace + Microsoft name: CIEXYZTRIPLE Object +*/ +typedef struct { + U_CIEXYZ ciexyzRed; //!< CIE XYZ coord of red endpoint of colorspace + U_CIEXYZ ciexyzGreen; //!< CIE XYZ coord of green endpoint of colorspace + U_CIEXYZ ciexyzBlue; //!< CIE XYZ coord of blue endpoint of colorspace +} U_CIEXYZTRIPLE, *PU_CIEXYZTRIPLE; + +/** + \brief For U_EMRCREATECOLORSPACE lcs field + Microsoft name: LOGCOLORSPACEA Object +*/ +typedef struct { + uint32_t lcsSignature; //!< must be U_LCS_SIGNATURE + uint32_t lcsVersion; //!< must be U_LCS_VERSION + uint32_t lcsSize; //!< Size in bytes of this structure + int32_t lcsCSType; //!< LCS_CSType Enumeration + int32_t lcsIntent; //!< LCS_Intent Enumeration + U_CIEXYZTRIPLE lcsEndpoints; //!< CIE XYZ color space endpoints + U_LCS_GAMMARGB lcsGammaRGB; //!< Gamma For RGB + char lcsFilename[U_MAX_PATH]; //!< Names an external color profile file, otherwise empty string +} U_LOGCOLORSPACEA, *PU_LOGCOLORSPACEA; + +/** + \brief For U_EMRCREATECOLORSPACEW lcs field + Microsoft name: LOGCOLORSPACEW Object +*/ +typedef struct { + uint32_t lcsSignature; //!< must be U_LCS_SIGNATURE + uint32_t lcsVersion; //!< must be U_LCS_VERSION + uint32_t lcsSize; //!< Size in bytes of this structure + int32_t lcsCSType; //!< lcsCSType Enumeration + int32_t lcsIntent; //!< lcsIntent Enumeration + U_CIEXYZTRIPLE lcsEndpoints; //!< CIE XYZ color space endpoints + U_LCS_GAMMARGB lcsGammaRGB; //!< Gamma For RGB + uint16_t lcsFilename[U_MAX_PATH]; //!< Could name an external color profile file, otherwise empty string +} U_LOGCOLORSPACEW, *PU_LOGCOLORSPACEW; + +/** + \brief For U_EMREXTCREATEPEN lopn field + Microsoft name: EXTLOGPEN Object +*/ +typedef struct { + uint32_t elpPenStyle; //!< PenStyle Enumeration + uint32_t elpWidth; //!< Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel) + uint32_t elpBrushStyle; //!< LB_Style Enumeration + U_COLORREF elpColor; //!< Pen color + uint32_t elpHatch; //!< HatchStyle Enumeration + U_NUM_STYLEENTRY elpNumEntries; //!< Count of StyleEntry array + U_STYLEENTRY elpStyleEntry[1]; //!< Array of StyleEntry (For user specified dot/dash patterns) +} U_EXTLOGPEN, *PU_EXTLOGPEN; + +/** + \brief For U_BITMAPINFO bmiHeader field + Microsoft name: BITMAPINFOHEADER Object +*/ +typedef struct { + uint32_t biSize; //!< Structure size in bytes + int32_t biWidth; //!< Bitmap width in pixels + int32_t biHeight; //!< Bitmap height in pixels, may be negative. + //!< abs(biHeight) is bitmap height + //!< bitmap may appear in two orientations: + //!< biHeight > 0 origin is LL corner, may be compressed, this is height after decompression. + //!< biHeight < 0 origin is UL corner, may not be compressed + uint16_t biPlanes; //!< Planes (must be 1) + uint16_t biBitCount; //!< BitCount Enumeration (determines number of RBG colors) + uint32_t biCompression; //!< BI_Compression Enumeration + uint32_t biSizeImage; //!< Image size in bytes or 0 = "default size (calculated from geometry?)" + int32_t biXPelsPerMeter; //!< X Resolution in pixels/meter + int32_t biYPelsPerMeter; //!< Y Resolution in pixels/meter + U_NUM_RGBQUAD biClrUsed; //!< Number of bmciColors in U_BITMAPINFO/U_BITMAPCOREINFO that are used by the bitmap + uint32_t biClrImportant; //!< Number of bmciColors needed (0 means all). +} U_BITMAPINFOHEADER, *PU_BITMAPINFOHEADER; + +/** + \brief For U_EMR_* OffBmi* fields + Description of a Bitmap which in some cases is a Device Independent Bitmap (DIB) + Microsoft name: BITMAPINFO Object +*/ +typedef struct { + U_BITMAPINFOHEADER bmiHeader; //!< Geometry and pixel properties + U_RGBQUAD bmiColors[1]; //!< Color table. 24 bit images do not use color table values. +} U_BITMAPINFO, *PU_BITMAPINFO; + +/** + \brief U_EMRALPHABLEND Blend field +*/ +typedef struct { + uint8_t Operation; //!< Must be 0 + uint8_t Flags; //!< Must be 0 + uint8_t Global; //!< Alpha for whole thing if Op is U_AC_SRC_GLOBAL (AKA U_AC_SRC_GLOBAL) + uint8_t Op; //!< Blend Enumeration +} U_BLEND, *PU_BLEND; +# + +/** + General form of an EMF record. + Microsoft name: ENHMETARECORD Object + For generic cast of other U_EMR_* records +*/ +typedef struct { + uint32_t iType; //!< Type of EMR record + uint32_t nSize; //!< Size of entire record in bytes (multiple of 4). + uint32_t dParm[1]; //!< Data in record +} U_ENHMETARECORD, *PU_ENHMETARECORD; + +/** First two fields of all EMF records + For accessing iType and nSize files in all U_EMR* records + Microsoft name: EMR Object +*/ +typedef struct { + uint32_t iType; //!< Type of EMR record + uint32_t nSize; //!< Size of entire record in bytes (multiple of 4). +} U_EMR, *PU_EMR; + +typedef struct { + U_EMR emr; //!< U_EMR + U_PAIR pair; //!< pair of 32 bit values +} U_EMRGENERICPAIR, *PU_EMRGENERICPAIR; + + + + +// *********************************************************************************** +// The following have U_EMR_# records + +/* Index 1 */ +/** + \brief The firstU_ENHMETARECORD record in the metafile. + + Microsoft names instead: Header, HeaderExtension1, and HeaderExtension2 objects. These are + used nowhere else, so they are combined here, along with the first two fields which were not listed in the Header. + + Note also that three fields in this file (nBytes, nRecords, nHandles) must be (re)set after the entire EMF + is constructed, since typically they are not known until then. bOpenGL may or may not be knowable when this + header is written. + + Note also that rclBounds and rclFrame are supposed to be the region bounding the drawn content within the + EMF. This is generally smaller than the size from szlDevice. However, since libUEMF does not actually draw + anything it has no way of knowing what these values are. Instead when it creates a header it sets these to + match the szl* fields. +*/ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_RECTL rclFrame; //!< Bounding rectangle in 0.01 mm units + uint32_t dSignature; //!< FormatSignature Enumeration (must be U_ENHMETA_SIGNATURE) + uint32_t nVersion; //!< Must be U_ENHMETA_VERSION (0x00010000) + uint32_t nBytes; //!< Length in bytes of the Metafile + uint32_t nRecords; //!< Records in the Metafile + uint16_t nHandles; //!< Number of graphics objects used in the Metafile + uint16_t sReserved; //!< Must be 0 + uint32_t nDescription; //!< Characters in the Description field, 0 if no description + uint32_t offDescription; //!< Offset in bytes to Description field + uint32_t nPalEntries; //!< Number of Palette entries (in U_EMR_EOF record). + U_SIZEL szlDevice; //!< Reference device size in pixels + U_SIZEL szlMillimeters; //!< Reference device size in 0.01 mm + /** Fields for winver >= win95 */ + U_CBPXLFMT cbPixelFormat; //!< Size in bytes of PixelFormatDescriptor, 0 if no PFD + U_OFFPXLFMT offPixelFormat; //!< Offset in bytes to PixelFormatDescriptor from the start of the RECORD, 0 if no PFD + uint32_t bOpenGL; //!< nonZero if OpenGL commands are included + /** Fields for winver >= win98 */ + U_SIZEL szlMicrometers; //!< Size of the display device in micrometer + //!< Record may include optional Description, UTF-16BE string + //!< Record may include optional PxlFmtDescriptor, U_PIXELFORMATDESCRIPTOR +} U_EMRHEADER, *PU_EMRHEADER; + +/* Index 2,3,4,5,6*/ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< bounding rectangle in device units + U_NUM_POINTL cptl; //!< Number of points to draw + U_POINTL aptl[1]; //!< array of points +} U_EMRPOLYBEZIER, *PU_EMRPOLYBEZIER, + U_EMRPOLYGON, *PU_EMRPOLYGON, + U_EMRPOLYLINE, *PU_EMRPOLYLINE, + U_EMRPOLYBEZIERTO, *PU_EMRPOLYBEZIERTO, + U_EMRPOLYLINETO, *PU_EMRPOLYLINETO; + +/* Index 7,8 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< bounding rectangle in device units + U_NUM_POLYCOUNTS nPolys; //!< Number of elements in aPolyCounts + U_NUM_POINTL cptl; //!< Total number of points (over all poly) + U_POLYCOUNTS aPolyCounts[1]; //!< Number of points in each poly (sequential) +// This will appear somewhere but is not really part of the core structure. +// U_POINTL aptl[1]; //!< array of points +} U_EMRPOLYPOLYLINE, *PU_EMRPOLYPOLYLINE, + U_EMRPOLYPOLYGON, *PU_EMRPOLYPOLYGON; + +/* Index 9,11 (numbers interleave with next one) */ +typedef struct { + U_EMR emr; //!< U_EMR + U_SIZEL szlExtent; //!< H & V extent in logical units +} U_EMRSETWINDOWEXTEX, *PU_EMRSETWINDOWEXTEX, + U_EMRSETVIEWPORTEXTEX, *PU_EMRSETVIEWPORTEXTEX; + +/* Index 10,12,13 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL ptlOrigin; //!< H & V origin in logical units +} U_EMRSETWINDOWORGEX, *PU_EMRSETWINDOWORGEX, + U_EMRSETVIEWPORTORGEX, *PU_EMRSETVIEWPORTORGEX, + U_EMRSETBRUSHORGEX, *PU_EMRSETBRUSHORGEX; + +/* Index 14 +*/ +/** +This is a very odd structure because the nSizeLast follows an optional variable size field. Consequently +even though nSizeLast has a name it cannot actually be accessed by it! Following the core appear these fields: + + U_LOGPLTNTRY PalEntries[1]; Record may include optional array of PalEntries + + uint32_t nSizeLast; Mandatory, but position isn't fixed. Must have same value as emr.nSize in header record +*/ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBPLENTRIES cbPalEntries; //!< Number of palette entries + U_OFFPLENTRIES offPalEntries; //!< Offset in bytes to array of palette entries +} U_EMREOF, *PU_EMREOF; + +/* Index 15 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL ptlPixel; //!< Pixel coordinates (logical) + U_COLORREF crColor; //!< Pixel color +} U_EMRSETPIXELV, *PU_EMRSETPIXELV; + +/* Index 16 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t dwFlags; //!< must be 1 +} U_EMRSETMAPPERFLAGS, *PU_EMRSETMAPPERFLAGS; + +/* Index 17,18,19,20,21,22,67,98,115 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t iMode; //!< enumeration varies with type +} U_EMRSETMAPMODE, *PU_EMRSETMAPMODE, //!< MapMode enumeration + U_EMRSETBKMODE, *PU_EMRSETBKMODE, //!< BackgroundMode Enumeration + U_EMRSETPOLYFILLMODE, *PU_EMRSETPOLYFILLMODE, //!< PolygonFillMode Enumeration + U_EMRSETROP2, *PU_EMRSETROP2, //!< Binary Raster Operation Enumeration + U_EMRSETSTRETCHBLTMODE, *PU_EMRSETSTRETCHBLTMODE, //!< StretchMode Enumeration + U_EMRSETTEXTALIGN, *PU_EMRSETTEXTALIGN, //!< TextAlignment enumeration + U_EMRSELECTCLIPPATH, *PU_EMRSELECTCLIPPATH, //!< RegionMode Enumeration + U_EMRSETICMMODE, *PU_EMRSETICMMODE, //!< ICMMode Enumeration + U_EMRSETLAYOUT, *PU_EMRSETLAYOUT; //!< Mirroring Enumeration + +/* Index 23 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_COLORADJUSTMENT ColorAdjustment; //!< Color Adjustment +} U_EMRSETCOLORADJUSTMENT, *PU_EMRSETCOLORADJUSTMENT; + +/* Index 24, 25 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_COLORREF crColor; //!< Color +} U_EMRSETTEXTCOLOR, *PU_EMRSETTEXTCOLOR, + U_EMRSETBKCOLOR, *PU_EMRSETBKCOLOR; + +/* Index 26 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL ptlOffset; //!< Clipping region +} U_EMROFFSETCLIPRGN, *PU_EMROFFSETCLIPRGN; + +/* Index 27, 54 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL ptl; //!< Point coordinates +} U_EMRMOVETOEX, *PU_EMRMOVETOEX, + U_EMRLINETO, *PU_EMRLINETO; + +/* Index 28,33,52,59,60,61,65,66,68 */ +typedef struct { + U_EMR emr; //!< U_EMR +} + U_EMRSETMETARGN, *PU_EMRSETMETARGN, + U_EMRSAVEDC, *PU_EMRSAVEDC, + U_EMRREALIZEPALETTE, *PU_EMRREALIZEPALETTE, + U_EMRBEGINPATH, *PU_EMRBEGINPATH, + U_EMRENDPATH, *PU_EMRENDPATH, + U_EMRCLOSEFIGURE, *PU_EMRCLOSEFIGURE, + U_EMRFLATTENPATH, *PU_EMRFLATTENPATH, + U_EMRWIDENPATH, *PU_EMRWIDENPATH, + U_EMRABORTPATH, *PU_EMRABORTPATH; + +/* Index 29,30 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclClip; //!< Clipping Region +} U_EMREXCLUDECLIPRECT, *PU_EMREXCLUDECLIPRECT, + U_EMRINTERSECTCLIPRECT, *PU_EMRINTERSECTCLIPRECT; + +/* Index 31,32 */ +typedef struct { + U_EMR emr; //!< U_EMR + int32_t xNum; //!< Horizontal multiplier (!=0) + int32_t xDenom; //!< Horizontal divisor (!=0) + int32_t yNum; //!< Vertical multiplier (!=0) + int32_t yDenom; //!< Vertical divisor (!=0) +} U_EMRSCALEVIEWPORTEXTEX, *PU_EMRSCALEVIEWPORTEXTEX, + U_EMRSCALEWINDOWEXTEX, *PU_EMRSCALEWINDOWEXTEX; + +/* Index 33 (see 28) */ + +/* Index 34 */ +typedef struct { + U_EMR emr; //!< U_EMR + int32_t iRelative; //!< DC to restore. -1 is preceding +} U_EMRRESTOREDC, *PU_EMRRESTOREDC; + +/* Index 35 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_XFORM xform; //!< Transform +} U_EMRSETWORLDTRANSFORM, *PU_EMRSETWORLDTRANSFORM; + +/* Index 36 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_XFORM xform; //!< Transform + uint32_t iMode; //!< ModifyWorldTransformMode Enumeration +} U_EMRMODIFYWORLDTRANSFORM, *PU_EMRMODIFYWORLDTRANSFORM; + +/* Index 37,40 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihObject; //!< Number of a stock or created object +} U_EMRDELETEOBJECT, *PU_EMRDELETEOBJECT, + U_EMRSELECTOBJECT, *PU_EMRSELECTOBJECT; + +/* Index 38 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihPen; //!< Index to place object in EMF object table (this entry must not yet exist) + U_LOGPEN lopn; //!< Pen properties +} U_EMRCREATEPEN, *PU_EMRCREATEPEN; + +/* Index 39 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihBrush; //!< Index to place object in EMF object table (this entry must not yet exist) + U_LOGBRUSH lb; //!< Brush properties +} U_EMRCREATEBRUSHINDIRECT, *PU_EMRCREATEBRUSHINDIRECT; + +/* Index 40 see 37 */ + +/* Index 41 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL ptlCenter; //!< Center in logical units + uint32_t nRadius; //!< Radius in logical units + U_FLOAT eStartAngle; //!< Starting angle in degrees (counter clockwise from x axis) + U_FLOAT eSweepAngle; //!< Sweep angle in degrees +} U_EMRANGLEARC, *PU_EMRANGLEARC; + +/* Index 42,43 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBox; //!< bounding rectangle in logical units +} U_EMRELLIPSE, *PU_EMRELLIPSE, + U_EMRRECTANGLE, *PU_EMRRECTANGLE; + +/* Index 44 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBox; //!< bounding rectangle in logical units + U_SIZEL szlCorner; //!< W & H in logical units of ellipse used to round corner +} U_EMRROUNDRECT, *PU_EMRROUNDRECT; + +/* Index 45, 46 ,47, 55 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBox; //!< bounding rectangle in logical units + U_POINTL ptlStart; //!< Start point in logical units + U_POINTL ptlEnd; //!< End point in logical units +} U_EMRARC, *PU_EMRARC, + U_EMRCHORD, *PU_EMRCHORD, + U_EMRPIE, *PU_EMRPIE, + U_EMRARCTO, *PU_EMRARCTO; + +/* Index 48 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihPal; //!< Index of a Palette object in the EMF object table +} U_EMRSELECTPALETTE, *PU_EMRSELECTPALETTE; + +/* Index 49 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihPal; //!< Index to place object in EMF object table (this entry must not yet exist) + U_LOGPALETTE lgpl; //!< Palette properties +} U_EMRCREATEPALETTE, *PU_EMRCREATEPALETTE; + +/* Index 50 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihPal; //!< Index of a Palette object in the EMF object table + uint32_t iStart; //!< First Palette entry in selected object to set + U_NUM_LOGPLTNTRY cEntries; //!< Number of Palette entries in selected object to set + U_LOGPLTNTRY aPalEntries[1]; //!< Values to set with +} U_EMRSETPALETTEENTRIES, *PU_EMRSETPALETTEENTRIES; + +/* Index 51 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihPal; //!< Index of a Palette object in the EMF object table + uint32_t cEntries; //!< Number to expand or truncate the Palette entry list to. +} U_EMRRESIZEPALETTE, *PU_EMRRESIZEPALETTE; + +/* Index 52 (see 28) */ + +/* Index 53 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL ptlStart; //!< Start point in logical units + U_COLORREF crColor; //!< Color to fill with + uint32_t iMode; //!< FloodFill Enumeration +} U_EMREXTFLOODFILL, *PU_EMREXTFLOODFILL; + +/* Index 54 (see 27) */ + +/* Index 55 (see 45) */ + +/* Index 56 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_NUM_POINTL cptl; //!< Number of U_POINTL objects + U_POINTL aptl[1]; //!< Array of U_POINTL objects + uint8_t abTypes[1]; //!< Array of Point Enumeration +} U_EMRPOLYDRAW, *PU_EMRPOLYDRAW; + +/* Index 57 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t iArcDirection; //!< ArcDirection Enumeration +} U_EMRSETARCDIRECTION, *PU_EMRSETARCDIRECTION; + +/* Index 58 +IMPORTANT!!!! The Microsoft structure uses a float for the miterlimit but the EMF file record +uses an unsigned int. The latter form is used in this structure. +*/ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t eMiterLimit; //!< Miter limit (max value of mitered length / line width) +} U_EMRSETMITERLIMIT, *PU_EMRSETMITERLIMIT; + +/* Index 59,60,61 (see 28) */ + +/* Index 62,63,64 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units +} U_EMRFILLPATH, *PU_EMRFILLPATH, + U_EMRSTROKEANDFILLPATH, *PU_EMRSTROKEANDFILLPATH, + U_EMRSTROKEPATH, *PU_EMRSTROKEPATH; + +/* Index 65,66 (see 28) */ +/* Index 67 (see 17) */ +/* Index 68 (see 28) */ +/* Index 69 (not a defined U_EMR record type ) */ + +/* Index 70 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cbData; //!< Number of bytes in comment + uint8_t Data[1]; //!< Comment (any binary data, interpretation is program specific) +} U_EMRCOMMENT, *PU_EMRCOMMENT; //!< AKA GDICOMMENT + +/* variant comment types */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cbData; //!< Number of bytes in comment + uint32_t cIdent; //!< Comment identifier, must be U_EMR_COMMENT_EMFPLUSRECORD + uint8_t Data[1]; //!< EMF Plus record +} U_EMRCOMMENT_EMFPLUS, *PU_EMRCOMMENT_EMFPLUS; //!< EMF Plus comment + +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cbData; //!< Number of bytes in comment + uint32_t cIdent; //!< Comment identifier, must be U_EMR_COMMENT_SPOOL + uint32_t esrIdent; //!< EMFSpoolRecordIdentifier, may be U_EMR_COMMENT_SPOOLFONTDEF + uint8_t Data[1]; //!< EMF Spool records +} U_EMRCOMMENT_SPOOL, *PU_EMRCOMMENT_SPOOL; //!< EMF Spool comment + +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cbData; //!< Number of bytes in comment + uint32_t cIdent; //!< Comment identifier, must be U_EMR_COMMENT_PUBLIC + uint32_t pcIdent; //!< Public Comment Identifier, from EMRComment Enumeration + uint8_t Data[1]; //!< Public comment data +} U_EMRCOMMENT_PUBLIC, *PU_EMRCOMMENT_PUBLIC; //!< EMF Public comment + +/* Index 71 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data + uint32_t ihBrush; //!< Index of a Brush object in the EMF object table + U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure +} U_EMRFILLRGN, *PU_EMRFILLRGN; + +/* Index 72 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data + uint32_t ihBrush; //!< Index of a Brush object in the EMF object table + U_SIZEL szlStroke; //!< W & H of Brush stroke + U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure +} U_EMRFRAMERGN, *PU_EMRFRAMERGN; + +/* Index 73,74 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data + U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure +} U_EMRINVERTRGN, *PU_EMRINVERTRGN, + U_EMRPAINTRGN, *PU_EMRPAINTRGN; + +/* Index 75 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data + uint32_t iMode; //!< RegionMode Enumeration + U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure +} U_EMREXTSELECTCLIPRGN, *PU_EMREXTSELECTCLIPRGN; + +/* Index 76 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL cDest; //!< Destination width in logical units + uint32_t dwRop; //!< Ternary Raster Operation enumeration + U_POINTL Src; //!< Source retangle UL corner in logical units + U_XFORM xformSrc; //!< Source bitmap transform (world to page coordinates) + U_COLORREF crBkColorSrc; //!< Source bitmap background color + uint32_t iUsageSrc; //!< DIBcolors Enumeration + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer) + U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap + //!< Record may include optional bitmapbuffer +} U_EMRBITBLT, *PU_EMRBITBLT; + +/* Index 77 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL cDest; //!< Destination width in logical units + uint32_t dwRop; //!< Ternary Raster Operation enumeration + U_POINTL Src; //!< Source UL corner in logical units + U_XFORM xformSrc; //!< Transform to apply to source + U_COLORREF crBkColorSrc; //!< Background color + uint32_t iUsageSrc; //!< DIBcolors Enumeration + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer) + U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap + U_POINTL cSrc; //!< Src W & H in logical units + //!< Record may include optional bitmapbuffer +} U_EMRSTRETCHBLT, *PU_EMRSTRETCHBLT; + +/* Index 78 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL cDest; //!< Destination width in logical units + uint32_t dwRop; //!< Ternary Raster Operation enumeration + U_POINTL Src; //!< Source UL corner in logical units + U_XFORM xformSrc; //!< Transform to apply to source + U_COLORREF crBkColorSrc; //!< Background color + uint32_t iUsageSrc; //!< DIBcolors Enumeration + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within srcbitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the src bitmap (within srcbitmapbuffer) + U_CBBITS cbBitsSrc; //!< Size in bytes of src bitmap + U_POINTL Mask; //!< Mask UL corner in logical units + uint32_t iUsageMask; //!< DIBcolors Enumeration + U_OFFBMIMSK offBmiMask; //!< Offset in bytes to U_BITMAPINFO (within maskbitmapbuffer) + U_CBBMIMSK cbBmiMask; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSMSK offBitsMask; //!< Offset in bytes to the mask bitmap (within maskbitmapbuffer) + U_CBBITSMSK cbBitsMask; //!< Size in bytes of bitmap + //!< Record may include optional Source and mask bitmapbuffers +} U_EMRMASKBLT, *PU_EMRMASKBLT; + +/* Index 79 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL aptlDst[3]; //!< Defines parallelogram, UL, UR, LL corners, LR is derived. + U_POINTL Src; //!< Source UL corner in logical units + U_POINTL cSrc; //!< Src W & H in logical units + U_XFORM xformSrc; //!< Transform to apply to source + U_COLORREF crBkColorSrc; //!< Background color + uint32_t iUsageSrc; //!< DIBcolors Enumeration + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within srcbitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the src bitmap (within srcbitmapbuffer) + U_CBBITS cbBitsSrc; //!< Size in bytes of src bitmap + U_POINTL Mask; //!< Mask UL corner in logical units + uint32_t iUsageMask; //!< DIBcolors Enumeration + U_OFFBMIMSK offBmiMask; //!< Offset in bytes to U_BITMAPINFO (within maskbitmapbuffer) + U_CBBMIMSK cbBmiMask; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSMSK offBitsMask; //!< Offset in bytes to the mask bitmap (within maskbitmapbuffer) + U_CBBITSMSK cbBitsMask; //!< Size in bytes of bitmap + //!< Record may include optional Source and mask bitmapbuffers +} U_EMRPLGBLT, *PU_EMRPLGBLT; + +/* Index 80 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL Src; //!< Source LL corner in logical units + U_POINTL cSrc; //!< Src W & H in logical units + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to bitmap + U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap + uint32_t iUsageSrc; //!< DIBColors Enumeration + uint32_t iStartScan; //!< First scan line + uint32_t cScans; //!< Number of scan lines + //!< Record may includes optional bitmapbuffer +} U_EMRSETDIBITSTODEVICE, *PU_EMRSETDIBITSTODEVICE; + +/* Index 81 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL Src; //!< Source UL corner in logical units + U_POINTL cSrc; //!< Source W & H in logical units + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to bitmap + U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap + uint32_t iUsageSrc; //!< DIBColors Enumeration + uint32_t dwRop; //!< Ternary Raster Operation enumeration + U_POINTL cDest; //!< Destination W & H in logical units + //!< Record may includes optional bitmapbuffer +} U_EMRSTRETCHDIBITS, *PU_EMRSTRETCHDIBITS; + +/* Index 82 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihFont; //!< Index of the font in the EMF object table + U_LOGFONT_PANOSE elfw; //!< Font parameters, either U_LOGFONT or U_LOGFONT_PANOSE, the latter is bigger so use that type here +} U_EMREXTCREATEFONTINDIRECTW, *PU_EMREXTCREATEFONTINDIRECTW; + +/* Index 83,84 */ +/** +Variable and optional fields may follow core structure in record: + + U_RECTL rcl; absent when fOptions & U_ETO_NO_RECT) grayed/clipping/opaque rectangle + + U_OFFDX offDx; (required) Offset in bytes to the character spacing array from the start of the RECORD + + uint32_t Dx (optional) character spacing array (Required, but position is not static.) +*/ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + uint32_t iGraphicsMode; //!< GraphicsMode Enumeration + U_FLOAT exScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE) + U_FLOAT eyScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE) + U_EMRTEXT emrtext; //!< Text parameters +// U_RECTL rcl; absent when fOptions & U_ETO_NO_RECT) grayed/clipping/opaque rectangle +// U_OFFDX offDx; (required) but position isn't static. Offset in bytes to the character spacing array from the start of the RECORD +// Record may include optional Dx, character spacing, array of uint32_t +} U_EMREXTTEXTOUTA, *PU_EMREXTTEXTOUTA, + U_EMREXTTEXTOUTW, *PU_EMREXTTEXTOUTW; + +/* Index 85,86,87,88,89 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_NUM_POINT16 cpts; //!< Number of POINT16 in array + U_POINT16 apts[1]; //!< Array of POINT16 +} U_EMRPOLYBEZIER16,*PU_EMRPOLYBEZIER16, + U_EMRPOLYGON16,*PU_EMRPOLYGON16, + U_EMRPOLYLINE16,*PU_EMRPOLYLINE16, + U_EMRPOLYBEZIERTO16,*PU_EMRPOLYBEZIERTO16, + U_EMRPOLYLINETO16,*PU_EMRPOLYLINETO16; + +/* Index 90,91 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_NUM_POLYCOUNTS nPolys; //!< Number of elements in aPolyCounts + U_NUM_POINT16 cpts; //!< Total number of points (over all poly) + U_POLYCOUNTS aPolyCounts[1]; //!< Number of points in each poly (sequential) +// This will appear somewhere but is not really part of the core structure. +// U_POINT16 apts[1]; //!< array of point16 +} U_EMRPOLYPOLYLINE16,*PU_EMRPOLYPOLYLINE16, + U_EMRPOLYPOLYGON16,*PU_EMRPOLYPOLYGON16; + +/* Index 92 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_NUM_POINT16 cpts; //!< Total number of points (over all poly) + U_POINT16 apts[1]; //!< array of points + uint8_t abTypes[1]; //!< Array of Point Enumeration +} U_EMRPOLYDRAW16,*PU_EMRPOLYDRAW16; + +/* Index 93 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihBrush; //!< Index to place object in EMF object table (this entry must not yet exist) + uint32_t iUsage; //!< DIBcolors Enumeration + U_OFFBMI offBmi; //!< Offset in bytes to U_BITMAPINFO (within DIBbitmapbuffer) + U_CBBMI cbBmi; //!< Size in bytes of U_BITMAPINFO + U_OFFBITS offBits; //!< Offset in bytes to the DIB bitmap data (within DIBbitmapbuffer + U_CBBITS cbBits; //!< Size in bytes of DIB bitmap + //!< Record may include optional DIB bitmapbuffer +} U_EMRCREATEMONOBRUSH, *PU_EMRCREATEMONOBRUSH; + +/* Index 94 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihBrush; //!< Index to place object in EMF object table (this entry must not yet exist) + uint32_t iUsage; //!< DIBcolors Enumeration + U_OFFBMI offBmi; //!< Offset in bytes to U_BITMAPINFO (within DIB bitmapbuffer) + U_CBBMI cbBmi; //!< Size in bytes of U_BITMAPINFO + U_OFFBITS offBits; //!< Offset in bytes to the DIB bitmap data (within DIB bitmapbuffer + U_CBBITS cbBits; //!< Size in bytes of DIB bitmap + //!< Record may include optional DIB bitmapbuffer +} U_EMRCREATEDIBPATTERNBRUSHPT, *PU_EMRCREATEDIBPATTERNBRUSHPT; + +/* Index 95 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihPen; //!< Index to place object in EMF object table (this entry must not yet exist) + U_OFFBMI offBmi; //!< Offset in bytes to U_BITMAPINFO (within DIB bitmapbuffer) + U_CBBMI cbBmi; //!< Size in bytes of U_BITMAPINFO + U_OFFBITS offBits; //!< Offset in bytes to the DIB bitmap data (within DIB bitmapbuffer + U_CBBITS cbBits; //!< Size in bytes of DIB bitmap + U_EXTLOGPEN elp; //!< Pen parameters (Size is Variable!!!!) + //!< Record may include optional DIB bitmap +} U_EMREXTCREATEPEN, *PU_EMREXTCREATEPEN; + +/* Index 96.97 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + uint32_t iGraphicsMode; //!< GraphicsMode Enumeration + U_FLOAT exScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE) + U_FLOAT eyScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE) + U_NUM_EMRTEXT cStrings; //!< Number of U_EMRTEXT in array + U_EMRTEXT emrtext[1]; //!< Text parameters +} U_EMRPOLYTEXTOUTA, *PU_EMRPOLYTEXTOUTA, + U_EMRPOLYTEXTOUTW, *PU_EMRPOLYTEXTOUTW; + +/* Index 98 (see 17) */ + +/* Index 99 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihCS; //!< Index to place object in EMF object table (this entry must not yet exist) + U_LOGCOLORSPACEA lcs; //!< ColorSpace parameters +} U_EMRCREATECOLORSPACE, *PU_EMRCREATECOLORSPACE; + +/* Index 100,101 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihCS; //!< Index of object in EMF object table +} U_EMRDELETECOLORSPACE, *PU_EMRDELETECOLORSPACE, + U_EMRSETCOLORSPACE, *PU_EMRSETCOLORSPACE; + +/* Index 102 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cbData; //!< Size of OpenGL data in bytes + U_DATA Data[1]; //!< OpenGL data +} U_EMRGLSRECORD, *PU_EMRGLSRECORD; + +/* Index 103 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_CBDATA cbData; //!< Size of OpenGL data in bytes + U_DATA Data[1]; //!< OpenGL data +} U_EMRGLSBOUNDEDRECORD, *PU_EMRGLSBOUNDEDRECORD; + +/* Index 104 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_PIXELFORMATDESCRIPTOR pfd; //!< PixelFormatDescriptor +} U_EMRPIXELFORMAT, *PU_EMRPIXELFORMAT; + +/* Index 105 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cjIn; //!< Number of bytes to send to printer driver + U_DATA Data[1]; //!< Data to send +} U_EMRDRAWESCAPE, *PU_EMRDRAWESCAPE; + +/* Index 106 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cjIn; //!< Number of bytes to send to printer driver + U_DATA Data[1]; //!< Data to send +} U_EMREXTESCAPE, *PU_EMREXTESCAPE; + +/* Index 107 (not implemented ) */ + +/* Index 108 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_POINTL Dest; //!< Where to draw the text + U_NUM_STR cChars; //!< Characters in TextString (not null terminated) + uint32_t fuOptions; //!< ExtTextOutOptions Enumeration + uint32_t iGraphicsMode; //!< GraphicsMode Enumeration + U_FLOAT exScale; //!< scale on X axis + U_FLOAT eyScale; //!< scale on Y axis +//!< the tail end of this record is variable. +//!< U_RECTL rclBounds; Record may include optional Bounding rectangle (absent when: fuOPtions & ETO_NO_U_RECT) +//!< uint32_t TextString; text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit) +} U_EMRSMALLTEXTOUT, *PU_EMRSMALLTEXTOUT; + +/* Index 109 (not implemented ) */ + +/* Index 110 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_CBDATA cbDriver; //!< Number of bytes in driver name (note, BYTES, not CHARACTERS) + U_CBDATA cbData; //!< Number of bytes in data + uint16_t Driver[1]; //!< Driver name in uint16_t characters, null terminated + uint8_t Data[1]; //!< Data for printer driver +} U_EMRNAMEDESCAPE, *PU_EMRNAMEDESCAPE; + +/* Index 111-113 (not implemented ) */ + +/* Index 114 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL cDest; //!< Destination W & H in logical units + U_BLEND Blend; //!< Blend Function + U_POINTL Src; //!< Source UL corner in logical units + U_XFORM xformSrc; //!< Transform to apply to source + U_COLORREF crBkColorSrc; //!< Background color + uint32_t iUsageSrc; //!< DIBcolors Enumeration + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer) + U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap + U_POINTL cSrc; //!< Source W & H in logical units + //!< Record may include optional DIB bitmap +} U_EMRALPHABLEND, *PU_EMRALPHABLEND; + +/* Index 115 (see 17) */ + +/* Index 116 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_POINTL Dest; //!< Destination UL corner in logical units + U_POINTL cDest; //!< Destination W & H in logical units + uint32_t TColor; //!< Bitmap color to be treated as transparent + U_POINTL Src; //!< Source UL corner in logical units + U_XFORM xformSrc; //!< Transform to apply to source + U_COLORREF crBkColorSrc; //!< Background color + uint32_t iUsageSrc; //!< DIBcolors Enumeration + U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer) + U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO + U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer) + U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap + U_POINTL cSrc; //!< Source W & H in logical units + //!< Record may includes optional bitmapbuffer +} U_EMRTRANSPARENTBLT, *PU_EMRTRANSPARENTBLT; + +/* Index 117 (not a defined U_EMR record type ) */ + +/* Index 118 */ +typedef struct { + U_EMR emr; //!< U_EMR + U_RECTL rclBounds; //!< Bounding rectangle in device units + U_NUM_TRIVERTEX nTriVert; //!< Number of TriVertex objects + U_NUM_GRADOBJ nGradObj; //!< Number of gradient triangle/rectangle objects + uint32_t ulMode; //!< Gradientfill Enumeration (determines Triangle/Rectangle) +//parts that are required but which are not included in the core structure +// U_TRIVERTEX TriVert[1]; Array of TriVertex objects +// uint32_t GradObj[1]; Array of gradient objects (each has 2 or 3 indices into TriVert array) +} U_EMRGRADIENTFILL, *PU_EMRGRADIENTFILL; + +/* Index 119,120 (not implemented ) */ + +/* Index 121 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t dwAction; //!< ColorSpace Enumeration + uint32_t dwFlags; //!< ColorMatchToTarget Enumeration + U_CBNAME cbName; //!< Number of bytes in in UTF16 name of the color profile + U_CBDATA cbData; //!< Number of bytes of the target profile + uint8_t Data[1]; //!< Data of size cbName+cbData: Name in UTF16 then color profile data +} U_EMRCOLORMATCHTOTARGETW, *PU_EMRCOLORMATCHTOTARGETW; + +/* Index 122 */ +typedef struct { + U_EMR emr; //!< U_EMR + uint32_t ihCS; //!< Index of the logical color space object in the EMF object table + U_LOGCOLORSPACEW lcs; //!< Description of the color profile + uint32_t dwFlags; //!< If low bit set Data is present + U_CBDATA cbData; //!< Number of bytes of theData field. + uint8_t Data[1]; //!< (Optional, dwFlags & 1) color profile data +} U_EMRCREATECOLORSPACEW, *PU_EMRCREATECOLORSPACEW; + +// ************************************************************************************************ +// Utility function structures + +typedef struct { + FILE *fp; //!< Open file + size_t allocated; //!< Size of the buffer + size_t used; //!< Amount consumed + uint32_t records; //!< Number of records already contained + uint16_t ignore; //!< size padding,not used + uint32_t PalEntries; //!< Number of PalEntries (set from U_EMREOF) + uint32_t chunk; //!< Number of bytes to add when more space is needed + char *buf; //!< Buffer for constructing the EMF in memory +} EMFTRACK; + +/** + The various create functions need a place to put their handles, these are stored in the table below. + We don't actually do anything much with these handles, that is up to whatever program finally plays back the EMF, but + we do need to keep track of the numbers so that they are not accidentally reused. This structure is used for that, + and all *_set functions that touch a handle reference it. + + Stock objects are not used in this limited model, so libUEMF cannot detect if a handle is still in use. Nor can it + tell when a handle has been deselected (by selecting another handle for the same type of graphic object, and thus + made deleteable). End user code must keep track of this for itself. +*/ +typedef struct { + uint32_t *table; //!< Array Buffer for constructing the EMF in memory + uint32_t *stack; //!< handles are either on the stack or in the table + size_t allocated; //!< Slots in the buffer + size_t chunk; //!< Number to add if a realloc is required + uint32_t sptr; //!< Pointer to next available handle in the stack + uint32_t top; //!< Highest slot occupied (currently) + uint32_t peak; //!< Highest slot occupied (ever) +} EMFHANDLES; + +/** + 2 x 2 matrix, used by xform_alt_set() function. +*/ +typedef struct { + double M11; //!< Matrix element 1,1 + double M12; //!< Matrix element 1,2 + double M21; //!< Matrix element 2,1 + double M22; //!< Matrix element 2,2 +} U_MAT2X2, *PU_MAT2X2; + +// ************************************************************************************************ +// Prototypes + +int memprobe(const void *buf, size_t size); +void wchar8show(const char *src); +void wchar16show(const uint16_t *src); +void wchar32show(const uint32_t *src); +void wchartshow(const wchar_t *src); +void dumpeht(char *string, unsigned int *handle, EMFHANDLES *eht); + + +char *U_emr_names(unsigned int idx); +uint32_t *dx_set(int32_t height, uint32_t weight, uint32_t members); +uint32_t emr_properties(uint32_t type); +int emr_arc_points(PU_ENHMETARECORD record, int *f1, int f2, PU_PAIRF center, PU_PAIRF start, PU_PAIRF end, PU_PAIRF size); +int emr_arc_points_common(PU_RECTL rclBox, PU_POINTL ArcStart, PU_POINTL ArcEnd, + int *f1, int f2, PU_PAIRF center, PU_PAIRF start, PU_PAIRF end, PU_PAIRF size); +int get_real_color_count(const char *Bmih); +int get_real_color_icount(int Colors, int BitCount, int Width, int Height); +int RGBA_to_DIB(char **px, uint32_t *cbPx, PU_RGBQUAD *ct, int *numCt, + const char *rgba_px, int w, int h, int stride, uint32_t colortype, int use_ct, int invert); +int get_DIB_params( void *pEmr, uint32_t offBitsSrc, uint32_t offBmiSrc, + const char **px, const U_RGBQUAD **ct, uint32_t *numCt, + uint32_t *width, uint32_t *height, uint32_t *colortype, uint32_t *invert ); +int DIB_to_RGBA(const char *px, const U_RGBQUAD *ct, int numCt, + char **rgba_px, int w, int h, uint32_t colortype, int use_ct, int invert); +char *RGBA_to_RGBA(char *rgba_px, int w, int h, int sl, int st, int *ew, int *eh); + +int device_size(const int xmm, const int ymm, const float dpmm, U_SIZEL *szlDev, U_SIZEL *szlMm); +int drawing_size(const int xmm, const int yum, const float dpmm, U_RECTL *rclBounds, U_RECTL *rclFrame); + +int emf_start(const char *name, const uint32_t initsize, const uint32_t chunksize, EMFTRACK **et); +int emf_finish(EMFTRACK *et, EMFHANDLES *eht); +int emf_free(EMFTRACK **et); +int emf_append(U_ENHMETARECORD *rec, EMFTRACK *et, int freerec); +int emf_readdata(const char *filename, char **contents, size_t *length); +FILE *emf_fopen(const char *filename, const int mode); + + +/* use these instead*/ +int emf_htable_create(uint32_t initsize, uint32_t chunksize, EMFHANDLES **eht); +int emf_htable_delete(uint32_t *ih, EMFHANDLES *eht); +int emf_htable_insert(uint32_t *ih, EMFHANDLES *eht); +int emf_htable_free(EMFHANDLES **eht); +/* Deprecated forms */ +#define htable_create emf_htable_create +#define htable_delete emf_htable_delete +#define htable_insert emf_htable_insert +#define htable_free emf_htable_free + +U_RECTL rectl_set(U_POINTL ul, U_POINTL lr); +U_SIZEL sizel_set(int32_t x, int32_t y); +U_POINTL point32_set(int32_t x, int32_t y); +#define point_set point32_set +#define pointl_set point32_set +U_POINT16 point16_set(int16_t x, int16_t y); +U_PANOSE panose_set(uint8_t bFamilyType, uint8_t bSerifStyle, uint8_t bWeight, uint8_t bProportion, + uint8_t bContrast, uint8_t bStrokeVariation, uint8_t bArmStyle, uint8_t bLetterform, + uint8_t bMidline, uint8_t bXHeight ); +U_COLORREF colorref_set(uint8_t red, uint8_t green, uint8_t blue); +U_LOGBRUSH logbrush_set(uint32_t lbStyle, U_COLORREF lbColor, int32_t lbHatch); +U_XFORM xform_set(U_FLOAT eM11, U_FLOAT eM12, U_FLOAT eM21, U_FLOAT eM22, U_FLOAT eDx, U_FLOAT eDy); +U_XFORM xform_alt_set(U_FLOAT scale, U_FLOAT ratio, U_FLOAT rot, U_FLOAT axisrot, U_FLOAT eDx, U_FLOAT eDy); +U_LOGPEN logpen_set( uint32_t lopnStyle, U_POINT lopnWidth, U_COLORREF lopnColor ); +PU_EXTLOGPEN extlogpen_set(uint32_t elpPenStyle, uint32_t elpWidth, uint32_t elpBrushStyle, + U_COLORREF elpColor, int32_t elpHatch, U_NUM_STYLEENTRY elpNumEntries, U_STYLEENTRY *elpStyleEntry ); +U_LOGFONT_PANOSE logfont_panose_set(U_LOGFONT elfLogFont, uint16_t *elfFullName, + uint16_t *elfStyle, uint32_t elfStyleSize, U_PANOSE elfPanose); +U_LOGFONT logfont_set( int32_t lfHeight, int32_t lfWidth, int32_t lfEscapement, int32_t lfOrientation, + int32_t lfWeight, uint8_t lfItalic, uint8_t lfUnderline, uint8_t lfStrikeOut, + uint8_t lfCharSet, uint8_t lfOutPrecision, uint8_t lfClipPrecision, + uint8_t lfQuality, uint8_t lfPitchAndFamily, uint16_t *lfFaceName); +char *emrtext_set(U_POINTL ptlReference, U_NUM_STR NumString, uint32_t cbChar, void *String, uint32_t fOptions, U_RECTL rcl, uint32_t *Dx); +U_LOGPLTNTRY logpltntry_set(uint8_t peReserved,uint8_t peRed,uint8_t peGreen,uint8_t peBlue); +PU_LOGPALETTE logpalette_set(U_NUM_LOGPLTNTRY palNumEntries,PU_LOGPLTNTRY *palPalEntry); +U_RGNDATAHEADER rgndataheader_set( U_NUM_RECTL nCount, U_RECTL rcBound); +PU_RGNDATA rgndata_set( U_RGNDATAHEADER rdh, PU_RECTL Buffer); +U_BITMAPINFOHEADER bitmapinfoheader_set(int32_t biWidth, int32_t biHeight, + uint16_t biPlanes, uint16_t biBitCount, uint32_t biCompression, + uint32_t biSizeImage, int32_t biXPelsPerMeter, + int32_t biYPelsPerMeter, U_NUM_RGBQUAD biClrUsed, uint32_t biClrImportant); +PU_BITMAPINFO bitmapinfo_set(U_BITMAPINFOHEADER BmiHeader, PU_RGBQUAD BmiColors); +U_LOGCOLORSPACEA logcolorspacea_set(int32_t lcsCSType, int32_t lcsIntent, + U_CIEXYZTRIPLE lcsEndpoints, U_LCS_GAMMARGB lcsGammaRGB, char *lcsFilename); +U_LOGCOLORSPACEW logcolorspacew_set(int32_t lcsCSType, int32_t lcsIntent, + U_CIEXYZTRIPLE lcsEndpoints, U_LCS_GAMMARGB lcsGammaRGB, uint16_t *lcsFilename); +U_COLORADJUSTMENT coloradjustment_set(uint16_t Size, uint16_t Flags, uint16_t IlluminantIndex, + uint16_t RedGamma, uint16_t GreenGamma, uint16_t BlueGamma, + uint16_t ReferenceBlack, uint16_t ReferenceWhite, + int16_t Contrast, int16_t Brightness, int16_t Colorfulness, int16_t RedGreenTint); +U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set( uint32_t dwFlags, uint8_t iPixelType, uint8_t cColorBits, + uint8_t cRedBits, uint8_t cRedShift, + uint8_t cGreenBits, uint8_t cGreenShift, + uint8_t cBlueBits, uint8_t cBlueShift, + uint8_t cAlphaBits, uint8_t cAlphaShift, + uint8_t cAccumBits, uint8_t cAccumRedBits, uint8_t cAccumGreenBits, uint8_t cAccumBlueBits, + uint8_t cAccumAlphaBits, uint8_t cDepthBits, uint8_t cStencilBits, + uint8_t cAuxBuffers, uint8_t iLayerType, uint8_t bReserved, uint32_t dwLayerMask, + uint32_t dwVisibleMask, uint32_t dwDamageMask); + +PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform); +PU_POINT16 point16_transform(PU_POINT16 points, int count, U_XFORM xform); +PU_TRIVERTEX trivertex_transform(PU_TRIVERTEX tv, int count, U_XFORM xform); +PU_POINT point16_to_point(PU_POINT16 points, int count); +PU_POINT16 point_to_point16(PU_POINT points, int count); + +U_RECT findbounds(uint32_t count, PU_POINT pts, uint32_t width); +U_RECT findbounds16(uint32_t count, PU_POINT16 pts, uint32_t width); +char *emr_dup(const char *emr); + +char *textcomment_set(const char *string); + +// These generate the handle and then call the underlying function +char *deleteobject_set(uint32_t *ihObject, EMFHANDLES *eht); +char *selectobject_set(uint32_t ihObject, EMFHANDLES *eht); +char *createpen_set(uint32_t *ihPen, EMFHANDLES *eht, U_LOGPEN lopn ); +char *extcreatepen_set(uint32_t *ihPen, EMFHANDLES *eht, + PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px, PU_EXTLOGPEN elp); +char *createbrushindirect_set(uint32_t *ihBrush, EMFHANDLES *eht, U_LOGBRUSH lb ); +char *createdibpatternbrushpt_set(uint32_t *ihBrush, EMFHANDLES *eht, uint32_t iUsage, + PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px); +char *createmonobrush_set(uint32_t *ihBrush, EMFHANDLES *eht, uint32_t iUsage, + PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px); +char *extcreatefontindirectw_set(uint32_t *ihFont, EMFHANDLES *eht, const char *elf, const char *elfw); +char *createpalette_set(uint32_t *ihPal, EMFHANDLES *eht, U_LOGPALETTE lgpl); +char *setpaletteentries_set(uint32_t *ihPal, EMFHANDLES *eht, uint32_t iStart, U_NUM_LOGPLTNTRY cEntries, PU_LOGPLTNTRY aPalEntries); +char *fillrgn_set(uint32_t *ihBrush, EMFHANDLES *eht, U_RECTL rclBounds,PU_RGNDATA RgnData); +char *framergn_set(uint32_t *ihBrush, EMFHANDLES *eht, U_RECTL rclBounds, U_SIZEL szlStroke, PU_RGNDATA RgnData); +char *createcolorspace_set(uint32_t *ihCS, EMFHANDLES *eht, U_LOGCOLORSPACEA lcs); +char *createcolorspacew_set(uint32_t *ihCS, EMFHANDLES *eht, U_LOGCOLORSPACEW lcs, uint32_t dwFlags, U_CBDATA cbData, uint8_t *Data); + +char *U_EMRHEADER_set( const U_RECTL rclBounds, const U_RECTL rclFrame, U_PIXELFORMATDESCRIPTOR* const pfmtDesc, + U_CBSTR nDesc, uint16_t* const Description, const U_SIZEL szlDevice, const U_SIZEL szlMillimeters, + const uint32_t bOpenGL); +char *U_EMRPOLYBEZIER_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points); +char *U_EMRPOLYGON_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points); +char *U_EMRPOLYLINE_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points); +char *U_EMRPOLYBEZIERTO_set(const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points); +char *U_EMRPOLYLINETO_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points); + +char *U_EMRPOLYPOLYLINE_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts, + const uint32_t cptl, const U_POINTL *points); +char *U_EMRPOLYPOLYGON_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts, + const uint32_t cptl, const U_POINTL *points); +char *U_EMRSETWINDOWEXTEX_set(const U_SIZEL szlExtent); +char *U_EMRSETWINDOWORGEX_set(const U_POINTL ptlOrigin); +char *U_EMRSETVIEWPORTEXTEX_set(const U_SIZEL szlExtent); +char *U_EMRSETVIEWPORTORGEX_set(const U_POINTL ptlOrigin); +char *U_EMRSETBRUSHORGEX_set(const U_POINTL ptlOrigin); +char *U_EMREOF_set(const U_CBPLENTRIES cbPalEntries, const PU_LOGPLTNTRY PalEntries, EMFTRACK *et); +char *U_EMRSETPIXELV_set(const U_POINTL ptlPixel, const U_COLORREF crColor); +char *U_EMRSETMAPPERFLAGS_set(void); +char *U_EMRSETMAPMODE_set(const uint32_t iMode); +char *U_EMRSETBKMODE_set(const uint32_t iMode); +char *U_EMRSETPOLYFILLMODE_set(const uint32_t iMode); +char *U_EMRSETROP2_set(const uint32_t iMode); +char *U_EMRSETSTRETCHBLTMODE_set(const uint32_t iMode); +char *U_EMRSETTEXTALIGN_set(const uint32_t iMode); +char *U_EMRSETCOLORADJUSTMENT_set(const U_COLORADJUSTMENT ColorAdjustment); +char *U_EMRSETTEXTCOLOR_set(const U_COLORREF crColor); +char *U_EMRSETBKCOLOR_set(const U_COLORREF crColor); +char *U_EMROFFSETCLIPRGN_set(const U_POINTL ptl); +char *U_EMRMOVETOEX_set(const U_POINTL ptl); +char *U_EMRSETMETARGN_set(void); +char *U_EMREXCLUDECLIPRECT_set(const U_RECTL rclClip); +char *U_EMRINTERSECTCLIPRECT_set(const U_RECTL rclClip); +char *U_EMRSCALEVIEWPORTEXTEX_set(const int32_t xNum, const int32_t xDenom, const int32_t yNum, const int32_t yDenom); +char *U_EMRSCALEWINDOWEXTEX_set(const int32_t xNum, const int32_t xDenom, const int32_t yNum, const int32_t yDenom); +char *U_EMRSAVEDC_set(void); +char *U_EMRRESTOREDC_set(const int32_t iRelative); +char *U_EMRSETWORLDTRANSFORM_set(const U_XFORM xform); +char *U_EMRMODIFYWORLDTRANSFORM_set(const U_XFORM xform, const uint32_t iMode); +char *U_EMRSELECTOBJECT_set(const uint32_t ihObject); // better to call selectobject_set() +char *U_EMRCREATEPEN_set(const uint32_t ihPen, const U_LOGPEN lopn ); +char *U_EMRCREATEBRUSHINDIRECT_set(const uint32_t ihBrush, const U_LOGBRUSH lb); +char *U_EMRDELETEOBJECT_set(const uint32_t ihObject); // better to call deleteobject_set() +char *U_EMRANGLEARC_set(const U_POINTL ptlCenter, const uint32_t nRadius, const U_FLOAT eStartAngle, const U_FLOAT eSweepAngle); +char *U_EMRELLIPSE_set(const U_RECTL rclBox); +char *U_EMRRECTANGLE_set(const U_RECTL rclBox); +char *U_EMRROUNDRECT_set(const U_RECTL rclBox, const U_SIZEL szlCorner); +char *U_EMRARC_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd); +char *U_EMRCHORD_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd); +char *U_EMRPIE_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd); +char *U_EMRSELECTPALETTE_set(const uint32_t ihPal); +char *U_EMRCREATEPALETTE_set(const uint32_t ihPal, const U_LOGPALETTE lgpl); +char *U_EMRSETPALETTEENTRIES_set(const uint32_t ihPal, const uint32_t iStart, const U_NUM_LOGPLTNTRY cEntries, const PU_LOGPLTNTRY aPalEntries); +char *U_EMRRESIZEPALETTE_set(const uint32_t ihPal, const uint32_t cEntries); +char *U_EMRREALIZEPALETTE_set(void); +char *U_EMREXTFLOODFILL_set(const U_POINTL ptlStart, const U_COLORREF crColor, const uint32_t iMode); +char *U_EMRLINETO_set(const U_POINTL ptl); +char *U_EMRARCTO_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd); +char *U_EMRPOLYDRAW_set(const U_RECTL rclBounds,const U_NUM_POINTL cptl,const U_POINTL *aptl,const uint8_t *abTypes); +char *U_EMRSETARCDIRECTION_set(const uint32_t iArcDirection); +char *U_EMRSETMITERLIMIT_set(const uint32_t eMiterLimit); +char *U_EMRBEGINPATH_set(void); +char *U_EMRENDPATH_set(void); +char *U_EMRCLOSEFIGURE_set(void); +char *U_EMRFILLPATH_set(const U_RECTL rclBox); +char *U_EMRSTROKEANDFILLPATH_set(const U_RECTL rclBox); +char *U_EMRSTROKEPATH_set(const U_RECTL rclBox); +char *U_EMRFLATTENPATH_set(void); +char *U_EMRWIDENPATH_set(void); +char *U_EMRSELECTCLIPPATH_set(const uint32_t iMode); +char *U_EMRABORTPATH_set(void); +// EMR_ENDEF69 +char *U_EMRCOMMENT_set(const U_CBDATA cbData, const char *Data); +char *U_EMRFILLRGN_set(const U_RECTL rclBounds, const uint32_t ihBrush, const PU_RGNDATA RgnData); +char *U_EMRFRAMERGN_set(const U_RECTL rclBounds, const uint32_t ihBrush, const U_SIZEL szlStroke, const PU_RGNDATA RgnData); +char *U_EMRINVERTRGN_set(const PU_RGNDATA RgnData); +char *U_EMRPAINTRGN_set(const PU_RGNDATA RgnData); +char *U_EMREXTSELECTCLIPRGN_set(const uint32_t iMode, const PU_RGNDATA RgnData); +char *U_EMRBITBLT_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest, + const U_POINTL Src, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, + const uint32_t iUsageSrc, const uint32_t dwRop, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px); +char *U_EMRSTRETCHBLT_set(U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest, + const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px); +char *U_EMRMASKBLT_set(U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest, + const U_POINTL Src, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, + const U_POINTL Mask, const uint32_t iUsageMask, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px, + const PU_BITMAPINFO BmiMsk, const uint32_t cbMsk, char *Msk); +char *U_EMRPLGBLT_set(const U_RECTL rclBounds, const PU_POINTL aptlDst, + const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, + const U_POINTL Mask, const uint32_t iUsageMask, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px, + const PU_BITMAPINFO BmiMsk, const uint32_t cbMsk, char *Msk); +char *U_EMRSETDIBITSTODEVICE_set(const U_RECTL rclBounds, const U_POINTL Dest, + const U_POINTL Src, const U_POINTL cSrc, const uint32_t iUsageSrc, + const uint32_t iStartScan, const uint32_t cScans, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px); +char *U_EMRSTRETCHDIBITS_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest, + const U_POINTL Src, const U_POINTL cSrc, const uint32_t iUsageSrc, + const uint32_t dwRop, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px); +char *U_EMREXTCREATEFONTINDIRECTW_set( uint32_t ihFont, const char *elf, const char *elfw); +char *U_EMREXTTEXTOUTA_set(U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext); +char *U_EMREXTTEXTOUTW_set(U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext); +char *U_EMRPOLYBEZIER16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYGON16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYLINE16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYBEZIERTO16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYLINETO16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYPOLYLINE16_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYPOLYGON16_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points); +char *U_EMRPOLYDRAW16_set(const U_RECTL rclBounds,const U_NUM_POINT16 cpts, const U_POINT16 *aptl, const uint8_t *abTypes); +char *U_EMRCREATEMONOBRUSH_set(const uint32_t ihBrush, const uint32_t iUsage, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px); +char *U_EMRCREATEDIBPATTERNBRUSHPT_set(const uint32_t ihBrush, const uint32_t iUsage, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px); +char *U_EMREXTCREATEPEN_set(const uint32_t ihPen, const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px, const PU_EXTLOGPEN elp ); +// U_EMRPOLYTEXTOUTA_set 96 NOT IMPLEMENTED, denigrated after Windows NT +// U_EMRPOLYTEXTOUTW_set 97 NOT IMPLEMENTED, denigrated after Windows NT +char *U_EMRSETICMMODE_set(const uint32_t iMode); +char *U_EMRCREATECOLORSPACE_set(const uint32_t ihCS, const U_LOGCOLORSPACEA lcs); +char *U_EMRSETCOLORSPACE_set(const uint32_t ihCS ); +char *U_EMRDELETECOLORSPACE_set(const uint32_t ihCS); +// U_EMRGLSRECORD_set 102 Not implemented +// U_EMRGLSBOUNDEDRECORD_set 103 Not implemented +char *U_EMRPIXELFORMAT_set(const U_PIXELFORMATDESCRIPTOR pfd); +char *U_EMRSMALLTEXTOUT_set(const U_POINTL Dest, const U_NUM_STR cChars, const uint32_t fuOptions, const uint32_t iGraphicsMode, + const U_FLOAT exScale, const U_FLOAT eyScale, const U_RECTL rclBounds, const char *TextString); +// U_EMRDRAWESCAPE_set 105 Not implemented +// U_EMREXTESCAPE_set 106 Not implemented +// U_EMRUNDEF107_set 107 Not implemented +// U_EMRSMALLTEXTOUT_set 108 +// U_EMRFORCEUFIMAPPING_set 109 Not implemented +// U_EMRNAMEDESCAPE_set 110 Not implemented +// U_EMRCOLORCORRECTPALETTE_set 111 Not implemented +// U_EMRSETICMPROFILEA_set 112 Not implemented +// U_EMRSETICMPROFILEW_set 113 Not implemented +char *U_EMRALPHABLEND_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest, + const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, + const U_BLEND Blend, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px); +char *U_EMRSETLAYOUT_set(const uint32_t iMode); +char *U_EMRTRANSPARENTBLT_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest, + const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, + const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, const uint32_t TColor, + const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px); +// U_EMRUNDEF117_set 117 Not implemented +char *U_EMRGRADIENTFILL_set(const U_RECTL rclBounds, const U_NUM_TRIVERTEX nTriVert, const U_NUM_GRADOBJ nGradObj, + const uint32_t ulMode, const PU_TRIVERTEX TriVert, const uint32_t *GradObj ); +// U_EMRSETLINKEDUFIS_set 119 Not implemented +// U_EMRSETTEXTJUSTIFICATION_set 120 Not implemented (denigrated) +// U_EMRCOLORMATCHTOTARGETW_set 121 Not implemented +char *U_EMRCREATECOLORSPACEW_set(const uint32_t ihCS, const U_LOGCOLORSPACEW lcs, const uint32_t dwFlags, + const U_CBDATA cbData, const uint8_t *Data); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEMF_ */ diff --git a/src/extension/internal/uemf_endian.c b/src/extension/internal/uemf_endian.c new file mode 100644 index 000000000..cdae07a3d --- /dev/null +++ b/src/extension/internal/uemf_endian.c @@ -0,0 +1,1783 @@ +/** + @file uemf_endian.c Functions for converting EMF records between Big Endian and Little Endian + + EMF files use Little Endian order. + On a Big Endian machine the data must be converted to/from Little Endian when it is writen to/read from a file. + On a Little Endian machine no conversion is required, but it is good to be able to test the routines on either platform. + When "torev" is true these routines convert from the native byte order to the reverse. + When "torev" is false these routines convert from the reverse byte order to the native. + Routines that do not use that variable swap byte order, and the way in which they do so does not depend + on the native byte order. + + The only function here which should be called directly is U_emf_endian(), and then,except for testing purposes, only on a BE machine. + + Many variables are initialized to zero even though they will always be set because + some versions of gcc give spurious "may be used uninitialized" warnings otherwise. +*/ + +/* +File: uemf_endian.h +Version: 0.0.12 +Date: 14-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "uemf.h" +#include "uemf_endian.h" + +// hide almost everuything in here from Doxygen +//! @cond + +/* ********************************************************************************************** + These functions convert standard objects used in the EMR records. +*********************************************************************************************** */ + +void U_swap2(void *ul, unsigned int count){ + uint8_t ctmp; + uint8_t *cl = (uint8_t *) ul; + for(; count; count--,cl+=2){ + ctmp = *cl; + *cl = *(cl+1); + *(cl+1) = ctmp; + } +} + +/* Note: U_swap4 is also used by uwmf_endian.c, in cases where the 32 bit data is not aligned on a 4 byte boundary */ +void U_swap4(void *ul, unsigned int count){ + uint8_t ctmp; + uint8_t *cl = (uint8_t *) ul; + for(; count; count--,cl+=4){ + ctmp = *(cl+0); + *(cl+0) = *(cl+3); + *(cl+3) = ctmp; + ctmp = *(cl+1); + *(cl+1) = *(cl+2); + *(cl+2) = ctmp; + } +} + +/** + U_COLORREF and U_RGBQUAD do NOT need to be swapped, they are always stored in memory in the proper order. +*/ + +/** + \brief Convert rect and rectl objects from Upper Left and Lower Right corner points. + \param rect U_RECTL object + \param count number to convert +*/ +void rectl_swap( + PU_RECTL rect, + unsigned int count + ){ + U_swap4(rect,4*count); +} + +/** + \brief Convert a U_SIZEL object. + \param sz U_SizeL object + \param count number to convert +*/ +void sizel_swap( + PU_SIZEL sz, + unsigned int count + ){ + U_swap4(sz,2*count); +} + +/** + \brief Convert a U_POINTL object + \param pt U_POINTL object + \param count number to convert +*/ +void pointl_swap( + PU_POINTL pt, + unsigned int count + ){ + U_swap4(pt,2*count); +} + +/** + \brief Convert a U_POINT16 object + \param pt U_POINT16 object + \param count number to convert +*/ +void point16_swap( + PU_POINT16 pt, + unsigned int count + ){ + U_swap2(pt,2*count); +} + + + +/** + \brief Convert a U_TRIVERTEX object. + \param tv U_TRIVERTEX object. + \param count number to convert +*/ +void trivertex_swap( + PU_TRIVERTEX tv, + unsigned int count + ){ + for(;count; count--, tv++){ + U_swap4(tv,2); /* x,y */ + U_swap2(&(tv->Red),4); /* Red, Green, Blue, Alpha */ + } +} + +/** + \brief Convert a U_GRADIENT3 object. + \param tv U_GRADIENT3 object. + \param count number to convert +*/ +void gradient3_swap( + PU_GRADIENT3 g3, + unsigned int count + ){ + U_swap4(g3,3*count); +} + +/** + \brief Convert a U_GRADIENT4 object. + \param tv U_GRADIENT4 object. + \param count number to convert +*/ +void gradient4_swap( + PU_GRADIENT4 g4, + unsigned int count + ){ + U_swap4(g4,2*count); //a gradient4 object has 2 int4's, NOT 4! +} + +/** + \brief Convert a U_LOGBRUSH object. + \param lb U_LOGBRUSH object. +*/ +void logbrush_swap( + PU_LOGBRUSH lb + ){ + U_swap4(&(lb->lbStyle),1); // lbStyle + // ordered bytes: lbColor + U_swap4(&(lb->lbHatch),1); // lbHatch +} + +/** + \brief Convert a U_XFORM object. + \param xform U_XFORM object +*/ +void xform_swap( + PU_XFORM xform + ){ + U_swap4(xform,6); +} + + +/** + \brief Convert a U_CIEXYZTRIPLE object + \param cie3 U_CIEXYZTRIPLE object +*/ +void ciexyztriple_swap( + PU_CIEXYZTRIPLE cie3 + ){ + U_swap4(cie3,9); +} +/** + \brief Convert a U_LOGCOLORSPACEA object. + \param lcsa U_LOGCOLORSPACEA object +*/ +void logcolorspacea_swap( + PU_LOGCOLORSPACEA lcsa + ){ + U_swap4(lcsa,5); // lcsSignature lcsVersion lcsSize lcsCSType lcsIntent + ciexyztriple_swap(&(lcsa->lcsEndpoints)); + // ordered bytes: lcsGammaRGB + // ordered bytes: lcsFilename +} + +/** + + \brief Convert a U_LOGCOLORSPACEW object. + \param lcsa U_LOGCOLORSPACEW object +*/ +void logcolorspacew_swap( + PU_LOGCOLORSPACEW lcsa + ){ + U_swap4(lcsa,5); // lcsSignature lcsVersion lcsSize lcsCSType lcsIntent + ciexyztriple_swap(&(lcsa->lcsEndpoints)); + // ordered bytes: lcsGammaRGB + // UTF-16LE, already in order: lcsFilename +} + + +/** + \brief Convert a U_LOGFONT object. + \param lf U_LOGFONT object +*/ +void logfont_swap( + PU_LOGFONT lf + ){ + U_swap4(lf,5); // lfHeight lfWidth lfEscapement lfOrientation lfWeight + // ordered bytes: lfItalic lfUnderline lfStrikeOut lfCharSet lfOutPrecision lfClipPrecision lfQuality lfPitchAndFamily + // UTF16-LE, already in order +} + +/** + \brief Convert a U_LOGFONT_PANOSE object. + \return U_LOGFONT_PANOSE object +*/ +void logfont_panose_swap( + PU_LOGFONT_PANOSE lfp + ){ + logfont_swap(&(lfp->elfLogFont)); // elfLogFont + // UTF-16LE, already in order: elfFullName + // UTF-16LE, already in order: elfStyle + U_swap4(&(lfp->elfVersion),4); // elfVersion elfStyleSize elfMatch elfReserved + // ordered bytes: elfVendorId + U_swap4(&(lfp->elfCulture),1); // elfCulture + // ordered bytes: elfPanose +} + +/** + \brief Convert a U_BITMAPINFOHEADER object. + \param Bmi U_BITMAPINFOHEADER object +*/ +void bitmapinfoheader_swap( + PU_BITMAPINFOHEADER Bmi + ){ + U_swap4(Bmi,3); // biSize biWidth biHeight + U_swap2(&(Bmi->biPlanes),2); // biPlanes biBitCount + U_swap4(&(Bmi->biCompression),6); // biCompression biSizeImage biXPelsPerMeter biYPelsPerMeter biClrUsed biClrImportant +} + + +/** + \brief Convert a Pointer to a U_BITMAPINFO object. + \param Bmi Pointer to a U_BITMAPINFO object +*/ +void bitmapinfo_swap( + PU_BITMAPINFO Bmi + ){ + bitmapinfoheader_swap(&(Bmi->bmiHeader)); // bmIHeader + // ordered bytes: bmiColors +} + +/** + \brief Convert a pointer to a U_EXTLOGPEN object. + \param elp PU_EXTLOGPEN object +*/ +void extlogpen_swap( + PU_EXTLOGPEN elp, + int torev + ){ + int count=0; + U_swap4(elp,3); // elpPenStyle elpWidth elpBrushStyle + // ordered bytes: elpColor + if(torev){ + count = elp->elpNumEntries; + } + U_swap4(&(elp->elpHatch),2); // elpHatch elpNumEntries + if(!torev){ + count = elp->elpNumEntries; + } + U_swap4(&(elp->elpStyleEntry),count); // elpStyleEntry[] +} + +/** + \brief Convert a U_LOGPEN object. + \param lp U_LOGPEN object + +*/ +void logpen_swap( + PU_LOGPEN lp + ){ + U_swap4(lp,1); // lopnStyle + pointl_swap(&(lp->lopnWidth),1); // lopnWidth + // ordered bytes: lopnColor +} + + +/** + \brief Convert a pointer to a U_LOGPALETTE object. + \param lp Pointer to a U_LOGPALETTE object. +*/ +void logpalette_swap( + PU_LOGPALETTE lp + ){ + U_swap2(lp,2); // palVersion palNumEntries + // ordered bytes: palPalEntry[] +} + +/** + \brief Convert a U_RGNDATAHEADER object. + \param rdh U_RGNDATAHEADER object +*/ +void rgndataheader_swap( + PU_RGNDATAHEADER rdh + ){ + U_swap4(rdh,4); // dwSize iType nCount nRgnSize + rectl_swap(&(rdh->rclBounds),1); // rclBounds +} + +/** + \brief Convert a pointer to a U_RGNDATA object. + \param rgd pointer to a U_RGNDATA object. +*/ +void rgndata_swap( + PU_RGNDATA rd + ){ + int count = rd->rdh.nCount; + rgndataheader_swap(&(rd->rdh)); + U_swap4(rd->Buffer,4*count); +} + +/** + \brief Convert a U_COLORADJUSTMENT object. + \param ca U_COLORADJUSTMENT object. +*/ +void coloradjustment_swap( + PU_COLORADJUSTMENT ca + ){ + U_swap2(ca,12); // caSize caFlags caIlluminantIndex caRedGamma caGreenGamma caBlueGamma caReferenceBlack caReferenceWhite caContrast caBrightness caColorfulness caRedGreenTint +} + +/** + \brief Convert a pointer to a U_PIXELFORMATDESCRIPTOR object. + \param pfd pointer to a U_PIXELFORMATDESCRIPTOR object. +*/ +void pixelformatdescriptor_swap( + PU_PIXELFORMATDESCRIPTOR pfd + ){ + U_swap2(pfd,2); // nSize nVersion + U_swap4(&(pfd->dwFlags),1); // dwFlags + // ordered bytes: iPixelType cColorBits cRedBits cRedShift cGreenBits cGreenShift cBlueBits cBlueShift cAlphaBits cAlphaShift cAccumBits cAccumRedBits cAccumGreenBits cAccumBlueBits cAccumAlphaBits cDepthBits cStencilBits cAuxBuffers iLayerType bReserved + U_swap4(&(pfd->dwLayerMask),3); // dwLayerMask dwVisibleMask dwDamageMask +} + +/** + \brief Convert a Pointer to a U_EMRTEXT record + \param pemt Pointer to a U_EMRTEXT record + \param record Pointer to the start of the record which contains this U_EMRTEXT + \param torev 1 for native to reversed, 0 for reversed to native +*/ +void emrtext_swap( + PU_EMRTEXT pemt, + char *record, + int torev + ){ + int off; + uint32_t count=0; + uint32_t offDx=0; + uint32_t fOptions=0; + pointl_swap(&(pemt->ptlReference),1); // ptlReference + if(torev){ + count = pemt->nChars; + fOptions = pemt->fOptions; + } + U_swap4(&(pemt->nChars),3); // nChars offString fOptions + if(!torev){ + count = pemt->nChars; + fOptions = pemt->fOptions; + } + off = sizeof(U_EMRTEXT); + if(!(fOptions & U_ETO_NO_RECT)){ + rectl_swap((PU_RECTL)((char *)pemt + off),1); // optional rectangle + off+=sizeof(U_RECTL); + } + if(torev){ + offDx = *(uint32_t *)((char *)pemt +off); + } + // ordered bytes OR UTF16-LE: the string at offString + U_swap4(((char *)pemt+off),1); // offDx + if(!torev){ + offDx = *(uint32_t *)((char *)pemt +off); + } + U_swap4((record+offDx),count); // Dx[], offset with respect to the Record, NOT the object +} + + + +/* ********************************************************************************************** +These functions contain shared code used by various U_EMR*_swap functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. + + + These all have this form: + + void core1_swap(char *record, int torev){ + + but some do not actually use torev. + + + +*********************************************************************************************** */ + +// all core*_swap call this, U_EMRSETMARGN_swap and some others all it directly +// numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype +void core5_swap(char *record, int torev){ + torev = torev; // shuts up compiler warnings about unused parameters + PU_ENHMETARECORD pEMR = (PU_ENHMETARECORD)(record); + U_swap4(pEMR,2); // iType nSize +} + +// Functions with the same form starting with U_EMRPOLYBEZIER_swap +void core1_swap(char *record, int torev){ + int count=0; + PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (record); + if(torev){ + count = pEmr->cptl; + } + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBounds),1 ); // rclBounds + U_swap4(&(pEmr->cptl),1); // cptl + if(!torev){ + count = pEmr->cptl; + } + pointl_swap((pEmr->aptl),count); // aptl[] +} + +// Functions with the same form starting with U_EMRPOLYPOLYLINE_swap +void core2_swap(char *record, int torev){ + int count=0; + int nPolys=0; + PU_EMRPOLYPOLYLINE pEmr = (PU_EMRPOLYPOLYLINE) (record); + if(torev){ + count = pEmr->cptl; + nPolys = pEmr->nPolys; + } + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->nPolys),2); // nPolys cptl + if(!torev){ + count = pEmr->cptl; + nPolys = pEmr->nPolys; + } + U_swap4(pEmr->aPolyCounts,nPolys); // aPolyCounts[] + pointl_swap((PU_POINT)(record + sizeof(U_EMRPOLYPOLYLINE) - 4 + sizeof(uint32_t)* nPolys), count); // paptl[] +} + + +// Functions with the same form starting with U_EMRSETMAPMODE_swap +void core3_swap(char *record, int torev){ + PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(record); + core5_swap(record, torev); + U_swap4(&(pEmr->iMode),1); // iMode +} + +// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_swap, also U_EMRFILLPATH_swap, +void core4_swap(char *record, int torev){ + PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( record); + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBox),1); // rclBox +} + +// Functions with the same form starting with U_EMRPOLYBEZIER16_swap +void core6_swap(char *record, int torev){ + int count=0; + PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (record); + if(torev){ + count = pEmr->cpts; + } + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->cpts),1); // cpts + if(!torev){ + count = pEmr->cpts; + } + point16_swap((pEmr->apts),count); // apts[] +} + + +// Records with the same form starting with U_EMRSETWINDOWEXTEX_swap, that is, all with two uint32_t values after the emr +void core7_swap(char *record, int torev){ + PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (record); + core5_swap(record, torev); + U_swap4(&(pEmr->pair),2); +} + +// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one +void core8_swap(char *record, int torev){ + PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (record); + emrtext_swap(&(pEmr->emrtext),record,torev); + core5_swap(record, torev); + U_swap4(&(pEmr->iGraphicsMode),1); // iGraphicsMode + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->exScale),2); // exScale eyScale +} + +// Functions that take a rect and a pair of points, starting with U_EMRARC_swap +void core9_swap(char *record, int torev){ + PU_EMRARC pEmr = (PU_EMRARC) (record); + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBox),1); // rclBox + U_swap4(&(pEmr->ptlStart),4); // ptlStart ptlEnd +} + +// Functions with the same form starting with U_EMRPOLYPOLYLINE16_swap +void core10_swap(char *record, int torev){ + int count=0; + int nPolys=0; + PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (record); + if(torev){ + count = pEmr->cpts; + nPolys = pEmr->nPolys; + } + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->nPolys),2); // nPolys cpts + if(!torev){ + count = pEmr->cpts; + nPolys = pEmr->nPolys; + } + U_swap4(pEmr->aPolyCounts,nPolys); // aPolyCounts[] + point16_swap((PU_POINT16)(record + sizeof(U_EMRPOLYPOLYLINE16) - 4 + sizeof(uint32_t)* nPolys), count); // apts[] +} + +// Functions with the same form starting with U_EMRINVERTRGN_swap and U_EMRPAINTRGN_swap, +void core11_swap(char *record, int torev){ + int roff=0; + int nextroff=0; + int limit=0; + PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (record); + roff = 0; + if(torev){ + limit = pEmr->emr.nSize; + nextroff = 0; + } + core5_swap(record, torev); + if(!torev){ + limit = pEmr->emr.nSize; + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->cbRgnData),1); // cbRgnData + if(!torev){ + limit = pEmr->emr.nSize; + } + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + char *prd = (char *) &(pEmr->RgnData); + while(roff + 28 < limit){ // up to the end of the record + if(torev){ + nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff = nextroff; + } + else { + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } + } +} + + +// common code for U_EMRCREATEMONOBRUSH_swap and U_EMRCREATEDIBPATTERNBRUSHPT_swap, +void core12_swap(char *record, int torev){ + PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (record); + if(torev && pEmr->cbBmi){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); // Bmi + } + core5_swap(record, torev); + U_swap4(&(pEmr->ihBrush),6); // ihBrush iUsage offBmi cbBmi offBits cbBits + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + if(!torev && pEmr->cbBmi){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); // Bmi + } +} + +// common code for U_EMRALPHABLEND_swap and U_EMRTRANSPARENTBLT_swap, +void core13_swap(char *record, int torev){ + PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (record); + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(&(pEmr->Dest),2); // Dest cDest + pointl_swap(&(pEmr->Dest),2); // Dest cDest + // ordered bytes: Blend + pointl_swap(&(pEmr->Src),2); // Src + xform_swap( &(pEmr->xformSrc)); // xformSrc + // ordered bytes: crBkColorSrc + U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } +} + +/* ********************************************************************************************** +These are the core EMR functions, each creates a particular type of record. +All return these records via a char* pointer, which is NULL if the call failed. +They are listed in order by the corresponding U_EMR_* index number. +*********************************************************************************************** */ + +/** + All of the record level (hidden) functions have this form: + \brief Convert a pointer to a U_EMR_whatever record which has not been implemented. + \param record pointer to a buffer holding the EMR record + \param torev 1 for native to reversed, 0 for reversed to native +*/ +void U_EMRNOTIMPLEMENTED_swap(char *record, int torev){ + core5_swap(record, torev); + printf("WARNING: could not convert data in record type that has not been implemented!\n"); +} + +// U_EMRHEADER 1 +void U_EMRHEADER_swap(char *record, int torev){ + int nDesc,offDesc,nSize,cbPix,offPix; + PU_EMRHEADER pEmr = (PU_EMRHEADER)(record); + if(torev){ + nSize = pEmr->emr.nSize; + core5_swap(record, torev); + } + else { + core5_swap(record, torev); + nSize = pEmr->emr.nSize; + } + + rectl_swap(&(pEmr->rclBounds),2); // rclBounds rclFrame + U_swap4(&(pEmr->dSignature), 4); // dSignature nVersion nBytes nRecords + U_swap2(&(pEmr->nHandles), 2); // nHandlessReserved + if(torev){ + nDesc = pEmr->nDescription; + offDesc = pEmr->offDescription; + U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries + } + else { + U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries + nDesc = pEmr->nDescription; + offDesc = pEmr->offDescription; + } + // UTF16-LE Description + sizel_swap(&(pEmr->szlDevice), 2); // szlDevice szlMillimeters + if((nDesc && (offDesc >= 100)) || + (!offDesc && nSize >= 100) + ){ + if(torev){ + cbPix = pEmr->cbPixelFormat; + offPix = pEmr->offPixelFormat; + if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); + U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat + } + else { + U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat + cbPix = pEmr->cbPixelFormat; + offPix = pEmr->offPixelFormat; + if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); + } + U_swap4(&(pEmr->bOpenGL), 1); // bOpenGL + if((nDesc && (offDesc >= 108)) || + (cbPix && (offPix >=108)) || + (!offDesc && !cbPix && nSize >= 108) + ){ + sizel_swap(&(pEmr->szlMicrometers), 1); // szlMicrometers + } + } +} + +// U_EMRPOLYBEZIER 2 +void U_EMRPOLYBEZIER_swap(char *record, int torev){ + core1_swap(record, torev); +} + +// U_EMRPOLYGON 3 +void U_EMRPOLYGON_swap(char *record, int torev){ + core1_swap(record, torev); +} + + +// U_EMRPOLYLINE 4 +void U_EMRPOLYLINE_swap(char *record, int torev){ + core1_swap(record, torev); +} + +// U_EMRPOLYBEZIERTO 5 +void U_EMRPOLYBEZIERTO_swap(char *record, int torev){ + core1_swap(record, torev); +} + +// U_EMRPOLYLINETO 6 +void U_EMRPOLYLINETO_swap(char *record, int torev){ + core1_swap(record, torev); +} + +// U_EMRPOLYPOLYLINE 7 +void U_EMRPOLYPOLYLINE_swap(char *record, int torev){ + core2_swap(record, torev); +} + +// U_EMRPOLYPOLYGON 8 +void U_EMRPOLYPOLYGON_swap(char *record, int torev){ + core2_swap(record, torev); +} + +// U_EMRSETWINDOWEXTEX 9 +void U_EMRSETWINDOWEXTEX_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRSETWINDOWORGEX 10 +void U_EMRSETWINDOWORGEX_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRSETVIEWPORTEXTEX 11 +void U_EMRSETVIEWPORTEXTEX_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRSETVIEWPORTORGEX 12 +void U_EMRSETVIEWPORTORGEX_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRSETBRUSHORGEX 13 +void U_EMRSETBRUSHORGEX_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMREOF 14 +void U_EMREOF_swap(char *record, int torev){ + int off=0; + int cbPalEntries=0; + core5_swap(record, torev); + PU_EMREOF pEmr = (PU_EMREOF)(record); + if(torev){ + cbPalEntries = pEmr->cbPalEntries; + if(cbPalEntries){ + logpalette_swap( (PU_LOGPALETTE)(record + pEmr->offPalEntries)); + } + } + U_swap4(&(pEmr->cbPalEntries),2); // cbPalEntries offPalEntries + if(!torev){ + cbPalEntries = pEmr->cbPalEntries; + if(cbPalEntries){ + logpalette_swap( (PU_LOGPALETTE)(record + pEmr->offPalEntries)); + } + } + off = sizeof(U_EMREOF) + 4 * cbPalEntries; + U_swap4(record + off,1); // nSizeLast +} + + +// U_EMRSETPIXELV 15 +void U_EMRSETPIXELV_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(record); + pointl_swap(&(pEmr->ptlPixel),1); // ptlPixel + // ordered bytes: crColor +} + + +// U_EMRSETMAPPERFLAGS 16 +void U_EMRSETMAPPERFLAGS_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(record); + U_swap4(&(pEmr->dwFlags),1); // dwFlags +} + + +// U_EMRSETMAPMODE 17 +void U_EMRSETMAPMODE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETBKMODE 18 +void U_EMRSETBKMODE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETPOLYFILLMODE 19 +void U_EMRSETPOLYFILLMODE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETROP2 20 +void U_EMRSETROP2_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETSTRETCHBLTMODE 21 +void U_EMRSETSTRETCHBLTMODE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETTEXTALIGN 22 +void U_EMRSETTEXTALIGN_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETCOLORADJUSTMENT 23 +void U_EMRSETCOLORADJUSTMENT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(record); + coloradjustment_swap(&(pEmr->ColorAdjustment)); +} + +// U_EMRSETTEXTCOLOR 24 +void U_EMRSETTEXTCOLOR_swap(char *record, int torev){ + core5_swap(record, torev); + // ordered bytes: crColor +} + +// U_EMRSETBKCOLOR 25 +void U_EMRSETBKCOLOR_swap(char *record, int torev){ + core5_swap(record, torev); + // ordered bytes: crColor +} + +// U_EMROFFSETCLIPRGN 26 +void U_EMROFFSETCLIPRGN_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRMOVETOEX 27 +void U_EMRMOVETOEX_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRSETMETARGN 28 +void U_EMRSETMETARGN_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMREXCLUDECLIPRECT 29 +void U_EMREXCLUDECLIPRECT_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRINTERSECTCLIPRECT 30 +void U_EMRINTERSECTCLIPRECT_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRSCALEVIEWPORTEXTEX 31 +void U_EMRSCALEVIEWPORTEXTEX_swap(char *record, int torev){ + core4_swap(record, torev); +} + + +// U_EMRSCALEWINDOWEXTEX 32 +void U_EMRSCALEWINDOWEXTEX_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRSAVEDC 33 +void U_EMRSAVEDC_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRRESTOREDC 34 +void U_EMRRESTOREDC_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETWORLDTRANSFORM 35 +void U_EMRSETWORLDTRANSFORM_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(record); + xform_swap(&(pEmr->xform)); +} + +// U_EMRMODIFYWORLDTRANSFORM 36 +void U_EMRMODIFYWORLDTRANSFORM_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(record); + xform_swap(&(pEmr->xform)); // xform + U_swap4(&(pEmr->iMode),1); // iMode +} + +// U_EMRSELECTOBJECT 37 +void U_EMRSELECTOBJECT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(record); + U_swap4(&(pEmr->ihObject),1); // ihObject +} + +// U_EMRCREATEPEN 38 +void U_EMRCREATEPEN_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(record); + U_swap4(&(pEmr->ihPen),1); // ihPen + logpen_swap(&(pEmr->lopn)); // lopn +} + +// U_EMRCREATEBRUSHINDIRECT 39 +void U_EMRCREATEBRUSHINDIRECT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(record); + U_swap4(&(pEmr->ihBrush),1); // ihBrush + logbrush_swap(&(pEmr->lb)); // lb +} + +// U_EMRDELETEOBJECT 40 +void U_EMRDELETEOBJECT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(record); + U_swap4(&(pEmr->ihObject),1); // ihObject +} + +// U_EMRANGLEARC 41 +void U_EMRANGLEARC_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(record); + pointl_swap(&(pEmr->ptlCenter),1); // ptlCenter + U_swap4(&(pEmr->nRadius),3); // nRadius eStartAngle eSweepAngle +} + +// U_EMRELLIPSE 42 +void U_EMRELLIPSE_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRRECTANGLE 43 +void U_EMRRECTANGLE_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRROUNDRECT 44 +void U_EMRROUNDRECT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(record); + rectl_swap(&(pEmr->rclBox),1); // rclBox + sizel_swap(&(pEmr->szlCorner), 1); // szlCorner +} + +// U_EMRARC 45 +void U_EMRARC_swap(char *record, int torev){ + core9_swap(record, torev); +} + +// U_EMRCHORD 46 +void U_EMRCHORD_swap(char *record, int torev){ + core9_swap(record, torev); +} + +// U_EMRPIE 47 +void U_EMRPIE_swap(char *record, int torev){ + core9_swap(record, torev); +} + +// U_EMRSELECTPALETTE 48 +void U_EMRSELECTPALETTE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRCREATEPALETTE 49 +void U_EMRCREATEPALETTE_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(record); + U_swap4(&(pEmr->ihPal),1); // ihPal + logpalette_swap( (PU_LOGPALETTE)&(pEmr->lgpl) ); // lgpl +} + +// U_EMRSETPALETTEENTRIES 50 +void U_EMRSETPALETTEENTRIES_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(record); + U_swap4(&(pEmr->ihPal),3); // ihPal iStart cEntries + // ordered bytes: aPalEntries[] +} + +// U_EMRRESIZEPALETTE 51 +void U_EMRRESIZEPALETTE_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRREALIZEPALETTE 52 +void U_EMRREALIZEPALETTE_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMREXTFLOODFILL 53 +void U_EMREXTFLOODFILL_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(record); + pointl_swap(&(pEmr->ptlStart),1); // ptlStart + // ordered bytes: crColor + U_swap4(&(pEmr->iMode),1); // iMode +} + +// U_EMRLINETO 54 +void U_EMRLINETO_swap(char *record, int torev){ + core7_swap(record, torev); +} + +// U_EMRARCTO 55 +void U_EMRARCTO_swap(char *record, int torev){ + core9_swap(record, torev); +} + +// U_EMRPOLYDRAW 56 +void U_EMRPOLYDRAW_swap(char *record, int torev){ + int count=0; + core5_swap(record, torev); + PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(record); + + if(torev){ + count = pEmr->cptl; + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->cptl),1); // cptl + if(!torev){ + count = pEmr->cptl; + } + pointl_swap(pEmr->aptl,count); // aptl[] + U_swap4(pEmr->abTypes,count); // abTypes[] +} + +// U_EMRSETARCDIRECTION 57 +void U_EMRSETARCDIRECTION_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRSETMITERLIMIT 58 +void U_EMRSETMITERLIMIT_swap(char *record, int torev){ + core3_swap(record, torev); +} + + +// U_EMRBEGINPATH 59 +void U_EMRBEGINPATH_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRENDPATH 60 +void U_EMRENDPATH_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRCLOSEFIGURE 61 +void U_EMRCLOSEFIGURE_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRFILLPATH 62 +void U_EMRFILLPATH_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRSTROKEANDFILLPATH 63 +void U_EMRSTROKEANDFILLPATH_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRSTROKEPATH 64 +void U_EMRSTROKEPATH_swap(char *record, int torev){ + core4_swap(record, torev); +} + +// U_EMRFLATTENPATH 65 +void U_EMRFLATTENPATH_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRWIDENPATH 66 +void U_EMRWIDENPATH_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRSELECTCLIPPATH 67 +void U_EMRSELECTCLIPPATH_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRABORTPATH 68 +void U_EMRABORTPATH_swap(char *record, int torev){ + core5_swap(record, torev); +} + +// U_EMRUNDEF69 69 +#define U_EMRUNDEF69_swap U_EMRNOTIMPLEMENTED_swap + +// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific) +void U_EMRCOMMENT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(record); + U_swap4(&(pEmr->cbData),1); // cbData + // program specific data, presumably byte ordered, otherwise, not portable +} + +// U_EMRFILLRGN 71 +void U_EMRFILLRGN_swap(char *record, int torev){ + int roff=0; + int nextroff=0; + int limit=0; + roff=0; + PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(record); + if(torev){ + limit = pEmr->emr.nSize; + nextroff = 0; + } + core5_swap(record, torev); + if(!torev){ + limit = pEmr->emr.nSize; + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->cbRgnData),2); // cbRgnData ihBrush + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + char *prd = (char *) &(pEmr->RgnData); + while(roff + 28 < limit){ // up to the end of the record + if(torev){ + nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff = nextroff; + } + else { + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } + } +} + +// U_EMRFRAMERGN 72 +void U_EMRFRAMERGN_swap(char *record, int torev){ + int roff=0; + int nextroff=0; + int limit=0; + PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(record); + roff = 0; + if(torev){ + limit = pEmr->emr.nSize; + nextroff = 0; + } + core5_swap(record, torev); + if(!torev){ + limit = pEmr->emr.nSize; + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->cbRgnData),2); // cbRgnData ihBrush + sizel_swap(&(pEmr->szlStroke), 2); // szlStroke + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + char *prd = (char *) &(pEmr->RgnData); + while(roff + 28 < limit){ // up to the end of the record + if(torev){ + nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff = nextroff; + } + else { + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } + } +} + +// U_EMRINVERTRGN 73 +void U_EMRINVERTRGN_swap(char *record, int torev){ + core11_swap(record, torev); +} + +// U_EMRPAINTRGN 74 +void U_EMRPAINTRGN_swap(char *record, int torev){ + core11_swap(record, torev); +} + +// U_EMREXTSELECTCLIPRGN 75 +void U_EMREXTSELECTCLIPRGN_swap(char *record, int torev){ + int roff=0; + int nextroff=0; + int limit=0; + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (record); + roff = 0; + if(torev){ + limit = pEmr->emr.nSize; + nextroff = 0; + } + core5_swap(record, torev); + if(!torev){ + limit = pEmr->emr.nSize; + } + U_swap4(&(pEmr->cbRgnData),2); // cbRgnData iMode + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + char *prd = (char *) &(pEmr->RgnData); + nextroff = roff = 0; + while(roff + 16 < limit){ // up to the end of the record + if(torev){ + nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff = nextroff; + } + else { + rgndata_swap((PU_RGNDATA) (prd + roff)); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } + } +} + +// U_EMRBITBLT 76 +void U_EMRBITBLT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record); + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(&(pEmr->Dest),2); // Dest cDest + U_swap4(&(pEmr->dwRop),1); // dwRop + pointl_swap(&(pEmr->Src),1); // Src + xform_swap(&(pEmr->xformSrc)); // xformSrc + // ordered bytes: crBkColorSrc + U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } +} + +// U_EMRSTRETCHBLT 77 +void U_EMRSTRETCHBLT_swap(char *record, int torev){ + PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (record); + core5_swap(record, torev); + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(&(pEmr->Dest),2); // Dest cDest + U_swap4(&(pEmr->dwRop),1); // dwRop + pointl_swap(&(pEmr->Src),1); // Src + xform_swap(&(pEmr->xformSrc)); // xformSrc + // ordered bytes: crBkColorSrc + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc + pointl_swap(&(pEmr->cSrc),1); // cSrc + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } +} + +// U_EMRMASKBLT 78 +void U_EMRMASKBLT_swap(char *record, int torev){ + PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (record); + core5_swap(record, torev); + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + if(torev && pEmr->cbBmiMask){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(&(pEmr->Dest),2); // Dest cDest + U_swap4(&(pEmr->dwRop),1); // dwRop + pointl_swap(&(pEmr->Src),1); // Src + xform_swap(&(pEmr->xformSrc)); // xformSrc + // ordered bytes: crBkColorSrc + U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc + pointl_swap(&(pEmr->Mask),1); // Mask + U_swap4(&(pEmr->iUsageMask),5); // iUsageMask offBmiMask cbBmiMask offBitsMask cbBitsMask + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + if(!torev && pEmr->cbBmiMask){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); + } +} + +// U_EMRPLGBLT 79 +void U_EMRPLGBLT_swap(char *record, int torev){ + PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (record); + core5_swap(record, torev); + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + if(torev && pEmr->cbBmiMask){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(pEmr->aptlDst,3); // aptlDst[] + pointl_swap(&(pEmr->Src),2); // Src cSrc + xform_swap(&(pEmr->xformSrc)); // xformSrc + // ordered bytes: crBkColorSrc + U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc + pointl_swap(&(pEmr->Mask),1); // Mask + U_swap4(&(pEmr->iUsageMask),5); // iUsageMask offBmiMask cbBmiMask offBitsMask cbBitsMask + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + if(!torev && pEmr->cbBmiMask){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); + } +} + +// U_EMRSETDIBITSTODEVICE 80 +void U_EMRSETDIBITSTODEVICE_swap(char *record, int torev){ + PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (record); + core5_swap(record, torev); + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(&(pEmr->Dest),1); // Dest + pointl_swap(&(pEmr->Src),2); // Src cSrc + U_swap4(&(pEmr->offBmiSrc),7); // offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc iUsageSrc iStartScan cScans + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } +} + +// U_EMRSTRETCHDIBITS 81 +void U_EMRSTRETCHDIBITS_swap(char *record, int torev){ + PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (record); + core5_swap(record, torev); + if(torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + pointl_swap(&(pEmr->Dest),1); // Dest + pointl_swap(&(pEmr->Src),2); // Src cSrc + U_swap4(&(pEmr->offBmiSrc),6); // offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc iUsageSrc dwRop + pointl_swap(&(pEmr->cDest),1); // cDest + if(!torev && pEmr->cbBmiSrc){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + } +} + +// U_EMREXTCREATEFONTINDIRECTW_swap 82 +void U_EMREXTCREATEFONTINDIRECTW_swap(char *record, int torev){ + PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (record); + if(torev){ + if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ + logfont_panose_swap(&(pEmr->elfw)); + } + else { + logfont_swap( (PU_LOGFONT) &(pEmr->elfw)); + } + } + core5_swap(record, torev); + if(!torev){ + if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ + logfont_panose_swap(&(pEmr->elfw)); + } + else { + logfont_swap( (PU_LOGFONT) &(pEmr->elfw)); + } + } + U_swap4(&(pEmr->ihFont),1); // ihFont +} + +// U_EMREXTTEXTOUTA 83 +void U_EMREXTTEXTOUTA_swap(char *record, int torev){ + core8_swap(record, torev); +} + +// U_EMREXTTEXTOUTW 84 +void U_EMREXTTEXTOUTW_swap(char *record, int torev){ + core8_swap(record, torev); +} + +// U_EMRPOLYBEZIER16 85 +/** + \brief Convert a pointer to a U_EMR_POLYBEZIER16 record. + \param record pointer to a buffer holding the EMR record +*/ +void U_EMRPOLYBEZIER16_swap(char *record, int torev){ + core6_swap(record, torev); +} + +// U_EMRPOLYGON16 86 +void U_EMRPOLYGON16_swap(char *record, int torev){ + core6_swap(record, torev); +} + +// U_EMRPOLYLINE16 87 +void U_EMRPOLYLINE16_swap(char *record, int torev){ + core6_swap(record, torev); +} + +// U_EMRPOLYBEZIERTO16 88 +void U_EMRPOLYBEZIERTO16_swap(char *record, int torev){ + core6_swap(record, torev); +} + +// U_EMRPOLYLINETO16 89 +/** + \brief Convert a pointer to a U_EMR_POLYLINETO16 record. + \param record pointer to a buffer holding the EMR record +*/ +void U_EMRPOLYLINETO16_swap(char *record, int torev){ + core6_swap(record, torev); +} + +// U_EMRPOLYPOLYLINE16 90 +void U_EMRPOLYPOLYLINE16_swap(char *record, int torev){ + core10_swap(record, torev); +} + +// U_EMRPOLYPOLYGON16 91 +void U_EMRPOLYPOLYGON16_swap(char *record, int torev){ + core10_swap(record, torev); +} + + +// U_EMRPOLYDRAW16 92 +void U_EMRPOLYDRAW16_swap(char *record, int torev){ + int count=0; + core5_swap(record, torev); + PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(record); + if(torev){ + count = pEmr->cpts; + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->cpts),1); // cpts + if(!torev){ + count = pEmr->cpts; + } + point16_swap(pEmr->apts,count); // apts[] + U_swap4(pEmr->abTypes,count); // abTypes[] +} + +// U_EMRCREATEMONOBRUSH 93 +void U_EMRCREATEMONOBRUSH_swap(char *record, int torev){ + core12_swap(record, torev); +} + +// U_EMRCREATEDIBPATTERNBRUSHPT_swap 94 +void U_EMRCREATEDIBPATTERNBRUSHPT_swap(char *record, int torev){ + core12_swap(record, torev); +} + + +// U_EMREXTCREATEPEN 95 +void U_EMREXTCREATEPEN_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(record); + if(torev && pEmr->cbBmi){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); + } + U_swap4(&(pEmr->ihPen),5); // ihPen offBmi cbBmi offBits cbBits + if(!torev && pEmr->cbBmi){ + bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); + } + extlogpen_swap((PU_EXTLOGPEN) &(pEmr->elp), torev); +} + +// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT +#define U_EMRPOLYTEXTOUTA_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT +#define U_EMRPOLYTEXTOUTW_swap U_EMRNOTIMPLEMENTED_swap + +// U_EMRSETICMMODE 98 +void U_EMRSETICMMODE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRCREATECOLORSPACE 99 +void U_EMRCREATECOLORSPACE_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(record); + U_swap4(&(pEmr->ihCS),1); // ihCS + logcolorspacea_swap(&(pEmr->lcs)); // lcs +} + +// U_EMRSETCOLORSPACE 100 +void U_EMRSETCOLORSPACE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRDELETECOLORSPACE 101 +void U_EMRDELETECOLORSPACE_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRGLSRECORD 102 Not implemented +#define U_EMRGLSRECORD_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRGLSBOUNDEDRECORD 103 Not implemented +#define U_EMRGLSBOUNDEDRECORD_swap U_EMRNOTIMPLEMENTED_swap + +// U_EMRPIXELFORMAT 104 +void U_EMRPIXELFORMAT_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(record); + pixelformatdescriptor_swap(&(pEmr->pfd)); // pfd +} + +// U_EMRDRAWESCAPE 105 Not implemented +#define U_EMRDRAWESCAPE_swap U_EMRNOTIMPLEMENTED_swap +// U_EMREXTESCAPE 106 Not implemented +#define U_EMREXTESCAPE_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRUNDEF107 107 Not implemented +#define U_EMRUNDEF107_swap U_EMRNOTIMPLEMENTED_swap + +// U_EMRSMALLTEXTOUT 108 +void U_EMRSMALLTEXTOUT_swap(char *record, int torev){ + int roff=0; + int fuOptions=0; + core5_swap(record, torev); + PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(record); + if(torev){ + fuOptions = pEmr->fuOptions; + } + pointl_swap(&(pEmr->Dest),1); // Dest + U_swap4(&(pEmr->cChars),5); // cChars fuOptions iGraphicsMode exScale eyScale + if(!torev){ + fuOptions = pEmr->fuOptions; + } + roff = sizeof(U_EMRSMALLTEXTOUT); // offset to the start of the variable fields + if(!(fuOptions & U_ETO_NO_RECT)){ + rectl_swap( (PU_RECTL) (record + roff),1); // rclBounds + } + // ordered bytes or UTF16-LE TextString +} + +// U_EMRFORCEUFIMAPPING 109 Not implemented +#define U_EMRFORCEUFIMAPPING_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRNAMEDESCAPE 110 Not implemented +#define U_EMRNAMEDESCAPE_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRCOLORCORRECTPALETTE 111 Not implemented +#define U_EMRCOLORCORRECTPALETTE_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRSETICMPROFILEA 112 Not implemented +#define U_EMRSETICMPROFILEA_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRSETICMPROFILEW 113 Not implemented +#define U_EMRSETICMPROFILEW_swap U_EMRNOTIMPLEMENTED_swap + +// U_EMRALPHABLEND 114 +void U_EMRALPHABLEND_swap(char *record, int torev){ + core13_swap(record, torev); +} + +// U_EMRSETLAYOUT 115 +void U_EMRSETLAYOUT_swap(char *record, int torev){ + core3_swap(record, torev); +} + +// U_EMRTRANSPARENTBLT 116 +void U_EMRTRANSPARENTBLT_swap(char *record, int torev){ + core13_swap(record, torev); +} + + +// U_EMRUNDEF117 117 Not implemented +#define U_EMRUNDEF117_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRGRADIENTFILL 118 +void U_EMRGRADIENTFILL_swap(char *record, int torev){ + int nTriVert=0; + int nGradObj=0; + int ulMode=0; + core5_swap(record, torev); + PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(record); + if(torev){ + nTriVert = pEmr->nTriVert; + nGradObj = pEmr->nGradObj; + ulMode = pEmr->ulMode; + } + rectl_swap(&(pEmr->rclBounds),1); // rclBounds + U_swap4(&(pEmr->nTriVert),3); // nTriVert nGradObj ulMode + if(!torev){ + nTriVert = pEmr->nTriVert; + nGradObj = pEmr->nGradObj; + ulMode = pEmr->ulMode; + } + record += sizeof(U_EMRGRADIENTFILL); + if(nTriVert){ + trivertex_swap((PU_TRIVERTEX)(record),nTriVert); // TriVert[] + } + record += nTriVert * sizeof(U_TRIVERTEX); + if(nGradObj){ + if( ulMode == U_GRADIENT_FILL_TRIANGLE){ + gradient3_swap((PU_GRADIENT3)(record), nGradObj); // GradObj[] + } + else if(ulMode == U_GRADIENT_FILL_RECT_H || ulMode == U_GRADIENT_FILL_RECT_V){ + gradient4_swap((PU_GRADIENT4)(record), nGradObj); // GradObj[] + } + } +} + +// U_EMRSETLINKEDUFIS 119 Not implemented +#define U_EMRSETLINKEDUFIS_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated) +#define U_EMRSETTEXTJUSTIFICATION_swap U_EMRNOTIMPLEMENTED_swap +// U_EMRCOLORMATCHTOTARGETW 121 Not implemented +#define U_EMRCOLORMATCHTOTARGETW_swap U_EMRNOTIMPLEMENTED_swap + +// U_EMRCREATECOLORSPACEW 122 +void U_EMRCREATECOLORSPACEW_swap(char *record, int torev){ + core5_swap(record, torev); + PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(record); + U_swap4(&(pEmr->ihCS),1); // ihCS + logcolorspacew_swap(&(pEmr->lcs)); // lcs + U_swap4(&(pEmr->dwFlags),2); // dwFlags cbData + // ordered bytes: Data +} + +//! @endcond + + +/** + \brief Convert an entire EMF in memory from Big Endian to Little Endian. + \return 0 on failure, 1 on success + \param contents pointer to the buffer holding the entire EMF in memory + \param length number of bytes in the buffer + \param torev 1 for native to reversed, 0 for reversed to native + + Normally this would be called immediately before writing the data to a file + or immediately after reading the data from a file. +*/ +int U_emf_endian(char *contents, size_t length, int torev){ + size_t off; + uint32_t OK, recnum, iType; + char *record; + PU_ENHMETARECORD pEmr; + + record = contents; + OK = 1; + off = 0; + recnum = 0; + while(OK){ + if(record > contents + length){ // this is most likely a corrupt EMF + return(0); + } + + pEmr = (PU_ENHMETARECORD)(record); + + iType = pEmr->iType; + off = pEmr->nSize; + if(!torev){ + U_swap4(&iType,1); + U_swap4(&off,1); + } + + switch (iType) + { + case U_EMR_HEADER: U_EMRHEADER_swap(record, torev); break; + case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_swap(record, torev); break; + case U_EMR_POLYGON: U_EMRPOLYGON_swap(record, torev); break; + case U_EMR_POLYLINE: U_EMRPOLYLINE_swap(record, torev); break; + case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_swap(record, torev); break; + case U_EMR_POLYLINETO: U_EMRPOLYLINETO_swap(record, torev); break; + case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_swap(record, torev); break; + case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_swap(record, torev); break; + case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_swap(record, torev); break; + case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_swap(record, torev); break; + case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_swap(record, torev); break; + case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_swap(record, torev); break; + case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_swap(record, torev); break; + case U_EMR_EOF: + U_EMREOF_swap(record, torev); + OK = 0; /* Exit triggered here */ + break; + case U_EMR_SETPIXELV: U_EMRSETPIXELV_swap(record, torev); break; + case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_swap(record, torev); break; + case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_swap(record, torev); break; + case U_EMR_SETBKMODE: U_EMRSETBKMODE_swap(record, torev); break; + case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_swap(record, torev); break; + case U_EMR_SETROP2: U_EMRSETROP2_swap(record, torev); break; + case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_swap(record, torev); break; + case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_swap(record, torev); break; + case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_swap(record, torev); break; + case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_swap(record, torev); break; + case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_swap(record, torev); break; + case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_swap(record, torev); break; + case U_EMR_MOVETOEX: U_EMRMOVETOEX_swap(record, torev); break; + case U_EMR_SETMETARGN: U_EMRSETMETARGN_swap(record, torev); break; + case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_swap(record, torev); break; + case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_swap(record, torev); break; + case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_swap(record, torev); break; + case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_swap(record, torev); break; + case U_EMR_SAVEDC: U_EMRSAVEDC_swap(record, torev); break; + case U_EMR_RESTOREDC: U_EMRRESTOREDC_swap(record, torev); break; + case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_swap(record, torev); break; + case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_swap(record, torev); break; + case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_swap(record, torev); break; + case U_EMR_CREATEPEN: U_EMRCREATEPEN_swap(record, torev); break; + case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_swap(record, torev); break; + case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_swap(record, torev); break; + case U_EMR_ANGLEARC: U_EMRANGLEARC_swap(record, torev); break; + case U_EMR_ELLIPSE: U_EMRELLIPSE_swap(record, torev); break; + case U_EMR_RECTANGLE: U_EMRRECTANGLE_swap(record, torev); break; + case U_EMR_ROUNDRECT: U_EMRROUNDRECT_swap(record, torev); break; + case U_EMR_ARC: U_EMRARC_swap(record, torev); break; + case U_EMR_CHORD: U_EMRCHORD_swap(record, torev); break; + case U_EMR_PIE: U_EMRPIE_swap(record, torev); break; + case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_swap(record, torev); break; + case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_swap(record, torev); break; + case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_swap(record, torev); break; + case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_swap(record, torev); break; + case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_swap(record, torev); break; + case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_swap(record, torev); break; + case U_EMR_LINETO: U_EMRLINETO_swap(record, torev); break; + case U_EMR_ARCTO: U_EMRARCTO_swap(record, torev); break; + case U_EMR_POLYDRAW: U_EMRPOLYDRAW_swap(record, torev); break; + case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_swap(record, torev); break; + case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_swap(record, torev); break; + case U_EMR_BEGINPATH: U_EMRBEGINPATH_swap(record, torev); break; + case U_EMR_ENDPATH: U_EMRENDPATH_swap(record, torev); break; + case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_swap(record, torev); break; + case U_EMR_FILLPATH: U_EMRFILLPATH_swap(record, torev); break; + case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_swap(record, torev); break; + case U_EMR_STROKEPATH: U_EMRSTROKEPATH_swap(record, torev); break; + case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_swap(record, torev); break; + case U_EMR_WIDENPATH: U_EMRWIDENPATH_swap(record, torev); break; + case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_swap(record, torev); break; + case U_EMR_ABORTPATH: U_EMRABORTPATH_swap(record, torev); break; + case U_EMR_UNDEF69: U_EMRUNDEF69_swap(record, torev); break; + case U_EMR_COMMENT: U_EMRCOMMENT_swap(record, torev); break; + case U_EMR_FILLRGN: U_EMRFILLRGN_swap(record, torev); break; + case U_EMR_FRAMERGN: U_EMRFRAMERGN_swap(record, torev); break; + case U_EMR_INVERTRGN: U_EMRINVERTRGN_swap(record, torev); break; + case U_EMR_PAINTRGN: U_EMRPAINTRGN_swap(record, torev); break; + case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_swap(record, torev); break; + case U_EMR_BITBLT: U_EMRBITBLT_swap(record, torev); break; + case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_swap(record, torev); break; + case U_EMR_MASKBLT: U_EMRMASKBLT_swap(record, torev); break; + case U_EMR_PLGBLT: U_EMRPLGBLT_swap(record, torev); break; + case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_swap(record, torev); break; + case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_swap(record, torev); break; + case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_swap(record, torev); break; + case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_swap(record, torev); break; + case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_swap(record, torev); break; + case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_swap(record, torev); break; + case U_EMR_POLYGON16: U_EMRPOLYGON16_swap(record, torev); break; + case U_EMR_POLYLINE16: U_EMRPOLYLINE16_swap(record, torev); break; + case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_swap(record, torev); break; + case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_swap(record, torev); break; + case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_swap(record, torev); break; + case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_swap(record, torev); break; + case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_swap(record, torev); break; + case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_swap(record, torev); break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_swap(record, torev); break; + case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_swap(record, torev); break; + case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_swap(record, torev); break; + case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_swap(record, torev); break; + case U_EMR_SETICMMODE: U_EMRSETICMMODE_swap(record, torev); break; + case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_swap(record, torev); break; + case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_swap(record, torev); break; + case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_swap(record, torev); break; + case U_EMR_GLSRECORD: U_EMRGLSRECORD_swap(record, torev); break; + case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_swap(record, torev); break; + case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_swap(record, torev); break; + case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_swap(record, torev); break; + case U_EMR_EXTESCAPE: U_EMREXTESCAPE_swap(record, torev); break; + case U_EMR_UNDEF107: U_EMRUNDEF107_swap(record, torev); break; + case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_swap(record, torev); break; + case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_swap(record, torev); break; + case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_swap(record, torev); break; + case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_swap(record, torev); break; + case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_swap(record, torev); break; + case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_swap(record, torev); break; + case U_EMR_ALPHABLEND: U_EMRALPHABLEND_swap(record, torev); break; + case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_swap(record, torev); break; + case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_swap(record, torev); break; + case U_EMR_UNDEF117: U_EMRUNDEF117_swap(record, torev); break; + case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_swap(record, torev); break; + case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_swap(record, torev); break; + case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_swap(record, torev); break; + case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_swap(record, torev); break; + case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_swap(record, torev); break; + default: U_EMRNOTIMPLEMENTED_swap(record, torev); break; + } //end of switch + record += off; + recnum++; + } //end of while + + return(1); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uemf_endian.h b/src/extension/internal/uemf_endian.h new file mode 100644 index 000000000..9866aacaf --- /dev/null +++ b/src/extension/internal/uemf_endian.h @@ -0,0 +1,37 @@ +/** + @file uemf_endian.h Prototype for function for converting EMF records between Big Endian and Little Endian +*/ + +/* +File: uemf_endian.h +Version: 0.0.3 +Date: 24-JUL-2012 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UEMF_ENDIAN_ +#define _UEMF_ENDIAN_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* There is no way for the preprocessor, in general, to figure out endianness. So the command line must define + WORDS_BIGENDIAN for a big endian machine. Otherwise we assume is is little endian. If it is something + else this code won't work in any case. */ +#ifdef WORDS_BIGENDIAN +#define U_BYTE_SWAP 1 +#else +#define U_BYTE_SWAP 0 +#endif + +// prototypes +int U_emf_endian(char *contents, size_t length, int torev); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEMF_ENDIAN_ */ diff --git a/src/extension/internal/uemf_print.c b/src/extension/internal/uemf_print.c new file mode 100644 index 000000000..1d6bebc40 --- /dev/null +++ b/src/extension/internal/uemf_print.c @@ -0,0 +1,2358 @@ +/** + @file uemf_print.c Functions for printing EMF records +*/ + +/* +File: uemf_print.c +Version: 0.0.12 +Date: 04-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> /* for offsetof() macro */ +#include <string.h> +#include "uemf.h" + +/** + \brief Print some number of hex bytes + \param buf pointer to the first byte + \param num number of bytes +*/ +void hexbytes_print(uint8_t *buf,unsigned int num){ + for(; num; num--,buf++){ + printf("%2.2X",*buf); + } +} + +/* ********************************************************************************************** + These functions print standard objects used in the EMR records. + The low level ones do not append EOL. +*********************************************************************************************** */ + + + +/** + \brief Print a U_COLORREF object. + \param color U_COLORREF object +*/ +void colorref_print( + U_COLORREF color + ){ + printf("{%u,%u,%u} ",color.Red,color.Green,color.Blue); +} + + +/** + \brief Print a U_RGBQUAD object. + \param color U_RGBQUAD object +*/ +void rgbquad_print( + U_RGBQUAD color + ){ + printf("{%u,%u,%u,%u} ",color.Blue,color.Green,color.Red,color.Reserved); +} + +/** + \brief Print rect and rectl objects from Upper Left and Lower Right corner points. + \param rect U_RECTL object +*/ +void rectl_print( + U_RECTL rect + ){ + printf("{%d,%d,%d,%d} ",rect.left,rect.top,rect.right,rect.bottom); +} + +/** + \brief Print a U_SIZEL object. + \param sz U_SizeL object +*/ +void sizel_print( + U_SIZEL sz + ){ + printf("{%d,%d} ",sz.cx ,sz.cy); +} + +/** + \brief Print a U_POINTL object + \param pt U_POINTL object +*/ +void pointl_print( + U_POINTL pt + ){ + printf("{%d,%d} ",pt.x ,pt.y); +} + +/** + \brief Print a pointer to a U_POINT16 object + \param pt pointer to a U_POINT16 object + Warning - WMF data may contain unaligned U_POINT16, do not call + this routine with a pointer to such data! +*/ +void point16_print( + U_POINT16 pt + ){ + printf("{%d,%d} ",pt.x ,pt.y); +} + +/** + \brief Print a U_LCS_GAMMA object + \param lg U_LCS_GAMMA object +*/ +void lcs_gamma_print( + U_LCS_GAMMA lg + ){ + uint8_t tmp; + tmp = lg.ignoreHi; printf("ignoreHi:%u ",tmp); + tmp = lg.intPart ; printf("intPart :%u ",tmp); + tmp = lg.fracPart; printf("fracPart:%u ",tmp); + tmp = lg.ignoreLo; printf("ignoreLo:%u ",tmp); +} + +/** + \brief Print a U_LCS_GAMMARGB object + \param lgr U_LCS_GAMMARGB object +*/ +void lcs_gammargb_print( + U_LCS_GAMMARGB lgr + ){ + printf("lcsGammaRed:"); lcs_gamma_print(lgr.lcsGammaRed ); + printf("lcsGammaGreen:"); lcs_gamma_print(lgr.lcsGammaGreen); + printf("lcsGammaBlue:"); lcs_gamma_print(lgr.lcsGammaBlue ); +} + +/** + \brief Print a U_TRIVERTEX object. + \param tv U_TRIVERTEX object. +*/ +void trivertex_print( + U_TRIVERTEX tv + ){ + printf("{{%d,%d},{%u,%u,%u,%u}} ",tv.x,tv.y,tv.Red,tv.Green,tv.Blue,tv.Alpha); +} + +/** + \brief Print a U_GRADIENT3 object. + \param g3 U_GRADIENT3 object. +*/ +void gradient3_print( + U_GRADIENT3 g3 + ){ + printf("{%u,%u,%u} ",g3.Vertex1,g3.Vertex2,g3.Vertex3); +} + +/** + \brief Print a U_GRADIENT4 object. + \param g4 U_GRADIENT4 object. +*/ +void gradient4_print( + U_GRADIENT4 g4 + ){ + printf("{%u,%u} ",g4.UpperLeft,g4.LowerRight); +} + +/** + \brief Print a U_LOGBRUSH object. + \param lb U_LOGBRUSH object. +*/ +void logbrush_print( + U_LOGBRUSH lb + ){ + printf("lbStyle:0x%8.8X ", lb.lbStyle); + printf("lbColor:"); colorref_print(lb.lbColor); + printf("lbHatch:0x%8.8X ", lb.lbHatch); +} + +/** + \brief Print a U_XFORM object. + \param xform U_XFORM object +*/ +void xform_print( + U_XFORM xform + ){ + printf("{%f,%f.%f,%f,%f,%f} ",xform.eM11,xform.eM12,xform.eM21,xform.eM22,xform.eDx,xform.eDy); +} + +/** + \brief Print a U_CIEXYZ object + \param ciexyz U_CIEXYZ object +*/ +void ciexyz_print( + U_CIEXYZ ciexyz + ){ + printf("{%d,%d.%d} ",ciexyz.ciexyzX,ciexyz.ciexyzY,ciexyz.ciexyzZ); + +} + +/** + \brief Print a U_CIEXYZTRIPLE object + \param cie3 U_CIEXYZTRIPLE object +*/ +void ciexyztriple_print( + U_CIEXYZTRIPLE cie3 + ){ + printf("{Red:"); ciexyz_print(cie3.ciexyzRed ); + printf(", Green:"); ciexyz_print(cie3.ciexyzGreen); + printf(", Blue:"); ciexyz_print(cie3.ciexyzBlue ); + printf("} "); +} +/** + \brief Print a U_LOGCOLORSPACEA object. + \param lcsa U_LOGCOLORSPACEA object +*/ +void logcolorspacea_print( + U_LOGCOLORSPACEA lcsa + ){ + printf("lcsSignature:%u ",lcsa.lcsSignature); + printf("lcsVersion:%u ", lcsa.lcsVersion ); + printf("lcsSize:%u ", lcsa.lcsSize ); + printf("lcsCSType:%d ", lcsa.lcsCSType ); + printf("lcsIntent:%d ", lcsa.lcsIntent ); + printf("lcsEndpoints:"); ciexyztriple_print(lcsa.lcsEndpoints); + printf("lcsGammaRGB: "); lcs_gammargb_print(lcsa.lcsGammaRGB ); + printf("filename:%s ", lcsa.lcsFilename ); +} + +/** + + \brief Print a U_LOGCOLORSPACEW object. + \param lcsa U_LOGCOLORSPACEW object +*/ +void logcolorspacew_print( + U_LOGCOLORSPACEW lcsa + ){ + char *string; + printf("lcsSignature:%d ",lcsa.lcsSignature); + printf("lcsVersion:%d ", lcsa.lcsVersion ); + printf("lcsSize:%d ", lcsa.lcsSize ); + printf("lcsCSType:%d ", lcsa.lcsCSType ); + printf("lcsIntent:%d ", lcsa.lcsIntent ); + printf("lcsEndpoints:"); ciexyztriple_print(lcsa.lcsEndpoints); + printf("lcsGammaRGB: "); lcs_gammargb_print(lcsa.lcsGammaRGB ); + string = U_Utf16leToUtf8(lcsa.lcsFilename, U_MAX_PATH, NULL); + printf("filename:%s ", string ); + free(string); +} + +/** + \brief Print a U_PANOSE object. + \param panose U_PANOSE object +*/ +void panose_print( + U_PANOSE panose + ){ + printf("bFamilyType:%u ", panose.bFamilyType ); + printf("bSerifStyle:%u ", panose.bSerifStyle ); + printf("bWeight:%u ", panose.bWeight ); + printf("bProportion:%u ", panose.bProportion ); + printf("bContrast:%u ", panose.bContrast ); + printf("bStrokeVariation:%u ",panose.bStrokeVariation); + printf("bArmStyle:%u ", panose.bArmStyle ); + printf("bLetterform:%u ", panose.bLetterform ); + printf("bMidline:%u ", panose.bMidline ); + printf("bXHeight:%u ", panose.bXHeight ); +} + +/** + \brief Print a U_LOGFONT object. + \param lf U_LOGFONT object +*/ +void logfont_print( + U_LOGFONT lf + ){ + char *string; + printf("lfHeight:%d ", lf.lfHeight ); + printf("lfWidth:%d ", lf.lfWidth ); + printf("lfEscapement:%d ", lf.lfEscapement ); + printf("lfOrientation:%d ", lf.lfOrientation ); + printf("lfWeight:%d ", lf.lfWeight ); + printf("lfItalic:0x%2.2X ", lf.lfItalic ); + printf("lfUnderline:0x%2.2X ", lf.lfUnderline ); + printf("lfStrikeOut:0x%2.2X ", lf.lfStrikeOut ); + printf("lfCharSet:0x%2.2X ", lf.lfCharSet ); + printf("lfOutPrecision:0x%2.2X ", lf.lfOutPrecision ); + printf("lfClipPrecision:0x%2.2X ", lf.lfClipPrecision ); + printf("lfQuality:0x%2.2X ", lf.lfQuality ); + printf("lfPitchAndFamily:0x%2.2X ", lf.lfPitchAndFamily); + string = U_Utf16leToUtf8(lf.lfFaceName, U_LF_FACESIZE, NULL); + printf("lfFaceName:%s ", string ); + free(string); +} + +/** + \brief Print a U_LOGFONT_PANOSE object. + \return U_LOGFONT_PANOSE object +*/ +void logfont_panose_print( + U_LOGFONT_PANOSE lfp + ){ + char *string; + printf("elfLogFont:"); logfont_print(lfp.elfLogFont); + string = U_Utf16leToUtf8(lfp.elfFullName, U_LF_FULLFACESIZE, NULL); + printf("elfFullName:%s ", string ); + free(string); + string = U_Utf16leToUtf8(lfp.elfStyle, U_LF_FACESIZE, NULL); + printf("elfStyle:%s ", string ); + free(string); + printf("elfVersion:%u " ,lfp.elfVersion ); + printf("elfStyleSize:%u " ,lfp.elfStyleSize); + printf("elfMatch:%u " ,lfp.elfMatch ); + printf("elfReserved:%u " ,lfp.elfReserved ); + printf("elfVendorId:"); hexbytes_print((uint8_t *)lfp.elfVendorId,U_ELF_VENDOR_SIZE); printf(" "); + printf("elfCulture:%u " ,lfp.elfCulture ); + printf("elfPanose:"); panose_print(lfp.elfPanose); +} + +/** + \brief Print a pointer to U_BITMAPINFOHEADER object. + + This may be called indirectly from WMF _print routines, where problems could occur + if the data was passed as the struct or a pointer to the struct, as the struct may not + be aligned in memory. + + \returns Actual number of color table entries. + \param Bmih pointer to a U_BITMAPINFOHEADER object +*/ +int bitmapinfoheader_print( + const char *Bmih + ){ + uint32_t utmp4; + int32_t tmp4; + int16_t tmp2; + int Colors, BitCount, Width, Height, RealColors; + + /* DIB from a WMF may not be properly aligned on a 4 byte boundary, will be aligned on a 2 byte boundary */ + + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSize), 4); printf("biSize:%u " ,utmp4 ); + memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biWidth), 4); printf("biWidth:%d " ,tmp4 ); + Width = tmp4; + memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); printf("biHeight:%d " ,tmp4 ); + Height = tmp4; + memcpy(&tmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biPlanes), 2); printf("biPlanes:%u " ,tmp2 ); + memcpy(&tmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2); printf("biBitCount:%u " ,tmp2 ); + BitCount = tmp2; + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biCompression), 4); printf("biCompression:%u " ,utmp4 ); + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSizeImage), 4); printf("biSizeImage:%u " ,utmp4 ); + memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biXPelsPerMeter), 4); printf("biXPelsPerMeter:%d " ,tmp4 ); + memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biYPelsPerMeter), 4); printf("biYPelsPerMeter:%d " ,tmp4 ); + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); printf("biClrUsed:%u " ,utmp4 ); + Colors = utmp4; + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrImportant), 4); printf("biClrImportant:%u " ,utmp4 ); + RealColors = get_real_color_icount(Colors, BitCount, Width, Height); + printf("ColorEntries:%d ",RealColors); + return(RealColors); +} + + +/** + \brief Print a Pointer to a U_BITMAPINFO object. + \param Bmi Pointer to a U_BITMAPINFO object + This may be called from WMF _print routines, where problems could occur + if the data was passed as the struct or a pointer to the struct, as the struct may not + be aligned in memory. +*/ +void bitmapinfo_print( + const char *Bmi + ){ + int i,k; + int ClrUsed; + U_RGBQUAD BmiColor; + printf("BmiHeader: "); + ClrUsed = bitmapinfoheader_print(Bmi + offsetof(U_BITMAPINFO,bmiHeader)); + if(ClrUsed){ + k= offsetof(U_BITMAPINFO,bmiColors); + for(i=0; i<ClrUsed; i++, k+= sizeof(U_RGBQUAD)){ + memcpy(&BmiColor, Bmi+k, sizeof(U_RGBQUAD)); + printf("%d:",i); rgbquad_print(BmiColor); + } + } +} + +/** + \brief Print a U_BLEND object. + \param blend a U_BLEND object +*/ +void blend_print( + U_BLEND blend + ){ + printf("Operation:%u " ,blend.Operation); + printf("Flags:%u " ,blend.Flags ); + printf("Global:%u " ,blend.Global ); + printf("Op:%u " ,blend.Op ); +} + +/** + \brief Print a pointer to a U_EXTLOGPEN object. + \param elp PU_EXTLOGPEN object +*/ +void extlogpen_print( + PU_EXTLOGPEN elp + ){ + int i; + U_STYLEENTRY *elpStyleEntry; + printf("elpPenStyle:0x%8.8X " ,elp->elpPenStyle ); + printf("elpWidth:%u " ,elp->elpWidth ); + printf("elpBrushStyle:0x%8.8X " ,elp->elpBrushStyle); + printf("elpColor"); colorref_print(elp->elpColor); + printf("elpHatch:%d " ,elp->elpHatch ); + printf("elpNumEntries:%u " ,elp->elpNumEntries); + if(elp->elpNumEntries){ + printf("elpStyleEntry:"); + elpStyleEntry = (uint32_t *) elp->elpStyleEntry; + for(i=0;i<elp->elpNumEntries;i++){ + printf("%d:%u ",i,elpStyleEntry[i]); + } + } +} + +/** + \brief Print a U_LOGPEN object. + \param lp U_LOGPEN object + +*/ +void logpen_print( + U_LOGPEN lp + ){ + printf("lopnStyle:%u " ,lp.lopnStyle ); + printf("lopnWidth:"); pointl_print( lp.lopnWidth ); + printf("lopnColor:"); colorref_print(lp.lopnColor ); +} + +/** + \brief Print a U_LOGPLTNTRY object. + \param lpny Ignore U_LOGPLTNTRY object. +*/ +void logpltntry_print( + U_LOGPLTNTRY lpny + ){ + printf("peReserved:%u " ,lpny.peReserved ); + printf("peRed:%u " ,lpny.peRed ); + printf("peGreen:%u " ,lpny.peGreen ); + printf("peBlue:%u " ,lpny.peBlue ); +} + +/** + \brief Print a pointer to a U_LOGPALETTE object. + \param lp Pointer to a U_LOGPALETTE object. +*/ +void logpalette_print( + PU_LOGPALETTE lp + ){ + int i; + PU_LOGPLTNTRY palPalEntry; + printf("palVersion:%u ", lp->palVersion ); + printf("palNumEntries:%u ", lp->palNumEntries ); + if(lp->palNumEntries){ + palPalEntry = (PU_LOGPLTNTRY) &(lp->palPalEntry); + for(i=0;i<lp->palNumEntries;i++){ + printf("%d:",i); logpltntry_print(palPalEntry[i]); + } + } +} + +/** + \brief Print a U_RGNDATAHEADER object. + \param rdh U_RGNDATAHEADER object +*/ +void rgndataheader_print( + U_RGNDATAHEADER rdh + ){ + printf("dwSize:%u ", rdh.dwSize ); + printf("iType:%u ", rdh.iType ); + printf("nCount:%u ", rdh.nCount ); + printf("nRgnSize:%u ", rdh.nRgnSize ); + printf("rclBounds:"); rectl_print(rdh.rclBounds ); +} + +/** + \brief Print a pointer to a U_RGNDATA object. + \param rd pointer to a U_RGNDATA object. +*/ +void rgndata_print( + PU_RGNDATA rd + ){ + int i; + PU_RECTL rects; + printf("rdh:"); rgndataheader_print(rd->rdh ); + if(rd->rdh.nCount){ + rects = (PU_RECTL) &(rd->Buffer); + for(i=0;i<rd->rdh.nCount;i++){ + printf("%d:",i); rectl_print(rects[i]); + } + } +} + +/** + \brief Print a U_COLORADJUSTMENT object. + \param ca U_COLORADJUSTMENT object. +*/ +void coloradjustment_print( + U_COLORADJUSTMENT ca + ){ + printf("caSize:%u " ,ca.caSize ); + printf("caFlags:%u " ,ca.caFlags ); + printf("caIlluminantIndex:%u " ,ca.caIlluminantIndex); + printf("caRedGamma:%u " ,ca.caRedGamma ); + printf("caGreenGamma:%u " ,ca.caGreenGamma ); + printf("caBlueGamma:%u " ,ca.caBlueGamma ); + printf("caReferenceBlack:%u " ,ca.caReferenceBlack ); + printf("caReferenceWhite:%u " ,ca.caReferenceWhite ); + printf("caContrast:%d " ,ca.caContrast ); + printf("caBrightness:%d " ,ca.caBrightness ); + printf("caColorfulness:%d " ,ca.caColorfulness ); + printf("caRedGreenTint:%d " ,ca.caRedGreenTint ); +} + +/** + \brief Print a U_PIXELFORMATDESCRIPTOR object. + \param pfd U_PIXELFORMATDESCRIPTOR object +*/ +void pixelformatdescriptor_print( + U_PIXELFORMATDESCRIPTOR pfd + ){ + printf("nSize:%u " ,pfd.nSize ); + printf("nVersion:%u " ,pfd.nVersion ); + printf("dwFlags:%u " ,pfd.dwFlags ); + printf("iPixelType:%u " ,pfd.iPixelType ); + printf("cColorBits:%u " ,pfd.cColorBits ); + printf("cRedBits:%u " ,pfd.cRedBits ); + printf("cRedShift:%u " ,pfd.cRedShift ); + printf("cGreenBits:%u " ,pfd.cGreenBits ); + printf("cGreenShift:%u " ,pfd.cGreenShift ); + printf("cBlueBits:%u " ,pfd.cBlueBits ); + printf("cBlueShift:%u " ,pfd.cBlueShift ); + printf("cAlphaBits:%u " ,pfd.cAlphaBits ); + printf("cAlphaShift:%u " ,pfd.cAlphaShift ); + printf("cAccumBits:%u " ,pfd.cAccumBits ); + printf("cAccumRedBits:%u " ,pfd.cAccumRedBits ); + printf("cAccumGreenBits:%u " ,pfd.cAccumGreenBits ); + printf("cAccumBlueBits:%u " ,pfd.cAccumBlueBits ); + printf("cAccumAlphaBits:%u " ,pfd.cAccumAlphaBits ); + printf("cDepthBits:%u " ,pfd.cDepthBits ); + printf("cStencilBits:%u " ,pfd.cStencilBits ); + printf("cAuxBuffers:%u " ,pfd.cAuxBuffers ); + printf("iLayerType:%u " ,pfd.iLayerType ); + printf("bReserved:%u " ,pfd.bReserved ); + printf("dwLayerMask:%u " ,pfd.dwLayerMask ); + printf("dwVisibleMask:%u " ,pfd.dwVisibleMask ); + printf("dwDamageMask:%u " ,pfd.dwDamageMask ); +} + +/** + \brief Print a Pointer to a U_EMRTEXT record + \param emt Pointer to a U_EMRTEXT record + \param record Pointer to the start of the record which contains this U_ERMTEXT + \param type 0 for 8 bit character, anything else for 16 +*/ +void emrtext_print( + const char *emt, + const char *record, + int type + ){ + int i,off; + char *string; + PU_EMRTEXT pemt = (PU_EMRTEXT) emt; + // constant part + printf("ptlReference:"); pointl_print(pemt->ptlReference); + printf("nChars:%u " ,pemt->nChars ); + printf("offString:%u " ,pemt->offString ); + if(pemt->offString){ + if(!type){ + printf("string8:<%s> ",record + pemt->offString); + } + else { + string = U_Utf16leToUtf8((uint16_t *)(record + pemt->offString), pemt->nChars, NULL); + printf("string16:<%s> ",string); + free(string); + } + } + printf("fOptions:%u " ,pemt->fOptions ); + off = sizeof(U_EMRTEXT); + if(!(pemt->fOptions & U_ETO_NO_RECT)){ + printf("rcl"); rectl_print( *((U_RECTL *)(emt+off)) ); + off += sizeof(U_RECTL); + } + printf("offDx:%u " , *((U_OFFDX *)(emt+off)) ); off = *(U_OFFDX *)(emt+off); + printf("Dx:"); + for(i=0; i<pemt->nChars; i++, off+=sizeof(uint32_t)){ + printf("%d:", *((uint32_t *)(record+off)) ); + } +} + + + + +// hide these from Doxygen +//! @cond +/* ********************************************************************************************** +These functions contain shared code used by various U_EMR*_print functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. + + + These are (mostly) ordered by U_EMR_* index number. + + The exceptions: + void core3_print(const char *name, const char *label, const char *contents) + void core7_print(const char *name, const char *field1, const char *field2, const char *contents) + void core8_print(const char *name, const char *contents, int type) + + +*********************************************************************************************** */ + + +// Functions with the same form starting with U_EMRPOLYBEZIER_print +void core1_print(const char *name, const char *contents){ + int i; + PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" cptl: %d\n",pEmr->cptl ); + printf(" Points: "); + for(i=0;i<pEmr->cptl; i++){ + printf("[%d]:",i); pointl_print(pEmr->aptl[i]); + } + printf("\n"); +} + +// Functions with the same form starting with U_EMRPOLYPOLYLINE_print +void core2_print(const char *name, const char *contents){ + int i; + PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) (contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" nPolys: %d\n",pEmr->nPolys ); + printf(" cptl: %d\n",pEmr->cptl ); + printf(" Counts: "); + for(i=0;i<pEmr->nPolys; i++){ + printf(" [%d]:%d ",i,pEmr->aPolyCounts[i] ); + } + printf("\n"); + PU_POINTL paptl = (PU_POINTL)((char *)pEmr->aPolyCounts + sizeof(uint32_t)* pEmr->nPolys); + printf(" Points: "); + for(i=0;i<pEmr->cptl; i++){ + printf(" [%d]:",i); pointl_print(paptl[i]); + } + printf("\n"); +} + + +// Functions with the same form starting with U_EMRSETMAPMODE_print +void core3_print(const char *name, const char *label, const char *contents){ + PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(contents); + if(!strcmp(label,"crColor:")){ + printf(" %-15s ",label); colorref_print(*(U_COLORREF *)&(pEmr->iMode)); printf("\n"); + } + else if(!strcmp(label,"iMode:")){ + printf(" %-15s 0x%8.8X\n",label,pEmr->iMode ); + } + else { + printf(" %-15s %d\n",label,pEmr->iMode ); + } +} + +// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_print, also U_EMRFILLPATH_print, +void core4_print(const char *name, const char *contents){ + PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( contents); + printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); +} + +// Functions with the same form starting with U_EMRPOLYBEZIER16_print +void core6_print(const char *name, const char *contents){ + int i; + PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" cpts: %d\n",pEmr->cpts ); + printf(" Points: "); + PU_POINT16 papts = (PU_POINT16)(&(pEmr->apts)); + for(i=0; i<pEmr->cpts; i++){ + printf(" [%d]:",i); point16_print(papts[i]); + } + printf("\n"); +} + + +// Records with the same form starting with U_EMRSETWINDOWEXTEX_print +// CAREFUL, in the _set equivalents all functions with two uint32_t values are mapped here, and member names differ, consequently +// print routines must supply the names of the two arguments. These cannot be null. If the second one is +// empty the values are printed as a pair {x,y}, otherwise each is printed with its own label on a separate line. +void core7_print(const char *name, const char *field1, const char *field2, const char *contents){ + PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (contents); + if(*field2){ + printf(" %-15s %d\n",field1,pEmr->pair.x); + printf(" %-15s %d\n",field2,pEmr->pair.y); + } + else { + printf(" %-15s {%d,%d}\n",field1,pEmr->pair.x,pEmr->pair.y); + } +} + +// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one +void core8_print(const char *name, const char *contents, int type){ + PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (contents); + printf(" iGraphicsMode: %u\n",pEmr->iGraphicsMode ); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" exScale: %f\n",pEmr->exScale ); + printf(" eyScale: %f\n",pEmr->eyScale ); + printf(" emrtext: "); + emrtext_print(contents + sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT),contents,type); + printf("\n"); +} + +// Functions that take a rect and a pair of points, starting with U_EMRARC_print +void core9_print(const char *name, const char *contents){ + PU_EMRARC pEmr = (PU_EMRARC) (contents); + printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); + printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); + printf(" ptlEnd: "); pointl_print(pEmr->ptlEnd); printf("\n"); +} + +// Functions with the same form starting with U_EMRPOLYPOLYLINE16_print +void core10_print(const char *name, const char *contents){ + int i; + PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" nPolys: %d\n",pEmr->nPolys ); + printf(" cpts: %d\n",pEmr->cpts ); + printf(" Counts: "); + for(i=0;i<pEmr->nPolys; i++){ + printf(" [%d]:%d ",i,pEmr->aPolyCounts[i] ); + } + printf("\n"); + printf(" Points: "); + PU_POINT16 papts = (PU_POINT16)((char *)pEmr->aPolyCounts + sizeof(uint32_t)* pEmr->nPolys); + for(i=0; i<pEmr->cpts; i++){ + printf(" [%d]:",i); point16_print(papts[i]); + } + printf("\n"); + +} + +// Functions with the same form starting with U_EMRINVERTRGN_print and U_EMRPAINTRGN_print, +void core11_print(const char *name, const char *contents){ + int i,roff; + PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" cbRgnData: %d\n",pEmr->cbRgnData); + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + roff=0; + i=1; + char *prd = (char *) &(pEmr->RgnData); + while(roff + 28 < pEmr->emr.nSize){ // up to the end of the record + printf(" RegionData:%d",i); + rgndata_print((PU_RGNDATA) (prd + roff)); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + printf("\n"); + } +} + + +// common code for U_EMRCREATEMONOBRUSH_print and U_EMRCREATEDIBPATTERNBRUSHPT_print, +void core12_print(const char *name, const char *contents){ + PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (contents); + printf(" ihBrush: %u\n",pEmr->ihBrush ); + printf(" iUsage : %u\n",pEmr->iUsage ); + printf(" offBmi : %u\n",pEmr->offBmi ); + printf(" cbBmi : %u\n",pEmr->cbBmi ); + if(pEmr->cbBmi){ + printf(" bitmap:"); + bitmapinfo_print(contents + pEmr->offBmi); + printf("\n"); + } + printf(" offBits: %u\n",pEmr->offBits ); + printf(" cbBits : %u\n",pEmr->cbBits ); +} + +// common code for U_EMRALPHABLEND_print and U_EMRTRANSPARENTBLT_print, +void core13_print(const char *name, const char *contents){ + PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); + printf(" Blend: "); blend_print(pEmr->Blend); printf("\n"); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n"); + printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n"); + printf(" iUsageSrc: %u\n",pEmr->iUsageSrc ); + printf(" offBmiSrc: %u\n",pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n",pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" bitmap:"); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n",pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n",pEmr->cbBitsSrc ); +} +//! @endcond + +/* ********************************************************************************************** +These are the core EMR functions, each creates a particular type of record. +All return these records via a char* pointer, which is NULL if the call failed. +They are listed in order by the corresponding U_EMR_* index number. +*********************************************************************************************** */ + +/** + \brief Print a pointer to a U_EMR_whatever record which has not been implemented. + \param name name of this type of record + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents){ + printf(" Not Implemented!\n"); +} + +// U_EMRHEADER 1 +/** + \brief Print a pointer to a U_EMR_HEADER record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRHEADER_print(const char *contents){ + char *string; + int p1len; + + PU_EMRHEADER pEmr = (PU_EMRHEADER)(contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" rclFrame: "); rectl_print( pEmr->rclFrame); printf("\n"); + printf(" dSignature: 0x%8.8X\n", pEmr->dSignature ); + printf(" nVersion: 0x%8.8X\n", pEmr->nVersion ); + printf(" nBytes: %d\n", pEmr->nBytes ); + printf(" nRecords: %d\n", pEmr->nRecords ); + printf(" nHandles: %d\n", pEmr->nHandles ); + printf(" sReserved: %d\n", pEmr->sReserved ); + printf(" nDescription: %d\n", pEmr->nDescription ); + printf(" offDescription: %d\n", pEmr->offDescription); + if(pEmr->offDescription){ + string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL); + printf(" Desc. A: %s\n",string); + free(string); + p1len = 2 + 2*wchar16len((uint16_t *)((char *) pEmr + pEmr->offDescription)); + string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription + p1len), pEmr->nDescription, NULL); + printf(" Desc. B: %s\n",string); + free(string); + } + printf(" nPalEntries: %d\n", pEmr->nPalEntries ); + printf(" szlDevice: {%d,%d} \n", pEmr->szlDevice.cx,pEmr->szlDevice.cy); + printf(" szlMillimeters: {%d,%d} \n", pEmr->szlMillimeters.cx,pEmr->szlMillimeters.cy); + if((pEmr->nDescription && (pEmr->offDescription >= 100)) || + (!pEmr->offDescription && pEmr->emr.nSize >= 100) + ){ + printf(" cbPixelFormat: %d\n", pEmr->cbPixelFormat ); + printf(" offPixelFormat: %d\n", pEmr->offPixelFormat); + if(pEmr->cbPixelFormat){ + printf(" PFD:"); + pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + pEmr->offPixelFormat)); + printf("\n"); + } + printf(" bOpenGL: %d\n",pEmr->bOpenGL ); + if((pEmr->nDescription && (pEmr->offDescription >= 108)) || + (pEmr->cbPixelFormat && (pEmr->offPixelFormat >=108)) || + (!pEmr->offDescription && !pEmr->cbPixelFormat && pEmr->emr.nSize >= 108) + ){ + printf(" szlMicrometers: {%d,%d} \n", pEmr->szlMicrometers.cx,pEmr->szlMicrometers.cy); + } + } +} + +// U_EMRPOLYBEZIER 2 +/** + \brief Print a pointer to a U_EMR_POLYBEZIER record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYBEZIER_print(const char *contents){ + core1_print("U_EMRPOLYBEZIER", contents); +} + +// U_EMRPOLYGON 3 +/** + \brief Print a pointer to a U_EMR_POLYGON record. + \param contents pointer to a buffer holding all EMR records + */ +void U_EMRPOLYGON_print(const char *contents){ + core1_print("U_EMRPOLYGON", contents); +} + + +// U_EMRPOLYLINE 4 +/** + \brief Print a pointer to a U_EMR_POLYLINE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYLINE_print(const char *contents){ + core1_print("U_EMRPOLYLINE", contents); +} + +// U_EMRPOLYBEZIERTO 5 +/** + \brief Print a pointer to a U_EMR_POLYBEZIERTO record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYBEZIERTO_print(const char *contents){ + core1_print("U_EMRPOLYBEZIERTO", contents); +} + +// U_EMRPOLYLINETO 6 +/** + \brief Print a pointer to a U_EMR_POLYLINETO record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYLINETO_print(const char *contents){ + core1_print("U_EMRPOLYLINETO", contents); +} + +// U_EMRPOLYPOLYLINE 7 +/** + \brief Print a pointer to a U_EMR_POLYPOLYLINE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYPOLYLINE_print(const char *contents){ + core2_print("U_EMRPOLYPOLYLINE", contents); +} + +// U_EMRPOLYPOLYGON 8 +/** + \brief Print a pointer to a U_EMR_POLYPOLYGON record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYPOLYGON_print(const char *contents){ + core2_print("U_EMRPOLYPOLYGON", contents); +} + +// U_EMRSETWINDOWEXTEX 9 +/** + \brief Print a pointer to a U_EMR_SETWINDOWEXTEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETWINDOWEXTEX_print(const char *contents){ + core7_print("U_EMRSETWINDOWEXTEX", "szlExtent:","",contents); +} + +// U_EMRSETWINDOWORGEX 10 +/** + \brief Print a pointer to a U_EMR_SETWINDOWORGEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETWINDOWORGEX_print(const char *contents){ + core7_print("U_EMRSETWINDOWORGEX", "ptlOrigin:","",contents); +} + +// U_EMRSETVIEWPORTEXTEX 11 +/** + \brief Print a pointer to a U_EMR_SETVIEWPORTEXTEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETVIEWPORTEXTEX_print(const char *contents){ + core7_print("U_EMRSETVIEWPORTEXTEX", "szlExtent:","",contents); +} + +// U_EMRSETVIEWPORTORGEX 12 +/** + \brief Print a pointer to a U_EMR_SETVIEWPORTORGEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETVIEWPORTORGEX_print(const char *contents){ + core7_print("U_EMRSETVIEWPORTORGEX", "ptlOrigin:","",contents); +} + +// U_EMRSETBRUSHORGEX 13 +/** + \brief Print a pointer to a U_EMR_SETBRUSHORGEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETBRUSHORGEX_print(const char *contents){ + core7_print("U_EMRSETBRUSHORGEX", "ptlOrigin:","",contents); +} + +// U_EMREOF 14 +/** + \brief Print a pointer to a U_EMR_EOF record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREOF_print(const char *contents){ + PU_EMREOF pEmr = (PU_EMREOF)(contents); + printf(" cbPalEntries: %u\n", pEmr->cbPalEntries ); + printf(" offPalEntries: %u\n", pEmr->offPalEntries); + if(pEmr->cbPalEntries){ + printf(" PE:"); + logpalette_print( (PU_LOGPALETTE)(contents + pEmr->offPalEntries)); + printf("\n"); + } +} + + +// U_EMRSETPIXELV 15 +/** + \brief Print a pointer to a U_EMR_SETPIXELV record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETPIXELV_print(const char *contents){ + PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(contents); + printf(" ptlPixel: "); pointl_print( pEmr->ptlPixel); printf("\n"); + printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n"); +} + + +// U_EMRSETMAPPERFLAGS 16 +/** + \brief Print a pointer to a U_EMR_SETMAPPERFLAGS record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETMAPPERFLAGS_print(const char *contents){ + PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(contents); + printf(" dwFlags: %u\n",pEmr->dwFlags); +} + + +// U_EMRSETMAPMODE 17 +/** + \brief Print a pointer to a U_EMR_SETMAPMODE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETMAPMODE_print(const char *contents){ + core3_print("U_EMRSETMAPMODE", "iMode:", contents); +} + +// U_EMRSETBKMODE 18 +/** + \brief Print a pointer to a U_EMR_SETBKMODE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETBKMODE_print(const char *contents){ + core3_print("U_EMRSETBKMODE", "iMode:", contents); +} + +// U_EMRSETPOLYFILLMODE 19 +/** + \brief Print a pointer to a U_EMR_SETPOLYFILLMODE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETPOLYFILLMODE_print(const char *contents){ + core3_print("U_EMRSETPOLYFILLMODE", "iMode:", contents); +} + +// U_EMRSETROP2 20 +/** + \brief Print a pointer to a U_EMR_SETROP2 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETROP2_print(const char *contents){ + core3_print("U_EMRSETROP2", "dwRop:", contents); +} + +// U_EMRSETSTRETCHBLTMODE 21 +/** + \brief Print a pointer to a U_EMR_SETSTRETCHBLTMODE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETSTRETCHBLTMODE_print(const char *contents){ + core3_print("U_EMRSETSTRETCHBLTMODE", "iMode:", contents); +} + +// U_EMRSETTEXTALIGN 22 +/** + \brief Print a pointer to a U_EMR_SETTEXTALIGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETTEXTALIGN_print(const char *contents){ + core3_print("U_EMRSETTEXTALIGN", "iMode:", contents); +} + +// U_EMRSETCOLORADJUSTMENT 23 +/** + \brief Print a pointer to a U_EMR_SETCOLORADJUSTMENT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETCOLORADJUSTMENT_print(const char *contents){ + PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(contents); + printf(" ColorAdjustment:"); + coloradjustment_print(pEmr->ColorAdjustment); + printf("\n"); +} + +// U_EMRSETTEXTCOLOR 24 +/** + \brief Print a pointer to a U_EMR_SETTEXTCOLOR record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETTEXTCOLOR_print(const char *contents){ + core3_print("U_EMRSETTEXTCOLOR", "crColor:", contents); +} + +// U_EMRSETBKCOLOR 25 +/** + \brief Print a pointer to a U_EMR_SETBKCOLOR record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETBKCOLOR_print(const char *contents){ + core3_print("U_EMRSETBKCOLOR", "crColor:", contents); +} + +// U_EMROFFSETCLIPRGN 26 +/** + \brief Print a pointer to a U_EMR_OFFSETCLIPRGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMROFFSETCLIPRGN_print(const char *contents){ + core7_print("U_EMROFFSETCLIPRGN", "ptl:","",contents); +} + +// U_EMRMOVETOEX 27 +/** + \brief Print a pointer to a U_EMR_MOVETOEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRMOVETOEX_print(const char *contents){ + core7_print("U_EMRMOVETOEX", "ptl:","",contents); +} + +// U_EMRSETMETARGN 28 +/** + \brief Print a pointer to a U_EMR_SETMETARGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETMETARGN_print(const char *contents){ +} + +// U_EMREXCLUDECLIPRECT 29 +/** + \brief Print a pointer to a U_EMR_EXCLUDECLIPRECT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXCLUDECLIPRECT_print(const char *contents){ + core4_print("U_EMREXCLUDECLIPRECT", contents); +} + +// U_EMRINTERSECTCLIPRECT 30 +/** + \brief Print a pointer to a U_EMR_INTERSECTCLIPRECT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRINTERSECTCLIPRECT_print(const char *contents){ + core4_print("U_EMRINTERSECTCLIPRECT", contents); +} + +// U_EMRSCALEVIEWPORTEXTEX 31 +/** + \brief Print a pointer to a U_EMR_SCALEVIEWPORTEXTEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSCALEVIEWPORTEXTEX_print(const char *contents){ + core4_print("U_EMRSCALEVIEWPORTEXTEX", contents); +} + + +// U_EMRSCALEWINDOWEXTEX 32 +/** + \brief Print a pointer to a U_EMR_SCALEWINDOWEXTEX record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSCALEWINDOWEXTEX_print(const char *contents){ + core4_print("U_EMRSCALEWINDOWEXTEX", contents); +} + +// U_EMRSAVEDC 33 +/** + \brief Print a pointer to a U_EMR_SAVEDC record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSAVEDC_print(const char *contents){ +} + +// U_EMRRESTOREDC 34 +/** + \brief Print a pointer to a U_EMR_RESTOREDC record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRRESTOREDC_print(const char *contents){ + core3_print("U_EMRRESTOREDC", "iRelative:", contents); +} + +// U_EMRSETWORLDTRANSFORM 35 +/** + \brief Print a pointer to a U_EMR_SETWORLDTRANSFORM record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETWORLDTRANSFORM_print(const char *contents){ + PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(contents); + printf(" xform:"); + xform_print(pEmr->xform); + printf("\n"); +} + +// U_EMRMODIFYWORLDTRANSFORM 36 +/** + \brief Print a pointer to a U_EMR_MODIFYWORLDTRANSFORM record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents){ + PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(contents); + printf(" xform:"); + xform_print(pEmr->xform); + printf("\n"); + printf(" iMode: %u\n", pEmr->iMode ); +} + +// U_EMRSELECTOBJECT 37 +/** + \brief Print a pointer to a U_EMR_SELECTOBJECT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSELECTOBJECT_print(const char *contents){ + PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(contents); + if(pEmr->ihObject & U_STOCK_OBJECT){ + printf(" StockObject: 0x%8.8X\n", pEmr->ihObject ); + } + else { + printf(" ihObject: %u\n", pEmr->ihObject ); + } +} + +// U_EMRCREATEPEN 38 +/** + \brief Print a pointer to a U_EMR_CREATEPEN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATEPEN_print(const char *contents){ + PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(contents); + printf(" ihPen: %u\n", pEmr->ihPen ); + printf(" lopn: "); logpen_print(pEmr->lopn); printf("\n"); +} + +// U_EMRCREATEBRUSHINDIRECT 39 +/** + \brief Print a pointer to a U_EMR_CREATEBRUSHINDIRECT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATEBRUSHINDIRECT_print(const char *contents){ + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(contents); + printf(" ihBrush: %u\n", pEmr->ihBrush ); + printf(" lb: "); logbrush_print(pEmr->lb); printf("\n"); +} + +// U_EMRDELETEOBJECT 40 +/** + \brief Print a pointer to a U_EMR_DELETEOBJECT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRDELETEOBJECT_print(const char *contents){ + PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(contents); + printf(" ihObject: %u\n", pEmr->ihObject ); +} + +// U_EMRANGLEARC 41 +/** + \brief Print a pointer to a U_EMR_ANGLEARC record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRANGLEARC_print(const char *contents){ + PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(contents); + printf(" ptlCenter: "), pointl_print(pEmr->ptlCenter ); printf("\n"); + printf(" nRadius: %u\n", pEmr->nRadius ); + printf(" eStartAngle: %f\n", pEmr->eStartAngle ); + printf(" eSweepAngle: %f\n", pEmr->eSweepAngle ); +} + +// U_EMRELLIPSE 42 +/** + \brief Print a pointer to a U_EMR_ELLIPSE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRELLIPSE_print(const char *contents){ + core4_print("U_EMRELLIPSE", contents); +} + +// U_EMRRECTANGLE 43 +/** + \brief Print a pointer to a U_EMR_RECTANGLE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRRECTANGLE_print(const char *contents){ + core4_print("U_EMRRECTANGLE", contents); +} + +// U_EMRROUNDRECT 44 +/** + \brief Print a pointer to a U_EMR_ROUNDRECT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRROUNDRECT_print(const char *contents){ + PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(contents); + printf(" rclBox: "), rectl_print(pEmr->rclBox ); printf("\n"); + printf(" szlCorner: "), sizel_print(pEmr->szlCorner ); printf("\n"); +} + +// U_EMRARC 45 +/** + \brief Print a pointer to a U_EMR_ARC record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRARC_print(const char *contents){ + core9_print("U_EMRARC", contents); +} + +// U_EMRCHORD 46 +/** + \brief Print a pointer to a U_EMR_CHORD record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCHORD_print(const char *contents){ + core9_print("U_EMRCHORD", contents); +} + +// U_EMRPIE 47 +/** + \brief Print a pointer to a U_EMR_PIE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPIE_print(const char *contents){ + core9_print("U_EMRPIE", contents); +} + +// U_EMRSELECTPALETTE 48 +/** + \brief Print a pointer to a U_EMR_SELECTPALETTE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSELECTPALETTE_print(const char *contents){ + core3_print("U_EMRSELECTPALETTE", "ihPal:", contents); +} + +// U_EMRCREATEPALETTE 49 +/** + \brief Print a pointer to a U_EMR_CREATEPALETTE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATEPALETTE_print(const char *contents){ + PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(contents); + printf(" ihPal: %u\n",pEmr->ihPal); + printf(" lgpl: "), logpalette_print( (PU_LOGPALETTE)&(pEmr->lgpl) ); printf("\n"); +} + +// U_EMRSETPALETTEENTRIES 50 +/** + \brief Print a pointer to a U_EMR_SETPALETTEENTRIES record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETPALETTEENTRIES_print(const char *contents){ + int i; + PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents); + printf(" ihPal: %u\n",pEmr->ihPal); + printf(" iStart: %u\n",pEmr->iStart); + printf(" cEntries: %u\n",pEmr->cEntries); + if(pEmr->cEntries){ + printf(" PLTEntries:"); + PU_LOGPLTNTRY aPalEntries = (PU_LOGPLTNTRY) &(pEmr->aPalEntries); + for(i=0; i<pEmr->cEntries; i++){ + printf("%d:",i); logpltntry_print(aPalEntries[i]); + } + printf("\n"); + } +} + +// U_EMRRESIZEPALETTE 51 +/** + \brief Print a pointer to a U_EMR_RESIZEPALETTE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRRESIZEPALETTE_print(const char *contents){ + core7_print("U_EMRRESIZEPALETTE", "ihPal:","cEntries",contents); +} + +// U_EMRREALIZEPALETTE 52 +/** + \brief Print a pointer to a U_EMR_REALIZEPALETTE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRREALIZEPALETTE_print(const char *contents){ +} + +// U_EMREXTFLOODFILL 53 +/** + \brief Print a pointer to a U_EMR_EXTFLOODFILL record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXTFLOODFILL_print(const char *contents){ + PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(contents); + printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); + printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n"); + printf(" iMode: %u\n",pEmr->iMode); +} + +// U_EMRLINETO 54 +/** + \brief Print a pointer to a U_EMR_LINETO record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRLINETO_print(const char *contents){ + core7_print("U_EMRLINETO", "ptl:","",contents); +} + +// U_EMRARCTO 55 +/** + \brief Print a pointer to a U_EMR_ARCTO record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRARCTO_print(const char *contents){ + core9_print("U_EMRARCTO", contents); +} + +// U_EMRPOLYDRAW 56 +/** + \brief Print a pointer to a U_EMR_POLYDRAW record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYDRAW_print(const char *contents){ + int i; + PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" cptl: %d\n",pEmr->cptl ); + printf(" Points: "); + for(i=0;i<pEmr->cptl; i++){ + printf(" [%d]:",i); + pointl_print(pEmr->aptl[i]); + } + printf("\n"); + printf(" Types: "); + for(i=0;i<pEmr->cptl; i++){ + printf(" [%d]:%u ",i,pEmr->abTypes[i]); + } + printf("\n"); +} + +// U_EMRSETARCDIRECTION 57 +/** + \brief Print a pointer to a U_EMR_SETARCDIRECTION record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETARCDIRECTION_print(const char *contents){ + core3_print("U_EMRSETARCDIRECTION","arcDirection:", contents); +} + +// U_EMRSETMITERLIMIT 58 +/** + \brief Print a pointer to a U_EMR_SETMITERLIMIT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETMITERLIMIT_print(const char *contents){ + core3_print("U_EMRSETMITERLIMIT", "eMiterLimit:", contents); +} + + +// U_EMRBEGINPATH 59 +/** + \brief Print a pointer to a U_EMR_BEGINPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRBEGINPATH_print(const char *contents){ +} + +// U_EMRENDPATH 60 +/** + \brief Print a pointer to a U_EMR_ENDPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRENDPATH_print(const char *contents){ +} + +// U_EMRCLOSEFIGURE 61 +/** + \brief Print a pointer to a U_EMR_CLOSEFIGURE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCLOSEFIGURE_print(const char *contents){ +} + +// U_EMRFILLPATH 62 +/** + \brief Print a pointer to a U_EMR_FILLPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRFILLPATH_print(const char *contents){ + core4_print("U_EMRFILLPATH", contents); +} + +// U_EMRSTROKEANDFILLPATH 63 +/** + \brief Print a pointer to a U_EMR_STROKEANDFILLPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSTROKEANDFILLPATH_print(const char *contents){ + core4_print("U_EMRSTROKEANDFILLPATH", contents); +} + +// U_EMRSTROKEPATH 64 +/** + \brief Print a pointer to a U_EMR_STROKEPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSTROKEPATH_print(const char *contents){ + core4_print("U_EMRSTROKEPATH", contents); +} + +// U_EMRFLATTENPATH 65 +/** + \brief Print a pointer to a U_EMR_FLATTENPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRFLATTENPATH_print(const char *contents){ +} + +// U_EMRWIDENPATH 66 +/** + \brief Print a pointer to a U_EMR_WIDENPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRWIDENPATH_print(const char *contents){ +} + +// U_EMRSELECTCLIPPATH 67 +/** + \brief Print a pointer to a U_EMR_SELECTCLIPPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSELECTCLIPPATH_print(const char *contents){ + core3_print("U_EMRSELECTCLIPPATH", "iMode:", contents); +} + +// U_EMRABORTPATH 68 +/** + \brief Print a pointer to a U_EMR_ABORTPATH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRABORTPATH_print(const char *contents){ +} + +// U_EMRUNDEF69 69 +#define U_EMRUNDEF69_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF69",A) + +// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific) +/** + \brief Print a pointer to a U_EMR_COMMENT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCOMMENT_print(const char *contents){ + char *string; + char *src; + uint32_t cIdent,cbData; + PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(contents); + + /* There are several different types of comments */ + + cbData = pEmr->cbData; + printf(" cbData: %d\n",cbData ); + src = (char *)&(pEmr->Data); // default + if(cbData >= 4){ + cIdent = *(uint32_t *)&(pEmr->Data); + if( cIdent == U_EMR_COMMENT_PUBLIC ){ + printf(" cIdent: Public\n"); + PU_EMRCOMMENT_PUBLIC pEmrp = (PU_EMRCOMMENT_PUBLIC) pEmr; + printf(" pcIdent: %8.8x\n",pEmrp->pcIdent); + src = (char *)&(pEmrp->Data); + cbData -= 8; + } + else if(cIdent == U_EMR_COMMENT_SPOOL ){ + printf(" cIdent: Spool\n"); + PU_EMRCOMMENT_SPOOL pEmrs = (PU_EMRCOMMENT_SPOOL) pEmr; + printf(" esrIdent: %8.8x\n",pEmrs->esrIdent); + src = (char *)&(pEmrs->Data); + cbData -= 8; + } + else if(cIdent == U_EMR_COMMENT_EMFPLUSRECORD){ + printf(" cIdent: EMF+\n"); + PU_EMRCOMMENT_EMFPLUS pEmrpl = (PU_EMRCOMMENT_EMFPLUS) pEmr; + src = (char *)&(pEmrpl->Data); + cbData -= 4; + } + else { + printf(" cIdent: not (Public or Spool or EMF+)\n"); + } + } + if(cbData){ // The data may not be printable, but try it just in case + string = malloc(cbData + 1); + (void)strncpy(string, src, cbData); + string[cbData] = '\0'; // it might not be terminated - it might not even be text! + printf(" Data: <%s>\n",string); + free(string); + } + +} + +// U_EMRFILLRGN 71 +/** + \brief Print a pointer to a U_EMR_FILLRGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRFILLRGN_print(const char *contents){ + int i,roff; + PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" cbRgnData: %u\n",pEmr->cbRgnData); + printf(" ihBrush: %u\n",pEmr->ihBrush); + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + roff=0; + i=1; + char *prd = (char *) &(pEmr->RgnData); + while(roff + 28 < pEmr->emr.nSize){ // up to the end of the record + printf(" RegionData[%d]: ",i); rgndata_print((PU_RGNDATA) (prd + roff)); printf("\n"); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } +} + +// U_EMRFRAMERGN 72 +/** + \brief Print a pointer to a U_EMR_FRAMERGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRFRAMERGN_print(const char *contents){ + int i,roff; + PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents); + printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); + printf(" cbRgnData: %u\n",pEmr->cbRgnData); + printf(" ihBrush: %u\n",pEmr->ihBrush); + printf(" szlStroke: "), sizel_print(pEmr->szlStroke ); printf("\n"); + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + roff=0; + i=1; + char *prd = (char *) &(pEmr->RgnData); + while(roff + 28 < pEmr->emr.nSize){ // up to the end of the record + printf(" RegionData[%d]: ",i); rgndata_print((PU_RGNDATA) (prd + roff)); printf("\n"); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } +} + +// U_EMRINVERTRGN 73 +/** + \brief Print a pointer to a U_EMR_INVERTRGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRINVERTRGN_print(const char *contents){ + core11_print("U_EMRINVERTRGN", contents); +} + +// U_EMRPAINTRGN 74 +/** + \brief Print a pointer to a U_EMR_PAINTRGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPAINTRGN_print(const char *contents){ + core11_print("U_EMRPAINTRGN", contents); +} + +// U_EMREXTSELECTCLIPRGN 75 +/** + \brief Print a pointer to a U_EMR_EXTSELECTCLIPRGN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXTSELECTCLIPRGN_print(const char *contents){ + int i,roff; + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents); + printf(" cbRgnData: %u\n",pEmr->cbRgnData); + printf(" iMode: %u\n",pEmr->iMode); + // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. + char *prd = (char *) &(pEmr->RgnData); + i=roff=0; + while(roff + 16 < pEmr->emr.nSize){ // stop at end of the record + printf(" RegionData[%d]: ",i++); rgndata_print((PU_RGNDATA) (prd + roff)); printf("\n"); + roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); + } +} + +// U_EMRBITBLT 76 +/** + \brief Print a pointer to a U_EMR_BITBLT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRBITBLT_print(const char *contents){ + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); + printf(" dwRop : %u\n", pEmr->dwRop ); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n"); + printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n"); + printf(" iUsageSrc: %u\n", pEmr->iUsageSrc ); + printf(" offBmiSrc: %u\n", pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc ); +} + +// U_EMRSTRETCHBLT 77 +/** + \brief Print a pointer to a U_EMR_STRETCHBLT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSTRETCHBLT_print(const char *contents){ + PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); + printf(" dwRop : %u\n", pEmr->dwRop ); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n"); + printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n"); + printf(" iUsageSrc: %u\n", pEmr->iUsageSrc ); + printf(" offBmiSrc: %u\n", pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc ); + printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n"); +} + +// U_EMRMASKBLT 78 +/** + \brief Print a pointer to a U_EMR_MASKBLT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRMASKBLT_print(const char *contents){ + PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); + printf(" dwRop : %u\n", pEmr->dwRop ); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n"); + printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n"); + printf(" iUsageSrc: %u\n", pEmr->iUsageSrc ); + printf(" offBmiSrc: %u\n", pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" Src bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc ); + printf(" Mask: "); pointl_print(pEmr->Mask); printf("\n"); + printf(" iUsageMask: %u\n", pEmr->iUsageMask ); + printf(" offBmiMask: %u\n", pEmr->offBmiMask ); + printf(" cbBmiMask: %u\n", pEmr->cbBmiMask ); + if(pEmr->cbBmiMask){ + printf(" Mask bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiMask); + printf("\n"); + } + printf(" offBitsMask: %u\n", pEmr->offBitsMask ); + printf(" cbBitsMask: %u\n", pEmr->cbBitsMask ); +} + +// U_EMRPLGBLT 79 +/** + \brief Print a pointer to a U_EMR_PLGBLT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPLGBLT_print(const char *contents){ + PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" aptlDst(UL): "); pointl_print(pEmr->aptlDst[0]); printf("\n"); + printf(" aptlDst(UR): "); pointl_print(pEmr->aptlDst[1]); printf("\n"); + printf(" aptlDst(LL): "); pointl_print(pEmr->aptlDst[2]); printf("\n"); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n"); + printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n"); + printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n"); + printf(" iUsageSrc: %u\n", pEmr->iUsageSrc ); + printf(" offBmiSrc: %u\n", pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" Src bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc ); + printf(" Mask: "); pointl_print(pEmr->Mask); printf("\n"); + printf(" iUsageMsk: %u\n", pEmr->iUsageMask ); + printf(" offBmiMask: %u\n", pEmr->offBmiMask ); + printf(" cbBmiMask: %u\n", pEmr->cbBmiMask ); + if(pEmr->cbBmiMask){ + printf(" Mask bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiMask); + printf("\n"); + } + printf(" offBitsMask: %u\n", pEmr->offBitsMask ); + printf(" cbBitsMask: %u\n", pEmr->cbBitsMask ); +} + +// U_EMRSETDIBITSTODEVICE 80 +/** + \brief Print a pointer to a U_EMRSETDIBITSTODEVICE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETDIBITSTODEVICE_print(const char *contents){ + PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n"); + printf(" offBmiSrc: %u\n", pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" Src bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc ); + printf(" iUsageSrc: %u\n", pEmr->iUsageSrc ); + printf(" iStartScan: %u\n", pEmr->iStartScan ); + printf(" cScans : %u\n", pEmr->cScans ); +} + +// U_EMRSTRETCHDIBITS 81 +/** + \brief Print a pointer to a U_EMR_STRETCHDIBITS record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSTRETCHDIBITS_print(const char *contents){ + PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); + printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n"); + printf(" offBmiSrc: %u\n", pEmr->offBmiSrc ); + printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); + if(pEmr->cbBmiSrc){ + printf(" Src bitmap: "); + bitmapinfo_print(contents + pEmr->offBmiSrc); + printf("\n"); + } + printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); + printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc ); + printf(" iUsageSrc: %u\n", pEmr->iUsageSrc ); + printf(" dwRop : %u\n", pEmr->dwRop ); + printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); +} + +// U_EMREXTCREATEFONTINDIRECTW_print 82 +/** + \brief Print a pointer to a U_EMR_EXTCREATEFONTINDIRECTW record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXTCREATEFONTINDIRECTW_print(const char *contents){ + PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (contents); + printf(" ihFont: %u\n",pEmr->ihFont ); + printf(" Font: "); + if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ // holds logfont_panose + logfont_panose_print(pEmr->elfw); + } + else { // holds logfont + logfont_print( *(PU_LOGFONT) &(pEmr->elfw)); + } + printf("\n"); +} + +// U_EMREXTTEXTOUTA 83 +/** + \brief Print a pointer to a U_EMR_EXTTEXTOUTA record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXTTEXTOUTA_print(const char *contents){ + core8_print("U_EMREXTTEXTOUTA", contents, 0); +} + +// U_EMREXTTEXTOUTW 84 +/** + \brief Print a pointer to a U_EMR_EXTTEXTOUTW record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXTTEXTOUTW_print(const char *contents){ + core8_print("U_EMREXTTEXTOUTW", contents, 1); +} + +// U_EMRPOLYBEZIER16 85 +/** + \brief Print a pointer to a U_EMR_POLYBEZIER16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYBEZIER16_print(const char *contents){ + core6_print("U_EMRPOLYBEZIER16", contents); +} + +// U_EMRPOLYGON16 86 +/** + \brief Print a pointer to a U_EMR_POLYGON16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYGON16_print(const char *contents){ + core6_print("U_EMRPOLYGON16", contents); +} + +// U_EMRPOLYLINE16 87 +/** + \brief Print a pointer to a U_EMR_POLYLINE16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYLINE16_print(const char *contents){ + core6_print("U_EMRPOLYLINE16", contents); +} + +// U_EMRPOLYBEZIERTO16 88 +/** + \brief Print a pointer to a U_EMR_POLYBEZIERTO16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYBEZIERTO16_print(const char *contents){ + core6_print("U_EMRPOLYBEZIERTO16", contents); +} + +// U_EMRPOLYLINETO16 89 +/** + \brief Print a pointer to a U_EMR_POLYLINETO16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYLINETO16_print(const char *contents){ + core6_print("U_EMRPOLYLINETO16", contents); +} + +// U_EMRPOLYPOLYLINE16 90 +/** + \brief Print a pointer to a U_EMR_POLYPOLYLINE16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYPOLYLINE16_print(const char *contents){ + core10_print("U_EMRPOLYPOLYLINE16", contents); +} + +// U_EMRPOLYPOLYGON16 91 +/** + \brief Print a pointer to a U_EMR_POLYPOLYGON16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYPOLYGON16_print(const char *contents){ + core10_print("U_EMRPOLYPOLYGON16", contents); +} + + +// U_EMRPOLYDRAW16 92 +/** + \brief Print a pointer to a U_EMR_POLYDRAW16 record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPOLYDRAW16_print(const char *contents){ + int i; + PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" cpts: %d\n",pEmr->cpts ); + printf(" Points: "); + for(i=0;i<pEmr->cpts; i++){ + printf(" [%d]:",i); + point16_print(pEmr->apts[i]); + } + printf("\n"); + printf(" Types: "); + for(i=0;i<pEmr->cpts; i++){ + printf(" [%d]:%u ",i,pEmr->abTypes[i]); + } + printf("\n"); +} + +// U_EMRCREATEMONOBRUSH 93 +/** + \brief Print a pointer to a U_EMR_CREATEMONOBRUSH record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATEMONOBRUSH_print(const char *contents){ + core12_print("U_EMRCREATEMONOBRUSH", contents); +} + +// U_EMRCREATEDIBPATTERNBRUSHPT_print 94 +/** + \brief Print a pointer to a U_EMR_CREATEDIBPATTERNBRUSHPT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATEDIBPATTERNBRUSHPT_print(const char *contents){ + core12_print("U_EMRCREATEDIBPATTERNBRUSHPT", contents); +} + + +// U_EMREXTCREATEPEN 95 +/** + \brief Print a pointer to a U_EMR_EXTCREATEPEN record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMREXTCREATEPEN_print(const char *contents){ + PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(contents); + printf(" ihPen: %u\n", pEmr->ihPen ); + printf(" offBmi: %u\n", pEmr->offBmi ); + printf(" cbBmi: %u\n", pEmr->cbBmi ); + if(pEmr->cbBmi){ + printf(" bitmap: "); + bitmapinfo_print(contents + pEmr->offBmi); + printf("\n"); + } + printf(" offBits: %u\n", pEmr->offBits ); + printf(" cbBits: %u\n", pEmr->cbBits ); + printf(" elp: "); extlogpen_print((PU_EXTLOGPEN) &(pEmr->elp)); printf("\n"); +} + +// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT +#define U_EMRPOLYTEXTOUTA_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTA",A) +// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT +#define U_EMRPOLYTEXTOUTW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTW",A) + +// U_EMRSETICMMODE 98 +/** + \brief Print a pointer to a U_EMR_SETICMMODE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETICMMODE_print(const char *contents){ + core3_print("U_EMRSETICMMODE", "iMode:", contents); +} + +// U_EMRCREATECOLORSPACE 99 +/** + \brief Print a pointer to a U_EMR_CREATECOLORSPACE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATECOLORSPACE_print(const char *contents){ + PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(contents); + printf(" ihCS: %u\n", pEmr->ihCS ); + printf(" ColorSpace: "); logcolorspacea_print(pEmr->lcs); printf("\n"); +} + +// U_EMRSETCOLORSPACE 100 +/** + \brief Print a pointer to a U_EMR_SETCOLORSPACE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETCOLORSPACE_print(const char *contents){ + core3_print("U_EMRSETCOLORSPACE", "ihCS:", contents); +} + +// U_EMRDELETECOLORSPACE 101 +/** + \brief Print a pointer to a U_EMR_DELETECOLORSPACE record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRDELETECOLORSPACE_print(const char *contents){ + core3_print("U_EMRDELETECOLORSPACE", "ihCS:", contents); +} + +// U_EMRGLSRECORD 102 Not implemented +#define U_EMRGLSRECORD_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRGLSRECORD",A) +// U_EMRGLSBOUNDEDRECORD 103 Not implemented +#define U_EMRGLSBOUNDEDRECORD_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRGLSBOUNDEDRECORD",A) + +// U_EMRPIXELFORMAT 104 +/** + \brief Print a pointer to a U_EMR_PIXELFORMAT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRPIXELFORMAT_print(const char *contents){ + PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(contents); + printf(" Pfd: "); pixelformatdescriptor_print(pEmr->pfd); printf("\n"); +} + +// U_EMRDRAWESCAPE 105 Not implemented +#define U_EMRDRAWESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRDRAWESCAPE",A) +// U_EMREXTESCAPE 106 Not implemented +#define U_EMREXTESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMREXTESCAPE",A) +// U_EMRUNDEF107 107 Not implemented +#define U_EMRUNDEF107_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF107",A) + +// U_EMRSMALLTEXTOUT 108 +/** + \brief Print a pointer to a U_EMR_SMALLTEXTOUT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSMALLTEXTOUT_print(const char *contents){ + int roff; + char *string; + PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(contents); + printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); + printf(" cChars: %u\n", pEmr->cChars ); + printf(" fuOptions: 0x%8.8X\n", pEmr->fuOptions ); + printf(" iGraphicsMode: 0x%8.8X\n", pEmr->iGraphicsMode ); + printf(" exScale: %f\n", pEmr->exScale ); + printf(" eyScale: %f\n", pEmr->eyScale ); + roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields + if(!(pEmr->fuOptions & U_ETO_NO_RECT)){ + printf(" rclBounds: "); rectl_print( *(PU_RECTL) (contents + roff)); printf("\n"); + roff += sizeof(U_RECTL); + } + if(pEmr->fuOptions & U_ETO_SMALL_CHARS){ + printf(" Text8: <%.*s>\n",pEmr->cChars,contents+roff); /* May not be null terminated */ + } + else { + string = U_Utf16leToUtf8((uint16_t *)(contents+roff), pEmr->cChars, NULL); + printf(" Text16: <%s>\n",contents+roff); + free(string); + } +} + +// U_EMRFORCEUFIMAPPING 109 Not implemented +#define U_EMRFORCEUFIMAPPING_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRFORCEUFIMAPPING",A) +// U_EMRNAMEDESCAPE 110 Not implemented +#define U_EMRNAMEDESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRNAMEDESCAPE",A) +// U_EMRCOLORCORRECTPALETTE 111 Not implemented +#define U_EMRCOLORCORRECTPALETTE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRCOLORCORRECTPALETTE",A) +// U_EMRSETICMPROFILEA 112 Not implemented +#define U_EMRSETICMPROFILEA_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEA",A) +// U_EMRSETICMPROFILEW 113 Not implemented +#define U_EMRSETICMPROFILEW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEW",A) + +// U_EMRALPHABLEND 114 +/** + \brief Print a pointer to a U_EMR_ALPHABLEND record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRALPHABLEND_print(const char *contents){ + core13_print("U_EMRALPHABLEND", contents); +} + +// U_EMRSETLAYOUT 115 +/** + \brief Print a pointer to a U_EMR_SETLAYOUT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRSETLAYOUT_print(const char *contents){ + core3_print("U_EMRSETLAYOUT", "iMode:", contents); +} + +// U_EMRTRANSPARENTBLT 116 +/** + \brief Print a pointer to a U_EMR_TRANSPARENTBLT record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRTRANSPARENTBLT_print(const char *contents){ + core13_print("U_EMRTRANSPARENTBLT", contents); +} + +// U_EMRUNDEF117 117 Not implemented +#define U_EMRUNDEF117_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF117",A) +// U_EMRGRADIENTFILL 118 +/** + \brief Print a pointer to a U_EMR_GRADIENTFILL record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRGRADIENTFILL_print(const char *contents){ + int i; + PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents); + printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); + printf(" nTriVert: %u\n", pEmr->nTriVert ); + printf(" nGradObj: %u\n", pEmr->nGradObj ); + printf(" ulMode: %u\n", pEmr->ulMode ); + contents += sizeof(U_EMRGRADIENTFILL); + if(pEmr->nTriVert){ + printf(" TriVert: "); + for(i=0; i<pEmr->nTriVert; i++, contents+=sizeof(U_TRIVERTEX)){ + trivertex_print(*(PU_TRIVERTEX)(contents)); + } + printf("\n"); + } + if(pEmr->nGradObj){ + printf(" GradObj: "); + if( pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){ + for(i=0; i<pEmr->nGradObj; i++, contents+=sizeof(U_GRADIENT3)){ + gradient3_print(*(PU_GRADIENT3)(contents)); + } + } + else if(pEmr->ulMode == U_GRADIENT_FILL_RECT_H || + pEmr->ulMode == U_GRADIENT_FILL_RECT_V){ + for(i=0; i<pEmr->nGradObj; i++, contents+=sizeof(U_GRADIENT4)){ + gradient4_print(*(PU_GRADIENT4)(contents)); + } + } + else { printf("invalid ulMode value!"); } + printf("\n"); + } +} + +// U_EMRSETLINKEDUFIS 119 Not implemented +#define U_EMRSETLINKEDUFIS_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_SETLINKEDUFIS",A) +// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated) +#define U_EMRSETTEXTJUSTIFICATION_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_SETTEXTJUSTIFICATION",A) +// U_EMRCOLORMATCHTOTARGETW 121 Not implemented +#define U_EMRCOLORMATCHTOTARGETW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_COLORMATCHTOTARGETW",A) + +// U_EMRCREATECOLORSPACEW 122 +/** + \brief Print a pointer to a U_EMR_CREATECOLORSPACEW record. + \param contents pointer to a buffer holding all EMR records +*/ +void U_EMRCREATECOLORSPACEW_print(const char *contents){ + int i; + PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents); + printf(" ihCS: %u\n", pEmr->ihCS ); + printf(" ColorSpace: "); logcolorspacew_print(pEmr->lcs); printf("\n"); + printf(" dwFlags: %u\n", pEmr->dwFlags ); + printf(" cbData: %u\n", pEmr->cbData ); + printf(" Data: "); + if(pEmr->dwFlags & 1){ + for(i=0; i<pEmr->cbData; i++){ + printf("[%d]:%2.2X ",i,pEmr->Data[i]); + } + } + printf("\n"); +} + +/** + \brief Print any record in an emf + \returns record length for a normal record, 0 for EMREOF, -1 for a bad record + \param contents pointer to a buffer holding all EMR records + \param blimit pointer to the byte after the last byte in the buffer holding all EMR records + \param recnum number of this record in contents + \param off offset to this record in contents +*/ +int U_emf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off){ + PU_ENHMETARECORD lpEMFR = (PU_ENHMETARECORD)(contents + off); + int size; + + printf("%-30srecord:%5d type:%3d offset:%8d size:%8d\n",U_emr_names(lpEMFR->iType),recnum,lpEMFR->iType,(int) off,lpEMFR->nSize); + size = lpEMFR->nSize; + contents += off; + + /* Check that the record size is OK, abort if not. + Pointer math might wrap, so check both sides of the range */ + if(size < sizeof(U_EMR) || + contents + size - 1 >= blimit || + contents + size - 1 < contents)return(-1); + + switch (lpEMFR->iType) + { + case U_EMR_HEADER: U_EMRHEADER_print(contents); break; + case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_print(contents); break; + case U_EMR_POLYGON: U_EMRPOLYGON_print(contents); break; + case U_EMR_POLYLINE: U_EMRPOLYLINE_print(contents); break; + case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_print(contents); break; + case U_EMR_POLYLINETO: U_EMRPOLYLINETO_print(contents); break; + case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_print(contents); break; + case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_print(contents); break; + case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_print(contents); break; + case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_print(contents); break; + case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_print(contents); break; + case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_print(contents); break; + case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_print(contents); break; + case U_EMR_EOF: U_EMREOF_print(contents); size=0; break; + case U_EMR_SETPIXELV: U_EMRSETPIXELV_print(contents); break; + case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_print(contents); break; + case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_print(contents); break; + case U_EMR_SETBKMODE: U_EMRSETBKMODE_print(contents); break; + case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_print(contents); break; + case U_EMR_SETROP2: U_EMRSETROP2_print(contents); break; + case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_print(contents); break; + case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_print(contents); break; + case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_print(contents); break; + case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_print(contents); break; + case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_print(contents); break; + case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_print(contents); break; + case U_EMR_MOVETOEX: U_EMRMOVETOEX_print(contents); break; + case U_EMR_SETMETARGN: U_EMRSETMETARGN_print(contents); break; + case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_print(contents); break; + case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_print(contents); break; + case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_print(contents); break; + case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_print(contents); break; + case U_EMR_SAVEDC: U_EMRSAVEDC_print(contents); break; + case U_EMR_RESTOREDC: U_EMRRESTOREDC_print(contents); break; + case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_print(contents); break; + case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_print(contents); break; + case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_print(contents); break; + case U_EMR_CREATEPEN: U_EMRCREATEPEN_print(contents); break; + case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_print(contents); break; + case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_print(contents); break; + case U_EMR_ANGLEARC: U_EMRANGLEARC_print(contents); break; + case U_EMR_ELLIPSE: U_EMRELLIPSE_print(contents); break; + case U_EMR_RECTANGLE: U_EMRRECTANGLE_print(contents); break; + case U_EMR_ROUNDRECT: U_EMRROUNDRECT_print(contents); break; + case U_EMR_ARC: U_EMRARC_print(contents); break; + case U_EMR_CHORD: U_EMRCHORD_print(contents); break; + case U_EMR_PIE: U_EMRPIE_print(contents); break; + case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_print(contents); break; + case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_print(contents); break; + case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_print(contents); break; + case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_print(contents); break; + case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_print(contents); break; + case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_print(contents); break; + case U_EMR_LINETO: U_EMRLINETO_print(contents); break; + case U_EMR_ARCTO: U_EMRARCTO_print(contents); break; + case U_EMR_POLYDRAW: U_EMRPOLYDRAW_print(contents); break; + case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_print(contents); break; + case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_print(contents); break; + case U_EMR_BEGINPATH: U_EMRBEGINPATH_print(contents); break; + case U_EMR_ENDPATH: U_EMRENDPATH_print(contents); break; + case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_print(contents); break; + case U_EMR_FILLPATH: U_EMRFILLPATH_print(contents); break; + case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_print(contents); break; + case U_EMR_STROKEPATH: U_EMRSTROKEPATH_print(contents); break; + case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_print(contents); break; + case U_EMR_WIDENPATH: U_EMRWIDENPATH_print(contents); break; + case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_print(contents); break; + case U_EMR_ABORTPATH: U_EMRABORTPATH_print(contents); break; + case U_EMR_UNDEF69: U_EMRUNDEF69_print(contents); break; + case U_EMR_COMMENT: U_EMRCOMMENT_print(contents); break; + case U_EMR_FILLRGN: U_EMRFILLRGN_print(contents); break; + case U_EMR_FRAMERGN: U_EMRFRAMERGN_print(contents); break; + case U_EMR_INVERTRGN: U_EMRINVERTRGN_print(contents); break; + case U_EMR_PAINTRGN: U_EMRPAINTRGN_print(contents); break; + case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_print(contents); break; + case U_EMR_BITBLT: U_EMRBITBLT_print(contents); break; + case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_print(contents); break; + case U_EMR_MASKBLT: U_EMRMASKBLT_print(contents); break; + case U_EMR_PLGBLT: U_EMRPLGBLT_print(contents); break; + case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_print(contents); break; + case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_print(contents); break; + case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_print(contents); break; + case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_print(contents); break; + case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_print(contents); break; + case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_print(contents); break; + case U_EMR_POLYGON16: U_EMRPOLYGON16_print(contents); break; + case U_EMR_POLYLINE16: U_EMRPOLYLINE16_print(contents); break; + case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_print(contents); break; + case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_print(contents); break; + case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_print(contents); break; + case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_print(contents); break; + case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_print(contents); break; + case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_print(contents); break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_print(contents); break; + case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_print(contents); break; + case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_print(contents); break; + case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_print(contents); break; + case U_EMR_SETICMMODE: U_EMRSETICMMODE_print(contents); break; + case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_print(contents); break; + case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_print(contents); break; + case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_print(contents); break; + case U_EMR_GLSRECORD: U_EMRGLSRECORD_print(contents); break; + case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_print(contents); break; + case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_print(contents); break; + case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_print(contents); break; + case U_EMR_EXTESCAPE: U_EMREXTESCAPE_print(contents); break; + case U_EMR_UNDEF107: U_EMRUNDEF107_print(contents); break; + case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_print(contents); break; + case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_print(contents); break; + case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_print(contents); break; + case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_print(contents); break; + case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_print(contents); break; + case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_print(contents); break; + case U_EMR_ALPHABLEND: U_EMRALPHABLEND_print(contents); break; + case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_print(contents); break; + case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_print(contents); break; + case U_EMR_UNDEF117: U_EMRUNDEF117_print(contents); break; + case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_print(contents); break; + case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_print(contents); break; + case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_print(contents); break; + case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_print(contents); break; + case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_print(contents); break; + default: U_EMRNOTIMPLEMENTED_print("?",contents); break; + } //end of switch + return(size); +} + + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uemf_print.h b/src/extension/internal/uemf_print.h new file mode 100644 index 000000000..238e0e659 --- /dev/null +++ b/src/extension/internal/uemf_print.h @@ -0,0 +1,169 @@ +/** + @file uemf_print.h Functions for printing records from EMF files. +*/ + +/* +File: uemf_print.h +Version: 0.0.5 +Date: 14-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UEMF_PRINT_ +#define _UEMF_PRINT_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* prototypes for objects used in EMR records */ +void hexbytes_print(uint8_t *buf,unsigned int num); +void colorref_print(U_COLORREF color); +void rgbquad_print(U_RGBQUAD color); +void rectl_print(U_RECTL rect); +void sizel_print(U_SIZEL sz); +void pointl_print(U_POINTL pt); +void point16_print(U_POINT16 pt); +void lcs_gamma_print(U_LCS_GAMMA lg); +void lcs_gammargb_print(U_LCS_GAMMARGB lgr); +void trivertex_print(U_TRIVERTEX tv); +void gradient3_print(U_GRADIENT3 g3); +void gradient4_print(U_GRADIENT4 g4); +void logbrush_print(U_LOGBRUSH lb); +void xform_print(U_XFORM xform); +void ciexyz_print(U_CIEXYZ ciexyz); +void ciexyztriple_print(U_CIEXYZTRIPLE cie3); +void logcolorspacea_print(U_LOGCOLORSPACEA lcsa); +void logcolorspacew_print(U_LOGCOLORSPACEW lcsa); +void panose_print(U_PANOSE panose); +void logfont_print(U_LOGFONT lf); +void logfont_panose_print(U_LOGFONT_PANOSE lfp); +void bitmapinfoheader_print(const char *Bmih); +void bitmapinfo_print(const char *Bmi); +void blend_print(U_BLEND blend); +void extlogpen_print(const PU_EXTLOGPEN elp); +void logpen_print(U_LOGPEN lp); +void logpltntry_print(U_LOGPLTNTRY lpny); +void logpalette_print(const PU_LOGPALETTE lp); +void rgndataheader_print(U_RGNDATAHEADER rdh); +void rgndata_print(const PU_RGNDATA rd); +void coloradjustment_print(U_COLORADJUSTMENT ca); +void pixelformatdescriptor_print(U_PIXELFORMATDESCRIPTOR pfd); +void emrtext_print(const char *emt, const char *record, int type); + +/* prototypes for EMR records */ +void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents, int recnum, int off); +void U_EMRHEADER_print(const char *contents, int recnum, int off); +void U_EMRPOLYBEZIER_print(const char *contents, int recnum, int off); +void U_EMRPOLYGON_print(const char *contents, int recnum, int off); +void U_EMRPOLYLINE_print(const char *contents, int recnum, int off); +void U_EMRPOLYBEZIERTO_print(const char *contents, int recnum, int off); +void U_EMRPOLYLINETO_print(const char *contents, int recnum, int off); +void U_EMRPOLYPOLYLINE_print(const char *contents, int recnum, int off); +void U_EMRPOLYPOLYGON_print(const char *contents, int recnum, int off); +void U_EMRSETWINDOWEXTEX_print(const char *contents, int recnum, int off); +void U_EMRSETWINDOWORGEX_print(const char *contents, int recnum, int off); +void U_EMRSETVIEWPORTEXTEX_print(const char *contents, int recnum, int off); +void U_EMRSETVIEWPORTORGEX_print(const char *contents, int recnum, int off); +void U_EMRSETBRUSHORGEX_print(const char *contents, int recnum, int off); +void U_EMREOF_print(const char *contents, int recnum, int off); +void U_EMRSETPIXELV_print(const char *contents, int recnum, int off); +void U_EMRSETMAPPERFLAGS_print(const char *contents, int recnum, int off); +void U_EMRSETMAPMODE_print(const char *contents, int recnum, int off); +void U_EMRSETBKMODE_print(const char *contents, int recnum, int off); +void U_EMRSETPOLYFILLMODE_print(const char *contents, int recnum, int off); +void U_EMRSETROP2_print(const char *contents, int recnum, int off); +void U_EMRSETSTRETCHBLTMODE_print(const char *contents, int recnum, int off); +void U_EMRSETTEXTALIGN_print(const char *contents, int recnum, int off); +void U_EMRSETCOLORADJUSTMENT_print(const char *contents, int recnum, int off); +void U_EMRSETTEXTCOLOR_print(const char *contents, int recnum, int off); +void U_EMRSETBKCOLOR_print(const char *contents, int recnum, int off); +void U_EMROFFSETCLIPRGN_print(const char *contents, int recnum, int off); +void U_EMRMOVETOEX_print(const char *contents, int recnum, int off); +void U_EMRSETMETARGN_print(const char *contents, int recnum, int off); +void U_EMREXCLUDECLIPRECT_print(const char *contents, int recnum, int off); +void U_EMRINTERSECTCLIPRECT_print(const char *contents, int recnum, int off); +void U_EMRSCALEVIEWPORTEXTEX_print(const char *contents, int recnum, int off); +void U_EMRSCALEWINDOWEXTEX_print(const char *contents, int recnum, int off); +void U_EMRSAVEDC_print(const char *contents, int recnum, int off); +void U_EMRRESTOREDC_print(const char *contents, int recnum, int off); +void U_EMRSETWORLDTRANSFORM_print(const char *contents, int recnum, int off); +void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents, int recnum, int off); +void U_EMRSELECTOBJECT_print(const char *contents, int recnum, int off); +void U_EMRCREATEPEN_print(const char *contents, int recnum, int off); +void U_EMRCREATEBRUSHINDIRECT_print(const char *contents, int recnum, int off); +void U_EMRDELETEOBJECT_print(const char *contents, int recnum, int off); +void U_EMRANGLEARC_print(const char *contents, int recnum, int off); +void U_EMRELLIPSE_print(const char *contents, int recnum, int off); +void U_EMRRECTANGLE_print(const char *contents, int recnum, int off); +void U_EMRROUNDRECT_print(const char *contents, int recnum, int off); +void U_EMRARC_print(const char *contents, int recnum, int off); +void U_EMRCHORD_print(const char *contents, int recnum, int off); +void U_EMRPIE_print(const char *contents, int recnum, int off); +void U_EMRSELECTPALETTE_print(const char *contents, int recnum, int off); +void U_EMRCREATEPALETTE_print(const char *contents, int recnum, int off); +void U_EMRSETPALETTEENTRIES_print(const char *contents, int recnum, int off); +void U_EMRRESIZEPALETTE_print(const char *contents, int recnum, int off); +void U_EMRREALIZEPALETTE_print(const char *contents, int recnum, int off); +void U_EMREXTFLOODFILL_print(const char *contents, int recnum, int off); +void U_EMRLINETO_print(const char *contents, int recnum, int off); +void U_EMRARCTO_print(const char *contents, int recnum, int off); +void U_EMRPOLYDRAW_print(const char *contents, int recnum, int off); +void U_EMRSETARCDIRECTION_print(const char *contents, int recnum, int off); +void U_EMRSETMITERLIMIT_print(const char *contents, int recnum, int off); +void U_EMRBEGINPATH_print(const char *contents, int recnum, int off); +void U_EMRENDPATH_print(const char *contents, int recnum, int off); +void U_EMRCLOSEFIGURE_print(const char *contents, int recnum, int off); +void U_EMRFILLPATH_print(const char *contents, int recnum, int off); +void U_EMRSTROKEANDFILLPATH_print(const char *contents, int recnum, int off); +void U_EMRSTROKEPATH_print(const char *contents, int recnum, int off); +void U_EMRFLATTENPATH_print(const char *contents, int recnum, int off); +void U_EMRWIDENPATH_print(const char *contents, int recnum, int off); +void U_EMRSELECTCLIPPATH_print(const char *contents, int recnum, int off); +void U_EMRABORTPATH_print(const char *contents, int recnum, int off); +void U_EMRCOMMENT_print(const char *contents, int recnum, int off); +void U_EMRFILLRGN_print(const char *contents, int recnum, int off); +void U_EMRFRAMERGN_print(const char *contents, int recnum, int off); +void U_EMRINVERTRGN_print(const char *contents, int recnum, int off); +void U_EMRPAINTRGN_print(const char *contents, int recnum, int off); +void U_EMREXTSELECTCLIPRGN_print(const char *contents, int recnum, int off); +void U_EMRBITBLT_print(const char *contents, int recnum, int off); +void U_EMRSTRETCHBLT_print(const char *contents, int recnum, int off); +void U_EMRMASKBLT_print(const char *contents, int recnum, int off); +void U_EMRPLGBLT_print(const char *contents, int recnum, int off); +void U_EMRSETDIBITSTODEVICE_print(const char *contents, int recnum, int off); +void U_EMRSTRETCHDIBITS_print(const char *contents, int recnum, int off); +void U_EMREXTCREATEFONTINDIRECTW_print(const char *contents, int recnum, int off); +void U_EMREXTTEXTOUTA_print(const char *contents, int recnum, int off); +void U_EMREXTTEXTOUTW_print(const char *contents, int recnum, int off); +void U_EMRPOLYBEZIER16_print(const char *contents, int recnum, int off); +void U_EMRPOLYGON16_print(const char *contents, int recnum, int off); +void U_EMRPOLYLINE16_print(const char *contents, int recnum, int off); +void U_EMRPOLYBEZIERTO16_print(const char *contents, int recnum, int off); +void U_EMRPOLYLINETO16_print(const char *contents, int recnum, int off); +void U_EMRPOLYPOLYLINE16_print(const char *contents, int recnum, int off); +void U_EMRPOLYPOLYGON16_print(const char *contents, int recnum, int off); +void U_EMRPOLYDRAW16_print(const char *contents, int recnum, int off); +void U_EMRCREATEMONOBRUSH_print(const char *contents, int recnum, int off); +void U_EMRCREATEDIBPATTERNBRUSHPT_print(const char *contents, int recnum, int off); +void U_EMREXTCREATEPEN_print(const char *contents, int recnum, int off); +void U_EMRSETICMMODE_print(const char *contents, int recnum, int off); +void U_EMRCREATECOLORSPACE_print(const char *contents, int recnum, int off); +void U_EMRSETCOLORSPACE_print(const char *contents, int recnum, int off); +void U_EMRDELETECOLORSPACE_print(const char *contents, int recnum, int off); +void U_EMRPIXELFORMAT_print(const char *contents, int recnum, int off); +void U_EMRSMALLTEXTOUT_print(const char *contents, int recnum, int off); +void U_EMRALPHABLEND_print(const char *contents, int recnum, int off); +void U_EMRSETLAYOUT_print(const char *contents, int recnum, int off); +void U_EMRTRANSPARENTBLT_print(const char *contents, int recnum, int off); +void U_EMRGRADIENTFILL_print(const char *contents, int recnum, int off); +void U_EMRCREATECOLORSPACEW_print(const char *contents, int recnum, int off); +int U_emf_onerec_print(const char *contents, char *blimit, int recnum, int off); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEMF_PRINT_ */ diff --git a/src/extension/internal/uemf_utf.c b/src/extension/internal/uemf_utf.c new file mode 100644 index 000000000..48d2510f0 --- /dev/null +++ b/src/extension/internal/uemf_utf.c @@ -0,0 +1,552 @@ +/** + @file uemf_utf.c Functions for manipulating UTF and various types of text. + + + Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for + uninitialized data. + + Compile with "SOL8" defined for Solaris 8 or 9 (Sparc). +*/ + +/* +File: uemf_utf.c +Version: 0.0.4 +Date: 19-MAR-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <iconv.h> +#include <wchar.h> +#include <errno.h> +#include <string.h> +#include <limits.h> // for INT_MAX, INT_MIN +#include <math.h> // for U_ROUND() +#include "uemf_utf.h" + +/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed +to be used in end user code. */ + +void U_swap2(void *ul, unsigned int count); + +/* ******************************************************************************************** */ + +/** \cond */ +/* iconv() has a funny cast on some older systems, on most recent ones + it is just char **. This tries to work around the issue. If you build this + on another funky system this code may need to be modified, or define ICONV_CAST + on the compile line(but it may be tricky). +*/ +#ifdef SOL8 +#define ICONV_CAST (const char **) +#endif //SOL8 +#if !defined(ICONV_CAST) +#define ICONV_CAST (char **) +#endif //ICONV_CAST +/** \endcond */ + +/* ********************************************************************************************** +These functions are used for development and debugging and should be be includied in production code. +*********************************************************************************************** */ + +/** + \brief Dump a UTF8 string. Not for use in production code. + \param src string to examine +*/ +void wchar8show( + const char *src + ){ + printf("char show\n"); + size_t srclen = 0; + while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; } +} + +/** + \brief Dump a UTF16 string. Not for use in production code. + \param src string to examine +*/ +void wchar16show( + const uint16_t *src + ){ + printf("uint16_t show\n"); + size_t srclen = 0; + while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; } +} + +/** + \brief Dump a UTF32 string. Not for use in production code. +*/ +void wchar32show( + const uint32_t *src + ){ + printf("uint32_t show\n"); + size_t srclen = 0; + while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; } +} + +/** + \brief Dump a wchar_t string. Not for use in production code. + \param src string to examine +*/ +void wchartshow( + const wchar_t *src + ){ + uint32_t val; + printf("wchar_t show\n"); + size_t srclen = 0; + while(*src){ + val = *src; // because *src is wchar_t is not strictly an integer type, can cause warnings on next line + printf("%d %d %x\n",(int) srclen,val,val); + srclen++; + src++; + } +} + +/* ********************************************************************************************** +These functions are used for character type conversions, Image conversions, and other +utility operations +*********************************************************************************************** */ + +/** + \brief Find the number of (storage) characters in a 16 bit character string, not including terminator. + \param src string to examine +*/ +size_t wchar16len( + const uint16_t *src + ){ + size_t srclen = 0; + while(*src){ srclen++; src++; } + return(srclen); +} + +/** + \brief Find the number of (storage) characters in a 32 bit character string, not including terminator. + \param src string to examine +*/ +size_t wchar32len( + const uint32_t *src + ){ + size_t srclen = 0; + while(*src){ srclen++; src++; } + return(srclen); +} + +/** + \brief Strncpy for wchar16 (UTF16). + \param dst destination (already allocated) + \param src source + \param nchars number of characters to copy +*/ +void wchar16strncpy( + uint16_t *dst, + const uint16_t *src, + size_t nchars + ){ + for(;nchars;nchars--,dst++,src++){ + *dst = *src; + if(!*src)break; + } +} + +/** + \brief Fill the output string with N characters, if the input string is shorter than N, pad with nulls. + \param dst destination (already allocated) + \param src source + \param nchars number of characters to copy + +*/ +void wchar16strncpypad( + uint16_t *dst, + const uint16_t *src, + size_t nchars + ){ + for(;*src && nchars;nchars--,dst++,src++){ *dst = *src; } + for(;nchars;nchars--,dst++){ *dst = 0; } // Pad the remainder +} + +/* For the following converstion functions, remember that iconv() modifies ALL of its parameters, + so save a pointer to the destination buffer!!!! + It isn't clear that terminators are being + copied properly, so be sure allocated space is a bit larger and cleared. +*/ + +/** + \brief Convert a UTF32LE string to a UTF16LE string. + \returns pointer to new string or NULL if it fails + \param src wchar_t string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint16_t *U_Utf32leToUtf16le( + const uint32_t *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + + if(max){ srclen = 4*max; } + else { srclen = 4 + 4*wchar32len(src); } //include terminator, length in BYTES + + dstlen = 2 + srclen; // this will always work, but may waste space + dst2 = dst = calloc(dstlen,1); // so there will be at least one terminator + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-16LE", "UTF-32LE"); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar16len((uint16_t *)dst2); + return((uint16_t *)dst2); +} + +/** + \brief Convert a UTF16LE string to a UTF32LE string. + \return pointer to new string or NULL if it fails + \param src UTF16LE string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint32_t *U_Utf16leToUtf32le( + const uint16_t *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = 2*max; } + else { srclen = 2*wchar16len(src)+2; } // include terminator, length in BYTES + dstlen = 2*(2 + srclen); // This should always work + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-32LE", "UTF-16LE"); + if ( conv == (iconv_t)-1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar32len((uint32_t *)dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a Latin1 string to a UTF32LE string. + \return pointer to new string or NULL if it fails + \param src Latin1 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator + + + U_EMR_EXTTEXTOUTA records are "8 bit ASCII". In theory that is ASCII in an 8 + bit character, but numerous applications store Latin1 in them, and some + _may_ store UTF-8 in them. Since very vew Latin1 strings are valid UTF-8 strings, + call U_Utf8ToUtf32le first, and if it fails, then call this function. +*/ +uint32_t *U_Latin1ToUtf32le( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = sizeof(uint32_t)*(1 + srclen); // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-32LE", "LATIN1"); + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar32len((uint32_t *)dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a UTF8 string to a UTF32LE string. + \return pointer to new string or NULL if it fails + \param src UTF8 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint32_t *U_Utf8ToUtf32le( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = sizeof(uint32_t)*(1 + srclen); // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-32LE", "UTF-8"); + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar32len((uint32_t *)dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a UTF32LE string to a UTF8 string. + \return pointer to new string or NULL if it fails + \param src wchar_t string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +char *U_Utf32leToUtf8( + const uint32_t *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = 4*max; } + else { srclen = 4*(1 + wchar32len(src)); } //include terminator, length in BYTES + dstlen = 1 + srclen; // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-8", "UTF-32LE"); + if ( conv == (iconv_t)-1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + return(dst2); +} + +/** + \brief Convert a UTF-8 string to a UTF16-LE string. + \return pointer to new string or NULL if it fails + \param src UTF8 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint16_t *U_Utf8ToUtf16le( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + iconv_t conv; + + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = 2 * (1 + srclen); // this will always work, but may waste space + dst2 = dst =calloc(dstlen,1); // so there will always be a terminator + if(!dst)return(NULL); + conv = iconv_open("UTF-16LE", "UTF-8"); + if (conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar16len((uint16_t *)dst2); + return((uint16_t *)dst2); +} + +/** + \brief Convert a UTF16LE string to a UTF8 string. + \return pointer to new UTF8 string or NULL if it fails + \param src UTF16LE string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +char *U_Utf16leToUtf8( + const uint16_t *src, + size_t max, + size_t *len + ){ + char *dst, *dst2; + char *ret=NULL; + size_t srclen,dstlen,status; + if(max){ srclen = 2*max; } + else { srclen = 2*(1 +wchar16len(src)); } //include terminator, length in BYTES + dstlen = 1 + 2*srclen; // this will always work, but may waste space + // worst case is all glyphs (==max) need 4 UTF-8 encoded bytes + terminator. + dst2 = dst = (char *) calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-8", "UTF-16LE"); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status != (size_t) -1){ + if(len)*len=strlen(dst2); + ret=U_strdup(dst2); // make a string of exactly the right size + } + free(dst2); // free the one which was probably too big + return(ret); +} + +/** + \brief Convert a UTF16LE string to a LATIN1 string. + \return pointer to new UTF8 string or NULL if it fails + \param src UTF16LE string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +char *U_Utf16leToLatin1( + const uint16_t *src, + size_t max, + size_t *len + ){ + char *dst, *dst2; + char *ret=NULL; + size_t srclen,dstlen,status; + if(max){ srclen = 2*max; } + else { srclen = 2*(1 +wchar16len(src)); } //include terminator, length in BYTES + dstlen = 1 + srclen; // this will always work as latin1 is always 1 byte/character + ret = dst2 = dst = (char *) calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("LATIN1//TRANSLIT", "UTF-16LE"); // translate what can be, fill in with something close for the rest + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status != (size_t) -1){ + if(len)*len=strlen(dst2); + } + return(ret); +} +/** + \brief Put a single 16 bit character into UTF-16LE form. + + Used in conjunction with U_Utf16leEdit(), because the character + representation would otherwise be dependent on machine Endianness. + + \return UTF16LE representation of the character. + \param src 16 bit character + +*/ +uint16_t U_Utf16le(const uint16_t src){ + uint16_t dst=src; +#if U_BYTE_SWAP + U_swap2(&dst,1); +#endif + return(dst); +} + +/** + \brief Convert a UTF8 string to a Latin1 string. + \return pointer to new string or NULL if it fails + \param src Latin1 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator + + + WMF uses latin1, others UTF-8, only some utf-8 can be converted to latin1. + +*/ +char *U_Utf8ToLatin1( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = (1 + srclen); // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("LATIN1//TRANSLIT", "UTF-8"); // translate what can be, fill in with something close for the rest + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + return((char *) dst2); +} + +/** + \brief Convert a Latin1 string to a UTF8 string. + \return pointer to new string or NULL if it fails + \param src Latin1 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator + + + WMF uses latin1, others UTF-8, all Latin1 should be able to convert to utf-8. + +*/ +char *U_Latin1ToUtf8( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, will waste some space + dstlen = (1 + 2*srclen); // This should always work because all latin1 convert to 1 or 2 byte UTF8, it might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-8", "LATIN1"); // everything should translate + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + return((char *) dst2); +} + +/** + \brief Single character replacement in a UTF-16LE string. + + Used solely for the Description field which contains + embedded nulls, which makes it difficult to manipulate. Use some other character and then swap it. + + \return number of substitutions, or -1 if src is not defined + \param src UTF16LE string to edit + \param find character to replace + \param replace replacestitute character + +*/ +int U_Utf16leEdit( + uint16_t *src, + uint16_t find, + uint16_t replace + ){ + int count=0; + if(!src)return(-1); + while(*src){ + if(*src == find){ *src = replace; count++; } + src++; + } + return(count); +} + +/** + \brief strdup for when strict C99 compliance is enforced + \returns duplicate string or NULL on error + \param s string to duplicate +*/ +char *U_strdup(const char *s){ + char *news=NULL; + size_t slen; + if(s){ + slen = strlen(s) + 1; //include the terminator! + news = malloc(slen); + if(news){ + memcpy(news,s,slen); + } + } + return(news); + +} + + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uemf_utf.h b/src/extension/internal/uemf_utf.h new file mode 100644 index 000000000..e42de23e6 --- /dev/null +++ b/src/extension/internal/uemf_utf.h @@ -0,0 +1,53 @@ +/** + @file uemf_utf.h for manipulating UTF and various types of text. + +*/ + +/* +File: uemf_utf.h +Version: 0.0.1 +Date: 04-DEC-2012 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UEMF_UTF_ +#define _UEMF_UTF_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> +#include "uemf_endian.h" + +void wchar8show(const char *src); +void wchar16show(const uint16_t *src); +void wchar32show(const uint32_t *src); +void wchartshow(const wchar_t *src); + +size_t wchar16len(const uint16_t *src); +size_t wchar32len(const uint32_t *src); +void wchar16strncpy(uint16_t *dst, const uint16_t *src, size_t nchars); +void wchar16strncpypad(uint16_t *dst, const uint16_t *src, size_t nchars); +uint16_t *U_Utf8ToUtf16le( const char *src, size_t max, size_t *len ); +uint32_t *U_Utf8ToUtf32le( const char *src, size_t max, size_t *len ); +uint32_t *U_Latin1ToUtf32le( const char *src, size_t max, size_t *len ); +uint16_t *U_Utf32leToUtf16le( const uint32_t *src, size_t max, size_t *len ); +char *U_Utf32leToUtf8( const uint32_t *src, size_t max, size_t *len ); +uint32_t *U_Utf16leToUtf32le( const uint16_t *src, size_t max, size_t *len ); +char *U_Utf16leToUtf8( const uint16_t *src, size_t max, size_t *len ); +char *U_Utf16leToLatin1( const uint16_t *src, size_t max, size_t *len ); +char *U_Utf8ToLatin1( const char *src, size_t max, size_t *len ); +char *U_Latin1ToUtf8( const char *src, size_t max, size_t *len ); +uint16_t U_Utf16le(const uint16_t src); +int U_Utf16leEdit( uint16_t *src, uint16_t find, uint16_t replace ); +char *U_strdup(const char *s); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEMF_UTF_ */ diff --git a/src/extension/internal/uwmf.c b/src/extension/internal/uwmf.c new file mode 100644 index 000000000..9d916ecee --- /dev/null +++ b/src/extension/internal/uwmf.c @@ -0,0 +1,6880 @@ +/** + @file uwmf.c Functions for manipulating WMF files and structures. + + [U_WMR*]_set all take data and return a pointer to memory holding the constructed record. + If something goes wrong a NULL pointer is returned. + [U_WMR*]_get takes a pointer to memory and returns the length of that record as well + as the values from it (in the provided fields, passed by reference.) + If something goes wrong, a size of 0 is returned. + + The _set material comes first, then all of the _get material. + + Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for + uninitialized data. + + Compile with "SOL8" defined for Solaris 8 or 9 (Sparc). +*/ + +/* +File: uwmf.c +Version: 0.0.11 +Date: 19-MAR-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> /* for offsetof() */ +#include <string.h> +#include <iconv.h> +#include <wchar.h> +#include <errno.h> +#include <string.h> +#include <limits.h> // for INT_MAX, INT_MIN +#include <math.h> // for U_ROUND() +#if 0 +#include <windef.h> //Not actually used, looking for collisions +#include <winnt.h> //Not actually used, looking for collisions +#include <wingdi.h> //Not actually used, looking for collisions +#endif +#include "uwmf.h" +#include "uwmf_endian.h" + +/** + \brief Look up the full numeric type of a WMR record by type. + + \return Full numeric value for this type of WMR record, Returns 0xFFFFFFFF if out of range. + \param idx WMR record type. + +*/ +uint32_t U_wmr_values(int idx){ + int ret; + int U_WMR_VALUES[256]={ + 0x0000, //!< U_WMR_EOF + 0x0201, //!< U_WMR_SETBKCOLOR + 0x0102, //!< U_WMR_SETBKMODE + 0x0103, //!< U_WMR_SETMAPMODE + 0x0104, //!< U_WMR_SETROP2 + 0x0105, //!< U_WMR_SETRELABS + 0x0106, //!< U_WMR_SETPOLYFILLMODE + 0x0107, //!< U_WMR_SETSTRETCHBLTMODE + 0x0108, //!< U_WMR_SETTEXTCHAREXTRA + 0x0209, //!< U_WMR_SETTEXTCOLOR + 0x020A, //!< U_WMR_SETTEXTJUSTIFICATION + 0x020B, //!< U_WMR_SETWINDOWORG + 0x020C, //!< U_WMR_SETWINDOWEXT + 0x020D, //!< U_WMR_SETVIEWPORTORG + 0x020E, //!< U_WMR_SETVIEWPORTEXT + 0x020F, //!< U_WMR_OFFSETWINDOWORG + 0x0410, //!< U_WMR_SCALEWINDOWEXT + 0x0211, //!< U_WMR_OFFSETVIEWPORTORG + 0x0412, //!< U_WMR_SCALEVIEWPORTEXT + 0x0213, //!< U_WMR_LINETO + 0x0214, //!< U_WMR_MOVETO + 0x0415, //!< U_WMR_EXCLUDECLIPRECT + 0x0416, //!< U_WMR_INTERSECTCLIPRECT + 0x0817, //!< U_WMR_ARC + 0x0418, //!< U_WMR_ELLIPSE + 0x0419, //!< U_WMR_FLOODFILL + 0x081A, //!< U_WMR_PIE + 0x041B, //!< U_WMR_RECTANGLE + 0x061C, //!< U_WMR_ROUNDRECT + 0x061D, //!< U_WMR_PATBLT + 0x001E, //!< U_WMR_SAVEDC + 0x041F, //!< U_WMR_SETPIXEL + 0x0220, //!< U_WMR_OFFSETCLIPRGN + 0x0521, //!< U_WMR_TEXTOUT + 0x0922, //!< U_WMR_BITBLT + 0x0B23, //!< U_WMR_STRETCHBLT + 0x0324, //!< U_WMR_POLYGON + 0x0325, //!< U_WMR_POLYLINE + 0x0626, //!< U_WMR_ESCAPE + 0x0127, //!< U_WMR_RESTOREDC + 0x0228, //!< U_WMR_FILLREGION + 0x0429, //!< U_WMR_FRAMEREGION + 0x012A, //!< U_WMR_INVERTREGION + 0x012B, //!< U_WMR_PAINTREGION + 0x012C, //!< U_WMR_SELECTCLIPREGION + 0x012D, //!< U_WMR_SELECTOBJECT + 0x012E, //!< U_WMR_SETTEXTALIGN + 0x062F, //!< U_WMR_DRAWTEXT + 0x0830, //!< U_WMR_CHORD + 0x0231, //!< U_WMR_SETMAPPERFLAGS + 0x0A32, //!< U_WMR_EXTTEXTOUT + 0x0D33, //!< U_WMR_SETDIBTODEV + 0x0234, //!< U_WMR_SELECTPALETTE + 0x0035, //!< U_WMR_REALIZEPALETTE + 0x0436, //!< U_WMR_ANIMATEPALETTE + 0x0037, //!< U_WMR_SETPALENTRIES + 0x0538, //!< U_WMR_POLYPOLYGON + 0x0139, //!< U_WMR_RESIZEPALETTE + 0x003A, //!< U_WMR_3A + 0x003B, //!< U_WMR_3B + 0x003C, //!< U_WMR_3C + 0x003D, //!< U_WMR_3D + 0x003E, //!< U_WMR_3E + 0x003F, //!< U_WMR_3F + 0x0940, //!< U_WMR_DIBBITBLT + 0x0B41, //!< U_WMR_DIBSTRETCHBLT + 0x0142, //!< U_WMR_DIBCREATEPATTERNBRUSH + 0x0F43, //!< U_WMR_STRETCHDIB + 0x0044, //!< U_WMR_44 + 0x0045, //!< U_WMR_45 + 0x0046, //!< U_WMR_46 + 0x0047, //!< U_WMR_47 + 0x0548, //!< U_WMR_EXTFLOODFILL + 0x0049, //!< U_WMR_49 + 0x004A, //!< U_WMR_4A + 0x004B, //!< U_WMR_4B + 0x014C, //!< U_WMR_4C + 0x014D, //!< U_WMR_4D + 0x004E, //!< U_WMR_4E + 0x004F, //!< U_WMR_4F + 0x0050, //!< U_WMR_50 + 0x0051, //!< U_WMR_51 + 0x0052, //!< U_WMR_52 + 0x0053, //!< U_WMR_53 + 0x0054, //!< U_WMR_54 + 0x0055, //!< U_WMR_55 + 0x0056, //!< U_WMR_56 + 0x0057, //!< U_WMR_57 + 0x0058, //!< U_WMR_58 + 0x0059, //!< U_WMR_59 + 0x005A, //!< U_WMR_5A + 0x005B, //!< U_WMR_5B + 0x005C, //!< U_WMR_5C + 0x005D, //!< U_WMR_5D + 0x005E, //!< U_WMR_5E + 0x005F, //!< U_WMR_5F + 0x0060, //!< U_WMR_60 + 0x0061, //!< U_WMR_61 + 0x0062, //!< U_WMR_62 + 0x0063, //!< U_WMR_63 + 0x0064, //!< U_WMR_64 + 0x0065, //!< U_WMR_65 + 0x0066, //!< U_WMR_66 + 0x0067, //!< U_WMR_67 + 0x0068, //!< U_WMR_68 + 0x0069, //!< U_WMR_69 + 0x006A, //!< U_WMR_6A + 0x006B, //!< U_WMR_6B + 0x006C, //!< U_WMR_6C + 0x006D, //!< U_WMR_6D + 0x006E, //!< U_WMR_6E + 0x006F, //!< U_WMR_6F + 0x0070, //!< U_WMR_70 + 0x0071, //!< U_WMR_71 + 0x0072, //!< U_WMR_72 + 0x0073, //!< U_WMR_73 + 0x0074, //!< U_WMR_74 + 0x0075, //!< U_WMR_75 + 0x0076, //!< U_WMR_76 + 0x0077, //!< U_WMR_77 + 0x0078, //!< U_WMR_78 + 0x0079, //!< U_WMR_79 + 0x007A, //!< U_WMR_7A + 0x007B, //!< U_WMR_7B + 0x007C, //!< U_WMR_7C + 0x007D, //!< U_WMR_7D + 0x007E, //!< U_WMR_7E + 0x007F, //!< U_WMR_7F + 0x0080, //!< U_WMR_80 + 0x0081, //!< U_WMR_81 + 0x0082, //!< U_WMR_82 + 0x0083, //!< U_WMR_83 + 0x0084, //!< U_WMR_84 + 0x0085, //!< U_WMR_85 + 0x0086, //!< U_WMR_86 + 0x0087, //!< U_WMR_87 + 0x0088, //!< U_WMR_88 + 0x0089, //!< U_WMR_89 + 0x008A, //!< U_WMR_8A + 0x008B, //!< U_WMR_8B + 0x008C, //!< U_WMR_8C + 0x008D, //!< U_WMR_8D + 0x008E, //!< U_WMR_8E + 0x008F, //!< U_WMR_8F + 0x0090, //!< U_WMR_90 + 0x0091, //!< U_WMR_91 + 0x0092, //!< U_WMR_92 + 0x0093, //!< U_WMR_93 + 0x0094, //!< U_WMR_94 + 0x0095, //!< U_WMR_95 + 0x0096, //!< U_WMR_96 + 0x0097, //!< U_WMR_97 + 0x0098, //!< U_WMR_98 + 0x0099, //!< U_WMR_99 + 0x009A, //!< U_WMR_9A + 0x009B, //!< U_WMR_9B + 0x009C, //!< U_WMR_9C + 0x009D, //!< U_WMR_9D + 0x009E, //!< U_WMR_9E + 0x009F, //!< U_WMR_9F + 0x00A0, //!< U_WMR_A0 + 0x00A1, //!< U_WMR_A1 + 0x00A2, //!< U_WMR_A2 + 0x00A3, //!< U_WMR_A3 + 0x00A4, //!< U_WMR_A4 + 0x00A5, //!< U_WMR_A5 + 0x00A6, //!< U_WMR_A6 + 0x00A7, //!< U_WMR_A7 + 0x00A8, //!< U_WMR_A8 + 0x00A9, //!< U_WMR_A9 + 0x00AA, //!< U_WMR_AA + 0x00AB, //!< U_WMR_AB + 0x00AC, //!< U_WMR_AC + 0x00AD, //!< U_WMR_AD + 0x00AE, //!< U_WMR_AE + 0x00AF, //!< U_WMR_AF + 0x00B0, //!< U_WMR_B0 + 0x00B1, //!< U_WMR_B1 + 0x00B2, //!< U_WMR_B2 + 0x00B3, //!< U_WMR_B3 + 0x00B4, //!< U_WMR_B4 + 0x00B5, //!< U_WMR_B5 + 0x00B6, //!< U_WMR_B6 + 0x00B7, //!< U_WMR_B7 + 0x00B8, //!< U_WMR_B8 + 0x00B9, //!< U_WMR_B9 + 0x00BA, //!< U_WMR_BA + 0x00BB, //!< U_WMR_BB + 0x00BC, //!< U_WMR_BC + 0x00BD, //!< U_WMR_BD + 0x00BE, //!< U_WMR_BE + 0x00BF, //!< U_WMR_BF + 0x00C0, //!< U_WMR_C0 + 0x00C1, //!< U_WMR_C1 + 0x00C2, //!< U_WMR_C2 + 0x00C3, //!< U_WMR_C3 + 0x00C4, //!< U_WMR_C4 + 0x00C5, //!< U_WMR_C5 + 0x00C6, //!< U_WMR_C6 + 0x00C7, //!< U_WMR_C7 + 0x00C8, //!< U_WMR_C8 + 0x00C9, //!< U_WMR_C9 + 0x00CA, //!< U_WMR_CA + 0x00CB, //!< U_WMR_CB + 0x00CC, //!< U_WMR_CC + 0x00CD, //!< U_WMR_CD + 0x00CE, //!< U_WMR_CE + 0x00CF, //!< U_WMR_CF + 0x00D0, //!< U_WMR_D0 + 0x00D1, //!< U_WMR_D1 + 0x00D2, //!< U_WMR_D2 + 0x00D3, //!< U_WMR_D3 + 0x00D4, //!< U_WMR_D4 + 0x00D5, //!< U_WMR_D5 + 0x00D6, //!< U_WMR_D6 + 0x00D7, //!< U_WMR_D7 + 0x00D8, //!< U_WMR_D8 + 0x00D9, //!< U_WMR_D9 + 0x00DA, //!< U_WMR_DA + 0x00DB, //!< U_WMR_DB + 0x00DC, //!< U_WMR_DC + 0x00DD, //!< U_WMR_DD + 0x00DE, //!< U_WMR_DE + 0x00DF, //!< U_WMR_DF + 0x00E0, //!< U_WMR_E0 + 0x00E1, //!< U_WMR_E1 + 0x00E2, //!< U_WMR_E2 + 0x00E3, //!< U_WMR_E3 + 0x00E4, //!< U_WMR_E4 + 0x00E5, //!< U_WMR_E5 + 0x00E6, //!< U_WMR_E6 + 0x00E7, //!< U_WMR_E7 + 0x00E8, //!< U_WMR_E8 + 0x00E9, //!< U_WMR_E9 + 0x00EA, //!< U_WMR_EA + 0x00EB, //!< U_WMR_EB + 0x00EC, //!< U_WMR_EC + 0x00ED, //!< U_WMR_ED + 0x00EE, //!< U_WMR_EE + 0x00EF, //!< U_WMR_EF + 0x01F0, //!< U_WMR_DELETEOBJECT + 0x00F1, //!< U_WMR_F1 + 0x00F2, //!< U_WMR_F2 + 0x00F3, //!< U_WMR_F3 + 0x00F4, //!< U_WMR_F4 + 0x00F5, //!< U_WMR_F5 + 0x00F6, //!< U_WMR_F6 + 0x00F7, //!< U_WMR_CREATEPALETTE + 0x00F8, //!< U_WMR_CREATEBRUSH + 0x01F9, //!< U_WMR_CREATEPATTERNBRUSH + 0x02FA, //!< U_WMR_CREATEPENINDIRECT + 0x02FB, //!< U_WMR_CREATEFONTINDIRECT + 0x02FC, //!< U_WMR_CREATEBRUSHINDIRECT + 0x02FD, //!< U_WMR_CREATEBITMAPINDIRECT + 0x06FE, //!< U_WMR_CREATEBITMAP + 0x06FF //!< U_WMR_CREATEREGION + }; + if(idx<U_WMR_MIN || idx > U_WMR_MAX){ ret = 0xFFFFFFFF; } + else { ret = U_WMR_VALUES[idx]; } + return(ret); +} + +/** + \brief Look up the name of the WMR record by type. Returns U_WMR_INVALID if out of range. + + \return name of the WMR record, "U_WMR_INVALID" if out of range. + \param idx WMR record type. + +*/ +char *U_wmr_names(int idx){ + int ret; + static char *U_WMR_NAMES[257]={ + "U_WMR_EOF", + "U_WMR_SETBKCOLOR", + "U_WMR_SETBKMODE", + "U_WMR_SETMAPMODE", + "U_WMR_SETROP2", + "U_WMR_SETRELABS", + "U_WMR_SETPOLYFILLMODE", + "U_WMR_SETSTRETCHBLTMODE", + "U_WMR_SETTEXTCHAREXTRA", + "U_WMR_SETTEXTCOLOR", + "U_WMR_SETTEXTJUSTIFICATION", + "U_WMR_SETWINDOWORG", + "U_WMR_SETWINDOWEXT", + "U_WMR_SETVIEWPORTORG", + "U_WMR_SETVIEWPORTEXT", + "U_WMR_OFFSETWINDOWORG", + "U_WMR_SCALEWINDOWEXT", + "U_WMR_OFFSETVIEWPORTORG", + "U_WMR_SCALEVIEWPORTEXT", + "U_WMR_LINETO", + "U_WMR_MOVETO", + "U_WMR_EXCLUDECLIPRECT", + "U_WMR_INTERSECTCLIPRECT", + "U_WMR_ARC", + "U_WMR_ELLIPSE", + "U_WMR_FLOODFILL", + "U_WMR_PIE", + "U_WMR_RECTANGLE", + "U_WMR_ROUNDRECT", + "U_WMR_PATBLT", + "U_WMR_SAVEDC", + "U_WMR_SETPIXEL", + "U_WMR_OFFSETCLIPRGN", + "U_WMR_TEXTOUT", + "U_WMR_BITBLT", + "U_WMR_STRETCHBLT", + "U_WMR_POLYGON", + "U_WMR_POLYLINE", + "U_WMR_ESCAPE", + "U_WMR_RESTOREDC", + "U_WMR_FILLREGION", + "U_WMR_FRAMEREGION", + "U_WMR_INVERTREGION", + "U_WMR_PAINTREGION", + "U_WMR_SELECTCLIPREGION", + "U_WMR_SELECTOBJECT", + "U_WMR_SETTEXTALIGN", + "U_WMR_DRAWTEXT", + "U_WMR_CHORD", + "U_WMR_SETMAPPERFLAGS", + "U_WMR_EXTTEXTOUT", + "U_WMR_SETDIBTODEV", + "U_WMR_SELECTPALETTE", + "U_WMR_REALIZEPALETTE", + "U_WMR_ANIMATEPALETTE", + "U_WMR_SETPALENTRIES", + "U_WMR_POLYPOLYGON", + "U_WMR_RESIZEPALETTE", + "U_WMR_3A", + "U_WMR_3B", + "U_WMR_3C", + "U_WMR_3D", + "U_WMR_3E", + "U_WMR_3F", + "U_WMR_DIBBITBLT", + "U_WMR_DIBSTRETCHBLT", + "U_WMR_DIBCREATEPATTERNBRUSH", + "U_WMR_STRETCHDIB", + "U_WMR_44", + "U_WMR_45", + "U_WMR_46", + "U_WMR_47", + "U_WMR_EXTFLOODFILL", + "U_WMR_49", + "U_WMR_4A", + "U_WMR_4B", + "U_WMR_4C", + "U_WMR_4D", + "U_WMR_4E", + "U_WMR_4F", + "U_WMR_50", + "U_WMR_51", + "U_WMR_52", + "U_WMR_53", + "U_WMR_54", + "U_WMR_55", + "U_WMR_56", + "U_WMR_57", + "U_WMR_58", + "U_WMR_59", + "U_WMR_5A", + "U_WMR_5B", + "U_WMR_5C", + "U_WMR_5D", + "U_WMR_5E", + "U_WMR_5F", + "U_WMR_60", + "U_WMR_61", + "U_WMR_62", + "U_WMR_63", + "U_WMR_64", + "U_WMR_65", + "U_WMR_66", + "U_WMR_67", + "U_WMR_68", + "U_WMR_69", + "U_WMR_6A", + "U_WMR_6B", + "U_WMR_6C", + "U_WMR_6D", + "U_WMR_6E", + "U_WMR_6F", + "U_WMR_70", + "U_WMR_71", + "U_WMR_72", + "U_WMR_73", + "U_WMR_74", + "U_WMR_75", + "U_WMR_76", + "U_WMR_77", + "U_WMR_78", + "U_WMR_79", + "U_WMR_7A", + "U_WMR_7B", + "U_WMR_7C", + "U_WMR_7D", + "U_WMR_7E", + "U_WMR_7F", + "U_WMR_80", + "U_WMR_81", + "U_WMR_82", + "U_WMR_83", + "U_WMR_84", + "U_WMR_85", + "U_WMR_86", + "U_WMR_87", + "U_WMR_88", + "U_WMR_89", + "U_WMR_8A", + "U_WMR_8B", + "U_WMR_8C", + "U_WMR_8D", + "U_WMR_8E", + "U_WMR_8F", + "U_WMR_90", + "U_WMR_91", + "U_WMR_92", + "U_WMR_93", + "U_WMR_94", + "U_WMR_95", + "U_WMR_96", + "U_WMR_97", + "U_WMR_98", + "U_WMR_99", + "U_WMR_9A", + "U_WMR_9B", + "U_WMR_9C", + "U_WMR_9D", + "U_WMR_9E", + "U_WMR_9F", + "U_WMR_A0", + "U_WMR_A1", + "U_WMR_A2", + "U_WMR_A3", + "U_WMR_A4", + "U_WMR_A5", + "U_WMR_A6", + "U_WMR_A7", + "U_WMR_A8", + "U_WMR_A9", + "U_WMR_AA", + "U_WMR_AB", + "U_WMR_AC", + "U_WMR_AD", + "U_WMR_AE", + "U_WMR_AF", + "U_WMR_B0", + "U_WMR_B1", + "U_WMR_B2", + "U_WMR_B3", + "U_WMR_B4", + "U_WMR_B5", + "U_WMR_B6", + "U_WMR_B7", + "U_WMR_B8", + "U_WMR_B9", + "U_WMR_BA", + "U_WMR_BB", + "U_WMR_BC", + "U_WMR_BD", + "U_WMR_BE", + "U_WMR_BF", + "U_WMR_C0", + "U_WMR_C1", + "U_WMR_C2", + "U_WMR_C3", + "U_WMR_C4", + "U_WMR_C5", + "U_WMR_C6", + "U_WMR_C7", + "U_WMR_C8", + "U_WMR_C9", + "U_WMR_CA", + "U_WMR_CB", + "U_WMR_CC", + "U_WMR_CD", + "U_WMR_CE", + "U_WMR_CF", + "U_WMR_D0", + "U_WMR_D1", + "U_WMR_D2", + "U_WMR_D3", + "U_WMR_D4", + "U_WMR_D5", + "U_WMR_D6", + "U_WMR_D7", + "U_WMR_D8", + "U_WMR_D9", + "U_WMR_DA", + "U_WMR_DB", + "U_WMR_DC", + "U_WMR_DD", + "U_WMR_DE", + "U_WMR_DF", + "U_WMR_E0", + "U_WMR_E1", + "U_WMR_E2", + "U_WMR_E3", + "U_WMR_E4", + "U_WMR_E5", + "U_WMR_E6", + "U_WMR_E7", + "U_WMR_E8", + "U_WMR_E9", + "U_WMR_EA", + "U_WMR_EB", + "U_WMR_EC", + "U_WMR_ED", + "U_WMR_EE", + "U_WMR_EF", + "U_WMR_DELETEOBJECT", + "U_WMR_F1", + "U_WMR_F2", + "U_WMR_F3", + "U_WMR_F4", + "U_WMR_F5", + "U_WMR_F6", + "U_WMR_CREATEPALETTE", + "U_WMR_CREATEBRUSH", + "U_WMR_CREATEPATTERNBRUSH", + "U_WMR_CREATEPENINDIRECT", + "U_WMR_CREATEFONTINDIRECT", + "U_WMR_CREATEBRUSHINDIRECT", + "U_WMR_CREATEBITMAPINDIRECT", + "U_WMR_CREATEBITMAP", + "U_WMR_CREATEREGION" + }; + if(idx<U_WMR_MIN || idx > U_WMR_MAX){ ret = 256; } + else { ret = idx; } + return(U_WMR_NAMES[ret]); +} + +/** + \brief Text description of Escape record type. + \return name of the WMR record, "UNKNOWN_ESCAPE" if out of range. + \param idx Escape record type. +*/ +char *U_wmr_escnames(int idx){ + char *name; + if(idx>=0 && idx <= 0x0023){ + switch(idx){ + case 0x0001: name = "NEWFRAME"; break; + case 0x0002: name = "ABORTDOC"; break; + case 0x0003: name = "NEXTBAND"; break; + case 0x0004: name = "SETCOLORTABLE"; break; + case 0x0005: name = "GETCOLORTABLE"; break; + case 0x0006: name = "FLUSHOUT"; break; + case 0x0007: name = "DRAFTMODE"; break; + case 0x0008: name = "QUERYESCSUPPORT"; break; + case 0x0009: name = "SETABORTPROC"; break; + case 0x000A: name = "STARTDOC"; break; + case 0x000B: name = "ENDDOC"; break; + case 0x000C: name = "GETPHYSPAGESIZE"; break; + case 0x000D: name = "GETPRINTINGOFFSET"; break; + case 0x000E: name = "GETSCALINGFACTOR"; break; + case 0x000F: name = "META_ESCAPE_ENHANCED_METAFILE"; break; + case 0x0010: name = "SETPENWIDTH"; break; + case 0x0011: name = "SETCOPYCOUNT"; break; + case 0x0012: name = "SETPAPERSOURCE"; break; + case 0x0013: name = "PASSTHROUGH"; break; + case 0x0014: name = "GETTECHNOLOGY"; break; + case 0x0015: name = "SETLINECAP"; break; + case 0x0016: name = "SETLINEJOIN"; break; + case 0x0017: name = "SETMITERLIMIT"; break; + case 0x0018: name = "BANDINFO"; break; + case 0x0019: name = "DRAWPATTERNRECT"; break; + case 0x001A: name = "GETVECTORPENSIZE"; break; + case 0x001B: name = "GETVECTORBRUSHSIZE"; break; + case 0x001C: name = "ENABLEDUPLEX"; break; + case 0x001D: name = "GETSETPAPERBINS"; break; + case 0x001E: name = "GETSETPRINTORIENT"; break; + case 0x001F: name = "ENUMPAPERBINS"; break; + case 0x0020: name = "SETDIBSCALING"; break; + case 0x0021: name = "EPSPRINTING"; break; + case 0x0022: name = "ENUMPAPERMETRICS"; break; + case 0x0023: name = "GETSETPAPERMETRICS"; break; + } + } + else if(idx == 0x0025){ name = "POSTSCRIPT_DATA"; } + else if(idx == 0x0026){ name = "POSTSCRIPT_IGNORE"; } + else if(idx == 0x002A){ name = "GETDEVICEUNITS"; } + else if(idx == 0x0100){ name = "GETEXTENDEDTEXTMETRICS"; } + else if(idx == 0x0102){ name = "GETPAIRKERNTABLE"; } + else if(idx == 0x0200){ name = "EXTTEXTOUT"; } + else if(idx == 0x0201){ name = "GETFACENAME"; } + else if(idx == 0x0202){ name = "DOWNLOADFACE"; } + else if(idx == 0x0801){ name = "METAFILE_DRIVER"; } + else if(idx == 0x0C01){ name = "QUERYDIBSUPPORT"; } + else if(idx == 0x1000){ name = "BEGIN_PATH"; } + else if(idx == 0x1001){ name = "CLIP_TO_PATH"; } + else if(idx == 0x1002){ name = "END_PATH"; } + else if(idx == 0x100E){ name = "OPEN_CHANNEL"; } + else if(idx == 0x100F){ name = "DOWNLOADHEADER"; } + else if(idx == 0x1010){ name = "CLOSE_CHANNEL"; } + else if(idx == 0x1013){ name = "POSTSCRIPT_PASSTHROUGH"; } + else if(idx == 0x1014){ name = "ENCAPSULATED_POSTSCRIPT";} + else if(idx == 0x1015){ name = "POSTSCRIPT_IDENTIFY"; } + else if(idx == 0x1016){ name = "POSTSCRIPT_INJECTION"; } + else if(idx == 0x1017){ name = "CHECKJPEGFORMAT"; } + else if(idx == 0x1018){ name = "CHECKPNGFORMAT"; } + else if(idx == 0x1019){ name = "GET_PS_FEATURESETTING"; } + else if(idx == 0x101A){ name = "MXDC_ESCAPE"; } + else if(idx == 0x11D8){ name = "SPCLPASSTHROUGH2"; } + else { name = "UNKNOWN_ESCAPE"; } + return(name); +} + +/* one prototype from uwmf_endian. Put it here because end user should never need to see it, so +not in uemf.h or uwmf_endian.h */ +void U_swap2(void *ul, unsigned int count); + +/** + \brief Derive from bounding box and start and end arc, for WMF arc, chord, or pie records, the center, start, and end points, and the bounding rectangle. + + \return 0 on success, other values on errors. + \param rclBox Bounding box of Arc + \param ArcStart Coordinates for Start of Arc + \param ArcEnd Coordinates for End of Arc + \param f1 1 if rotation angle >= 180, else 0 + \param f2 Rotation direction, 1 if counter clockwise, else 0 + \param center Center coordinates + \param start Start coordinates (point on the ellipse defined by rect) + \param end End coordinates (point on the ellipse defined by rect) + \param size W,H of the x,y axes of the bounding rectangle. +*/ +int wmr_arc_points( + U_RECT16 rclBox16, + U_POINT16 ArcStart16, + U_POINT16 ArcEnd16, + int *f1, + int f2, + PU_PAIRF center, + PU_PAIRF start, + PU_PAIRF end, + PU_PAIRF size + ){ + U_RECTL rclBox; + U_POINTL ArcStart,ArcEnd; + rclBox.left = rclBox16.left; + rclBox.top = rclBox16.top; + rclBox.right = rclBox16.right; + rclBox.bottom = rclBox16.bottom; + ArcStart.x = ArcStart16.x; + ArcStart.y = ArcStart16.y; + ArcEnd.x = ArcEnd16.x; + ArcEnd.y = ArcEnd16.y; + return emr_arc_points_common(&rclBox, &ArcStart, &ArcEnd, f1, f2, center, start, end, size); +} + +/** + \brief A U_RECT16 may have its values swapped, L<->R and T<->B, this extracts the leftmost as left, and so forth. + \param rc U_RECT156 binary contents of an WMF file + \param left the leftmost of rc.left and rc.right + \param top the topmost of rc.top and rc.bottom + \param right the rightmost of rc.left and rc.right + \param bottom the bottommost of rc.top and rc.bottom +*/ +void U_sanerect16(U_RECT16 rc, double *left, double *top, double *right, double *bottom){ + if(rc.left < rc.right) { *left = rc.left; *right = rc.right; } + else { *left = rc.right; *right = rc.left; } + if(rc.top < rc.bottom){ *top = rc.top; *bottom = rc.bottom; } + else{ *top = rc.bottom; *bottom = rc.top; } +} + +/* ********************************************************************************************** +These definitions are for code pieces that are used many times in the following implementation. These +definitions are not needed in end user code, so they are here rather than in uwmf.h. +*********************************************************************************************** */ + +/** + \brief Get record size in bytes from U_WMR* record, which may not be aligned + \return number of bytes in record. +*/ +uint32_t U_wmr_size(const U_METARECORD *record){ + uint32_t Size16; + memcpy(&Size16,record, 4); + return(2*Size16); +} + +#define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \ + if(A){\ + if(!B)return(NULL); /* size is derived from U_BITMAPINFO, but NOT from its size field, go figure*/ \ + C = F;\ + D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \ + E = U_SIZE_BITMAPINFOHEADER + 4 * get_real_color_count((char *)&(B->bmiHeader)); /* bmiheader + colortable*/ \ + }\ + else { C = 0; D = 0; E=0; } + + +/** + \brief Create and return a U_FONT structure. + \return pointer to the created U_FONT structure. + \param Height Height in Logical units + \param Width Average Width in Logical units + \param Escapement Angle in 0.1 degrees betweem escapement vector and X axis + \param Orientation Angle in 0.1 degrees between baseline and X axis + \param Weight LF_Weight Enumeration + \param Italic LF_Italic Enumeration + \param Underline LF_Underline Enumeration + \param StrikeOut LF_StrikeOut Enumeration + \param CharSet LF_CharSet Enumeration + \param OutPrecision LF_OutPrecision Enumeration + \param ClipPrecision LF_ClipPrecision Enumeration + \param Quality LF_Quality Enumeration + \param PitchAndFamily LF_PitchAndFamily Enumeration + \param FaceName Name of font. ANSI Latin1, null terminated. +*/ +PU_FONT U_FONT_set( + int16_t Height, //!< Height in Logical units + int16_t Width, //!< Average Width in Logical units + int16_t Escapement, //!< Angle in 0.1 degrees betweem escapement vector and X axis + int16_t Orientation, //!< Angle in 0.1 degrees between baseline and X axis + int16_t Weight, //!< LF_Weight Enumeration + uint8_t Italic, //!< LF_Italic Enumeration + uint8_t Underline, //!< LF_Underline Enumeration + uint8_t StrikeOut, //!< LF_StrikeOut Enumeration + uint8_t CharSet, //!< LF_CharSet Enumeration + uint8_t OutPrecision, //!< LF_OutPrecision Enumeration + uint8_t ClipPrecision, //!< LF_ClipPrecision Enumeration + uint8_t Quality, //!< LF_Quality Enumeration + uint8_t PitchAndFamily, //!< LF_PitchAndFamily Enumeration + char *FaceName //!< Name of font. ANSI Latin1, null terminated. + ){ + PU_FONT font; + int slen = 1 + strlen(FaceName); /* include terminator */ + if(slen & 1)slen++; /* storage length even */ + font = (PU_FONT) calloc(1,slen + U_SIZE_FONT_CORE); /* use calloc to auto fill in terminating '\0'*/ + if(font){ + font->Height = Height; + font->Width = Width; + font->Escapement = Escapement; + font->Orientation = Orientation; + font->Weight = Weight; + font->Italic = Italic; + font->Underline = Underline; + font->StrikeOut = StrikeOut; + font->CharSet = CharSet; + font->OutPrecision = OutPrecision; + font->ClipPrecision = ClipPrecision; + font->Quality = Quality; + font->PitchAndFamily = PitchAndFamily; + strcpy((char *)&font->FaceName, FaceName); + } + return(font); +} + +/** + \brief Create and return a U_PLTENTRY structure. + \return the created U_PLTENTRY structure. + \param Color Color for the U_PLTENTRY +*/ +U_PLTNTRY U_PLTNTRY_set(U_COLORREF Color){ + U_PLTNTRY pe; + pe.Value = Color.Reserved; + pe.Blue = Color.Blue; + pe.Green = Color.Green; + pe.Red = Color.Red; + return(pe); +} + +/** + \brief Create and return a U_PALETTE structure. + \return pointer to the created U_PALETTE structure. + \param Start Either 0x0300 or an offset into the Palette table + \param NumEntries Number of U_LOGPLTNTRY objects + \param PalEntries Pointer to array of PaletteEntry Objects +*/ +PU_PALETTE U_PLTENTRY_set( + uint16_t Start, //!< Either 0x0300 or an offset into the Palette table + uint16_t NumEntries, //!< Number of U_LOGPLTNTRY objects + PU_PLTNTRY PalEntries //!< Pointer to array of PaletteEntry Objects + ){ + PU_PALETTE Palette = NULL; + if(NumEntries){ + Palette = malloc(4 + 4*NumEntries); + if(Palette){ + Palette->Start = Start; + Palette->NumEntries = NumEntries; + memcpy(&Palette->PalEntries, PalEntries, NumEntries*4); + } + } + return(Palette); +} + +/** + \brief Create and return a U_PEN structure. + \return the created U_PEN structure. + \param Style PenStyle Enumeration + \param Width Width of Pen + \param Color Pen Color. +*/ +U_PEN U_PEN_set( + uint16_t Style, //!< PenStyle Enumeration + uint16_t Width, //!< Width of Pen + U_COLORREF Color //!< Pen Color. + ){ + U_PEN p; + p.Style = Style; + p.Widthw[0] = Width; + p.Widthw[1] = 0; /* ignored */ + p.Color.Red = Color.Red; + p.Color.Green = Color.Green; + p.Color.Blue = Color.Blue; + p.Color.Reserved = Color.Reserved; + return(p); +} + +/** + \brief Create and return a U_RECT16 structure from Upper Left and Lower Right corner points. + \param ul upper left corner of rectangle + \param lr lower right corner of rectangle +*/ +U_RECT16 U_RECT16_set( + U_POINT16 ul, + U_POINT16 lr + ){ + U_RECT16 rect; + rect.left = ul.x; + rect.top = ul.y; + rect.right = lr.x; + rect.bottom = lr.y; + return(rect); +} + +/** + \brief Create and return a U_BITMAP16 structure + \return pointer to the U_BITMAP16 structure, or NULL on failure + \param Type bitmap Type (not described at all in the WMF PDF) + \param Width bitmap width in pixels. + \param Height bitmap height in scan lines. + \param LineN each array line in Bits is a multiple of this (4 for a DIB) + \param BitsPixel number of adjacent color bits on each plane (R bits + G bits + B bits ????) + \param Bits bitmap pixel data. Bytes contained = (((Width * BitsPixel + 15) >> 4) << 1) * Height +*/ +PU_BITMAP16 U_BITMAP16_set( + const int16_t Type, + const int16_t Width, + const int16_t Height, + const int16_t LineN, + const uint8_t BitsPixel, + const char *Bits + ){ + PU_BITMAP16 bm16; + uint32_t irecsize; + int cbBits,iHeight; + int usedbytes; + int16_t WidthBytes; // total bytes per scan line (used and padding). + + usedbytes = (Width * BitsPixel + 7)/8; // width of line in fully and partially occupied bytes + WidthBytes = (LineN * ((usedbytes + (LineN - 1) ) / LineN)); // Account for padding required by line alignment in the pixel array + + iHeight = (Height < 0 ? -Height : Height); /* DIB can use a negative height, but it does not look like a Bitmap16 object can */ + cbBits = WidthBytes * iHeight; + if(!Bits || cbBits<=0)return(NULL); + irecsize = U_SIZE_BITMAP16 + cbBits; + bm16 = (PU_BITMAP16) malloc(irecsize); + if(bm16){ + bm16->Type = Type; + bm16->Width = Width; + bm16->Height = iHeight; + bm16->WidthBytes = WidthBytes; + bm16->Planes = 1; + bm16->BitsPixel = BitsPixel; + memcpy((char *)bm16 + U_SIZE_BITMAP16,Bits,cbBits); + } + return(bm16); +} + +/** + \brief Create and return a U_SCAN structure + \return U_SCAN structure + \param count Number of entries in the ScanLines array + \param top Y coordinate of the top scanline + \param bottom Y coordinate of the bottom scanline + \param ScanLines Array of 16 bit left/right pairs, array has 2*count entries +*/ +PU_SCAN U_SCAN_set( + uint16_t count, //!< Number of entries in the ScanLines array + uint16_t top, //!< Y coordinate of the top scanline + uint16_t bottom, //!< Y coordinate of the bottom scanline + uint16_t *ScanLines //!< Array of 16 bit left/right pairs, array has 2*count entries + ){ + PU_SCAN scan=NULL; + int size = 6 + count*4; + scan = malloc(size); + if(scan){ + scan->count = count; + scan->top = top; + scan->bottom = bottom; + memcpy(&scan->ScanLines,ScanLines,4*count); + } + return(scan); +} + +/** + \brief Create and return a U_REGION structure + \return pointer to created U_REGION structure or NULL on error + \param Size aScans in bytes + regions size in bytes (size of this header plus all U_SCAN objects?) + \param sCount number of scan objects in region (docs say scanlines, but then no way to add sizes) + \param sMax largest number of points in any scan + \param sRect bounding rectangle + \param aScans series of U_SCAN objects to append. This is also an array of uint16_t, but should be handled as a bunch of U_SCAN objects tightly packed into the buffer. +*/ +PU_REGION U_REGION_set( + int16_t Size, //!< aScans in bytes + regions size in bytes (size of this header plus all U_SCAN objects?) + int16_t sCount, //!< number of scan objects in region (docs say scanlines, but then no way to add sizes) + int16_t sMax, //!< largest number of points in any scan + U_RECT16 sRect, //!< bounding rectangle + uint16_t *aScans //!< series of U_SCAN objects to append. This is also an array of uint16_t, but should be handled as a bunch of U_SCAN objects tightly packed into the buffer. + ){ + PU_REGION region=NULL; + char *psc; + int scansize,i,off; + psc = (char *)aScans; + for(scansize=i=0; i<sCount; i++){ + off = 6 + 4*(((PU_SCAN)psc)->count); + scansize += off; + psc += off; + } + region = malloc(U_SIZE_REGION + scansize); + if(region){ + region->ignore1 = 0; + region->Type = 0x0006; + region->ignore2 = 0; + region->Size = Size; + region->sCount = sCount; + region->sMax = sMax; + region->sRect = sRect; + memcpy(®ion->aScans,aScans,scansize); + } + return(region); +} + + +/** + \brief Create and return a U_WLOGBRUSH structure. + \return the created U_WLOGBRUSH structure. + \param Style BrushStyle Enumeration + \param Color Brush Color value + \param Hatch HatchStyle Enumeration +*/ +U_WLOGBRUSH U_WLOGBRUSH_set( + uint16_t Style, //!< BrushStyle Enumeration + U_COLORREF Color, //!< Brush Color value + uint16_t Hatch //!< HatchStyle Enumeration + ){ + U_WLOGBRUSH lb; + lb.Style = Style; + lb.Color.Red = Color.Red; + lb.Color.Green = Color.Green; + lb.Color.Blue = Color.Blue; + lb.Color.Reserved = Color.Reserved; + lb.Hatch = Hatch; + return(lb); +} + + +/** + \brief Create and return a U_PAIRF structure. + \return pointer to the created U_PAIRF structure. + \param x x value + \param y y value +*/ +PU_PAIRF U_PAIRF_set( + float x, //!< x value + float y //!< y value + ){ + PU_PAIRF pf=malloc(U_SIZE_PAIRF); + if(pf){ + pf->x = x; + pf->y = y; + } + return(pf); +} + +/* ********************************************************************************************** +These functions are used for Image conversions and other +utility operations. Character type conversions are in uwmf_utf.c +*********************************************************************************************** */ + +/** + \brief Calculate the int16_t checksum of the buffer for the number of positions specified. This is XOR of all values. + \return checksum + \param buf array of uint16_t values + \param count number of members in buf + +*/ +int16_t U_16_checksum(int16_t *buf, int count){ + int16_t result=0; + for(;count;count--){ + result ^= *buf++; + } + return(result); +} + +/** + \brief Dump a WMFHANDLES structure. Not for use in production code. + \param string Text to output before dumping eht structure + \param handle Handle + \param wht WMFHANDLES structure to dump +*/ +void dumpwht( + char *string, + unsigned int *handle, + WMFHANDLES *wht + ){ + uint32_t i; + printf("%s\n",string); + printf("lo: %d hi: %d peak: %d\n", wht->lolimit, wht->hilimit, wht->peak); + if(handle){ + printf("handle: %d \n",*handle); + } + for(i=0;i<=5;i++){ + printf("table[%d]: %d\n",i,wht->table[i]); + } +} + +/** + \brief Make up an approximate dx array to pass to U_WMREXTTEXTOUT_set(), based on character height and weight. + + Take abs. value of character height, get width by multiplying by 0.6, and correct weight + approximately, with formula (measured on screen for one text line of Arial). + Caller is responsible for free() on the returned pointer. + + \return pointer to dx array + \param height character height (absolute value will be used) + \param weight LF_Weight Enumeration (character weight) + \param members Number of entries to put into dx + +*/ +int16_t *dx16_set( + int32_t height, + uint32_t weight, + uint32_t members + ){ + uint32_t i, width; + int16_t *dx; + dx = (int16_t *) malloc(members * sizeof(int16_t)); + if(dx){ + if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL; + width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904)); + for ( i = 0; i < members; i++ ){ dx[i] = (width > INT16_MAX ? INT16_MAX : width); } + } + return(dx); +} +/** + \brief Look up the properties (a bit map) of a type of WMR record. + Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc.. + \return bitmap of WMR record properties, or U_WMR_INVALID on error or release of all memory. + \param type WMR record type. If U_WMR_INVALID release memory. (There is no U_WMR_INVALID WMR record type) + +*/ +uint32_t U_wmr_properties(uint32_t type){ + static uint32_t *table=NULL; + uint32_t result = U_WMR_INVALID; // initialized to indicate an error (on a lookup) or nothing (on a memory release) + if(type == U_WMR_INVALID){ + if(table)free(table); + table=NULL; + } + else if(type<=U_WMR_MAX){ // type is uint so always >=0, no need to test U_WMR_MIN, which is 0. + if(!table){ + table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_WMR_MAX)); + if(!table)return(result); + // 0x200 0x100 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01 + // properties (U_DRAW_*) TEXT ALTERS ONLYTO VISIBLE + // NOFILL OBJECT PATH FORCE CLOSED NOTEMPTY + // Record Type + table[0x00] = 0x0A0; // U_WMREOF 0 0 1 0 1 0 0 0 0 0 Force out any pending draw + table[0x01] = 0x020; // U_WMRSETBKCOLOR 0 0 0 0 1 0 0 0 0 0 + table[0x02] = 0x020; // U_WMRSETBKMODE 0 0 0 0 1 0 0 0 0 0 + table[0x03] = 0x0A0; // U_WMRSETMAPMODE 0 0 1 0 1 0 0 0 0 0 + table[0x04] = 0x0A0; // U_WMRSETROP2 0 0 1 0 1 0 0 0 0 0 + table[0x05] = 0x000; // U_WMRSETRELABS 0 0 0 0 0 0 0 0 0 0 No idea what this is supposed to do + table[0x06] = 0x0A0; // U_WMRSETPOLYFILLMODE 0 0 1 0 1 0 0 0 0 0 + table[0x07] = 0x0A0; // U_WMRSETSTRETCHBLTMODE 0 0 1 0 1 0 0 0 0 0 + table[0x08] = 0x000; // U_WMRSETTEXTCHAREXTRA 0 0 0 0 0 0 0 0 0 0 + table[0x09] = 0x020; // U_WMRSETTEXTCOLOR 0 0 0 0 1 0 0 0 0 0 + table[0x0A] = 0x020; // U_WMRSETTEXTJUSTIFICATION 0 0 0 0 1 0 0 0 0 0 + table[0x0B] = 0x0A0; // U_WMRSETWINDOWORG 0 0 1 0 1 0 0 0 0 0 + table[0x0C] = 0x0A0; // U_WMRSETWINDOWEXT 0 0 1 0 1 0 0 0 0 0 + table[0x0D] = 0x0A0; // U_WMRSETVIEWPORTORG 0 0 1 0 1 0 0 0 0 0 + table[0x0E] = 0x0A0; // U_WMRSETVIEWPORTEXT 0 0 1 0 1 0 0 0 0 0 + table[0x0F] = 0x000; // U_WMROFFSETWINDOWORG 0 0 0 0 0 0 0 0 0 0 + table[0x10] = 0x000; // U_WMRSCALEWINDOWEXT 0 0 0 0 0 0 0 0 0 0 + table[0x11] = 0x0A0; // U_WMROFFSETVIEWPORTORG 0 0 1 0 1 0 0 0 0 0 + table[0x12] = 0x0A0; // U_WMRSCALEVIEWPORTEXT 0 0 1 0 1 0 0 0 0 0 + table[0x13] = 0x28B; // U_WMRLINETO 1 0 1 0 0 0 1 0 1 1 + table[0x14] = 0x289; // U_WMRMOVETO 1 0 1 0 0 0 1 0 0 1 + table[0x15] = 0x0A0; // U_WMREXCLUDECLIPRECT 0 0 1 0 1 0 0 0 0 0 + table[0x16] = 0x0A0; // U_WMRINTERSECTCLIPRECT 0 0 1 0 1 0 0 0 0 0 + table[0x17] = 0x283; // U_WMRARC 1 0 1 0 0 0 0 0 1 1 + table[0x18] = 0x087; // U_WMRELLIPSE 0 0 1 0 0 0 0 1 1 1 + table[0x19] = 0x082; // U_WMRFLOODFILL 0 0 1 0 0 0 0 0 1 0 + table[0x1A] = 0x087; // U_WMRPIE 0 0 1 0 0 0 0 1 1 1 + table[0x1B] = 0x087; // U_WMRRECTANGLE 0 0 1 0 0 0 0 1 1 1 + table[0x1C] = 0x087; // U_WMRROUNDRECT 0 0 1 0 0 0 0 1 1 1 + table[0x1D] = 0x000; // U_WMRPATBLT 0 0 1 0 0 0 0 1 1 1 + table[0x1E] = 0x0A0; // U_WMRSAVEDC 0 0 1 0 1 0 0 0 0 0 + table[0x1F] = 0x082; // U_WMRSETPIXEL 0 0 1 0 0 0 0 0 1 0 + table[0x20] = 0x0A0; // U_WMROFFSETCLIPRGN 0 0 1 0 1 0 0 0 0 0 + table[0x21] = 0x002; // U_WMRTEXTOUT 0 0 0 0 0 0 0 0 1 0 + table[0x22] = 0x082; // U_WMRBITBLT 0 0 1 0 0 0 0 0 1 0 + table[0x23] = 0x082; // U_WMRSTRETCHBLT 0 0 1 0 0 0 0 0 1 0 + table[0x24] = 0x083; // U_WMRPOLYGON 0 0 1 0 0 0 0 0 1 1 + table[0x25] = 0x283; // U_WMRPOLYLINE 1 0 1 0 0 0 0 0 1 1 + table[0x26] = 0x0A0; // U_WMRESCAPE 0 0 1 0 1 0 0 0 0 0 + table[0x27] = 0x0A0; // U_WMRRESTOREDC 0 0 1 0 1 0 0 0 0 0 + table[0x28] = 0x082; // U_WMRFILLREGION 0 0 1 0 0 0 0 0 1 0 + table[0x29] = 0x082; // U_WMRFRAMEREGION 0 0 1 0 0 0 0 0 1 0 + table[0x2A] = 0x082; // U_WMRINVERTREGION 0 0 1 0 0 0 0 0 1 0 + table[0x2B] = 0x082; // U_WMRPAINTREGION 0 0 1 0 0 0 0 0 1 0 + table[0x2C] = 0x0A0; // U_WMRSELECTCLIPREGION 0 0 1 0 1 0 0 0 0 0 + table[0x2D] = 0x020; // U_WMRSELECTOBJECT 0 0 0 0 1 0 0 0 0 0 + table[0x2E] = 0x020; // U_WMRSETTEXTALIGN 0 0 0 0 1 0 0 0 0 0 + table[0x2F] = 0x002; // U_WMRDRAWTEXT 0 0 0 0 0 0 0 0 1 0 no idea what this is supposed to do + table[0x30] = 0x087; // U_WMRCHORD 0 0 1 0 0 0 0 1 1 1 + table[0x31] = 0x0A0; // U_WMRSETMAPPERFLAGS 0 0 1 0 1 0 0 0 0 0 + table[0x32] = 0x002; // U_WMREXTTEXTOUT 0 0 0 0 0 0 0 0 1 0 + table[0x33] = 0x000; // U_WMRSETDIBTODEV 0 0 0 0 0 0 0 0 0 0 + table[0x34] = 0x0A0; // U_WMRSELECTPALETTE 0 0 1 0 1 0 0 0 0 0 + table[0x35] = 0x0A0; // U_WMRREALIZEPALETTE 0 0 1 0 1 0 0 0 0 0 + table[0x36] = 0x0A0; // U_WMRANIMATEPALETTE 0 0 1 0 1 0 0 0 0 0 + table[0x37] = 0x0A0; // U_WMRSETPALENTRIES 0 0 1 0 1 0 0 0 0 0 + table[0x38] = 0x087; // U_WMRPOLYPOLYGON 0 0 1 0 0 0 0 1 1 1 + table[0x39] = 0x0A0; // U_WMRRESIZEPALETTE 0 0 1 0 1 0 0 0 0 0 + table[0x3A] = 0x000; // U_WMR3A 0 0 0 0 0 0 0 0 0 0 + table[0x3B] = 0x000; // U_WMR3B 0 0 0 0 0 0 0 0 0 0 + table[0x3C] = 0x000; // U_WMR3C 0 0 0 0 0 0 0 0 0 0 + table[0x3D] = 0x000; // U_WMR3D 0 0 0 0 0 0 0 0 0 0 + table[0x3E] = 0x000; // U_WMR3E 0 0 0 0 0 0 0 0 0 0 + table[0x3F] = 0x000; // U_WMR3F 0 0 0 0 0 0 0 0 0 0 + table[0x40] = 0x0A0; // U_WMRDIBBITBLT 0 0 1 0 1 0 0 0 0 0 + table[0x41] = 0x0A0; // U_WMRDIBSTRETCHBLT 0 0 1 0 1 0 0 0 0 0 + table[0x42] = 0x080; // U_WMRDIBCREATEPATTERNBRUSH 0 0 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions + table[0x43] = 0x0A0; // U_WMRSTRETCHDIB 0 0 1 0 1 0 0 0 0 0 + table[0x44] = 0x000; // U_WMR44 0 0 0 0 0 0 0 0 0 0 + table[0x45] = 0x000; // U_WMR45 0 0 0 0 0 0 0 0 0 0 + table[0x46] = 0x000; // U_WMR46 0 0 0 0 0 0 0 0 0 0 + table[0x47] = 0x000; // U_WMR47 0 0 0 0 0 0 0 0 0 0 + table[0x48] = 0x082; // U_WMREXTFLOODFILL 0 0 1 0 0 0 0 0 1 0 + table[0x49] = 0x000; // U_WMR49 0 0 0 0 0 0 0 0 0 0 + table[0x4A] = 0x000; // U_WMR4A 0 0 0 0 0 0 0 0 0 0 + table[0x4B] = 0x000; // U_WMR4B 0 0 0 0 0 0 0 0 0 0 + table[0x4C] = 0x000; // U_WMR4C 0 0 0 0 0 0 0 0 0 0 + table[0x4D] = 0x000; // U_WMR4D 0 0 0 0 0 0 0 0 0 0 + table[0x4E] = 0x000; // U_WMR4E 0 0 0 0 0 0 0 0 0 0 + table[0x4F] = 0x000; // U_WMR4F 0 0 0 0 0 0 0 0 0 0 + table[0x50] = 0x000; // U_WMR50 0 0 0 0 0 0 0 0 0 0 + table[0x51] = 0x000; // U_WMR51 0 0 0 0 0 0 0 0 0 0 + table[0x52] = 0x000; // U_WMR52 0 0 0 0 0 0 0 0 0 0 + table[0x53] = 0x000; // U_WMR53 0 0 0 0 0 0 0 0 0 0 + table[0x54] = 0x000; // U_WMR54 0 0 0 0 0 0 0 0 0 0 + table[0x55] = 0x000; // U_WMR55 0 0 0 0 0 0 0 0 0 0 + table[0x56] = 0x000; // U_WMR56 0 0 0 0 0 0 0 0 0 0 + table[0x57] = 0x000; // U_WMR57 0 0 0 0 0 0 0 0 0 0 + table[0x58] = 0x000; // U_WMR58 0 0 0 0 0 0 0 0 0 0 + table[0x59] = 0x000; // U_WMR59 0 0 0 0 0 0 0 0 0 0 + table[0x5A] = 0x000; // U_WMR5A 0 0 0 0 0 0 0 0 0 0 + table[0x5B] = 0x000; // U_WMR5B 0 0 0 0 0 0 0 0 0 0 + table[0x5C] = 0x000; // U_WMR5C 0 0 0 0 0 0 0 0 0 0 + table[0x5D] = 0x000; // U_WMR5D 0 0 0 0 0 0 0 0 0 0 + table[0x5E] = 0x000; // U_WMR5E 0 0 0 0 0 0 0 0 0 0 + table[0x5F] = 0x000; // U_WMR5F 0 0 0 0 0 0 0 0 0 0 + table[0x60] = 0x000; // U_WMR60 0 0 0 0 0 0 0 0 0 0 + table[0x61] = 0x000; // U_WMR61 0 0 0 0 0 0 0 0 0 0 + table[0x62] = 0x000; // U_WMR62 0 0 0 0 0 0 0 0 0 0 + table[0x63] = 0x000; // U_WMR63 0 0 0 0 0 0 0 0 0 0 + table[0x64] = 0x000; // U_WMR64 0 0 0 0 0 0 0 0 0 0 + table[0x65] = 0x000; // U_WMR65 0 0 0 0 0 0 0 0 0 0 + table[0x66] = 0x000; // U_WMR66 0 0 0 0 0 0 0 0 0 0 + table[0x67] = 0x000; // U_WMR67 0 0 0 0 0 0 0 0 0 0 + table[0x68] = 0x000; // U_WMR68 0 0 0 0 0 0 0 0 0 0 + table[0x69] = 0x000; // U_WMR69 0 0 0 0 0 0 0 0 0 0 + table[0x6A] = 0x000; // U_WMR6A 0 0 0 0 0 0 0 0 0 0 + table[0x6B] = 0x000; // U_WMR6B 0 0 0 0 0 0 0 0 0 0 + table[0x6C] = 0x000; // U_WMR6C 0 0 0 0 0 0 0 0 0 0 + table[0x6D] = 0x000; // U_WMR6D 0 0 0 0 0 0 0 0 0 0 + table[0x6E] = 0x000; // U_WMR6E 0 0 0 0 0 0 0 0 0 0 + table[0x6F] = 0x000; // U_WMR6F 0 0 0 0 0 0 0 0 0 0 + table[0x70] = 0x000; // U_WMR70 0 0 0 0 0 0 0 0 0 0 + table[0x71] = 0x000; // U_WMR71 0 0 0 0 0 0 0 0 0 0 + table[0x72] = 0x000; // U_WMR72 0 0 0 0 0 0 0 0 0 0 + table[0x73] = 0x000; // U_WMR73 0 0 0 0 0 0 0 0 0 0 + table[0x74] = 0x000; // U_WMR74 0 0 0 0 0 0 0 0 0 0 + table[0x75] = 0x000; // U_WMR75 0 0 0 0 0 0 0 0 0 0 + table[0x76] = 0x000; // U_WMR76 0 0 0 0 0 0 0 0 0 0 + table[0x77] = 0x000; // U_WMR77 0 0 0 0 0 0 0 0 0 0 + table[0x78] = 0x000; // U_WMR78 0 0 0 0 0 0 0 0 0 0 + table[0x79] = 0x000; // U_WMR79 0 0 0 0 0 0 0 0 0 0 + table[0x7A] = 0x000; // U_WMR7A 0 0 0 0 0 0 0 0 0 0 + table[0x7B] = 0x000; // U_WMR7B 0 0 0 0 0 0 0 0 0 0 + table[0x7C] = 0x000; // U_WMR7C 0 0 0 0 0 0 0 0 0 0 + table[0x7D] = 0x000; // U_WMR7D 0 0 0 0 0 0 0 0 0 0 + table[0x7E] = 0x000; // U_WMR7E 0 0 0 0 0 0 0 0 0 0 + table[0x7F] = 0x000; // U_WMR7F 0 0 0 0 0 0 0 0 0 0 + table[0x80] = 0x000; // U_WMR80 0 0 0 0 0 0 0 0 0 0 + table[0x81] = 0x000; // U_WMR81 0 0 0 0 0 0 0 0 0 0 + table[0x82] = 0x000; // U_WMR82 0 0 0 0 0 0 0 0 0 0 + table[0x83] = 0x000; // U_WMR83 0 0 0 0 0 0 0 0 0 0 + table[0x84] = 0x000; // U_WMR84 0 0 0 0 0 0 0 0 0 0 + table[0x85] = 0x000; // U_WMR85 0 0 0 0 0 0 0 0 0 0 + table[0x86] = 0x000; // U_WMR86 0 0 0 0 0 0 0 0 0 0 + table[0x87] = 0x000; // U_WMR87 0 0 0 0 0 0 0 0 0 0 + table[0x88] = 0x000; // U_WMR88 0 0 0 0 0 0 0 0 0 0 + table[0x89] = 0x000; // U_WMR89 0 0 0 0 0 0 0 0 0 0 + table[0x8A] = 0x000; // U_WMR8A 0 0 0 0 0 0 0 0 0 0 + table[0x8B] = 0x000; // U_WMR8B 0 0 0 0 0 0 0 0 0 0 + table[0x8C] = 0x000; // U_WMR8C 0 0 0 0 0 0 0 0 0 0 + table[0x8D] = 0x000; // U_WMR8D 0 0 0 0 0 0 0 0 0 0 + table[0x8E] = 0x000; // U_WMR8E 0 0 0 0 0 0 0 0 0 0 + table[0x8F] = 0x000; // U_WMR8F 0 0 0 0 0 0 0 0 0 0 + table[0x90] = 0x000; // U_WMR90 0 0 0 0 0 0 0 0 0 0 + table[0x91] = 0x000; // U_WMR91 0 0 0 0 0 0 0 0 0 0 + table[0x92] = 0x000; // U_WMR92 0 0 0 0 0 0 0 0 0 0 + table[0x93] = 0x000; // U_WMR93 0 0 0 0 0 0 0 0 0 0 + table[0x94] = 0x000; // U_WMR94 0 0 0 0 0 0 0 0 0 0 + table[0x95] = 0x000; // U_WMR95 0 0 0 0 0 0 0 0 0 0 + table[0x96] = 0x000; // U_WMR96 0 0 0 0 0 0 0 0 0 0 + table[0x97] = 0x000; // U_WMR97 0 0 0 0 0 0 0 0 0 0 + table[0x98] = 0x000; // U_WMR98 0 0 0 0 0 0 0 0 0 0 + table[0x99] = 0x000; // U_WMR99 0 0 0 0 0 0 0 0 0 0 + table[0x9A] = 0x000; // U_WMR9A 0 0 0 0 0 0 0 0 0 0 + table[0x9B] = 0x000; // U_WMR9B 0 0 0 0 0 0 0 0 0 0 + table[0x9C] = 0x000; // U_WMR9C 0 0 0 0 0 0 0 0 0 0 + table[0x9D] = 0x000; // U_WMR9D 0 0 0 0 0 0 0 0 0 0 + table[0x9E] = 0x000; // U_WMR9E 0 0 0 0 0 0 0 0 0 0 + table[0x9F] = 0x000; // U_WMR9F 0 0 0 0 0 0 0 0 0 0 + table[0xA0] = 0x000; // U_WMRA0 0 0 0 0 0 0 0 0 0 0 + table[0xA1] = 0x000; // U_WMRA1 0 0 0 0 0 0 0 0 0 0 + table[0xA2] = 0x000; // U_WMRA2 0 0 0 0 0 0 0 0 0 0 + table[0xA3] = 0x000; // U_WMRA3 0 0 0 0 0 0 0 0 0 0 + table[0xA4] = 0x000; // U_WMRA4 0 0 0 0 0 0 0 0 0 0 + table[0xA5] = 0x000; // U_WMRA5 0 0 0 0 0 0 0 0 0 0 + table[0xA6] = 0x000; // U_WMRA6 0 0 0 0 0 0 0 0 0 0 + table[0xA7] = 0x000; // U_WMRA7 0 0 0 0 0 0 0 0 0 0 + table[0xA8] = 0x000; // U_WMRA8 0 0 0 0 0 0 0 0 0 0 + table[0xA9] = 0x000; // U_WMRA9 0 0 0 0 0 0 0 0 0 0 + table[0xAA] = 0x000; // U_WMRAA 0 0 0 0 0 0 0 0 0 0 + table[0xAB] = 0x000; // U_WMRAB 0 0 0 0 0 0 0 0 0 0 + table[0xAC] = 0x000; // U_WMRAC 0 0 0 0 0 0 0 0 0 0 + table[0xAD] = 0x000; // U_WMRAD 0 0 0 0 0 0 0 0 0 0 + table[0xAE] = 0x000; // U_WMRAE 0 0 0 0 0 0 0 0 0 0 + table[0xAF] = 0x000; // U_WMRAF 0 0 0 0 0 0 0 0 0 0 + table[0xB0] = 0x000; // U_WMRB0 0 0 0 0 0 0 0 0 0 0 + table[0xB1] = 0x000; // U_WMRB1 0 0 0 0 0 0 0 0 0 0 + table[0xB2] = 0x000; // U_WMRB2 0 0 0 0 0 0 0 0 0 0 + table[0xB3] = 0x000; // U_WMRB3 0 0 0 0 0 0 0 0 0 0 + table[0xB4] = 0x000; // U_WMRB4 0 0 0 0 0 0 0 0 0 0 + table[0xB5] = 0x000; // U_WMRB5 0 0 0 0 0 0 0 0 0 0 + table[0xB6] = 0x000; // U_WMRB6 0 0 0 0 0 0 0 0 0 0 + table[0xB7] = 0x000; // U_WMRB7 0 0 0 0 0 0 0 0 0 0 + table[0xB8] = 0x000; // U_WMRB8 0 0 0 0 0 0 0 0 0 0 + table[0xB9] = 0x000; // U_WMRB9 0 0 0 0 0 0 0 0 0 0 + table[0xBA] = 0x000; // U_WMRBA 0 0 0 0 0 0 0 0 0 0 + table[0xBB] = 0x000; // U_WMRBB 0 0 0 0 0 0 0 0 0 0 + table[0xBC] = 0x000; // U_WMRBC 0 0 0 0 0 0 0 0 0 0 + table[0xBD] = 0x000; // U_WMRBD 0 0 0 0 0 0 0 0 0 0 + table[0xBE] = 0x000; // U_WMRBE 0 0 0 0 0 0 0 0 0 0 + table[0xBF] = 0x000; // U_WMRBF 0 0 0 0 0 0 0 0 0 0 + table[0xC0] = 0x000; // U_WMRC0 0 0 0 0 0 0 0 0 0 0 + table[0xC1] = 0x000; // U_WMRC1 0 0 0 0 0 0 0 0 0 0 + table[0xC2] = 0x000; // U_WMRC2 0 0 0 0 0 0 0 0 0 0 + table[0xC3] = 0x000; // U_WMRC3 0 0 0 0 0 0 0 0 0 0 + table[0xC4] = 0x000; // U_WMRC4 0 0 0 0 0 0 0 0 0 0 + table[0xC5] = 0x000; // U_WMRC5 0 0 0 0 0 0 0 0 0 0 + table[0xC6] = 0x000; // U_WMRC6 0 0 0 0 0 0 0 0 0 0 + table[0xC7] = 0x000; // U_WMRC7 0 0 0 0 0 0 0 0 0 0 + table[0xC8] = 0x000; // U_WMRC8 0 0 0 0 0 0 0 0 0 0 + table[0xC9] = 0x000; // U_WMRC9 0 0 0 0 0 0 0 0 0 0 + table[0xCA] = 0x000; // U_WMRCA 0 0 0 0 0 0 0 0 0 0 + table[0xCB] = 0x000; // U_WMRCB 0 0 0 0 0 0 0 0 0 0 + table[0xCC] = 0x000; // U_WMRCC 0 0 0 0 0 0 0 0 0 0 + table[0xCD] = 0x000; // U_WMRCD 0 0 0 0 0 0 0 0 0 0 + table[0xCE] = 0x000; // U_WMRCE 0 0 0 0 0 0 0 0 0 0 + table[0xCF] = 0x000; // U_WMRCF 0 0 0 0 0 0 0 0 0 0 + table[0xD0] = 0x000; // U_WMRD0 0 0 0 0 0 0 0 0 0 0 + table[0xD1] = 0x000; // U_WMRD1 0 0 0 0 0 0 0 0 0 0 + table[0xD2] = 0x000; // U_WMRD2 0 0 0 0 0 0 0 0 0 0 + table[0xD3] = 0x000; // U_WMRD3 0 0 0 0 0 0 0 0 0 0 + table[0xD4] = 0x000; // U_WMRD4 0 0 0 0 0 0 0 0 0 0 + table[0xD5] = 0x000; // U_WMRD5 0 0 0 0 0 0 0 0 0 0 + table[0xD6] = 0x000; // U_WMRD6 0 0 0 0 0 0 0 0 0 0 + table[0xD7] = 0x000; // U_WMRD7 0 0 0 0 0 0 0 0 0 0 + table[0xD8] = 0x000; // U_WMRD8 0 0 0 0 0 0 0 0 0 0 + table[0xD9] = 0x000; // U_WMRD9 0 0 0 0 0 0 0 0 0 0 + table[0xDA] = 0x000; // U_WMRDA 0 0 0 0 0 0 0 0 0 0 + table[0xDB] = 0x000; // U_WMRDB 0 0 0 0 0 0 0 0 0 0 + table[0xDC] = 0x000; // U_WMRDC 0 0 0 0 0 0 0 0 0 0 + table[0xDD] = 0x000; // U_WMRDD 0 0 0 0 0 0 0 0 0 0 + table[0xDE] = 0x000; // U_WMRDE 0 0 0 0 0 0 0 0 0 0 + table[0xDF] = 0x000; // U_WMRDF 0 0 0 0 0 0 0 0 0 0 + table[0xE0] = 0x000; // U_WMRE0 0 0 0 0 0 0 0 0 0 0 + table[0xE1] = 0x000; // U_WMRE1 0 0 0 0 0 0 0 0 0 0 + table[0xE2] = 0x000; // U_WMRE2 0 0 0 0 0 0 0 0 0 0 + table[0xE3] = 0x000; // U_WMRE3 0 0 0 0 0 0 0 0 0 0 + table[0xE4] = 0x000; // U_WMRE4 0 0 0 0 0 0 0 0 0 0 + table[0xE5] = 0x000; // U_WMRE5 0 0 0 0 0 0 0 0 0 0 + table[0xE6] = 0x000; // U_WMRE6 0 0 0 0 0 0 0 0 0 0 + table[0xE7] = 0x000; // U_WMRE7 0 0 0 0 0 0 0 0 0 0 + table[0xE8] = 0x000; // U_WMRE8 0 0 0 0 0 0 0 0 0 0 + table[0xE9] = 0x000; // U_WMRE9 0 0 0 0 0 0 0 0 0 0 + table[0xEA] = 0x000; // U_WMREA 0 0 0 0 0 0 0 0 0 0 + table[0xEB] = 0x000; // U_WMREB 0 0 0 0 0 0 0 0 0 0 + table[0xEC] = 0x000; // U_WMREC 0 0 0 0 0 0 0 0 0 0 + table[0xED] = 0x000; // U_WMRED 0 0 0 0 0 0 0 0 0 0 + table[0xEE] = 0x000; // U_WMREE 0 0 0 0 0 0 0 0 0 0 + table[0xEF] = 0x000; // U_WMREF 0 0 0 0 0 0 0 0 0 0 + table[0xF0] = 0x020; // U_WMRDELETEOBJECT 0 0 0 0 1 0 0 0 0 0 + table[0xF1] = 0x000; // U_WMRF1 0 0 0 0 0 0 0 0 0 0 + table[0xF2] = 0x000; // U_WMRF2 0 0 0 0 0 0 0 0 0 0 + table[0xF3] = 0x000; // U_WMRF3 0 0 0 0 0 0 0 0 0 0 + table[0xF4] = 0x000; // U_WMRF4 0 0 0 0 0 0 0 0 0 0 + table[0xF5] = 0x000; // U_WMRF5 0 0 0 0 0 0 0 0 0 0 + table[0xF6] = 0x000; // U_WMRF6 0 0 0 0 0 0 0 0 0 0 + table[0xF7] = 0x120; // U_WMRCREATEPALETTE 0 1 0 0 1 0 0 0 0 0 Not selected yet, so no change in drawing conditions + table[0xF8] = 0x120; // U_WMRCREATEBRUSH 0 1 0 0 1 0 0 0 0 0 " + table[0xF9] = 0x120; // U_WMRCREATEPATTERNBRUSH 0 1 0 0 1 0 0 0 0 0 " + table[0xFA] = 0x120; // U_WMRCREATEPENINDIRECT 0 1 0 0 1 0 0 0 0 0 " + table[0xFB] = 0x120; // U_WMRCREATEFONTINDIRECT 0 1 0 0 1 0 0 0 0 0 " + table[0xFC] = 0x120; // U_WMRCREATEBRUSHINDIRECT 0 1 0 0 1 0 0 0 0 0 " + table[0xFD] = 0x020; // U_WMRCREATEBITMAPINDIRECT 0 0 0 0 1 0 0 0 0 0 " + table[0xFE] = 0x020; // U_WMRCREATEBITMAP 0 0 0 0 1 0 0 0 0 0 " + table[0xFF] = 0x120; // U_WMRCREATEREGION 0 1 0 0 1 0 0 0 0 0 " + } + result = table[type]; + } + return(result); +} + +/* ********************************************************************************************** +These functions are for setting up, appending to, and then tearing down an WMF structure, including +writing the final data structure out to a file. +*********************************************************************************************** */ + +/** + \brief Duplicate an WMR record. + \param wmr record to duplicate +*/ +char *wmr_dup( + const char *wmr + ){ + char *dup; + uint32_t irecsize; + + if(!wmr)return(NULL); + memcpy(&irecsize,wmr,4); /* Size16_4 field is at offset 0 */ + irecsize *= 2; + dup=malloc(irecsize); + if(dup){ memcpy(dup,wmr,irecsize); } + return(dup); +} + + +/* some of these functions are identical to the emf ones, handled by defines in uemf.h,use the emf versions */ + +/** + \brief Start constructing an wmf in memory. Supply the file name and initial size. + \return 0 for success, >=0 for failure. + \param name WMF filename (will be opened) + \param initsize Initialize WMF in memory to hold this many bytes + \param chunksize When needed increase WMF in memory by this number of bytes + \param wt WMF in memory + + +*/ +int wmf_start( + const char *name, + const uint32_t initsize, + const uint32_t chunksize, + WMFTRACK **wt + ){ + FILE *fp; + WMFTRACK *wtl=NULL; + + if(initsize < 1)return(1); + if(chunksize < 1)return(2); + if(!name)return(3); + wtl = (WMFTRACK *) malloc(sizeof(WMFTRACK)); + if(!wtl)return(4); + wtl->buf = malloc(initsize); // no need to zero the memory + if(!wtl->buf){ + free(wtl); + return(5); + } + fp=wmf_fopen(name,U_WRITE); + if(!fp){ + free(wtl->buf); + free(wtl); + return(6); + } + wtl->fp = fp; + wtl->allocated = initsize; + wtl->used = 0; + wtl->records = 0; + wtl->PalEntries = 0; + wtl->chunk = chunksize; + wtl->largest = 0; /* only used by WMF */ + wtl->sumObjects = 0; /* only used by WMF */ + *wt=wtl; + return(0); +} + +/** + \brief Release memory for an wmf structure in memory. Call this after wmf_finish(). + \return 0 on success, >=1 on failure + \param wt WMF in memory +*/ +int wmf_free( + WMFTRACK **wt + ){ + WMFTRACK *wtl; + if(!wt)return(1); + wtl=*wt; + if(!wtl)return(2); + free(wtl->buf); + free(wtl); + *wt=NULL; + return(0); +} + +/** + \brief Finalize the emf in memory and write it to the file. + \return 0 on success, >=1 on failure + \param wt WMF in memory +*/ +int wmf_finish( + WMFTRACK *wt + ){ + char *record; + int off; + uint32_t tmp; + uint16_t tmp16; + + if(!wt->fp)return(1); // This could happen if something stomps on memory, otherwise should be caught in wmf_start + + // Set the header fields which were unknown up until this point + + + if(((PU_WMRPLACEABLE) wt->buf)->Key == 0x9AC6CDD7){ off = U_SIZE_WMRPLACEABLE; } + else { off = 0; } + + record = (wt->buf + off); + tmp = (wt->used)/2; + memcpy(record + offsetof(U_WMRHEADER,Sizew), &tmp, 4); /* 16 bit words in file. not aligned */ + tmp = (wt->largest)/2; + memcpy(record + offsetof(U_WMRHEADER,maxSize), &tmp, 4); /* 16 bit words in largest record, not aligned */ + if(wt->sumObjects > UINT16_MAX)return(3); + tmp16 = wt->sumObjects; + memcpy(record + offsetof(U_WMRHEADER,nObjects), &tmp16, 2); /* Total number of brushes, pens, and other graphics objects defined in this file */ + +#if U_BYTE_SWAP + //This is a Big Endian machine, WMF data must be Little Endian + U_wmf_endian(wt->buf,wt->used,1); +#endif + + (void) U_wmr_properties(U_WMR_INVALID); /* force the release of the lookup table memory, returned value is irrelevant */ + if(1 != fwrite(wt->buf,wt->used,1,wt->fp))return(2); + (void) fclose(wt->fp); + wt->fp=NULL; + return(0); +} + +/** + \brief Retrieve contents of an WMF file by name. + \return 0 on success, >=1 on failure + \param filename Name of file to open, including the path + \param contents Contents of the file. Buffer must be free()'d by caller. + \param length Number of bytes in Contents +*/ +int wmf_readdata( + const char *filename, + char **contents, + size_t *length + ){ + FILE *fp; + int status=0; + + *contents=NULL; + fp=wmf_fopen(filename,U_READ); + if(!fp){ status = 1; } + else { + // read the entire file into memory + fseek(fp, 0, SEEK_END); // move to end + *length = ftell(fp); + rewind(fp); + *contents = (char *) malloc(*length); + if(!*contents){ + status = 2; + } + else { + size_t inbytes = fread(*contents,*length,1,fp); + if(inbytes != 1){ + free(*contents); + status = 3; + } + else { +#if U_BYTE_SWAP + //This is a Big Endian machine, WMF data is Little Endian + U_wmf_endian(*contents,*length,0); // LE to BE +#endif + } + } + fclose(fp); + } + return(status); +} + +/** + \brief Append an WMF record to a wmf in memory. This may reallocate buf memory. + \return 0 for success, >=1 for failure. + \param rec Record to append to WMF in memory + \param wt WMF in memory + \param freerec If true, free rec after append +*/ +int wmf_append( + U_METARECORD *rec, + WMFTRACK *wt, + int freerec + ){ + size_t deficit; + uint32_t wp; + uint32_t size; + + size = U_wmr_size(rec); +#ifdef U_VALGRIND + printf("\nbefore \n"); + printf(" probe %d\n",memprobe(rec, size)); + printf("after \n"); +#endif + if(!rec)return(1); + if(!wt)return(2); + if(size + wt->used > wt->allocated){ + deficit = size + wt->used - wt->allocated; + if(deficit < wt->chunk)deficit = wt->chunk; + wt->allocated += deficit; + wt->buf = realloc(wt->buf,wt->allocated); + if(!wt->buf)return(3); + } + memcpy(wt->buf + wt->used, rec, size); + wt->used += size; + wt->records++; + if(wt->largest < size)wt->largest=size; + /* does the record create an object: brush, font, palette, pen, or region ? + Following EOF properties comes back as U_WMR_INVALID */ + wp = U_wmr_properties(U_WMRTYPE(rec)); + if((wp != U_WMR_INVALID) && (U_DRAW_OBJECT & wp))wt->sumObjects++; + if(freerec){ free(rec); } + return(0); +} + +/** + \brief Append an WMF header to a wmf in memory. This may reallocate buf memory. + WMF header is not a normal record, method used to figure out its size is different. + \return 0 for success, >=1 for failure. + \param rec header to append to WMF in memory + \param wt WMF in memory + \param freerec If true, free rec after append +*/ +int wmf_header_append( + PU_METARECORD rec, + WMFTRACK *wt, + int freerec + ){ + size_t deficit; + unsigned int hsize; + + hsize = (((PU_WMRPLACEABLE) rec)->Key == 0x9AC6CDD7 ? U_SIZE_WMRHEADER + U_SIZE_WMRPLACEABLE: U_SIZE_WMRHEADER); + +#ifdef U_VALGRIND + printf("\nbefore \n"); + printf(" probe %d\n",memprobe(rec, hsize)); + printf("after \n"); +#endif + if(!rec)return(1); + if(!wt)return(2); + if(U_wmr_size(rec) + wt->used > wt->allocated){ + deficit = hsize + wt->used - wt->allocated; + if(deficit < wt->chunk)deficit = wt->chunk; + wt->allocated += deficit; + wt->buf = realloc(wt->buf,wt->allocated); + if(!wt->buf)return(3); + } + memcpy(wt->buf + wt->used, rec, hsize); + wt->used += hsize; + /* do NOT increment records count, this is not strictly a record */ + if(wt->largest < hsize)wt->largest=hsize; + if(freerec){ free(rec); } + return(0); +} + +/** + \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle. + \return 0 for success, >=1 for failure. + \param initsize Initialize with space for this number of handles + \param chunksize When needed increase space by this number of handles + \param wht WMF handle table +*/ +int wmf_htable_create( + uint32_t initsize, + uint32_t chunksize, + WMFHANDLES **wht + ){ + WMFHANDLES *whtl; + + if(initsize<1)return(1); + if(chunksize<1)return(2); + whtl = (WMFHANDLES *) malloc(sizeof(WMFHANDLES)); + if(!whtl)return(3); + whtl->table = malloc(initsize * sizeof(uint32_t)); + if(!whtl->table){ + free(whtl); + return(4); + } + memset(whtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table + whtl->allocated = initsize; + whtl->chunk = chunksize; + whtl->table[0] = 0; // This slot isn't actually ever used + whtl->lolimit = 1; // first available table entry + whtl->hilimit = 0; // no entries in the table yet. + whtl->peak = 0; // no entries in the table ever + *wht = whtl; + return(0); +} + +/** + \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0. + \return 0 for success, >=1 for failure. + \param ih handle + \param wht WMF handle table + +*/ +int wmf_htable_delete( + uint32_t *ih, + WMFHANDLES *wht + ){ + if(!wht)return(1); + if(!wht->table)return(2); + if(*ih < 1)return(4); // invalid handle + if(!wht->table[*ih])return(5); // requested table position was not in use + wht->table[*ih]=0; // remove handle from table + while(wht->hilimit>0 && !wht->table[wht->hilimit]){ // adjust hilimit + wht->hilimit--; + } + if(*ih < wht->lolimit)wht->lolimit = *ih; // adjust lolimit + *ih=0; // invalidate handle variable, so a second delete will of it is not possible + return(0); +} + +/** + \brief Returns the index of the first free slot. + Call realloc() if needed. The slot is set to handle (indicates occupied) and the peak value is adjusted. + \return 0 for success, >=1 for failure. + \param ih handle + \param wht WMF handle table +*/ +int wmf_htable_insert( + uint32_t *ih, + WMFHANDLES *wht + ){ + size_t newsize; + + if(!wht)return(1); + if(!wht->table)return(2); + if(!ih)return(4); + if(wht->lolimit >= wht->allocated - 1){ // need to reallocate + newsize=wht->allocated + wht->chunk; + wht->table = realloc(wht->table,newsize * sizeof(uint32_t)); + if(!wht->table)return(5); + memset(&wht->table[wht->allocated] , 0, wht->chunk * sizeof(uint32_t)); // zero all NEW slots in the table + wht->allocated = newsize; + } + *ih = wht->lolimit; // handle that is inserted in first available slot + wht->table[*ih] = *ih; // handle goes into preexisting (but zero) slot in table, handle number is the same as the slot number + if(*ih > wht->hilimit){ wht->hilimit = *ih; } + if(*ih > wht->peak){ wht->peak = *ih; } + /* Find the next available slot, it will be at least one higher than the present position, and will have a zero in it. */ + wht->lolimit++; + while(wht->lolimit<= wht->hilimit && wht->table[wht->lolimit]){ wht->lolimit++; } + return(0); +} + +/** + \brief Free all memory in an htable. Sets the pointer to NULL. + \return 0 for success, >=1 for failure. + \param wht WMF handle table +*/ +int wmf_htable_free( + WMFHANDLES **wht + ){ + WMFHANDLES *whtl; + if(!wht)return(1); + whtl = *wht; + if(!whtl)return(2); + if(!whtl->table)return(3); + free(whtl->table); + free(whtl); + *wht=NULL; + return(0); +} + + +/* ********************************************************************************************** +These functions create standard structures used in the WMR records. +*********************************************************************************************** */ + +// hide these from Doxygen +//! @cond +/* ********************************************************************************************** +These functions contain shared code used by various U_WMR*_print functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. +*********************************************************************************************** */ + +/* These definitons only used here */ +#define U_SIZE_WMR_NOARGS 6 +#define U_SIZE_WMR_1ARG16 8 +#define U_SIZE_WMR_2ARG16 10 +#define U_SIZE_WMR_3ARG16 12 +#define U_SIZE_WMR_4ARG16 14 +#define U_SIZE_WMR_5ARG16 16 +#define U_SIZE_WMR_6ARG16 18 +#define U_SIZE_WMR_8ARG16 22 + +char *U_WMRCORENONE_set(char *string){ + printf("unimplemented creator for:%s\n",string); + return(NULL); +} + +void U_WMRCORE_SETRECHEAD(char *record, uint32_t irecsize, int iType){ + uint32_t Size16; + Size16 = irecsize/2; + memcpy(record,&Size16,4); /*Size16_4 is at offset 0 in the record */ + ((PU_METARECORD) record)->iType = iType; + ((PU_METARECORD) record)->xb = U_WMR_XB_FROM_TYPE(iType); +} + +/* records that have no arguments */ +char *U_WMRCORE_NOARGS_set( + int iType +){ + char *record=NULL; + uint32_t irecsize; + irecsize = U_SIZE_METARECORD; + record = malloc(irecsize); + if(record)U_WMRCORE_SETRECHEAD(record,irecsize,iType); + return(record); +} + + +/* records like U_WMRFLOODFILL and others. all args are optional, Color is not */ +char *U_WMRCORE_1U16_CRF_2U16_set( + int iType, + uint16_t *arg1, + U_COLORREF Color, + uint16_t *arg2, + uint16_t *arg3 +){ + char *record=NULL; + uint32_t irecsize,off; + irecsize = U_SIZE_METARECORD + U_SIZE_COLORREF; + if(arg1)irecsize+=2; + if(arg2)irecsize+=2; + if(arg3)irecsize+=2; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + if(arg1){ memcpy(record + off, arg1, 2); off+=2; } + memcpy(record + off, &Color, 4); off+=4; + if(arg2){ memcpy(record + off, arg2, 2); off+=2; } + if(arg3){ memcpy(record + off, arg3, 2); } + } + return(record); +} + +/* records that have a single uint16_t argument like PU_WMRSETMAPMODE + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_1U16_set( + int iType, + uint16_t arg1 +){ + char *record=NULL; + uint32_t irecsize,off; + irecsize = U_SIZE_WMR_1ARG16; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off,&arg1,2); + } + return(record); +} + +/* records that have two uint16_t arguments like U_WMRSETBKMODE + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_2U16_set( + int iType, + uint16_t arg1, + uint16_t arg2 +){ + char *record=NULL; + uint32_t irecsize,off; + irecsize = U_SIZE_WMR_2ARG16; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off,&arg1,2); off+=2; + memcpy(record+off,&arg2,2); + } + return(record); +} + +/* records that have four uint16_t arguments like U_WMRSCALEWINDOWEXT + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_4U16_set( + int iType, + uint16_t arg1, + uint16_t arg2, + uint16_t arg3, + uint16_t arg4 +){ + char *record=NULL; + uint32_t irecsize, off; + irecsize = U_SIZE_WMR_4ARG16; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off,&arg1,2); off+=2; + memcpy(record+off,&arg2,2); off+=2; + memcpy(record+off,&arg3,2); off+=2; + memcpy(record+off,&arg4,2); + } + return(record); +} + +/* records that have five uint16_t arguments like U_WMRCREATEPENINDIRECT + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_5U16_set( + int iType, + uint16_t arg1, + uint16_t arg2, + uint16_t arg3, + uint16_t arg4, + uint16_t arg5 +){ + char *record=NULL; + uint32_t irecsize, off; + irecsize = U_SIZE_WMR_5ARG16; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off,&arg1,2); off+=2; + memcpy(record+off,&arg2,2); off+=2; + memcpy(record+off,&arg3,2); off+=2; + memcpy(record+off,&arg4,2); off+=2; + memcpy(record+off,&arg5,2); + } + return(record); +} + +/* records that have size uint16_t arguments like U_ROUNDREC + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_6U16_set( + int iType, + uint16_t arg1, + uint16_t arg2, + uint16_t arg3, + uint16_t arg4, + uint16_t arg5, + uint16_t arg6 +){ + char *record=NULL; + uint32_t irecsize, off; + irecsize = U_SIZE_WMR_6ARG16; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off,&arg1,2); off+=2; + memcpy(record+off,&arg2,2); off+=2; + memcpy(record+off,&arg3,2); off+=2; + memcpy(record+off,&arg4,2); off+=2; + memcpy(record+off,&arg5,2); off+=2; + memcpy(record+off,&arg6,2); + } + return(record); +} + +/* records that have eight uint16_t arguments like U_WMRARC + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_8U16_set( + int iType, + uint16_t arg1, + uint16_t arg2, + uint16_t arg3, + uint16_t arg4, + uint16_t arg5, + uint16_t arg6, + uint16_t arg7, + uint16_t arg8 +){ + char *record=NULL; + uint32_t irecsize, off; + irecsize = U_SIZE_WMR_8ARG16; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off,&arg1,2); off+=2; + memcpy(record+off,&arg2,2); off+=2; + memcpy(record+off,&arg3,2); off+=2; + memcpy(record+off,&arg4,2); off+=2; + memcpy(record+off,&arg5,2); off+=2; + memcpy(record+off,&arg6,2); off+=2; + memcpy(record+off,&arg7,2); off+=2; + memcpy(record+off,&arg8,2); + } + return(record); +} + +/* records that have + arg1 an (optional) (u)int16 + arg2 an (optional( (u)int16 + N16 number of (u)int16_t cells in array. may be zero + array of N16 (u)int16_t cells (or any structure that is 2N bytes in size), should be NULL if N16 is 0. + like U_WMRCREATEBRUSHINDIRECT with arg1=arg2=NULL +*/ +char *U_WMRCORE_2U16_N16_set( + int iType, + const uint16_t *arg1, + const uint16_t *arg2, + const uint16_t N16, + const void *array + ){ + char *record=NULL; + uint32_t irecsize, off; + irecsize = U_SIZE_METARECORD + N16*2; + if(arg1)irecsize += 2; + if(arg2)irecsize += 2; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + if(arg1){ memcpy(record+off,arg1,2); off+=2; } + if(arg2){ memcpy(record+off,arg2,2); off+=2; } + if(N16){ memcpy(record+off,array,2*N16); } + } + return(record); +} + + + +/* records that set a U_PALETTE , then a count and then a uint16_t list like U_WMRANIMATEPALETTE + May also be used with int16_t with appropriate casts */ +char *U_WMRCORE_PALETTE_set( + int iType, + PU_PALETTE Palette +){ + char *record=NULL; + uint32_t irecsize, off, nPE; + nPE = 4*Palette->NumEntries; + if(!nPE)return(NULL); /* What would it mean to load an empty palette??? */ + irecsize = U_SIZE_METARECORD + 2 + 2 + nPE; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,iType); + off = U_SIZE_METARECORD; + memcpy(record+off, &Palette->Start, 2); off+=2; + memcpy(record+off, &Palette->NumEntries, 2); off+=2; + memcpy(record+off, &Palette->PalEntries, nPE); off+=2; + } + return(record); +} + +//! @endcond + +/* ********************************************************************************************** +These functions are simpler or more convenient ways to generate the specified types of WMR records. +Each should be called in preference to the underlying "base" WMR function. +*********************************************************************************************** */ + + +/** + \brief Allocate and construct a U_WMRDELETEOBJECT record and also delete the requested object from the table. + Use this function instead of calling U_WMRDELETEOBJECT_set() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_WMRDELETEOBJECT record, or NULL on error. + \param ihObject Pointer to handle to delete. This value is set to 0xFFFFFFFF if the function succeeds. + \param wht WMF handle table + + Note that calling this function should always be conditional on the specifed object being defined. It is easy to + write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined. + Then a later modification, possibly quite far away in the code, causes it to be undefined. That distant change will + result in a failure when this function reutrns. That problem cannot be handled here because the only values which + may be returned are a valid U_WMRDELETEOBJECT record or a NULL, and other errors could result in the NULL. + So the object must be checked before the call. +*/ +char *wdeleteobject_set( + uint32_t *ihObject, + WMFHANDLES *wht + ){ + uint32_t saveObject=*ihObject; /* caller 0->N */ + *ihObject += 1; /* caller 0->N --> 1->N+1 table*/ + if(wmf_htable_delete(ihObject,wht))return(NULL); /* invalid handle or other problem, cannot be deleted */ + *ihObject = 0xFFFFFFFF; /* EMF would have set to 0, but 0 is an allowed index in WMF */ + return(U_WMRDELETEOBJECT_set(saveObject)); /* caller 0->N */ +} + +/** + \brief Allocate and construct a U_WMRSELECTOBJECT record, checks that the handle specified is one that can actually be selected. + Use this function instead of calling U_WMRSELECTOBJECT_set() directly. + Object Pointer in WMF (caller) is 0->N, so is record, so no correction to 1->N+1 needed here. + \return pointer to the U_WMRSELECTOBJECT record, or NULL on error. + \param ihObject handle to select + \param wht WMF handle table +*/ +char *wselectobject_set( + uint32_t ihObject, + WMFHANDLES *wht + ){ + /* WMF has no stock objects! */ + if(ihObject > wht->hilimit)return(NULL); // handle this high is not in the table + /* caller uses 0->N, table uses 1->N+1 */ + if(!wht->table[ihObject+1])return(NULL); // handle is not in the table, so cannot be selected + /* file uses 0->N */ + return(U_WMRSELECTOBJECT_set(ihObject)); +} + +/** + \brief Allocate and construct a U_WMRCREATEPENINDIRECT record, create a handle and returns it + Use this function instead of calling U_WMRCREATEPENINDIRECT_set() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_WMRCREATEPENINDIRECT record, or NULL on error. + \param ihPen handle to be used by new object + \param wht WMF handle table + \param pen Pen parameters (U_PEN) +*/ +char *wcreatepenindirect_set( + uint32_t *ihPen, + WMFHANDLES *wht, + U_PEN pen + ){ + if(wmf_htable_insert(ihPen, wht))return(NULL); + *ihPen -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRCREATEPENINDIRECT_set(pen)); +} + +/** + \brief Allocate and construct a U_WMRCREATEBRUSHINDIRECT record, create a handle and returns it + Use this function instead of calling U_WMRCREATEBRUSHINDIRECT_set() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_WMRCREATEBRUSHINDIRECT record, or NULL on error. + \param ihBrush handle to be used by new object + \param wht WMF handle table + \param lb Brush parameters +*/ +char *wcreatebrushindirect_set( + uint32_t *ihBrush, + WMFHANDLES *wht, + U_WLOGBRUSH lb + ){ + if(wmf_htable_insert(ihBrush, wht))return(NULL); + *ihBrush -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRCREATEBRUSHINDIRECT_set(lb)); +} + +/** + \brief Allocate and construct a U_WMRDIBCREATEPATTERNBRUSH record from a DIB. + Use this function instead of calling U_WMRDIBCREATEPATTERNBRUSH_set() directly. + \return pointer to the U_WMRDIBCREATEPATTERNBRUSH record, or NULL on error. + \param ihBrush handle to be used by new object + \param wht WMF handle table + \param iUsage DIBColors enumeration + \param Bmi Bitmap info + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *wcreatedibpatternbrush_srcdib_set( + uint32_t *ihBrush, + WMFHANDLES *wht, + const uint32_t iUsage, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + + ){ + if(wmf_htable_insert(ihBrush, wht))return(NULL); + *ihBrush -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRDIBCREATEPATTERNBRUSH_set(U_BS_DIBPATTERNPT, iUsage, Bmi, cbPx, Px,NULL)); +} + +/** + \brief Allocate and construct a U_WMRCREATEPATTERNBRUSH record from a U_BITMAP16 object. + Use this function instead of calling U_WMRCREATEPATTERNBRUSH_set() directly. + \return pointer to the U_WMRCREATEPATTERNBRUSH record, or NULL on error. + \param ihBrush handle to be used by new object + \param wht WMF handle table + \param iUsage DIBColors enumeration + \param Bm16 Pointer to a Bitmap16 object +*/ +char *wcreatedibpatternbrush_srcbm16_set( + uint32_t *ihBrush, + WMFHANDLES *wht, + const uint32_t iUsage, + PU_BITMAP16 Bm16 + ){ + if(wmf_htable_insert(ihBrush, wht))return(NULL); + *ihBrush -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRDIBCREATEPATTERNBRUSH_set(U_BS_PATTERN, iUsage, NULL, 0, NULL, Bm16)); +} + +/** + \brief Allocate and construct a U_WMRCREATEPATTERNBRUSH record, create a handle and returns it + Use this function instead of calling U_WMRCREATEPATTERNBRUSH_set() directly. + Warning - application support for U_WMRCREATEPATTERNBRUSH is spotty, better to use U_WMRDIBCREATEPATTERNBRUSH. + \return pointer to the U_WMRCREATEPATTERNBRUSH record, or NULL on error. + \param ihBrush handle to be used by new object + \param wht WMF handle table + \param Bm16 Pointer to a Bitmap16 structure (only first 10 bytes are used). + \param Pattern Pointer to a byte array described by Bm16. (Pattern may be a pointer to the BM16 Bits field.) +*/ +char *wcreatepatternbrush_set( + uint32_t *ihBrush, + WMFHANDLES *wht, + PU_BITMAP16 Bm16, + char *Pattern + ){ + if(wmf_htable_insert(ihBrush, wht))return(NULL); + *ihBrush -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRCREATEPATTERNBRUSH_set(Bm16, Pattern)); +} + +/** + \brief Allocate and construct a U_WMRCREATEFONTINDIRECT record, create a handle and returns it + Use this function instead of calling U_WMRCREATEFONTINDIRECT_set() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_WMRCREATEFONTINDIRECT record, or NULL on error. + \param ihFont Font handle, will be created and returned + \param wht Pointer to structure holding all WMF handles + \param uf Pointer to Font parameters as PU_FONT +*/ +char *wcreatefontindirect_set( + uint32_t *ihFont, + WMFHANDLES *wht, + PU_FONT uf + ){ + if(wmf_htable_insert(ihFont, wht))return(NULL); + *ihFont -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRCREATEFONTINDIRECT_set(uf)); +} + +/** + \brief Allocate and construct a U_WMRCREATEPALETTE record, create a handle and returns it + Use this function instead of calling U_WMRCREATEPALETTE_set() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_WMRCREATEPALETTE record, or NULL on error. + \param ihPal Palette handle, will be created and returned + \param wht Pointer to structure holding all WMF handles + \param up Palette parameters +*/ +char *wcreatepalette_set( + uint32_t *ihPal, + WMFHANDLES *wht, + PU_PALETTE up + ){ + if(wmf_htable_insert(ihPal, wht))return(NULL); + *ihPal -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRCREATEPALETTE_set(up)); +} + +/** + \brief Allocate and construct a U_WMRSETPALENTRIES record, create a handle and returns it + Use this function instead of calling U_WMRSETPALENTRIES_set() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_WMRSETPALENTRIES record, or NULL on error. + \param ihPal Palette handle, will be created and returned + \param wht Pointer to structure holding all WMF handles + \param Palettes Values to set with +*/ +char *wsetpaletteentries_set( + uint32_t *ihPal, + WMFHANDLES *wht, + const PU_PALETTE Palettes + ){ + if(wmf_htable_insert(ihPal, wht))return(NULL); + *ihPal -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRSETPALENTRIES_set(Palettes)); +} + +/** + \brief Allocate and construct a U_WMRCREATEREGION record, create a handle and returns it + Use this function instead of calling U_WMRCREATEREGION() directly. + Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here. + \return pointer to the U_REGIONS record, or NULL on error. + \param ihReg Region handle, will be created and returned + \param wht Pointer to structure holding all WMF handles + \param Region Values to set with +*/ +char *wcreateregion_set( + uint32_t *ihReg, + WMFHANDLES *wht, + const PU_REGION Region + ){ + if(wmf_htable_insert(ihReg, wht))return(NULL); + *ihReg -= 1; /* 1->N+1 --> 0->N */ + return(U_WMRCREATEREGION_set(Region)); +} +/* A few escape functions are implemented, just those that set a state or a single value */ + +/** + \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it + Use this function instead of calling U_WMRESCAPE_set() directly. + \return pointer to the U_WMRESCAPE structure, or NULL on error. +*/ +char *wbegin_path_set(void){ + return(U_WMRESCAPE_set(U_MFE_BEGIN_PATH,0,NULL)); +} + +/** + \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it + Use this function instead of calling U_WMRESCAPE_set() directly. + \return pointer to the U_WMRESCAPE structure, or NULL on error. +*/ +char *wend_path_set(void){ + return(U_WMRESCAPE_set(U_MFE_END_PATH,0,NULL)); +} + +/** + \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it + Use this function instead of calling U_WMRESCAPE_set() directly. + \return pointer to the U_WMRESCAPE structure, or NULL on error. + \param Type PostScriptCap Enumeration, anything else is an error +*/ +char *wlinecap_set( + int32_t Type + ){ + char *record =NULL; + if(Type == U_WPS_CAP_NOTSET || + Type == U_WPS_CAP_FLAT || + Type == U_WPS_CAP_ROUND || + Type == U_WPS_CAP_SQUARE){ record = U_WMRESCAPE_set(U_MFE_SETLINECAP,4,&Type); } + return(record); +} + +/** + \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it + Use this function instead of calling U_WMRESCAPE_set() directly. + \return pointer to the U_WMRESCAPE structure, or NULL on error. + \param Type PostScriptCap Enumeration, anything else is an error +*/ +char *wlinejoin_set( + int32_t Type + ){ + char *record =NULL; + if(Type == U_WPS_JOIN_NOTSET || + Type == U_WPS_JOIN_MITER || + Type == U_WPS_JOIN_ROUND || + Type == U_WPS_JOIN_BEVEL){ record = U_WMRESCAPE_set(U_MFE_SETLINEJOIN,4,&Type); } + return(record); +} + +/** + \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it + Use this function instead of calling U_WMRESCAPE_set() directly. + \return pointer to the U_WMRESCAPE structure, or NULL on error. + \param limit PostScriptCap Enumeration, anything else is an error +*/ +char *wmiterlimit_set( + int32_t limit + ){ + return(U_WMRESCAPE_set(U_MFE_SETMITERLIMIT,4,&limit)); +} + +/* ********************************************************************************************** +These are the core WMR functions, each creates a particular type of record. +All return these records via a char* pointer, which is NULL if the call failed. +They are listed in order by the corresponding U_WMR_* index number. +*********************************************************************************************** */ + +/** + \brief Set up fields for a (placeable) WMR_HEADER. Most of the fields are blank and are not set until all is written. + Typically values are something like (8.5,11.0), 1440 (Letter paper, 1440 DPI). + The scaled paper size must fit in the range 0<->32767 inclusive, because it must be represented by a signed 16bit number. + If the size + dpi result in out of range values a failure will result. + \return pointer to the WMF header record, or NULL on failure + \param size Pointer to page size (if NULL, not a placeable header) in inches. Values must be positive and scaled + \param dpi Logical units/inch. If 0 defaults to 1440. +*/ +char *U_WMRHEADER_set( + PU_PAIRF size, + unsigned int dpi + ){ + char *record=NULL; + uint32_t irecsize,off; + double xmax,ymax; + int16_t xm16,ym16; + irecsize = (size ? U_SIZE_WMRHEADER + U_SIZE_WMRPLACEABLE : U_SIZE_WMRHEADER); + record = calloc(1,irecsize); /* most will be zero*/ + off = 0; + if(record){ + if(size){ /* placeable */ + if(!dpi)dpi=1440; + xmax = U_ROUND((double) size->x * (double) dpi); + ymax = U_ROUND((double) size->y * (double) dpi); + if(xmax < 0 || ymax < 0 || xmax > 32767 || ymax > 32767){ + free(record); + return(NULL); + } + xm16 = xmax; + ym16 = ymax; + ((PU_WMRPLACEABLE) record)->Key = 0x9AC6CDD7; + ((PU_WMRPLACEABLE) record)->HWmf = 0; /* Manual says number of 16 bit words in record, but all WMF examples had it as 0 */ + ((PU_WMRPLACEABLE) record)->Dst.left = 0; + ((PU_WMRPLACEABLE) record)->Dst.top = 0; + ((PU_WMRPLACEABLE) record)->Dst.right = xm16; + ((PU_WMRPLACEABLE) record)->Dst.bottom = ym16; + ((PU_WMRPLACEABLE) record)->Inch = dpi; + ((PU_WMRPLACEABLE) record)->Reserved = 0; + ((PU_WMRPLACEABLE) record)->Checksum = U_16_checksum((int16_t *)record,10); + off = U_SIZE_WMRPLACEABLE; + } + ((PU_WMRHEADER) (record + off))->iType = 1; + ((PU_WMRHEADER) (record + off))->version = U_METAVERSION300; + ((PU_WMRHEADER) (record + off))->Size16w = U_SIZE_WMRHEADER/2; + } + return(record); +} + + +/** + \brief Allocate and construct a U_WMREOF record + \return pointer to the U_WMREOF record, or NULL on error. +*/ +char *U_WMREOF_set(void){ + return U_WMRCORE_NOARGS_set(U_WMR_EOF); +} + +/** + \brief Create and return a U_WMRSETBKCOLOR record + \return pointer to the U_WMRSETBKCOLOR record, or NULL on error + \param Color Background Color. +*/ +char *U_WMRSETBKCOLOR_set(U_COLORREF Color){ + return U_WMRCORE_1U16_CRF_2U16_set(U_WMR_SETBKCOLOR,NULL,Color,NULL,NULL); +} + +/** + \brief Create and return a U_WMRSETBKMODE record + \return pointer to the U_WMRSETBKMODE record, or NULL on error + \param Mode MixMode Enumeration +*/ +char *U_WMRSETBKMODE_set(uint16_t Mode){ + return U_WMRCORE_2U16_set(U_WMR_SETBKMODE, Mode, 0); +} + +/** + \brief Create and return a U_WMRSETMAPMODE record + \return pointer to the U_WMRSETMAPMODE record, or NULL on error + \param Mode MapMode Enumeration +*/ +char *U_WMRSETMAPMODE_set(uint16_t Mode){ + return U_WMRCORE_1U16_set(U_WMR_SETMAPMODE, Mode); +} + +/** + \brief Create and return a U_WMRSETROP2 record + \return pointer to the U_WMRSETROP2 record, or NULL on error + \param Mode Binary Raster Operation Enumeration +*/ +char *U_WMRSETROP2_set(uint16_t Mode){ + return U_WMRCORE_2U16_set(U_WMR_SETROP2, Mode, 0); +} + +/** + \brief Allocate and construct a U_WMRSETRELABS record + \return pointer to the U_WMRSETRELABS record, or NULL on error. +*/ +char *U_WMRSETRELABS_set(void){ + return U_WMRCORE_NOARGS_set(U_WMR_SETRELABS); +} + +/** + \brief Create and return a U_WMRSETPOLYFILLMODE record + \return pointer to the U_WMRSETPOLYFILLMODE record, or NULL on error + \param Mode PolyFillMode Enumeration +*/ +char *U_WMRSETPOLYFILLMODE_set(uint16_t Mode){ + return U_WMRCORE_2U16_set(U_WMR_SETPOLYFILLMODE, Mode, 0); +} + +/** + \brief Create and return a U_WMRSETSTRETCHBLTMODE record + \return pointer to the U_WMRSETSTRETCHBLTMODE record, or NULL on error + \param Mode StretchMode Enumeration +*/ +char *U_WMRSETSTRETCHBLTMODE_set(uint16_t Mode){ + return U_WMRCORE_2U16_set(U_WMR_SETSTRETCHBLTMODE, Mode, 0); +} + +/** + \brief Create and return a U_WMRSETTEXTCHAREXTRA record + \return pointer to the U_WMRSETTEXTCHAREXTRA record, or NULL on error + \param Mode Extra space in logical units to add to each character +*/ +char *U_WMRSETTEXTCHAREXTRA_set(uint16_t Mode){ + return U_WMRCORE_1U16_set(U_WMR_SETTEXTCHAREXTRA, Mode); +} + +/** + \brief Create and return a U_WMRSETTEXTCOLOR record + \return pointer to the U_WMRSETTEXTCOLOR record, or NULL on error + \param Color Text Color. +*/ +char *U_WMRSETTEXTCOLOR_set(U_COLORREF Color){ + return U_WMRCORE_1U16_CRF_2U16_set(U_WMR_SETTEXTCOLOR,NULL,Color,NULL,NULL); +} + +/** + \brief Create and return a U_WMRSETTEXTJUSTIFICATION record + \return pointer to the U_WMRSETTEXTJUSTIFICATION record, or NULL on error + \param Count Number of space characters in the line. + \param Extra Number of extra space characters to add to the line. +*/ +char *U_WMRSETTEXTJUSTIFICATION_set(uint16_t Count, uint16_t Extra){ + return U_WMRCORE_2U16_set(U_WMR_SETBKMODE, Count, Extra); +} + +/** + \brief Create and return a U_WMRSETWINDOWORG record + \return pointer to the U_WMRSETWINDOWORG record, or NULL on error + \param coord Window Origin. +*/ +char *U_WMRSETWINDOWORG_set(U_POINT16 coord){ + return U_WMRCORE_2U16_set(U_WMR_SETWINDOWORG, U_U16(coord.y), U_U16(coord.x)); +} + +/** + \brief Create and return a U_WMRSETWINDOWEXT record + \return pointer to the U_WMRSETWINDOWEXT record, or NULL on error + \param extent Window Extent. +*/ +char *U_WMRSETWINDOWEXT_set(U_POINT16 extent){ + return U_WMRCORE_2U16_set(U_WMR_SETWINDOWEXT, U_U16(extent.y), U_U16(extent.x)); +} + +/** + \brief Create and return a U_WMRSETVIEWPORTORG record + \return pointer to the U_WMRSETVIEWPORTORG record, or NULL on error + \param coord Viewport Origin. +*/ +char *U_WMRSETVIEWPORTORG_set(U_POINT16 coord){ + return U_WMRCORE_2U16_set(U_WMR_SETVIEWPORTORG, U_U16(coord.y), U_U16(coord.x)); +} + +/** + \brief Create and return a U_WMRSETVIEWPORTEXT record + \return pointer to the U_WMRSETVIEWPORTEXT record, or NULL on error + \param extent Viewport Extent. +*/ +char *U_WMRSETVIEWPORTEXT_set(U_POINT16 extent){ + return U_WMRCORE_2U16_set(U_WMR_SETWINDOWEXT, U_U16(extent.y), U_U16(extent.x)); +} + +/** + \brief Create and return a U_WMROFFSETWINDOWORG record + \return pointer to the U_WMROFFSETWINDOWORG record, or NULL on error + \param offset Window offset in device units. +*/ +char *U_WMROFFSETWINDOWORG_set(U_POINT16 offset){ + return U_WMRCORE_2U16_set(U_WMR_OFFSETWINDOWORG, U_U16(offset.y), U_U16(offset.x)); +} + +/** + \brief Create and return a U_WMRSCALEWINDOWEXT record + \return pointer to the U_WMRSCALEWINDOWEXT record, or NULL on error + \param Denom {X,Y} denominators. + \param Num {X,Y} numerators. +*/ +char *U_WMRSCALEWINDOWEXT_set(U_POINT16 Denom, U_POINT16 Num){ + return U_WMRCORE_4U16_set(U_WMR_SCALEWINDOWEXT, U_U16(Denom.y), U_U16(Num.y), U_U16(Denom.x), U_U16(Num.x)); +} + +/** + \brief Create and return a U_WMROFFSETVIEWPORTORG record + \return pointer to the U_WMROFFSETVIEWPORTORG record, or NULL on error + \param offset Viewport offset in device units. +*/ +char *U_WMROFFSETVIEWPORTORG_set(U_POINT16 offset){ + return U_WMRCORE_2U16_set(U_WMR_OFFSETVIEWPORTORG, U_U16(offset.y), U_U16(offset.x)); +} + +/** + \brief Create and return a U_WMRSCALEVIEWPORTEXT record + \return pointer to the U_WMRSCALEVIEWPORTEXT record, or NULL on error + \param Denom {X,Y} denominators. + \param Num {X,Y} numerators. +*/ +char *U_WMRSCALEVIEWPORTEXT_set(U_POINT16 Denom, U_POINT16 Num){ + return U_WMRCORE_4U16_set(U_WMR_SCALEVIEWPORTEXT, U_U16(Denom.y), U_U16(Num.y), U_U16(Denom.x), U_U16(Num.x)); +} + +/** + \brief Create and return a U_WMRLINETO record + \return pointer to the U_WMRLINETO record, or NULL on error + \param coord Draw line to {X,Y}. +*/ +char *U_WMRLINETO_set(U_POINT16 coord){ + return U_WMRCORE_2U16_set(U_WMR_LINETO, U_U16(coord.y), U_U16(coord.x)); +} + +/** + \brief Create and return a U_WMRMOVETO record + \return pointer to the U_WMRMOVETO record, or NULL on error + \param coord Move to {X,Y}. +*/ +char *U_WMRMOVETO_set(U_POINT16 coord){ + return U_WMRCORE_2U16_set(U_WMR_MOVETO, U_U16(coord.y), U_U16(coord.x)); +} + +/** + \brief Create and return a U_WMREXCLUDECLIPRECT record + \return pointer to the U_WMREXCLUDECLIPRECT record, or NULL on error + \param rect Exclude rect from clipping region. +*/ +char *U_WMREXCLUDECLIPRECT_set(U_RECT16 rect){ + return U_WMRCORE_4U16_set( + U_WMR_EXCLUDECLIPRECT, + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Create and return a U_WMRINTERSECTCLIPRECT record + \return pointer to the U_WMRINTERSECTCLIPRECT record, or NULL on error + \param rect Clipping region is intersection of existing clipping region with rect. +*/ +char *U_WMRINTERSECTCLIPRECT_set(U_RECT16 rect){ + return U_WMRCORE_4U16_set( + U_WMR_INTERSECTCLIPRECT, + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Create and return a U_WMRARC record + \return pointer to the U_WMRARC record, or NULL on error + \param StartArc Start of Arc + \param EndArc End of Arc + \param rect Bounding rectangle. +*/ +char *U_WMRARC_set(U_POINT16 StartArc, U_POINT16 EndArc, U_RECT16 rect){ + return U_WMRCORE_8U16_set( + U_WMR_ARC, + U_U16(EndArc.y), + U_U16(EndArc.x), + U_U16(StartArc.y), + U_U16(StartArc.x), + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Create and return a U_WMRELLIPSE record + \return pointer to the U_WMRELLIPSE record, or NULL on error + \param rect Bounding rectangle for Ellipse. +*/ +char *U_WMRELLIPSE_set(U_RECT16 rect){ + return U_WMRCORE_4U16_set( + U_WMR_ELLIPSE, + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Create and return a U_WMRFLOODFILL record + \return pointer to the U_WMRFLOODFILL record, or NULL on error + \param Mode FloodFill Enumeration. + \param Color Color to Fill with. + \param coord Location to start fill. +*/ +char *U_WMRFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord){ + return U_WMRCORE_1U16_CRF_2U16_set( + U_WMR_FLOODFILL, + &Mode, + Color, + U_P16(coord.y), + U_P16(coord.x) + ); +} + +/** + \brief Create and return a U_WMRPIE record + \return pointer to the U_WMRPIE record, or NULL on error + \param Radial1 Start of Pie + \param Radial2 End of Pie + \param rect Bounding rectangle. +*/ +char *U_WMRPIE_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect){ + return U_WMRCORE_8U16_set( + U_WMR_PIE, + U_U16(Radial2.y), + U_U16(Radial2.x), + U_U16(Radial1.y), + U_U16(Radial1.x), + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Create and return a U_WMRRECTANGLE record + \return pointer to the U_WMRRECTANGLE record, or NULL on error + \param rect Boundaries. +*/ +char *U_WMRRECTANGLE_set(U_RECT16 rect){ + return U_WMRCORE_4U16_set( + U_WMR_RECTANGLE, + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Create and return a U_WMRROUNDRECT record + \return pointer to the U_WMRROUNDRECT record, or NULL on error + \param Width Horizontal rounding length. + \param Height Vertical rounding length. + \param rect Boundaries. +*/ +char *U_WMRROUNDRECT_set(int16_t Width, int16_t Height, U_RECT16 rect){ + return U_WMRCORE_6U16_set( + U_WMR_ROUNDRECT, + U_U16(Height), + U_U16(Width), + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Allocate and construct a U_WMRPATBLT record. + \return pointer to the U_WMRPATBLT record, or NULL on error. + \param Dst Destination UL corner in logical units + \param cwh W & H for Dst and Src in logical units + \param dwRop3 RasterOPeration Enumeration +*/ +char *U_WMRPATBLT_set( + U_POINT16 Dst, + U_POINT16 cwh, + uint32_t dwRop3 + ){ + char *record=NULL; + uint32_t irecsize; + PU_WMRPATBLT pmr; + + irecsize = U_SIZE_WMRPATBLT; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_PATBLT); + pmr = (PU_WMRPATBLT) record; + memcpy(pmr->rop3w, &dwRop3, 4); + pmr->Height = cwh.y; + pmr->Width = cwh.x; + pmr->yDst = Dst.y; + pmr->xDst = Dst.x; + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRSAVEDC record + \return pointer to the U_WMRSAVEDC record, or NULL on error. +*/ +char *U_WMRSAVEDC_set(void){ + return U_WMRCORE_NOARGS_set(U_WMR_SAVEDC); +} + +char *U_WMRSETPIXEL_set(U_COLORREF Color, U_POINT16 coord){ + return U_WMRCORE_1U16_CRF_2U16_set( + U_WMR_SETPIXEL, + NULL, + Color, + U_P16(coord.y), + U_P16(coord.x) + ); +} + +char *U_WMROFFSETCLIPRGN_set(U_POINT16 offset){ + return U_WMRCORE_2U16_set(U_WMR_OFFSETCLIPRGN, U_U16(offset.y), U_U16(offset.x)); +} + +/** + \brief Allocate and construct a U_WMRTEXTOUT record. + \return pointer to the U_WMRTEXTOUT record, or NULL on error. + \param Dst Destinationin logical units + \param string Null terminated string to write. The terminator is NOT placed in the record! +*/ +char *U_WMRTEXTOUT_set(U_POINT16 Dst, char *string){ + char *record=NULL; + uint32_t irecsize,off; + int L2; + int16_t Length; + irecsize = 2 + U_SIZE_METARECORD + 4; /* core + length + Dst */ + Length = strlen(string); + L2 = ( Length & 1 ? Length + 1 : Length); + irecsize += L2; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_TEXTOUT); + off = U_SIZE_METARECORD; + memcpy(record+off,&Length,2); off+=2; + memcpy(record+off,string,Length); off+=Length; + if(Length!=L2){ + memset(record+off,0,1); off+=1; + } + memcpy(record+off,&Dst.y,2); off+=2; + memcpy(record+off,&Dst.x,2); off+=2; + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRBITBLT record. + Note that unlike U_EMRBITBLT there is no scaling available - the Src and Dst + rectangles must be the same size. + \return pointer to the U_WMRBITBLT record, or NULL on error. + \param Dst Destination UL corner in logical units + \param cwh W & H for Dst and Src in logical units + \param Src Source UL corner in logical units + \param dwRop3 RasterOPeration Enumeration + \param Bm16 (Optional) bitmap16 object +*/ +char *U_WMRBITBLT_set( + U_POINT16 Dst, + U_POINT16 cwh, + U_POINT16 Src, + uint32_t dwRop3, + const PU_BITMAP16 Bm16 + ){ + char *record=NULL; + uint32_t irecsize; + int cbBm16,cbBm164,off; + PU_WMRBITBLT_PX pmr_px; + PU_WMRBITBLT_NOPX pmr_nopx; + + if(Bm16){ + cbBm16 = U_SIZE_BITMAP16 + (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height; + cbBm164 = UP4(cbBm16); + irecsize = U_SIZE_WMRBITBLT_PX + cbBm164; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_BITBLT); + pmr_px = (PU_WMRBITBLT_PX) record; + memcpy(pmr_px->rop3w, &dwRop3, 4); + pmr_px->ySrc = Src.y; + pmr_px->xSrc = Src.x; + pmr_px->Height = cwh.y; + pmr_px->Width = cwh.x; + pmr_px->yDst = Dst.y; + pmr_px->xDst = Dst.x; + off = U_SIZE_WMRBITBLT_PX; + memcpy(record + off, Bm16, cbBm16); off += cbBm16; + if(cbBm164 - cbBm16)memset(record+off,0,cbBm164 - cbBm16); + } + } + else { + irecsize = U_SIZE_WMRBITBLT_NOPX; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_BITBLT); + pmr_nopx = (PU_WMRBITBLT_NOPX) record; + memcpy(pmr_nopx->rop3w, &dwRop3, 4); + pmr_nopx->ySrc = Src.y; + pmr_nopx->xSrc = Src.x; + pmr_nopx->Height = cwh.y; + pmr_nopx->Width = cwh.x; + pmr_nopx->ignore = 0; + pmr_nopx->yDst = Dst.y; + pmr_nopx->xDst = Dst.x; + } + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRSTRETCHBLT record. + \return pointer to the U_WMRSTRETCHBLT record, or NULL on error. + \param Dst Destination UL corner in logical units + \param cDst Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param dwRop3 RasterOPeration Enumeration + \param Bm16 (Optional) bitmap16 object +*/ +char *U_WMRSTRETCHBLT_set( + U_POINT16 Dst, + U_POINT16 cDst, + U_POINT16 Src, + U_POINT16 cSrc, + uint32_t dwRop3, + const PU_BITMAP16 Bm16 + ){ + char *record=NULL; + uint32_t irecsize; + int cbBm16,cbBm164,off; + PU_WMRSTRETCHBLT_PX pmr_px; + PU_WMRSTRETCHBLT_NOPX pmr_nopx; + + if(Bm16){ + cbBm16 = U_SIZE_BITMAP16 + (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height; + cbBm164 = UP4(cbBm16); + irecsize = U_SIZE_WMRSTRETCHBLT_PX + cbBm164; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_STRETCHBLT); + pmr_px = (PU_WMRSTRETCHBLT_PX) record; + memcpy(pmr_px->rop3w, &dwRop3, 4); + pmr_px->hSrc = cSrc.y; + pmr_px->wSrc = cSrc.x; + pmr_px->ySrc = Src.y; + pmr_px->xSrc = Src.x; + pmr_px->hDst = cDst.y; + pmr_px->wDst = cDst.x; + pmr_px->yDst = Dst.y; + pmr_px->xDst = Dst.x; + off = U_SIZE_WMRSTRETCHBLT_PX; + memcpy(record + off, Bm16, cbBm16); off += cbBm16; + if(cbBm164 - cbBm16)memset(record+off,0,cbBm164 - cbBm16); + } + } + else { + irecsize = U_SIZE_WMRSTRETCHBLT_NOPX; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_STRETCHBLT); + pmr_nopx = (PU_WMRSTRETCHBLT_NOPX) record; + memcpy(pmr_nopx->rop3w, &dwRop3, 4); + pmr_nopx->hSrc = cSrc.y; + pmr_nopx->wSrc = cSrc.x; + pmr_nopx->ySrc = Src.y; + pmr_nopx->xSrc = Src.x; + pmr_nopx->ignore = 0; + pmr_nopx->hDst = cDst.y; + pmr_nopx->wDst = cDst.x; + pmr_nopx->yDst = Dst.y; + pmr_nopx->xDst = Dst.x; + } + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRPOLYGON record. + \return pointer to the U_WMRPOLYGON record, or NULL on error. + \param Length Number of points in the Polygon + \param Data Array of Length points +*/ +char *U_WMRPOLYGON_set(uint16_t Length, const PU_POINT16 Data){ + return U_WMRCORE_2U16_N16_set(U_WMR_POLYGON, NULL, &Length, 2*Length, Data); +} + +/** + \brief Allocate and construct a U_WMRPOLYLINE record. + \return pointer to the U_WMRPOLYLINE record, or NULL on error. + \param Length Number of points in the Polyline + \param Data Array of Length points +*/ +char *U_WMRPOLYLINE_set(uint16_t Length, const PU_POINT16 Data){ + return U_WMRCORE_2U16_N16_set(U_WMR_POLYLINE, NULL, &Length, 2*Length, Data); +} + +/** + \brief Allocate and construct a U_WMRESCAPE record. + WARNING! Only three Escape record types are fully supported: SETLINECAP, SETLINEJOIN, SETMITERLIMIT. + Even these should not be set here directly, instead use the wsetlinecap_set(), wsetlinejoin_set(), + or wsetmiterlimit_set() functions. + Escape records created with this function, with the exception of the three named above, will not have + the byte orders in Data adjusted automatically. The user code must set Data to be little endian no + matter what the endianness of the current platform where the user code is running. + \return pointer to the U_WMRESCAPE record, or NULL on error. + \param Escape Escape function + \param Length Bytes in the Data + \param Data Array of Length bytes +*/ +char *U_WMRESCAPE_set(uint16_t Escape, uint16_t Length, const void *Data){ + return U_WMRCORE_2U16_N16_set(U_WMR_ESCAPE, &Escape, &Length, Length/2, Data); +} + +/** + \brief Allocate and construct a U_WMRRESTOREDC record + \return pointer to the U_WMRRESTOREDC record, or NULL on error. + \param DC Drawing Context to restore. (negative is relative to current, positive is absolute) +*/ +char *U_WMRRESTOREDC_set(int16_t DC){ + return U_WMRCORE_1U16_set(U_WMR_SETMAPMODE, DC); +} + +/** + \brief Allocate and construct a U_WMRFILLREGION record. + \return pointer to the U_WMRFILLREGION record, or NULL on error. + \param Region Region to fill + \param Brush Brush to fill with +*/ +char *U_WMRFILLREGION_set(uint16_t Region, uint16_t Brush){ + return U_WMRCORE_2U16_set(U_WMR_FILLREGION, Region, Brush); +} + +/** + \brief Allocate and construct a U_WMRFRAMEREGION record. + \return pointer to the U_WMRFRAMEREGION record, or NULL on error. + \param Region Index of region to frame in object table + \param Brush Index of brush to use in frame in object table + \param Height in logical units (of frame) + \param Width in logical units (of frame) +*/ +char *U_WMRFRAMEREGION_set(uint16_t Region, uint16_t Brush, int16_t Height, int16_t Width){ + return U_WMRCORE_4U16_set(U_WMR_FRAMEREGION, Region, Brush, U_U16(Height), U_U16(Width)); +} + +/** + \brief Allocate and construct a U_WMRINVERTREGION record. + \return pointer to the U_WMRINVERTREGION record, or NULL on error. + \param Region Index of region to invert. +*/ +char *U_WMRINVERTREGION_set(uint16_t Region){ + return U_WMRCORE_1U16_set(U_WMR_INVERTREGION, Region); +} + +/** + \brief Allocate and construct a U_WMRPAINTREGION record. + \return pointer to the U_WMRPAINTREGION record, or NULL on error. + \param Region Index of region to paint with the current Brush. +*/ +char *U_WMRPAINTREGION_set(uint16_t Region){ + return U_WMRCORE_1U16_set(U_WMR_PAINTREGION, Region); +} + +/** + \brief Allocate and construct a U_WMRSELECTCLIPREGION record. + \return pointer to the U_WMRSELECTCLIPREGION record, or NULL on error. + \param Region Index of region to become clipping region.. +*/ +char *U_WMRSELECTCLIPREGION_set(uint16_t Region){ + return U_WMRCORE_1U16_set(U_WMR_SELECTCLIPREGION, Region); +} + +/** + \brief Allocate and construct a U_WMRSELECTOBJECT record. + \return pointer to the U_WMRSELECTOBJECT record, or NULL on error. + \param object Index of object which is made active. +*/ +char *U_WMRSELECTOBJECT_set(uint16_t object){ + return U_WMRCORE_1U16_set(U_WMR_SELECTOBJECT, object); +} + +/** + \brief Allocate and construct a U_WMRSETTEXTALIGN record. + \return pointer to the U_WMRSETTEXTALIGN record, or NULL on error. + \param Mode TextAlignment Enumeration. +*/ +char *U_WMRSETTEXTALIGN_set(uint16_t Mode){ + return U_WMRCORE_2U16_set(U_WMR_SETTEXTALIGN, Mode, 0); +} + +/* in Wine, not in WMF PDF. */ + char *U_WMRDRAWTEXT_set(void){ /* in Wine, not in WMF PDF. */ + return U_WMRCORENONE_set("U_WMRDRAWTEXT"); +} + +/** + \brief Create and return a U_WMRCHORD record + \return pointer to the U_WMRCHORD record, or NULL on error + \param Radial1 Start of Chord + \param Radial2 End of Chord + \param rect Bounding rectangle. +*/ +char *U_WMRCHORD_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect){ + return U_WMRCORE_8U16_set( + U_WMR_CHORD, + U_U16(Radial2.y), + U_U16(Radial2.x), + U_U16(Radial1.y), + U_U16(Radial1.x), + U_U16(rect.bottom), + U_U16(rect.right), + U_U16(rect.top), + U_U16(rect.left) + ); +} + +/** + \brief Allocate and construct a U_WMRSETMAPPERFLAGS record. + \return pointer to the U_WMRSETMAPPERFLAGS record, or NULL on error. + \param Mode If 1 bit set font mapper selects only matching aspect fonts. +*/ +char *U_WMRSETMAPPERFLAGS_set(uint32_t Mode){ + return U_WMRCORE_2U16_set(U_WMR_SETMAPPERFLAGS, 0xFFFF & Mode, Mode>>16); +} + +/** + \brief Allocate and construct a U_WMREXTTEXTOUT record. + \return pointer to the U_WMREXTTEXTOUT record, or NULL on error. + \param Dst {X,Y} coordinates where the string is to be written. + \param Length Stringlength in bytes + \param Opts ExtTextOutOptions Flags + \param string String to write (Latin1 encoding) + \param dx Kerning information. Must have same number of entries as Length. + \param rect Used when when U_ETO_OPAQUE or U_ETO_CLIPPED bits are set in Opts +*/ +char *U_WMREXTTEXTOUT_set(U_POINT16 Dst, int16_t Length, uint16_t Opts, + const char *string, int16_t *dx, U_RECT16 rect){ + + char *record=NULL; + uint32_t irecsize,off; + int slen; + irecsize = U_SIZE_METARECORD + 8; /* 8 = y,x,Length,Opts*/ + slen = ( Length & 1 ? Length + 1 : Length); + irecsize += slen; + if(dx)irecsize += 2*Length; + if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){ + irecsize += U_SIZE_RECT16; + } + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_EXTTEXTOUT); + off = U_SIZE_METARECORD; + memcpy(record+off,&Dst.y,2); off+=2; + memcpy(record+off,&Dst.x,2); off+=2; + memcpy(record+off,&Length,2); off+=2; + memcpy(record+off,&Opts,2); off+=2; + if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){ + memcpy(record+off,&rect.bottom,2); off+=2; + memcpy(record+off,&rect.right, 2); off+=2; + memcpy(record+off,&rect.top, 2); off+=2; + memcpy(record+off,&rect.left, 2); off+=2; + } + memcpy(record+off,string,strlen(string)); off+=Length; + if(Length!=slen){ + memset(record+off,0,1); off+=1; + } + if(dx){ + memcpy(record+off,dx,2*Length); + } + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRSETDIBTODEV record + \return pointer to the U_WMRSETDIBTODEV record, or NULL on error. +*/ +char *U_WMRSETDIBTODEV_set(void){ + return U_WMRCORENONE_set("U_WMRSETDIBTODEV"); +} + +/** + \brief Allocate and construct a U_WMRSELECTPALETTE record + \return pointer to the U_WMRSELECTPALETTE record, or NULL on error. + \param Palette Index of Palette to make active. +*/ +char *U_WMRSELECTPALETTE_set(uint16_t Palette){ + return U_WMRCORE_1U16_set(U_WMR_SELECTPALETTE, Palette); +} + +/** + \brief Allocate and construct a U_WMRREALIZEPALETTE record + \return pointer to the U_WMRREALIZEPALETTE record, or NULL on error. +*/ +char *U_WMRREALIZEPALETTE_set(void){ + return U_WMRCORE_NOARGS_set(U_WMR_REALIZEPALETTE); +} + +/** + \brief Allocate and construct a U_WMRSETPALENTRIES record + \return pointer to the U_WMRSETPALENTRIES record, or NULL on error. + \param Palette Redefines a set of RGB values for the current active Palette. +*/ +char *U_WMRANIMATEPALETTE_set(PU_PALETTE Palette){ + return U_WMRCORE_PALETTE_set(U_WMR_ANIMATEPALETTE, Palette); +} + +/** + \brief Allocate and construct a U_WMRSETPALENTRIES record + \return pointer to the U_WMRSETPALENTRIES record, or NULL on error. + \param Palette Defines a set of RGB values for the current active Palette. +*/ +char *U_WMRSETPALENTRIES_set(PU_PALETTE Palette){ + return U_WMRCORE_PALETTE_set(U_WMR_SETPALENTRIES, Palette); +} + +/** + \brief Allocate and construct a U_WMR_POLYPOLYGON record. + \return pointer to the U_WMR_POLYPOLYGON record, or NULL on error. + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param Points array of points +*/ +char *U_WMRPOLYPOLYGON_set( + const uint16_t nPolys, + const uint16_t *aPolyCounts, + const PU_POINT16 Points + ){ + char *record; + uint32_t irecsize; + int i,cbPolys,cbPoints,off; + + cbPolys = sizeof(uint16_t)*nPolys; + for(i=cbPoints=0; i<nPolys; i++){ cbPoints += U_SIZE_POINT16*aPolyCounts[i]; } + + if(nPolys==0 || cbPoints==0)return(NULL); + + irecsize = U_SIZE_METARECORD + 2 + cbPolys + cbPoints; /* core WMR + nPolys + two array sizes in bytes */ + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_POLYPOLYGON); + off = U_SIZE_METARECORD; + memcpy(record + off, &nPolys, 2); off+=2; + memcpy(record + off, aPolyCounts, cbPolys); off+=cbPolys; + memcpy(record + off, Points, cbPoints); + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRRESIZEPALETTE record + \return pointer to the U_WMRRESIZEPALETTE record, or NULL on error. + \param Palette Changes the size of the currently active Palette. +*/ +char *U_WMRRESIZEPALETTE_set(uint16_t Palette){ + return U_WMRCORE_1U16_set(U_WMR_RESIZEPALETTE, Palette); +} + +char *U_WMR3A_set(void){ + return U_WMRCORENONE_set("U_WMR3A"); +} + +char *U_WMR3B_set(void){ + return U_WMRCORENONE_set("U_WMR3B"); +} + +char *U_WMR3C_set(void){ + return U_WMRCORENONE_set("U_WMR3C"); +} + +char *U_WMR3D_set(void){ + return U_WMRCORENONE_set("U_WMR3D"); +} + +char *U_WMR3E_set(void){ + return U_WMRCORENONE_set("U_WMR3E"); +} + +char *U_WMR3F_set(void){ + return U_WMRCORENONE_set("U_WMR3F"); +} + +// U_WMRDIBBITBLT_set +/** + \brief Allocate and construct a U_WMRDIBITBLT record. + \return pointer to the U_WMRDIBITBLT record, or NULL on error. + \param Dst Destination UL corner in logical units + \param Src Source UL corner in logical units + \param cwh W & H in logical units of Src and Dst + \param dwRop3 RasterOPeration Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_WMRDIBBITBLT_set( + U_POINT16 Dst, + U_POINT16 cwh, + U_POINT16 Src, + uint32_t dwRop3, + const PU_BITMAPINFO Bmi, + uint32_t cbPx, + const char *Px + ){ + char *record=NULL; + uint32_t irecsize; + int cbImage,cbImage4,cbBmi,off; + PU_WMRDIBBITBLT_PX pmr_px; + PU_WMRDIBBITBLT_NOPX pmr_nopx; + + + if(Px && Bmi){ + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + irecsize = U_SIZE_WMRDIBBITBLT_PX + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBBITBLT); + pmr_px = (PU_WMRDIBBITBLT_PX) record; + memcpy(pmr_px->rop3w, &dwRop3, 4); + pmr_px->ySrc = Src.y; + pmr_px->xSrc = Src.x; + pmr_px->Height = cwh.y; + pmr_px->Width = cwh.x; + pmr_px->yDst = Dst.y; + pmr_px->xDst = Dst.x; + off = U_SIZE_WMRDIBBITBLT_PX; + memcpy(record + off, Bmi, cbBmi); off += cbBmi; + memcpy(record + off, Px, cbPx); off += cbPx; + if(cbImage4 - cbImage)memset(record+off,0,cbImage4 - cbImage); + } + } + else if(!Px && !Bmi){ + irecsize = U_SIZE_WMRDIBBITBLT_NOPX; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBBITBLT); + pmr_nopx = (PU_WMRDIBBITBLT_NOPX) record; + memcpy(pmr_nopx->rop3w, &dwRop3, 4); + pmr_nopx->ySrc = Src.y; + pmr_nopx->xSrc = Src.x; + pmr_nopx->ignore = 0; + pmr_nopx->Height = cwh.y; + pmr_nopx->Width = cwh.x; + pmr_nopx->yDst = Dst.y; + pmr_nopx->xDst = Dst.x; + } + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRSTRETCHDIB record. + \return pointer to the U_WMRSTRETCHDIB record, or NULL on error. + \param Dst Destination UL corner in logical units + \param cDst Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param dwRop3 RasterOPeration Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_WMRDIBSTRETCHBLT_set( + U_POINT16 Dst, + U_POINT16 cDst, + U_POINT16 Src, + U_POINT16 cSrc, + uint32_t dwRop3, + const PU_BITMAPINFO Bmi, + uint32_t cbPx, + const char *Px + ){ + char *record=NULL; + uint32_t irecsize; + int cbImage,cbImage4,cbBmi,off; + PU_WMRDIBSTRETCHBLT_PX pmr_px; + PU_WMRDIBSTRETCHBLT_NOPX pmr_nopx; + if(Px && Bmi){ + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + irecsize = U_SIZE_WMRDIBSTRETCHBLT_PX + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBSTRETCHBLT); + pmr_px = (PU_WMRDIBSTRETCHBLT_PX) record; + memcpy(pmr_px->rop3w, &dwRop3, 4); + pmr_px->hSrc = cSrc.y; + pmr_px->wSrc = cSrc.x; + pmr_px->ySrc = Src.y; + pmr_px->xSrc = Src.x; + pmr_px->hDst = cDst.y; + pmr_px->wDst = cDst.x; + pmr_px->yDst = Dst.y; + pmr_px->xDst = Dst.x; + off = U_SIZE_WMRDIBSTRETCHBLT_PX; + memcpy(record + off, Bmi, cbBmi); off += cbBmi; + memcpy(record + off, Px, cbPx); off += cbPx; + if(cbImage4 - cbImage)memset(record+off,0,cbImage4 - cbImage); + } + } + else if(!Px && !Bmi){ + irecsize = U_SIZE_WMRDIBSTRETCHBLT_NOPX; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBSTRETCHBLT); + pmr_nopx = (PU_WMRDIBSTRETCHBLT_NOPX) record; + memcpy(pmr_nopx->rop3w, &dwRop3, 4); + pmr_nopx->hSrc = cSrc.y; + pmr_nopx->wSrc = cSrc.x; + pmr_nopx->ySrc = Src.y; + pmr_nopx->xSrc = Src.x; + pmr_nopx->ignore = 0; + pmr_nopx->hDst = cDst.y; + pmr_nopx->wDst = cDst.x; + pmr_nopx->yDst = Dst.y; + pmr_nopx->xDst = Dst.x; + } + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRDIBCREATEPATTERNBRUSH record. + Accepts an image as either a DIB (Bmi/CbPx/Px defined) or a Bitmap16 (Bm16 defined). + \return pointer to the U_WMRDIBCREATEPATTERNBRUSH record, or NULL on error. + \param Style BrushStyle Enumeration + \param iUsage DIBcolors Enumeration + \param Bm16 pointer to U_BITMAP16 object for Style U_BS_PATTERN only + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row), for use with Bmi + \param Px bitmap buffer, for use with Bmi + \param Bmi pointer to U_BITMAPINFO for all Style OTHER than U_BS_PATTERN +*/ +char *U_WMRDIBCREATEPATTERNBRUSH_set( + const uint16_t Style, + const uint16_t iUsage, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px, + PU_BITMAP16 Bm16 + ){ + char *record=NULL; + uint32_t irecsize; + int cbImage,cbImage4,cbBmi,cbBm16,cbBm164,off; + + if(Style==U_BS_PATTERN && Bm16){ + cbBm16 = U_SIZE_BITMAP16 + (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height; + cbBm164 = UP4(cbBm16); + irecsize = U_SIZE_WMRDIBCREATEPATTERNBRUSH + cbBm164; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBCREATEPATTERNBRUSH); + off = U_SIZE_METARECORD; + memcpy(record + off, &Style, 2); off+=2; + memcpy(record + off, &iUsage, 2); off+=2; + memcpy(record + off, Bm16, cbBm16); off += cbBm16; + if(cbBm164 - cbBm16)memset(record+off,0,cbBm164 - cbBm16); + } + } + else if(Bmi){ + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + irecsize = U_SIZE_WMRDIBCREATEPATTERNBRUSH + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBCREATEPATTERNBRUSH); + off = U_SIZE_METARECORD; + memcpy(record + off, &Style, 2); off+=2; + memcpy(record + off, &iUsage, 2); off+=2; + memcpy(record + off, Bmi, cbBmi); off += cbBmi; + memcpy(record + off, Px, cbImage); off += cbImage; + if(cbImage4 - cbImage)memset(record + off, 0, cbImage4 - cbImage); + } + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRSTRETCHDIB record. + \return pointer to the U_WMRSTRETCHDIB record, or NULL on error. + \param Dst Destination UL corner in logical units + \param cDst Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param cUsage DIBColors Enumeration + \param dwRop3 RasterOPeration Enumeration + \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section) + \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *U_WMRSTRETCHDIB_set( + U_POINT16 Dst, + U_POINT16 cDst, + U_POINT16 Src, + U_POINT16 cSrc, + uint16_t cUsage, + uint32_t dwRop3, + const PU_BITMAPINFO Bmi, + uint32_t cbPx, + const char *Px + ){ + char *record; + uint32_t irecsize; + int cbImage,cbImage4,cbBmi,off; + PU_WMRSTRETCHDIB pmr; + + SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); + + irecsize = U_SIZE_WMRSTRETCHDIB + cbBmi + cbImage4; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_STRETCHDIB); + pmr = (PU_WMRSTRETCHDIB) record; + memcpy(pmr->rop3w, &dwRop3, 4); + pmr->cUsage = cUsage; + pmr->hSrc = cSrc.y; + pmr->wSrc = cSrc.x; + pmr->ySrc = Src.y; + pmr->xSrc = Src.x; + pmr->hDst = cDst.y; + pmr->wDst = cDst.x; + pmr->yDst = Dst.y; + pmr->xDst = Dst.x; + off = U_SIZE_WMRSTRETCHDIB; + if(cbBmi){ + memcpy(record + off, Bmi, cbBmi); off += cbBmi; + memcpy(record + off, Px, cbPx); off += cbPx; + if(cbImage4 - cbImage)memset(record+off,0,cbImage4 - cbImage); + } + } + return(record); +} + +char *U_WMR44_set(void){ + return U_WMRCORENONE_set("U_WMR44"); +} + +char *U_WMR45_set(void){ + return U_WMRCORENONE_set("U_WMR45"); +} + +char *U_WMR46_set(void){ + return U_WMRCORENONE_set("U_WMR46"); +} + +char *U_WMR47_set(void){ + return U_WMRCORENONE_set("U_WMR47"); +} + +/** + \brief Create and return a U_WMREXTFLOODFILL record + \return pointer to the U_WMREXTFLOODFILL record, or NULL on error + \param Mode FloodFill Enumeration. + \param Color Color to Fill with. + \param coord Location to start fill. +*/ +char *U_WMREXTFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord){ + return U_WMRCORE_1U16_CRF_2U16_set( + U_WMR_EXTFLOODFILL, + &Mode, + Color, + U_P16(coord.y), + U_P16(coord.x) + ); +} + +char *U_WMR49_set(void){ + return U_WMRCORENONE_set("U_WMR49"); +} + +char *U_WMR4A_set(void){ + return U_WMRCORENONE_set("U_WMR4A"); +} + +char *U_WMR4B_set(void){ + return U_WMRCORENONE_set("U_WMR4B"); +} + +char *U_WMR4C_set(void){ + return U_WMRCORENONE_set("U_WMRRESETDOC"); +} + +char *U_WMR4D_set(void){ + return U_WMRCORENONE_set("U_WMRSTARTDOC"); +} + +char *U_WMR4E_set(void){ + return U_WMRCORENONE_set("U_WMR4E"); +} + +char *U_WMR4F_set(void){ + return U_WMRCORENONE_set("U_WMRSTARTPAGE"); +} + +char *U_WMR50_set(void){ + return U_WMRCORENONE_set("U_WMRENDPAGE"); +} + +char *U_WMR51_set(void){ + return U_WMRCORENONE_set("U_WMR51"); +} + +char *U_WMRABORTDOC_set(void){ + return U_WMRCORENONE_set("U_WMRABORTDOC"); +} + +char *U_WMR53_set(void){ + return U_WMRCORENONE_set("U_WMR53"); +} + +char *U_WMR54_set(void){ + return U_WMRCORENONE_set("U_WMR54"); +} + +char *U_WMR55_set(void){ + return U_WMRCORENONE_set("U_WMR55"); +} + +char *U_WMR56_set(void){ + return U_WMRCORENONE_set("U_WMR56"); +} + +char *U_WMR57_set(void){ + return U_WMRCORENONE_set("U_WMR57"); +} + +char *U_WMR58_set(void){ + return U_WMRCORENONE_set("U_WMR58"); +} + +char *U_WMR59_set(void){ + return U_WMRCORENONE_set("U_WMR59"); +} + +char *U_WMR5A_set(void){ + return U_WMRCORENONE_set("U_WMR5A"); +} + +char *U_WMR5B_set(void){ + return U_WMRCORENONE_set("U_WMR5B"); +} + +char *U_WMR5C_set(void){ + return U_WMRCORENONE_set("U_WMR5C"); +} + +char *U_WMR5D_set(void){ + return U_WMRCORENONE_set("U_WMR5D"); +} + +char *U_WMR5E_set(void){ + return U_WMRCORENONE_set("U_WMRENDDOC"); +} + +char *U_WMR5F_set(void){ + return U_WMRCORENONE_set("U_WMR5F"); +} + +char *U_WMR60_set(void){ + return U_WMRCORENONE_set("U_WMR60"); +} + +char *U_WMR61_set(void){ + return U_WMRCORENONE_set("U_WMR61"); +} + +char *U_WMR62_set(void){ + return U_WMRCORENONE_set("U_WMR62"); +} + +char *U_WMR63_set(void){ + return U_WMRCORENONE_set("U_WMR63"); +} + +char *U_WMR64_set(void){ + return U_WMRCORENONE_set("U_WMR64"); +} + +char *U_WMR65_set(void){ + return U_WMRCORENONE_set("U_WMR65"); +} + +char *U_WMR66_set(void){ + return U_WMRCORENONE_set("U_WMR66"); +} + +char *U_WMR67_set(void){ + return U_WMRCORENONE_set("U_WMR67"); +} + +char *U_WMR68_set(void){ + return U_WMRCORENONE_set("U_WMR68"); +} + +char *U_WMR69_set(void){ + return U_WMRCORENONE_set("U_WMR69"); +} + +char *U_WMR6A_set(void){ + return U_WMRCORENONE_set("U_WMR6A"); +} + +char *U_WMR6B_set(void){ + return U_WMRCORENONE_set("U_WMR6B"); +} + +char *U_WMR6C_set(void){ + return U_WMRCORENONE_set("U_WMR6C"); +} + +char *U_WMR6D_set(void){ + return U_WMRCORENONE_set("U_WMR6D"); +} + +char *U_WMR6E_set(void){ + return U_WMRCORENONE_set("U_WMR6E"); +} + +char *U_WMR6F_set(void){ + return U_WMRCORENONE_set("U_WMR6F"); +} + +char *U_WMR70_set(void){ + return U_WMRCORENONE_set("U_WMR70"); +} + +char *U_WMR71_set(void){ + return U_WMRCORENONE_set("U_WMR71"); +} + +char *U_WMR72_set(void){ + return U_WMRCORENONE_set("U_WMR72"); +} + +char *U_WMR73_set(void){ + return U_WMRCORENONE_set("U_WMR73"); +} + +char *U_WMR74_set(void){ + return U_WMRCORENONE_set("U_WMR74"); +} + +char *U_WMR75_set(void){ + return U_WMRCORENONE_set("U_WMR75"); +} + +char *U_WMR76_set(void){ + return U_WMRCORENONE_set("U_WMR76"); +} + +char *U_WMR77_set(void){ + return U_WMRCORENONE_set("U_WMR77"); +} + +char *U_WMR78_set(void){ + return U_WMRCORENONE_set("U_WMR78"); +} + +char *U_WMR79_set(void){ + return U_WMRCORENONE_set("U_WMR79"); +} + +char *U_WMR7A_set(void){ + return U_WMRCORENONE_set("U_WMR7A"); +} + +char *U_WMR7B_set(void){ + return U_WMRCORENONE_set("U_WMR7B"); +} + +char *U_WMR7C_set(void){ + return U_WMRCORENONE_set("U_WMR7C"); +} + +char *U_WMR7D_set(void){ + return U_WMRCORENONE_set("U_WMR7D"); +} + +char *U_WMR7E_set(void){ + return U_WMRCORENONE_set("U_WMR7E"); +} + +char *U_WMR7F_set(void){ + return U_WMRCORENONE_set("U_WMR7F"); +} + +char *U_WMR80_set(void){ + return U_WMRCORENONE_set("U_WMR80"); +} + +char *U_WMR81_set(void){ + return U_WMRCORENONE_set("U_WMR81"); +} + +char *U_WMR82_set(void){ + return U_WMRCORENONE_set("U_WMR82"); +} + +char *U_WMR83_set(void){ + return U_WMRCORENONE_set("U_WMR83"); +} + +char *U_WMR84_set(void){ + return U_WMRCORENONE_set("U_WMR84"); +} + +char *U_WMR85_set(void){ + return U_WMRCORENONE_set("U_WMR85"); +} + +char *U_WMR86_set(void){ + return U_WMRCORENONE_set("U_WMR86"); +} + +char *U_WMR87_set(void){ + return U_WMRCORENONE_set("U_WMR87"); +} + +char *U_WMR88_set(void){ + return U_WMRCORENONE_set("U_WMR88"); +} + +char *U_WMR89_set(void){ + return U_WMRCORENONE_set("U_WMR89"); +} + +char *U_WMR8A_set(void){ + return U_WMRCORENONE_set("U_WMR8A"); +} + +char *U_WMR8B_set(void){ + return U_WMRCORENONE_set("U_WMR8B"); +} + +char *U_WMR8C_set(void){ + return U_WMRCORENONE_set("U_WMR8C"); +} + +char *U_WMR8D_set(void){ + return U_WMRCORENONE_set("U_WMR8D"); +} + +char *U_WMR8E_set(void){ + return U_WMRCORENONE_set("U_WMR8E"); +} + +char *U_WMR8F_set(void){ + return U_WMRCORENONE_set("U_WMR8F"); +} + +char *U_WMR90_set(void){ + return U_WMRCORENONE_set("U_WMR90"); +} + +char *U_WMR91_set(void){ + return U_WMRCORENONE_set("U_WMR91"); +} + +char *U_WMR92_set(void){ + return U_WMRCORENONE_set("U_WMR92"); +} + +char *U_WMR93_set(void){ + return U_WMRCORENONE_set("U_WMR93"); +} + +char *U_WMR94_set(void){ + return U_WMRCORENONE_set("U_WMR94"); +} + +char *U_WMR95_set(void){ + return U_WMRCORENONE_set("U_WMR95"); +} + +char *U_WMR96_set(void){ + return U_WMRCORENONE_set("U_WMR96"); +} + +char *U_WMR97_set(void){ + return U_WMRCORENONE_set("U_WMR97"); +} + +char *U_WMR98_set(void){ + return U_WMRCORENONE_set("U_WMR98"); +} + +char *U_WMR99_set(void){ + return U_WMRCORENONE_set("U_WMR99"); +} + +char *U_WMR9A_set(void){ + return U_WMRCORENONE_set("U_WMR9A"); +} + +char *U_WMR9B_set(void){ + return U_WMRCORENONE_set("U_WMR9B"); +} + +char *U_WMR9C_set(void){ + return U_WMRCORENONE_set("U_WMR9C"); +} + +char *U_WMR9D_set(void){ + return U_WMRCORENONE_set("U_WMR9D"); +} + +char *U_WMR9E_set(void){ + return U_WMRCORENONE_set("U_WMR9E"); +} + +char *U_WMR9F_set(void){ + return U_WMRCORENONE_set("U_WMR9F"); +} + +char *U_WMRA0_set(void){ + return U_WMRCORENONE_set("U_WMRA0"); +} + +char *U_WMRA1_set(void){ + return U_WMRCORENONE_set("U_WMRA1"); +} + +char *U_WMRA2_set(void){ + return U_WMRCORENONE_set("U_WMRA2"); +} + +char *U_WMRA3_set(void){ + return U_WMRCORENONE_set("U_WMRA3"); +} + +char *U_WMRA4_set(void){ + return U_WMRCORENONE_set("U_WMRA4"); +} + +char *U_WMRA5_set(void){ + return U_WMRCORENONE_set("U_WMRA5"); +} + +char *U_WMRA6_set(void){ + return U_WMRCORENONE_set("U_WMRA6"); +} + +char *U_WMRA7_set(void){ + return U_WMRCORENONE_set("U_WMRA7"); +} + +char *U_WMRA8_set(void){ + return U_WMRCORENONE_set("U_WMRA8"); +} + +char *U_WMRA9_set(void){ + return U_WMRCORENONE_set("U_WMRA9"); +} + +char *U_WMRAA_set(void){ + return U_WMRCORENONE_set("U_WMRAA"); +} + +char *U_WMRAB_set(void){ + return U_WMRCORENONE_set("U_WMRAB"); +} + +char *U_WMRAC_set(void){ + return U_WMRCORENONE_set("U_WMRAC"); +} + +char *U_WMRAD_set(void){ + return U_WMRCORENONE_set("U_WMRAD"); +} + +char *U_WMRAE_set(void){ + return U_WMRCORENONE_set("U_WMRAE"); +} + +char *U_WMRAF_set(void){ + return U_WMRCORENONE_set("U_WMRAF"); +} + +char *U_WMRB0_set(void){ + return U_WMRCORENONE_set("U_WMRB0"); +} + +char *U_WMRB1_set(void){ + return U_WMRCORENONE_set("U_WMRB1"); +} + +char *U_WMRB2_set(void){ + return U_WMRCORENONE_set("U_WMRB2"); +} + +char *U_WMRB3_set(void){ + return U_WMRCORENONE_set("U_WMRB3"); +} + +char *U_WMRB4_set(void){ + return U_WMRCORENONE_set("U_WMRB4"); +} + +char *U_WMRB5_set(void){ + return U_WMRCORENONE_set("U_WMRB5"); +} + +char *U_WMRB6_set(void){ + return U_WMRCORENONE_set("U_WMRB6"); +} + +char *U_WMRB7_set(void){ + return U_WMRCORENONE_set("U_WMRB7"); +} + +char *U_WMRB8_set(void){ + return U_WMRCORENONE_set("U_WMRB8"); +} + +char *U_WMRB9_set(void){ + return U_WMRCORENONE_set("U_WMRB9"); +} + +char *U_WMRBA_set(void){ + return U_WMRCORENONE_set("U_WMRBA"); +} + +char *U_WMRBB_set(void){ + return U_WMRCORENONE_set("U_WMRBB"); +} + +char *U_WMRBC_set(void){ + return U_WMRCORENONE_set("U_WMRBC"); +} + +char *U_WMRBD_set(void){ + return U_WMRCORENONE_set("U_WMRBD"); +} + +char *U_WMRBE_set(void){ + return U_WMRCORENONE_set("U_WMRBE"); +} + +char *U_WMRBF_set(void){ + return U_WMRCORENONE_set("U_WMRBF"); +} + +char *U_WMRC0_set(void){ + return U_WMRCORENONE_set("U_WMRC0"); +} + +char *U_WMRC1_set(void){ + return U_WMRCORENONE_set("U_WMRC1"); +} + +char *U_WMRC2_set(void){ + return U_WMRCORENONE_set("U_WMRC2"); +} + +char *U_WMRC3_set(void){ + return U_WMRCORENONE_set("U_WMRC3"); +} + +char *U_WMRC4_set(void){ + return U_WMRCORENONE_set("U_WMRC4"); +} + +char *U_WMRC5_set(void){ + return U_WMRCORENONE_set("U_WMRC5"); +} + +char *U_WMRC6_set(void){ + return U_WMRCORENONE_set("U_WMRC6"); +} + +char *U_WMRC7_set(void){ + return U_WMRCORENONE_set("U_WMRC7"); +} + +char *U_WMRC8_set(void){ + return U_WMRCORENONE_set("U_WMRC8"); +} + +char *U_WMRC9_set(void){ + return U_WMRCORENONE_set("U_WMRC9"); +} + +char *U_WMRCA_set(void){ + return U_WMRCORENONE_set("U_WMRCA"); +} + +char *U_WMRCB_set(void){ + return U_WMRCORENONE_set("U_WMRCB"); +} + +char *U_WMRCC_set(void){ + return U_WMRCORENONE_set("U_WMRCC"); +} + +char *U_WMRCD_set(void){ + return U_WMRCORENONE_set("U_WMRCD"); +} + +char *U_WMRCE_set(void){ + return U_WMRCORENONE_set("U_WMRCE"); +} + +char *U_WMRCF_set(void){ + return U_WMRCORENONE_set("U_WMRCF"); +} + +char *U_WMRD0_set(void){ + return U_WMRCORENONE_set("U_WMRD0"); +} + +char *U_WMRD1_set(void){ + return U_WMRCORENONE_set("U_WMRD1"); +} + +char *U_WMRD2_set(void){ + return U_WMRCORENONE_set("U_WMRD2"); +} + +char *U_WMRD3_set(void){ + return U_WMRCORENONE_set("U_WMRD3"); +} + +char *U_WMRD4_set(void){ + return U_WMRCORENONE_set("U_WMRD4"); +} + +char *U_WMRD5_set(void){ + return U_WMRCORENONE_set("U_WMRD5"); +} + +char *U_WMRD6_set(void){ + return U_WMRCORENONE_set("U_WMRD6"); +} + +char *U_WMRD7_set(void){ + return U_WMRCORENONE_set("U_WMRD7"); +} + +char *U_WMRD8_set(void){ + return U_WMRCORENONE_set("U_WMRD8"); +} + +char *U_WMRD9_set(void){ + return U_WMRCORENONE_set("U_WMRD9"); +} + +char *U_WMRDA_set(void){ + return U_WMRCORENONE_set("U_WMRDA"); +} + +char *U_WMRDB_set(void){ + return U_WMRCORENONE_set("U_WMRDB"); +} + +char *U_WMRDC_set(void){ + return U_WMRCORENONE_set("U_WMRDC"); +} + +char *U_WMRDD_set(void){ + return U_WMRCORENONE_set("U_WMRDD"); +} + +char *U_WMRDE_set(void){ + return U_WMRCORENONE_set("U_WMRDE"); +} + +char *U_WMRDF_set(void){ + return U_WMRCORENONE_set("U_WMRDF"); +} + +char *U_WMRE0_set(void){ + return U_WMRCORENONE_set("U_WMRE0"); +} + +char *U_WMRE1_set(void){ + return U_WMRCORENONE_set("U_WMRE1"); +} + +char *U_WMRE2_set(void){ + return U_WMRCORENONE_set("U_WMRE2"); +} + +char *U_WMRE3_set(void){ + return U_WMRCORENONE_set("U_WMRE3"); +} + +char *U_WMRE4_set(void){ + return U_WMRCORENONE_set("U_WMRE4"); +} + +char *U_WMRE5_set(void){ + return U_WMRCORENONE_set("U_WMRE5"); +} + +char *U_WMRE6_set(void){ + return U_WMRCORENONE_set("U_WMRE6"); +} + +char *U_WMRE7_set(void){ + return U_WMRCORENONE_set("U_WMRE7"); +} + +char *U_WMRE8_set(void){ + return U_WMRCORENONE_set("U_WMRE8"); +} + +char *U_WMRE9_set(void){ + return U_WMRCORENONE_set("U_WMRE9"); +} + +char *U_WMREA_set(void){ + return U_WMRCORENONE_set("U_WMREA"); +} + +char *U_WMREB_set(void){ + return U_WMRCORENONE_set("U_WMREB"); +} + +char *U_WMREC_set(void){ + return U_WMRCORENONE_set("U_WMREC"); +} + +char *U_WMRED_set(void){ + return U_WMRCORENONE_set("U_WMRED"); +} + +char *U_WMREE_set(void){ + return U_WMRCORENONE_set("U_WMREE"); +} + +char *U_WMREF_set(void){ + return U_WMRCORENONE_set("U_WMREF"); +} + +/** + \brief Create and return a U_WMRDELETEOBJECT record + \return pointer to the U_WMRDELETEOBJECT record, or NULL on error + \param object Index of object to delete. +*/ +char *U_WMRDELETEOBJECT_set(uint16_t object){ + return U_WMRCORE_1U16_set(U_WMR_DELETEOBJECT, object); +} + +char *U_WMRF1_set(void){ + return U_WMRCORENONE_set("U_WMRF1"); +} + +char *U_WMRF2_set(void){ + return U_WMRCORENONE_set("U_WMRF2"); +} + +char *U_WMRF3_set(void){ + return U_WMRCORENONE_set("U_WMRF3"); +} + +char *U_WMRF4_set(void){ + return U_WMRCORENONE_set("U_WMRF4"); +} + +char *U_WMRF5_set(void){ + return U_WMRCORENONE_set("U_WMRF5"); +} + +char *U_WMRF6_set(void){ + return U_WMRCORENONE_set("U_WMRF6"); +} + +/** + \brief Create and return a U_WMRCREATEPALETTE record + \return pointer to the U_WMRCREATEPALETTE record, or NULL on error + \param Palette Create a Palette object. +*/ +char *U_WMRCREATEPALETTE_set(PU_PALETTE Palette){ + return U_WMRCORE_PALETTE_set(U_WMR_CREATEPALETTE, Palette); +} + +char *U_WMRF8_set(void){ + return U_WMRCORENONE_set("U_WMRF8"); +} + +/** + \brief Allocate and construct a U_WMRCREATEPATTERNBRUSH record. + Warning - application support for U_WMRCREATEPATTERNBRUSH is spotty, better to use U_WMRDIBCREATEPATTERNBRUSH. + \return pointer to the U_WMRCREATEPATTERNBRUSH record, or NULL on error. + \param Bm16 Pointer to a Bitmap16 Object, only the first 10 bytes are used. + \param Pattern byte array pattern, described by Bm16, for brush +*/ +char *U_WMRCREATEPATTERNBRUSH_set( + PU_BITMAP16 Bm16, + char *Pattern + ){ + char *record; + uint32_t irecsize,off,cbPat; + if(!Bm16 || !Pattern)return(NULL); + + cbPat = (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height; + irecsize = U_SIZE_METARECORD + 14 + 4 + 18 + cbPat; /* core WMR + truncated Bm16 + pattern */ + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_CREATEPATTERNBRUSH); + off = U_SIZE_METARECORD; + memcpy(record + off, Bm16, 14); off+=14; /* Truncated bitmap16 object*/ + memset(record + off, 0, 4); off+=4; /* 4 bytes of its "bits", which are ignored */ + memset(record + off, 0, 18); off+=18; /* 18 bytes of zero, which are ignored */ + memcpy(record + off, Pattern, cbPat); /* The pattern array */ + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRCREATEPENINDIRECT record. + \return pointer to the U_WMRCREATEPENINDIRECT record, or NULL on error. + \param pen Parameters of the pen object to create. +*/ +char *U_WMRCREATEPENINDIRECT_set(U_PEN pen){ + return U_WMRCORE_2U16_N16_set(U_WMR_CREATEPENINDIRECT, NULL, NULL, U_SIZE_PEN/2, &pen); +} + +/** + \brief Allocate and construct a U_WMRCREATEFONTINDIRECT record. + \return pointer to the U_WMRCREATEFONTINDIRECT record, or NULL on error. + \param font Parameters of the font object to create. +*/ +char *U_WMRCREATEFONTINDIRECT_set(PU_FONT font){ + char *record=NULL; + uint32_t irecsize,off,flen; + flen = 1 + strlen((char *)font->FaceName); /* include the null terminator in the count */ + if(flen & 1) flen++; /* make the allocation end line up at an even byte */ + irecsize = U_SIZE_METARECORD + U_SIZE_FONT_CORE + flen; + record = calloc(1,irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_CREATEFONTINDIRECT); + off = U_SIZE_METARECORD; + memcpy(record+off,font,U_SIZE_FONT_CORE + flen); + } + return(record); +} + +/** + \brief Allocate and construct a U_WMRCREATEBRUSHINDIRECT record. + \return pointer to the U_WMRCREATEBRUSHINDIRECT record, or NULL on error. + \param brush Parameters of the brush object to create. +*/ +char *U_WMRCREATEBRUSHINDIRECT_set(U_WLOGBRUSH brush){ + return U_WMRCORE_2U16_N16_set(U_WMR_CREATEBRUSHINDIRECT, NULL, NULL, U_SIZE_WLOGBRUSH/2, &brush); +} + + /* in Wine, not in WMF PDF */ + char *U_WMRCREATEBITMAPINDIRECT_set(void){ + return U_WMRCORENONE_set("U_WMRCREATEBITMAPINDIRECT"); +} + + /* in Wine, not in WMF PDF */ + char *U_WMRCREATEBITMAP_set(void){ + return U_WMRCORENONE_set("U_WMRCREATEBITMAP"); +} + +/** + \brief Allocate and construct a U_WMRCREATEREGION record. + \return pointer to the U_WMRCREATEREGION record, or NULL on error. + \param region Parameters of the region object to create. +*/ +char *U_WMRCREATEREGION_set(PU_REGION region){ + char *record=NULL; + uint32_t irecsize,off; + irecsize = U_SIZE_METARECORD + region->Size; + record = malloc(irecsize); + if(record){ + U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_CREATEREGION); + off = U_SIZE_METARECORD; + memcpy(record+off,region,region->Size); + } + return(record); +} + + +/* all of the *_set are above, all of the *_get are below */ + +/* ********************************************************************************************** +These functions are used for Image conversions and other +utility operations. Character type conversions are in uwmf_utf.c +*********************************************************************************************** */ + + +/** + \brief Make up an approximate dx array to pass to U_WMREXTTEXTOUT_get(), based on character height and weight. + + Take abs. value of character height, get width by multiplying by 0.6, and correct weight + approximately, with formula (measured on screen for one text line of Arial). + Caller is responsible for free() on the returned pointer. + + \return pointer to dx array + \param height character height (absolute value will be used) + \param weight LF_Weight Enumeration (character weight) + \param members Number of entries to put into dx + +*/ +int16_t *dx16_get( + int32_t height, + uint32_t weight, + uint32_t members + ){ + uint32_t i, width; + int16_t *dx; + dx = (int16_t *) malloc(members * sizeof(int16_t)); + if(dx){ + if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL; + width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904)); + for ( i = 0; i < members; i++ ){ dx[i] = (width > INT16_MAX ? INT16_MAX : width); } + } + return(dx); +} + +/** + \brief Return the size of a WMF record, or 0 if it is found to be invalid. + A valid record will have a size that does not cause it to extend + beyond the end of data in memory. + A valid record will not be smaller than the smallest possible WMF record. + \return size of the record in bytes, 0 on failure + \param contents record to extract data from + \param blimit one byte past the last WMF record in memory. +*/ +size_t U_WMRRECSAFE_get( + const char *contents, + const char *blimit + ){ + size_t size=0; + uint32_t Size16; + memcpy(&Size16, contents + offsetof(U_METARECORD,Size16_4), 4); + size = 2*Size16; + /* Record is not self consistent - described size past the end of WMF in memory */ + if(size < U_SIZE_METARECORD || + contents + size - 1 >= blimit || + contents + size - 1 < contents)size=0; + return(size); +} + + +/* ********************************************************************************************** +These functions create standard structures used in the WMR records. +*********************************************************************************************** */ + +// hide these from Doxygen +//! @cond +/* ********************************************************************************************** +These functions contain shared code used by various U_WMR*_get functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. +*********************************************************************************************** */ + +int U_WMRCORENONE_get(char *string){ + printf("unimplemented creator for:%s\n",string); + return(0); +} + +/* Returns the record size in bytes for a valid record, or 0 for an invalid record. + A valid record's size is at least as large as the minimum size passed in through minsize. + Use U_WMRRECSAFE_get() to check if the record extends too far in memory. +*/ +int U_WMRCORE_RECSAFE_get( + const char *contents, + int minsize +){ + int size=0; + uint32_t Size16; + memcpy(&Size16, contents + offsetof(U_METARECORD,Size16_4),4); + size = 2*Size16; + if(size < minsize)size=0; + return(size); +} + + +/* records like U_WMRFLOODFILL and others. all args are optional, Color is not */ +int U_WMRCORE_1U16_CRF_2U16_get( + const char *contents, + int minsize, + uint16_t *arg1, + PU_COLORREF Color, + uint16_t *arg2, + uint16_t *arg3 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int irecsize,off; + irecsize = U_SIZE_METARECORD + U_SIZE_COLORREF; + if(arg1)irecsize+=2; + if(arg2)irecsize+=2; + if(arg3)irecsize+=2; + off = U_SIZE_METARECORD; + if(arg1){ memcpy(arg1, contents + off, 2); off+=2; } + memcpy(Color, contents + off, 4); off+=4; + if(arg2){ memcpy(arg2, contents + off, 2); off+=2; } + if(arg3){ memcpy(arg3, contents + off, 2); off+=2; } + return(size); +} + +/* records that have a single uint16_t argument like PU_WMRSETMAPMODE + May also be used with int16_t with appropriate casts */ +int U_WMRCORE_1U16_get( + const char *contents, + int minsize, + uint16_t *arg1 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + if(!size)return(0); + memcpy(arg1, contents + off, 2); + return(size); +} + +/* records that have two uint16_t arguments like U_WMRSETBKMODE + May also be used with int16_t with appropriate casts */ +int U_WMRCORE_2U16_get( + const char *contents, + int minsize, + uint16_t *arg1, + uint16_t *arg2 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + memcpy(arg1, contents + off, 2); off+=2; + memcpy(arg2, contents + off, 2); + return(size); +} + +/* records that have four uint16_t arguments like U_WMRSCALEWINDOWEXT + May also be used with int16_t with appropriate casts */ +int U_WMRCORE_4U16_get( + const char *contents, + int minsize, + uint16_t *arg1, + uint16_t *arg2, + uint16_t *arg3, + uint16_t *arg4 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + if(!size)return(0); + memcpy(arg1, contents + off, 2); off+=2; + memcpy(arg2, contents + off, 2); off+=2; + memcpy(arg3, contents + off, 2); off+=2; + memcpy(arg4, contents + off, 2); + return(size); +} + +/* records that have five uint16_t arguments like U_WMRCREATEPENINDIRECT + May also be used with int16_t with appropriate casts */ +int U_WMRCORE_5U16_get( + const char *contents, + int minsize, + uint16_t *arg1, + uint16_t *arg2, + uint16_t *arg3, + uint16_t *arg4, + uint16_t *arg5 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + if(!size)return(0); + memcpy(arg1, contents + off, 2); off+=2; + memcpy(arg2, contents + off, 2); off+=2; + memcpy(arg3, contents + off, 2); off+=2; + memcpy(arg4, contents + off, 2); off+=2; + memcpy(arg5, contents + off, 2); + return(size); +} + +/* records that have six uint16_t arguments like U_ROUNDREC + May also be used with int16_t with appropriate casts */ +int U_WMRCORE_6U16_get( + const char *contents, + int minsize, + uint16_t *arg1, + uint16_t *arg2, + uint16_t *arg3, + uint16_t *arg4, + uint16_t *arg5, + uint16_t *arg6 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + if(!size)return(0); + memcpy(arg1, contents + off, 2); off+=2; + memcpy(arg2, contents + off, 2); off+=2; + memcpy(arg3, contents + off, 2); off+=2; + memcpy(arg4, contents + off, 2); off+=2; + memcpy(arg5, contents + off, 2); off+=2; + memcpy(arg6, contents + off, 2); + return(size); +} + +/* records that have eight uint16_t arguments like U_WMRARC + May also be used with int16_t with appropriate casts */ +int U_WMRCORE_8U16_get( + const char *contents, + int minsize, + uint16_t *arg1, + uint16_t *arg2, + uint16_t *arg3, + uint16_t *arg4, + uint16_t *arg5, + uint16_t *arg6, + uint16_t *arg7, + uint16_t *arg8 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + if(!size)return(0); + memcpy(arg1, contents + off, 2); off+=2; + memcpy(arg2, contents + off, 2); off+=2; + memcpy(arg3, contents + off, 2); off+=2; + memcpy(arg4, contents + off, 2); off+=2; + memcpy(arg5, contents + off, 2); off+=2; + memcpy(arg6, contents + off, 2); off+=2; + memcpy(arg7, contents + off, 2); off+=2; + memcpy(arg8, contents + off, 2); + return(size); +} + +/* records that have + arg1 an (optional) (u)int16 + arg2 an (optional( (u)int16 + array of data cells or just a bunch of data. Passed as a char because the structures in the WMF in memory may + not be aligned properly for those structures. Caller has to take them apart - carefully. + like U_WMRCREATEBRUSHINDIRECT with arg1=arg2=NULL +*/ +int U_WMRCORE_2U16_N16_get( + const char *contents, + int minsize, + uint16_t *arg1, + uint16_t *arg2, + const char **array + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + int off = U_SIZE_METARECORD; + if(!size)return(0); + if(arg1){ memcpy(arg1, contents + off, 2); off+=2; } + if(arg2){ memcpy(arg2, contents + off, 2); off+=2; } + *array = (contents + off); + return(size); +} + + + +/* records that get a U_PALETTE like U_WMRANIMATEPALETTE. Fills in the first two fields of U_PALETTE only, and returns + returns a separateepointer to the PalEntries[] array. This pointer is most likely not aligned with the data. + */ +int U_WMRCORE_PALETTE_get( + const char *contents, + int minsize, + PU_PALETTE Palette, + const char **PalEntries + ){ + int size = U_WMRCORE_RECSAFE_get(contents, minsize); + if(!size)return(0); + contents += offsetof(U_WMRANIMATEPALETTE, Palette); + memset(Palette, 0, (U_SIZE_PALETTE)); + memcpy(Palette, contents, (U_SIZE_PALETTE)); + *PalEntries = (contents + offsetof(U_PALETTE, PalEntries)); + return(size); +} + +//! @endcond + +/** + \brief Return parameters from a bitmapcoreheader. + All are returned as 32 bit integers, regardless of their internal representation. + + \param BmiCh char * pointer to a U_BITMAPCOREHEADER. Note, data may not be properly aligned. + \param Size_4 size of the coreheader in bytes + \param Width; Width of pixel array + \param Height; Height of pixel array + \param BitCount Pixel Format (BitCount Enumeration) +*/ +void U_BITMAPCOREHEADER_get( + const char *BmiCh, + int32_t *Size, + int32_t *Width, + int32_t *Height, + int32_t *BitCount + ){ + uint32_t utmp4; + uint16_t utmp2; + memcpy(&utmp4, BmiCh + offsetof(U_BITMAPCOREHEADER,Size_4), 4); *Size = utmp4; + memcpy(&utmp2, BmiCh + offsetof(U_BITMAPCOREHEADER,Width), 2); *Width = utmp2; + memcpy(&utmp2, BmiCh + offsetof(U_BITMAPCOREHEADER,Height), 2); *Height = utmp2; + memcpy(&utmp2, BmiCh + offsetof(U_BITMAPCOREHEADER,BitCount), 2); *BitCount = utmp2; +} + +/** + \brief Return parameters from a bitinfoheader. + All are returned as 32 bit integers, regardless of their internal representation. + + \param Bmih char * pointer to a U_BITMAPINFOHEADER. Note, data may not be properly aligned. + \param Size Structure size in bytes + \param Width Bitmap width in pixels + \param Height Bitmap height in pixels, may be negative. + \param Planes Planes (must be 1) + \param BitCount BitCount Enumeration (determines number of RBG colors) + \param Compression BI_Compression Enumeration + \param SizeImage Image size in bytes or 0 = "default size (calculated from geometry?)" + \param XPelsPerMeter X Resolution in pixels/meter + \param YPelsPerMeter Y Resolution in pixels/meter + \param ClrUsed Number of bmciColors in U_BITMAPINFO/U_BITMAPCOREINFO that are used by the bitmap + \param ClrImportant Number of bmciColors needed (0 means all). + + +*/ +void U_BITMAPINFOHEADER_get( + const char *Bmih, + uint32_t *Size, + int32_t *Width, + int32_t *Height, + uint32_t *Planes, + uint32_t *BitCount, + uint32_t *Compression, + uint32_t *SizeImage, + int32_t *XPelsPerMeter, + int32_t *YPelsPerMeter, + uint32_t *ClrUsed, + uint32_t *ClrImportant + ){ + int32_t tmp4; + uint32_t utmp4; + uint16_t utmp2; + + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSize ), 4); *Size = utmp4; + memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biWidth ), 4); *Width = tmp4; + memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biHeight ), 4); *Height = tmp4; + memcpy(&utmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biPlanes ), 2); *Planes = utmp2; + memcpy(&utmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biBitCount ), 2); *BitCount = utmp2; + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biCompression ), 4); *Compression = utmp4; + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSizeImage ), 4); *SizeImage = utmp4; + memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biXPelsPerMeter), 4); *XPelsPerMeter = tmp4; + memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biYPelsPerMeter), 4); *YPelsPerMeter = tmp4; + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrUsed ), 4); *ClrUsed = utmp4; + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrImportant ), 4); *ClrImportant = utmp4; +} + +/** + \brief Assume a packed DIB and get the parameters from it, use by DBI_to_RGBA() + + \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid. + \param dib pointer to the start of the DIB in the record + \param px pointer to DIB pixel array + \param ct pointer to DIB color table + \param numCt DIB color table number of entries, for PNG or JPG returns the number of bytes in the image + \param width Width of pixel array + \param height Height of pixel array (always returned as a positive number) + \param colortype DIB BitCount Enumeration + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int wget_DIB_params( + const char *dib, + const char **px, + const U_RGBQUAD **ct, + int32_t *numCt, + int32_t *width, + int32_t *height, + int32_t *colortype, + int32_t *invert + ){ + uint32_t bic; + int32_t Size; + bic = U_BI_RGB; // this information is not in the coreheader; + U_BITMAPCOREHEADER_get(dib, &Size, width, height, colortype); + if(Size != 0xC ){ //BitmapCoreHeader + /* if biCompression is not U_BI_RGB some or all of the following might not hold real values. + Ignore most of the information returned from the bitmapinfoheader. + */ + uint32_t uig4; + int32_t ig4; + U_BITMAPINFOHEADER_get(dib, &uig4, width, height,&uig4, (uint32_t *) colortype, &bic, &uig4, &ig4, &ig4,&uig4, &uig4); + } + if(*height < 0){ + *height = -*height; + *invert = 1; + } + else { + *invert = 0; + } + *px = dib + U_SIZE_BITMAPINFOHEADER; + if(bic == U_BI_RGB){ + *numCt = get_real_color_count(dib); + if(*numCt){ + *ct = (PU_RGBQUAD) (dib + U_SIZE_BITMAPINFOHEADER); + *px += U_SIZE_COLORREF * (*numCt); + } + else { *ct = NULL; } + } + else { + memcpy(numCt, dib + offsetof(U_BITMAPINFOHEADER,biSizeImage), 4); + *ct = NULL; + } + return(bic); +} + + + +/* ********************************************************************************************** +These are the core WMR functions, each extracts data from a particular type of record. +In general routines fill in structures which have been passed in by the caller, and zero them +if that (optional) structure is not present. +Because the WMF records may not be aligned they are generally copied into the supplied + aligned structs, so that the caller may retrieve fields with the usual sorts of + structure operations: Struct.field or (*Struct)->field. +A few routines return pointers to data regions in the record. +They are listed in order by the corresponding U_WMR_* index number. +*********************************************************************************************** */ + +/** + \brief Get data from a (placeable) WMR_HEADER. + \return size of the record in bytes, 0 on failure + \param contents record to extract data from + \param blimit one byte past the last WMF record in memory. + \param Placeable U_WMRPLACEABLE data, if any + \param Header U_WMRHEADER data, if any +*/ +int wmfheader_get( + const char *contents, + const char *blimit, + PU_WMRPLACEABLE Placeable, + PU_WMRHEADER Header + ){ + uint32_t Key; + int size=0; + if(!Placeable || !Header || contents + 4 >= blimit)return(0); + memcpy(&Key, contents + offsetof(U_WMRPLACEABLE,Key), 4); + if(Key == 0x9AC6CDD7){ + size += U_SIZE_WMRPLACEABLE; + if(contents + size >= blimit)return(0); + memcpy(Placeable, contents, U_SIZE_WMRPLACEABLE); + contents += U_SIZE_WMRPLACEABLE; + } + else { + memset(Placeable, 0, U_SIZE_WMRPLACEABLE); + } + if(contents + size + U_SIZE_WMRHEADER >= blimit)return(0); + size += 2* (*(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w))); + if(contents + size >= blimit)return(0); + memcpy(Header, contents, U_SIZE_WMRHEADER); + return(size); +} + + +/** + \brief Get data from a U_WMREOF record + \return size of record in bytes, or 0 on error + \param contents record to extract data from +*/ +int U_WMREOF_get( + const char *contents + ){ + return(U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMREOF))); +} + +/** + \brief Retrieve values from a U_WMRSETBKCOLOR record + \return length of the U_WMRSETBKCOLOR record, or NULL on error + \param contents record to extract data from + \param Color Background Color. +*/ +int U_WMRSETBKCOLOR_get( + const char *contents, + PU_COLORREF Color + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETBKCOLOR)); + if(!size)return(0); + memcpy(Color,contents + offsetof(U_WMRSETBKCOLOR,Color),U_SIZE_COLORREF); + return(size); +} + +/** + \brief Retrieve values from a U_WMRSETBKMODE record + \return length of the U_WMRSETBKMODE record, or NULL on error + \param contents record to extract data from + \param Mode MixMode Enumeration +*/ +int U_WMRSETBKMODE_get( + const char *contents, + uint16_t *Mode + ){ + return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETBKMODE), Mode)); +} + +/** + \brief Retrieve values from a U_WMRSETMAPMODE record + \return length of the U_WMRSETMAPMODE record, or NULL on error + \param contents record to extract data from + \param Mode MapMode Enumeration +*/ +int U_WMRSETMAPMODE_get( + const char *contents, + uint16_t *Mode + ){ + return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETMAPMODE), Mode)); +} + +/** + \brief Retrieve values from a U_WMRSETROP2 record + \return length of the U_WMRSETROP2 record, or NULL on error + \param contents record to extract data from + \param Mode Binary Raster Operation Enumeration +*/ +int U_WMRSETROP2_get( + const char *contents, + uint16_t *Mode + ){ + return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETROP2), Mode)); +} + +/** + \brief Get data from a U_WMRSETRELABS record + \return length of the U_WMRSETRELABS record in bytes, or 0 on error + \param contents record to extract data from +*/ +int U_WMRSETRELABS_get( + const char *contents + ){ + return(U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETRELABS))); +} + +/** + \brief Retrieve values from a U_WMRSETPOLYFILLMODE record + \return length of the U_WMRSETPOLYFILLMODE record, or NULL on error + \param contents record to extract data from + \param Mode PolyFillMode Enumeration +*/ +int U_WMRSETPOLYFILLMODE_get( + const char *contents, + uint16_t *Mode + ){ + return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETPOLYFILLMODE), Mode)); +} + +/** + \brief Retrieve values from a U_WMRSETSTRETCHBLTMODE record + \return length of the U_WMRSETSTRETCHBLTMODE record, or NULL on error + \param contents record to extract data from + \param Mode StretchMode Enumeration +*/ +int U_WMRSETSTRETCHBLTMODE_get( + const char *contents, + uint16_t *Mode + ){ + return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETSTRETCHBLTMODE), Mode)); +} + +/** + \brief Retrieve values from a U_WMRSETTEXTCHAREXTRA record + \return length of the U_WMRSETTEXTCHAREXTRA record, or NULL on error + \param contents record to extract data from + \param Mode Extra space in logical units to add to each character +*/ +int U_WMRSETTEXTCHAREXTRA_get( + const char *contents, + uint16_t *Mode + ){ + return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETTEXTCHAREXTRA), Mode)); +} + +/** + \brief Retrieve values from a U_WMRSETTEXTCOLOR record + \return length of the U_WMRSETTEXTCOLOR record, or NULL on error + \param contents record to extract data from + \param Color Text Color. +*/ +int U_WMRSETTEXTCOLOR_get( + const char *contents, + PU_COLORREF Color + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETTEXTCOLOR)); + if(!size)return(0); + memcpy(Color,contents + offsetof(U_WMRSETTEXTCOLOR,Color),U_SIZE_COLORREF); + return(size); +} + +/** + \brief Retrieve values from a U_WMRSETTEXTJUSTIFICATION record + \return length of the U_WMRSETTEXTJUSTIFICATION record, or NULL on error + \param contents record to extract data from + \param Count Number of space characters in the line. + \param Extra Number of extra space characters to add to the line. +*/ +int U_WMRSETTEXTJUSTIFICATION_get( + const char *contents, + uint16_t *Count, + uint16_t *Extra + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETTEXTJUSTIFICATION), Count, Extra)); +} + +/** + \brief Retrieve values from a U_WMRSETWINDOWORG record + \return length of the U_WMRSETWINDOWORG record, or NULL on error + \param contents record to extract data from + \param coord Window Origin. +*/ +int U_WMRSETWINDOWORG_get( + const char *contents, + PU_POINT16 coord + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETWINDOWORG), U_P16(coord->y), U_P16(coord->x))); +} + +/** + \brief Retrieve values from a U_WMRSETWINDOWEXT record + \return length of the U_WMRSETWINDOWEXT record, or NULL on error + \param contents record to extract data from + \param extent Window Extent. +*/ +int U_WMRSETWINDOWEXT_get( + const char *contents, + PU_POINT16 extent + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETWINDOWEXT), U_P16(extent->y), U_P16(extent->x))); +} + +/** + \brief Retrieve values from a U_WMRSETVIEWPORTORG record + \return length of the U_WMRSETVIEWPORTORG record, or NULL on error + \param contents record to extract data from + \param coord Viewport Origin. +*/ +int U_WMRSETVIEWPORTORG_get( + const char *contents, + PU_POINT16 coord + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETVIEWPORTORG), U_P16(coord->y), U_P16(coord->x))); + +} + +/** + \brief Retrieve values from a U_WMRSETVIEWPORTEXT record + \return length of the U_WMRSETVIEWPORTEXT record, or NULL on error + \param contents record to extract data from + \param extent Viewport Extent. +*/ +int U_WMRSETVIEWPORTEXT_get( + const char *contents, + PU_POINT16 extent + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETVIEWPORTEXT), U_P16(extent->y), U_P16(extent->x))); +} + +/** + \brief Retrieve values from a U_WMROFFSETWINDOWORG record + \return length of the U_WMROFFSETWINDOWORG record, or NULL on error + \param contents record to extract data from + \param offset Window offset in device units. +*/ +int U_WMROFFSETWINDOWORG_get( + const char *contents, + PU_POINT16 offset + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMROFFSETWINDOWORG), U_P16(offset->y), U_P16(offset->x))); +} + +/** + \brief Retrieve values from a U_WMRSCALEWINDOWEXT record + \return length of the U_WMRSCALEWINDOWEXT record, or NULL on error + \param contents record to extract data from + \param Denom {X,Y} denominators. + \param Num {X,Y} numerators. +*/ +int U_WMRSCALEWINDOWEXT_get( + const char *contents, + PU_POINT16 Denom, + PU_POINT16 Num + ){ + return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMRSCALEWINDOWEXT), U_P16(Denom->y), U_P16(Denom->x), U_P16(Num->y), U_P16(Num->x))); +} + +/** + \brief Retrieve values from a U_WMROFFSETVIEWPORTORG record + \return length of the U_WMROFFSETVIEWPORTORG record, or NULL on error + \param contents record to extract data from + \param offset Viewport offset in device units. +*/ +int U_WMROFFSETVIEWPORTORG_get( + const char *contents, + PU_POINT16 offset + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMROFFSETVIEWPORTORG), U_P16(offset->y), U_P16(offset->x))); +} + +/** + \brief Retrieve values from a U_WMRSCALEVIEWPORTEXT record + \return length of the U_WMRSCALEVIEWPORTEXT record, or NULL on error + \param contents record to extract data from + \param Denom {X,Y} denominators. + \param Num {X,Y} numerators. +*/ +int U_WMRSCALEVIEWPORTEXT_get( + const char *contents, + PU_POINT16 Denom, + PU_POINT16 Num + ){ + return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMRSCALEVIEWPORTEXT), U_P16(Denom->y), U_P16(Denom->x), U_P16(Num->y), U_P16(Num->x))); +} + +/** + \brief Retrieve values from a U_WMRLINETO record + \return length of the U_WMRLINETO record, or NULL on error + \param contents record to extract data from + \param coord Draw line to {X,Y}. +*/ +int U_WMRLINETO_get( + const char *contents, + PU_POINT16 coord + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRLINETO), U_P16(coord->y), U_P16(coord->x))); +} + +/** + \brief Retrieve values from a U_WMRMOVETO record + \return length of the U_WMRMOVETO record, or NULL on error + \param contents record to extract data from + \param coord Move to {X,Y}. +*/ +int U_WMRMOVETO_get( + const char *contents, + PU_POINT16 coord + ){ + return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRMOVETO), U_P16(coord->y), U_P16(coord->x))); +} + +/** + \brief Retrieve values from a U_WMREXCLUDECLIPRECT record + \return length of the U_WMREXCLUDECLIPRECT record, or NULL on error + \param contents record to extract data from + \param rect Exclude rect from clipping region. +*/ +int U_WMREXCLUDECLIPRECT_get( + const char *contents, + PU_RECT16 rect + ){ + return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMREXCLUDECLIPRECT), U_P16(rect->bottom), U_P16(rect->right), U_P16(rect->top), U_P16(rect->left))); +} + +/** + \brief Retrieve values from a U_WMRINTERSECTCLIPRECT record + \return length of the U_WMRINTERSECTCLIPRECT record, or NULL on error + \param contents record to extract data from + \param rect Clipping region is intersection of existing clipping region with rect. +*/ +int U_WMRINTERSECTCLIPRECT_get( + const char *contents, + PU_RECT16 rect + ){ + return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMRINTERSECTCLIPRECT), U_P16(rect->bottom), U_P16(rect->right), U_P16(rect->top), U_P16(rect->left))); +} + +/** + \brief Retrieve values from a U_WMRARC record + \return length of the U_WMRARC record, or NULL on error + \param contents record to extract data from + \param StartArc Start of Arc + \param EndArc End of Arc + \param rect Bounding rectangle. +*/ +int U_WMRARC_get( + const char *contents, + PU_POINT16 StartArc, + PU_POINT16 EndArc, + PU_RECT16 rect + ){ + return U_WMRCORE_8U16_get( + contents, + (U_SIZE_WMRARC), + U_P16(EndArc->y), + U_P16(EndArc->x), + U_P16(StartArc->y), + U_P16(StartArc->x), + U_P16(rect->bottom), + U_P16(rect->right), + U_P16(rect->top), + U_P16(rect->left) + ); +} + +/** + \brief Retrieve values from a U_WMRELLIPSE record + \return length of the U_WMRELLIPSE record, or NULL on error + \param contents record to extract data from + \param rect Bounding rectangle for Ellipse. +*/ +int U_WMRELLIPSE_get( + const char *contents, + PU_RECT16 rect + ){ + return U_WMRCORE_4U16_get( + contents, + (U_SIZE_WMRELLIPSE), + U_P16(rect->bottom), + U_P16(rect->right), + U_P16(rect->top), + U_P16(rect->left) + ); +} + +/** + \brief Retrieve values from a U_WMRFLOODFILL record + \return length of the U_WMRFLOODFILL record, or NULL on error + \param contents record to extract data from + \param Mode FloodFill Enumeration. + \param Color Color to Fill with. + \param coord Location to start fill. +*/ +int U_WMRFLOODFILL_get( + const char *contents, + uint16_t *Mode, + PU_COLORREF Color, + PU_POINT16 coord + ){ + return U_WMRCORE_1U16_CRF_2U16_get( + contents, + (U_SIZE_WMRFLOODFILL), + Mode, + Color, + U_P16(coord->y), + U_P16(coord->x) + ); +} + +/** + \brief Retrieve values from a U_WMRPIE record + \return length of the U_WMRPIE record, or NULL on error + \param contents record to extract data from + \param Radial1 Start of Pie + \param Radial2 End of Pie + \param rect Bounding rectangle. +*/ +int U_WMRPIE_get( + const char *contents, + PU_POINT16 Radial1, + PU_POINT16 Radial2, + PU_RECT16 rect + ){ + return U_WMRCORE_8U16_get( + contents, + (U_SIZE_WMRPIE), + U_P16(Radial2->y), + U_P16(Radial2->x), + U_P16(Radial1->y), + U_P16(Radial1->x), + U_P16(rect->bottom), + U_P16(rect->right), + U_P16(rect->top), + U_P16(rect->left) + ); +} + +/** + \brief Retrieve values from a U_WMRRECTANGLE record + \return length of the U_WMRRECTANGLE record, or NULL on error + \param contents record to extract data from + \param rect Boundaries. +*/ +int U_WMRRECTANGLE_get( + const char *contents, + PU_RECT16 rect + ){ + return U_WMRCORE_4U16_get( + contents, + (U_SIZE_WMRRECTANGLE), + U_P16(rect->bottom), + U_P16(rect->right), + U_P16(rect->top), + U_P16(rect->left) + ); +} + +/** + \brief Retrieve values from a U_WMRROUNDRECT record + \return length of the U_WMRROUNDRECT record, or NULL on error + \param contents record to extract data from + \param Width Horizontal rounding length. + \param Height Vertical rounding length. + \param rect Boundaries. +*/ +int U_WMRROUNDRECT_get( + const char *contents, + int16_t *Width, + int16_t *Height, + PU_RECT16 rect + ){ + return U_WMRCORE_6U16_get( + contents, + (U_SIZE_WMRROUNDRECT), + U_PP16(Height), + U_PP16(Width), + U_P16(rect->bottom), + U_P16(rect->right), + U_P16(rect->top), + U_P16(rect->left) + ); +} + +/** + \brief Get data from a U_WMRPATBLT record. + \return length of the U_WMRPATBLT record in bytes, or 0 on error + \param contents record to extract data from + \param Dst Destination UL corner in logical units + \param cwh W & H for Dst and Src in logical units + \param dwRop3 RasterOPeration Enumeration +*/ +int U_WMRPATBLT_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cwh, + uint32_t *dwRop3 + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRPATBLT)); + if(!size)return(0); + memcpy(dwRop3, ( contents + offsetof(U_WMRPATBLT, rop3w)), 4); + cwh->y = *(int16_t *)( contents + offsetof(U_WMRPATBLT, Height )); + cwh->x = *(int16_t *)( contents + offsetof(U_WMRPATBLT, Width )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRPATBLT, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRPATBLT, xDst )); + return(size); +} + +/** + \brief Get data from a U_WMRSAVEDC record + \return length of the U_WMRSAVEDC record in bytes, or 0 on error + \param contents record to extract data from +*/ +int U_WMRSAVEDC_get( + const char *contents + ){ + return(U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSAVEDC))); +} + +int U_WMRSETPIXEL_get( + const char *contents, + PU_COLORREF Color, + PU_POINT16 coord){ + return U_WMRCORE_1U16_CRF_2U16_get( + contents, + (U_SIZE_WMRSETPIXEL), + NULL, + Color, + U_P16(coord->y), + U_P16(coord->x) + ); +} + +int U_WMROFFSETCLIPRGN_get( + const char *contents, + PU_POINT16 offset + ){ + return U_WMRCORE_2U16_get(contents, (U_SIZE_WMROFFSETCLIPRGN), U_P16(offset->y), U_P16(offset->x)); +} + +/** + \brief Get data from a U_WMRTEXTOUT record + \return length of the U_WMRTEXTOUT record in bytes, or 0 on error + \param contents record to extract data from + \param Dst coordinates where text will be written + \param Length Number of characters in string. + \param string Pointer to string in WMF buffer in memory. This text is generally NOT null terminated!!! +*/ +int U_WMRTEXTOUT_get( + const char *contents, + PU_POINT16 Dst, + int16_t *Length, + const char **string + ){ + int16_t L2; + int off; + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRPATBLT)); + if(!size)return(0); + *Length = *(int16_t *)(contents + offsetof(U_WMRTEXTOUT, Length)); + *string = contents + offsetof(U_WMRTEXTOUT, String); /* May not be null terminated!!! */ + L2 = *Length; + if(L2 & 1)L2++; + off = U_SIZE_METARECORD + 2 + L2; + memcpy(&Dst->y, contents + off, 2); off+=2; + memcpy(&Dst->x, contents + off, 2); off+=2; + return(size); +} + +/** + \brief Get data from a U_WMRBITBLT record. + Note that unlike U_EMRBITBLT there is no scaling available - the Src and Dst + rectangles must be the same size. + \return length of the U_WMRBITBLT record in bytes, or 0 on error + \param contents record to extract data from + \param Dst Destination UL corner in logical units + \param cwh W & H for Dst and Src in logical units + \param Src Source UL corner in logical units + \param dwRop3 RasterOPeration Enumeration + \param Bm16 bitmap16 object (fields in it are all 0 if no bitmap is used) + \param px pointer to bitmap in memory, or NULL if not used +*/ +int U_WMRBITBLT_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cwh, + PU_POINT16 Src, + uint32_t *dwRop3, + PU_BITMAP16 Bm16, + const char **px + ){ + uint8_t xb; + uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRBITBLT_NOPX)); + if(!size)return(0); + xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb)); + if(U_TEST_NOPXB(size,xb)){ /* no bitmap */ + memcpy(dwRop3, ( contents + offsetof(U_WMRBITBLT_NOPX, rop3w)), 4); + Src->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, xSrc )); + cwh->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, Height )); + cwh->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, Width )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, xDst )); + memset(Bm16, 0, U_SIZE_BITMAP16); + *px = NULL; + } + else { /* yes bitmap */ + memcpy(dwRop3, ( contents + offsetof(U_WMRBITBLT_PX, rop3w)), 4); + Src->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, xSrc )); + cwh->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, Height )); + cwh->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, Width )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, xDst )); + memcpy(Bm16, ( contents + offsetof(U_WMRBITBLT_PX, bitmap)), U_SIZE_BITMAP16); + *px = ( contents + offsetof(U_WMRBITBLT_PX, bitmap) + U_SIZE_BITMAP16); + } + return(size); +} + +/** + \brief Get data from a U_WMRSTRETCHBLT record. + \return length of the U_WMRSTRETCHBLT record in bytes, or 0 on error + \param contents record to extract data from + \param Dst Destination UL corner in logical units + \param cDst Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param dwRop3 RasterOPeration Enumeration + \param Bm16 bitmap16 object (fields in it are all 0 if no bitmap is used) + \param px pointer to bitmap in memory, or NULL if not used +*/ +int U_WMRSTRETCHBLT_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cDst, + PU_POINT16 Src, + PU_POINT16 cSrc, + uint32_t *dwRop3, + PU_BITMAP16 Bm16, + const char **px + ){ + uint8_t xb; + uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSTRETCHBLT_NOPX)); + if(!size)return(0); + xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb)); + if(U_TEST_NOPXB(size,xb)){ /* no bitmap */ + memcpy(dwRop3, ( contents + offsetof(U_WMRSTRETCHBLT_NOPX, rop3w)), 4); + cSrc->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, hSrc )); + cSrc->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, wSrc )); + Src->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, xSrc )); + cDst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, hDst )); + cDst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, wDst )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, xDst )); + memset(Bm16, 0, U_SIZE_BITMAP16); + *px = NULL; + } + else { /* yes bitmap */ + memcpy(dwRop3, ( contents + offsetof(U_WMRSTRETCHBLT_PX, rop3w)), 4); + cSrc->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, hSrc )); + cSrc->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, wSrc )); + Src->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, xSrc )); + cDst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, hDst )); + cDst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, wDst )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, xDst )); + memcpy(Bm16, ( contents + offsetof(U_WMRSTRETCHBLT_PX, bitmap)), U_SIZE_BITMAP16); + *px = ( contents + offsetof(U_WMRSTRETCHBLT_PX, bitmap) + U_SIZE_BITMAP16); + } + return(size); +} + +/** + \brief Get data from a U_WMRPOLYGON record. + \return length of the U_WMRPOLYGON record in bytes, or 0 on error + \param contents record to extract data from + \param Length Number of points in the Polygon + \param Data pointer to array of U_POINT16 in memory. Pointer may not be aligned properly for structures. +*/ +int U_WMRPOLYGON_get( + const char *contents, + uint16_t *Length, + const char **Data + ){ + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data); +} + +/** + \brief Get data from a U_WMRPOLYLINE record. + \return length of the U_WMRPOLYLINE record in bytes, or 0 on error + \param contents record to extract data from + \param Length Number of points in the Polyline + \param Data pointer to array of U_POINT16 in memory. Pointer may not be aligned properly for structures. +*/ +int U_WMRPOLYLINE_get( + const char *contents, + uint16_t *Length, + const char **Data + ){ + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYLINE), NULL, Length, Data); +} + +/** + \brief Get data from a U_WMRESCAPE record. + WARNING! Only three Escape record types are fully supported: SETLINECAP, SETLINEJOIN, SETMITERLIMIT. + Even these should not be set here directly, instead use the wsetlinecap_get(), wsetlinejoin_get(), + or wsetmiterlimit_get() functions. + Escape records created with this function, with the exception of the three named above, will not have + the byte orders in Data adjusted automatically. The user code must set Data to be little endian no + matter what the endianness of the current platform where the user code is running. + \return length of the U_WMRESCAPE record in bytes, or 0 on error + \param contents record to extract data from + \param Escape Escape function + \param Length Bytes in the Data + \param Data Array of Length bytes +*/ +int U_WMRESCAPE_get( + const char *contents, + uint16_t *Escape, + uint16_t *Length, + const char **Data + ){ + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data); +} + +/** + \brief Get data from a U_WMRRESTOREDC record + \return length of the U_WMRRESTOREDC record in bytes, or 0 on error + \param contents record to extract data from + \param DC DC to restore (relative if negative, absolute if positive) +*/ +int U_WMRRESTOREDC_get( + const char *contents, + int16_t *DC + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRRESTOREDC), (uint16_t *)DC); // signed, but it is just a memcpy, so this works +} + +/** + \brief Get data from a U_WMRFILLREGION record. + \return length of the U_WMRFILLREGION record in bytes, or 0 on error + \param contents record to extract data from + \param Region Region to fill + \param Brush Brush to fill with +*/ +int U_WMRFILLREGION_get( + const char *contents, + uint16_t *Region, + uint16_t *Brush + ){ + return U_WMRCORE_2U16_get(contents, (U_SIZE_WMRFILLREGION), Region, Brush); +} + +/** + \brief Get data from a U_WMRFRAMEREGION record. + \return length of the U_WMRFRAMEREGION record in bytes, or 0 on error + \param contents record to extract data from + \param Region Index of region to frame in object table + \param Brush Index of brush to use in frame in object table + \param Height in logical units (of frame) + \param Width in logical units (of frame) +*/ +int U_WMRFRAMEREGION_get( + const char *contents, + uint16_t *Region, + uint16_t *Brush, + int16_t *Height, + int16_t *Width + ){ + return U_WMRCORE_4U16_get(contents, (U_SIZE_WMRFRAMEREGION), Region, Brush, U_PP16(Height), U_PP16(Width)); +} + +/** + \brief Get data from a U_WMRINVERTREGION record. + \return length of the U_WMRINVERTREGION record in bytes, or 0 on error + \param contents record to extract data from + \param Region Index of region to invert. +*/ +int U_WMRINVERTREGION_get( + const char *contents, + uint16_t *Region + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRINVERTREGION), Region); +} + +/** + \brief Get data from a U_WMRPAINTREGION record. + \return length of the U_WMRPAINTREGION record in bytes, or 0 on error + \param contents record to extract data from + \param Region Index of region to paint with the current Brush. +*/ +int U_WMRPAINTREGION_get( + const char *contents, + uint16_t *Region + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRPAINTREGION), Region); +} + +/** + \brief Get data from a U_WMRSELECTCLIPREGION record. + \return length of the U_WMRSELECTCLIPREGION record in bytes, or 0 on error + \param contents record to extract data from + \param Region Index of region to become clipping region.. +*/ +int U_WMRSELECTCLIPREGION_get( + const char *contents, + uint16_t *Region + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSELECTCLIPREGION), Region); + +} + +/** + \brief Get data from a U_WMRSELECTOBJECT record. + \return length of the U_WMRSELECTOBJECT record in bytes, or 0 on error + \param contents record to extract data from + \param Object Index of object which is made active. +*/ +int U_WMRSELECTOBJECT_get( + const char *contents, + uint16_t *Object + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSELECTOBJECT), Object); +} + +/** + \brief Get data from a U_WMRSETTEXTALIGN record. + \return length of the U_WMRSETTEXTALIGN record in bytes, or 0 on error + \param contents record to extract data from + \param Mode TextAlignment Enumeration. +*/ +int U_WMRSETTEXTALIGN_get( + const char *contents, + uint16_t *Mode + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETTEXTALIGN), Mode); +} + +/* in Wine, not in WMF PDF. */ +int U_WMRDRAWTEXT_get(void){ /* in Wine, not in WMF PDF. */ + return U_WMRCORENONE_get("U_WMRDRAWTEXT"); +} + +/** + \brief Retrieve values from a U_WMRCHORD record + \return length of the U_WMRCHORD record, or NULL on error + \param contents record to extract data from + \param Radial1 Start of Chord + \param Radial2 End of Chord + \param rect Bounding rectangle. +*/ +int U_WMRCHORD_get( + const char *contents, + PU_POINT16 Radial1, + PU_POINT16 Radial2, + PU_RECT16 rect + ){ + return U_WMRCORE_8U16_get( + contents, + (U_SIZE_WMRCHORD), + U_P16(Radial2->y), + U_P16(Radial2->x), + U_P16(Radial1->y), + U_P16(Radial1->x), + U_P16(rect->bottom), + U_P16(rect->right), + U_P16(rect->top), + U_P16(rect->left) + ); +} + +/** + \brief Get data from a U_WMRSETMAPPERFLAGS record. + \return length of the U_WMRSETMAPPERFLAGS record in bytes, or 0 on error + \param contents record to extract data from + \param Mode If 1 bit set font mapper selects only matching aspect fonts. +*/ +int U_WMRSETMAPPERFLAGS_get( + const char *contents, + uint32_t *Mode + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETMAPPERFLAGS)); + if(!size)return(0); + memcpy(Mode, contents + U_SIZE_METARECORD, 4); + return(size); +} + +/** + \brief Get data from a U_WMREXTTEXTOUT record. + \return length of the U_WMREXTTEXTOUT record in bytes, or 0 on error + \param contents record to extract data from + \param Dst {X,Y} coordinates where the string is to be written. + \param Length Stringlength in bytes + \param Opts ExtTextOutOptions Flags + \param string String to write (Latin1 encoding) + \param dx Kerning information. Must have same number of entries as Length. + \param rect Used when when U_ETO_OPAQUE or U_ETO_CLIPPED bits are set in Opts +*/ +int U_WMREXTTEXTOUT_get( + const char *contents, + PU_POINT16 Dst, + int16_t *Length, + uint16_t *Opts, + const char **string, + const int16_t **dx, + PU_RECT16 rect + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMREXTTEXTOUT)); + int off = U_SIZE_METARECORD; + if(!size)return(0); + Dst->y = *(int16_t *)( contents + offsetof(U_WMREXTTEXTOUT, y )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMREXTTEXTOUT, x )); + *Length = *(int16_t *)( contents + offsetof(U_WMREXTTEXTOUT, Length )); + *Opts = *(uint16_t *)(contents + offsetof(U_WMREXTTEXTOUT, Opts )); + off = U_SIZE_WMREXTTEXTOUT; + if(*Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){ memcpy(rect, (contents + off), U_SIZE_RECT16); off += U_SIZE_RECT16; } + else { memset(rect, 0, U_SIZE_RECT16); } + *string = (contents + off); + off += 2*((*Length +1)/2); + if(*Length){ *dx = (int16_t *)(contents + off); } + else { *dx = NULL; } + return(size); +} + +/** + \brief Get data from a U_WMRSETDIBTODEV record + \return length of the U_WMRSETDIBTODEV record in bytes, or 0 on error + \param contents record to extract data from + \param Dst UL corner of Dst rect in logical units + \param cwh Width and Height in logical units + \param Src UL corner of Src rect in logical units + \param cUsage ColorUsage enumeration + \param ScanCount Number of scan lines in Src + \param StartScan First Scan line in Src + \param dib DeviceIndependentBitmap object +*/ +int U_WMRSETDIBTODEV_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cwh, + PU_POINT16 Src, + uint16_t *cUsage, + uint16_t *ScanCount, + uint16_t *StartScan, + const char **dib + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETDIBTODEV)); + if(!size)return(0); + *cUsage = *(uint16_t *)(contents + offsetof(U_WMRSETDIBTODEV, cUsage )); + *ScanCount = *(uint16_t *)(contents + offsetof(U_WMRSETDIBTODEV, ScanCount )); + *StartScan = *(uint16_t *)(contents + offsetof(U_WMRSETDIBTODEV, StartScan )); + Src->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, xSrc )); + cwh->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, Height )); + cwh->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, Width )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, xDst )); + *dib = ( contents + offsetof(U_WMRSETDIBTODEV, dib )); + return(size); +} + +/** + \brief Get data from a U_WMRSELECTPALETTE record + \return length of the U_WMRSELECTPALETTE record in bytes, or 0 on error + \param contents record to extract data from + \param Palette Index of Palette to make active. +*/ +int U_WMRSELECTPALETTE_get( + const char *contents, + uint16_t *Palette + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSELECTPALETTE), Palette); +} + +/** + \brief Get data from a U_WMRREALIZEPALETTE record + \return length of the U_WMRREALIZEPALETTE record in bytes, or 0 on error + \param contents record to extract data from +*/ +int U_WMRREALIZEPALETTE_get( + const char *contents + ){ + return U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRREALIZEPALETTE)); +} + +/** + \brief Get data from a U_WMRSETPALENTRIES record + \return length of the U_WMRSETPALENTRIES record in bytes, or 0 on error + \param contents record to extract data from + \param Palette Redefines a set of RGB values for the current active Palette. + \param PalEntries Array of Palette Entries +*/ +int U_WMRANIMATEPALETTE_get( + const char *contents, + PU_PALETTE Palette, + const char **PalEntries + ){ + return U_WMRCORE_PALETTE_get(contents, (U_SIZE_WMRANIMATEPALETTE), Palette, PalEntries); +} + +/** + \brief Get data from a U_WMRSETPALENTRIES record + \return length of the U_WMRSETPALENTRIES record in bytes, or 0 on error + \param contents record to extract data from + \param Palette Defines a set of RGB values for the current active Palette. + \param PalEntries Array of Palette Entries +*/ +int U_WMRSETPALENTRIES_get( + const char *contents, + PU_PALETTE Palette, + const char **PalEntries + ){ + return U_WMRCORE_PALETTE_get(contents, (U_SIZE_WMRSETPALENTRIES), Palette, PalEntries); +} + +/** + \brief Get data from a U_WMR_POLYPOLYGON record. + \return length of the U_WMR_POLYPOLYGON record in bytes, or 0 on error + \param contents record to extract data from + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param Points pointer to array of U_POINT16 in memory. Probably not aligned. +*/ +int U_WMRPOLYPOLYGON_get( + const char *contents, + uint16_t *nPolys, + const uint16_t **aPolyCounts, + const char **Points + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRPOLYPOLYGON)); + if(!size)return(0); + contents += offsetof(U_WMRPOLYPOLYGON, PPolygon); + memcpy(nPolys, contents + offsetof(U_POLYPOLYGON, nPolys), 2); + *aPolyCounts = (uint16_t *)(contents + offsetof(U_POLYPOLYGON, aPolyCounts)); + *Points = (contents + offsetof(U_POLYPOLYGON, aPolyCounts) + *nPolys*2); + return(size); +} + +/** + \brief Get data from a U_WMRRESIZEPALETTE record + \return length of the U_WMRRESIZEPALETTE record in bytes, or 0 on error + \param contents record to extract data from + \param Palette Changes the size of the currently active Palette. +*/ +int U_WMRRESIZEPALETTE_get( + const char *contents, + uint16_t *Palette + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRRESIZEPALETTE), Palette); +} + +int U_WMR3A_get(void){ + return U_WMRCORENONE_get("U_WMR3A"); +} + +int U_WMR3B_get(void){ + return U_WMRCORENONE_get("U_WMR3B"); +} + +int U_WMR3C_get(void){ + return U_WMRCORENONE_get("U_WMR3C"); +} + +int U_WMR3D_get(void){ + return U_WMRCORENONE_get("U_WMR3D"); +} + +int U_WMR3E_get(void){ + return U_WMRCORENONE_get("U_WMR3E"); +} + +int U_WMR3F_get(void){ + return U_WMRCORENONE_get("U_WMR3F"); +} + +// U_WMRDIBBITBLT_get +/** + \brief Get data from a U_WMRDIBITBLT record. + \return length of the U_WMRDIBITBLT record in bytes, or 0 on error + \param contents record to extract data from + \param Dst Destination UL corner in logical units + \param Src Source UL corner in logical units + \param cwh W & H in logical units of Src and Dst + \param dwRop3 RasterOPeration Enumeration + \param dib pointer to dib in WMF in memory. Most likely not aligned. +*/ +int U_WMRDIBBITBLT_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cwh, + PU_POINT16 Src, + uint32_t *dwRop3, + const char **dib + ){ + uint8_t xb; + uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRDIBBITBLT_NOPX)); + if(!size)return(0); + xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb)); + if(U_TEST_NOPXB(size,xb)){ /* no bitmap */ + memcpy(dwRop3, ( contents + offsetof(U_WMRDIBBITBLT_NOPX, rop3w)), 4); + Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, xSrc )); + cwh->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, Height )); + cwh->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, Width )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, xDst )); + *dib = NULL; + } + else { /* yes bitmap */ + memcpy(dwRop3, ( contents + offsetof(U_WMRDIBBITBLT_PX, rop3w)), 4); + Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, xSrc )); + cwh->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, Height )); + cwh->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, Width )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, xDst )); + *dib = ( contents + offsetof(U_WMRDIBBITBLT_PX, dib )); + } + return(size); +} + +/** + \brief Get data from a U_WMRSTRETCHDIB record. + \return length of the U_WMRSTRETCHDIB record in bytes, or 0 on error + \param contents record to extract data from + \param Dst Destination UL corner in logical units + \param cDst Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param dwRop3 RasterOPeration Enumeration + \param dib pointer to dib in WMF in memory. Most likely not aligned. +*/ +int U_WMRDIBSTRETCHBLT_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cDst, + PU_POINT16 Src, + PU_POINT16 cSrc, + uint32_t *dwRop3, + const char **dib + ){ + uint8_t xb; + uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRDIBSTRETCHBLT_NOPX)); + if(!size)return(0); + xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb)); + if(U_TEST_NOPXB(size,xb)){ /* no bitmap */ + memcpy(dwRop3 , ( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, rop3w)), 4); + Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, xSrc )); + cSrc->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, hSrc )); + cSrc->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, wSrc )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, xDst )); + cDst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, hDst )); + cDst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, wDst )); + *dib = NULL; + } + else { /* yes bitmap */ + memcpy(dwRop3 , ( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, rop3w)), 4); + Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, xSrc )); + cSrc->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, hSrc )); + cSrc->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, wSrc )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, xDst )); + cDst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, hDst )); + cDst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, wDst )); + *dib = ( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, dib )); + } + return(size); +} + +/** + \brief Get data from a U_WMRDIBCREATEPATTERNBRUSH record. + Returns an image as either a DIB (Bmi/CbPx/Px defined) or a Bitmap16 (Bm16 defined). + \return length of the U_WMRDIBCREATEPATTERNBRUSH record in bytes, or 0 on error + \param contents record to extract data from + \param Style BrushStyle Enumeration + \param cUsage DIBcolors Enumeration + \param Bm16 pointer to a U_BITMAP16 in WMF in memory. Most likely not aligned. NULL if dib is used instead. + \param dib pointer to a dib in WMF in memory. Most likely not aligned. NULL if Bm16 is used instead. + */ +int U_WMRDIBCREATEPATTERNBRUSH_get( + const char *contents, + uint16_t *Style, + uint16_t *cUsage, + const char **Bm16, + const char **dib + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRDIBCREATEPATTERNBRUSH)); + if(!size)return(0); + + *Style = *(uint16_t *)(contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Style )); + *cUsage = *(uint16_t *)(contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, cUsage )); + if(*Style == U_BS_PATTERN){ + *Bm16 = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src)); + *dib = NULL; + /* The WMF spec says that Style == U_BS_PATTERN _SHOULD_ be a bitmap16. + However there are instances when it is actually a DIB. U_WMRDIBCREATEPATTERNBRUSH_get + tries to detect this by looking for bogus values when the BM16 is interpreted as such, + and if it finds them, then it returns a dib instead. + */ + U_BITMAP16 TmpBm16; + memcpy(&TmpBm16, *Bm16, U_SIZE_BITMAP16); + if(TmpBm16.Width <= 0 || TmpBm16.Height <= 0 || TmpBm16.Planes != 1 || TmpBm16.BitsPixel == 0){ + *Bm16 = NULL; + *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src)); + } + } + else { /* from DIB */ + *Bm16 = NULL; + *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src)); + } + return(size); +} + +/** + \brief Get data from a U_WMRSTRETCHDIB record. + \return length of the U_WMRSTRETCHDIB record in bytes, or 0 on error + \param contents record to extract data from + \param Dst Destination UL corner in logical units + \param cDst Destination W & H in logical units + \param Src Source UL corner in logical units + \param cSrc Source W & H in logical units + \param cUsage DIBColors Enumeration + \param dwRop3 RasterOPeration Enumeration + \param dib (Optional) device independent bitmap +*/ +int U_WMRSTRETCHDIB_get( + const char *contents, + PU_POINT16 Dst, + PU_POINT16 cDst, + PU_POINT16 Src, + PU_POINT16 cSrc, + uint16_t *cUsage, + uint32_t *dwRop3, + const char **dib + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSTRETCHDIB)); + if(!size)return(0); + + memcpy(dwRop3, ( contents + offsetof(U_WMRSTRETCHDIB, rop3w)), 4); + *cUsage = *(uint16_t *)( contents + offsetof(U_WMRSTRETCHDIB, cUsage )); + cSrc->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, hSrc )); + cSrc->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, wSrc )); + Src->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, ySrc )); + Src->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, xSrc )); + cDst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, hDst )); + cDst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, wDst )); + Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, yDst )); + Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, xDst )); + *dib = ( contents + offsetof(U_WMRSTRETCHDIB, dib )); + return(size); +} + +int U_WMR44_get(void){ + return U_WMRCORENONE_get("U_WMR44"); +} + +int U_WMR45_get(void){ + return U_WMRCORENONE_get("U_WMR45"); +} + +int U_WMR46_get(void){ + return U_WMRCORENONE_get("U_WMR46"); +} + +int U_WMR47_get(void){ + return U_WMRCORENONE_get("U_WMR47"); +} + +/** + \brief Retrieve values from a U_WMREXTFLOODFILL record + \return length of the U_WMREXTFLOODFILL record, or NULL on error + \param contents record to extract data from + \param Mode FloodFill Enumeration. + \param Color Color to Fill with. + \param coord Location to start fill. +*/ +int U_WMREXTFLOODFILL_get( + const char *contents, + uint16_t *Mode, + PU_COLORREF Color, + PU_POINT16 coord + ){ + return U_WMRCORE_1U16_CRF_2U16_get( + contents, + (U_SIZE_WMREXTFLOODFILL), + Mode, + Color, + U_P16(coord->y), + U_P16(coord->x) + ); +} + +int U_WMR49_get(void){ + return U_WMRCORENONE_get("U_WMR49"); +} + +int U_WMR4A_get(void){ + return U_WMRCORENONE_get("U_WMR4A"); +} + +int U_WMR4B_get(void){ + return U_WMRCORENONE_get("U_WMR4B"); +} + +int U_WMR4C_get(void){ + return U_WMRCORENONE_get("U_WMRRESETDOC"); +} + +int U_WMR4D_get(void){ + return U_WMRCORENONE_get("U_WMRSTARTDOC"); +} + +int U_WMR4E_get(void){ + return U_WMRCORENONE_get("U_WMR4E"); +} + +int U_WMR4F_get(void){ + return U_WMRCORENONE_get("U_WMRSTARTPAGE"); +} + +int U_WMR50_get(void){ + return U_WMRCORENONE_get("U_WMRENDPAGE"); +} + +int U_WMR51_get(void){ + return U_WMRCORENONE_get("U_WMR51"); +} + +int U_WMRABORTDOC_get(void){ + return U_WMRCORENONE_get("U_WMRABORTDOC"); +} + +int U_WMR53_get(void){ + return U_WMRCORENONE_get("U_WMR53"); +} + +int U_WMR54_get(void){ + return U_WMRCORENONE_get("U_WMR54"); +} + +int U_WMR55_get(void){ + return U_WMRCORENONE_get("U_WMR55"); +} + +int U_WMR56_get(void){ + return U_WMRCORENONE_get("U_WMR56"); +} + +int U_WMR57_get(void){ + return U_WMRCORENONE_get("U_WMR57"); +} + +int U_WMR58_get(void){ + return U_WMRCORENONE_get("U_WMR58"); +} + +int U_WMR59_get(void){ + return U_WMRCORENONE_get("U_WMR59"); +} + +int U_WMR5A_get(void){ + return U_WMRCORENONE_get("U_WMR5A"); +} + +int U_WMR5B_get(void){ + return U_WMRCORENONE_get("U_WMR5B"); +} + +int U_WMR5C_get(void){ + return U_WMRCORENONE_get("U_WMR5C"); +} + +int U_WMR5D_get(void){ + return U_WMRCORENONE_get("U_WMR5D"); +} + +int U_WMR5E_get(void){ + return U_WMRCORENONE_get("U_WMRENDDOC"); +} + +int U_WMR5F_get(void){ + return U_WMRCORENONE_get("U_WMR5F"); +} + +int U_WMR60_get(void){ + return U_WMRCORENONE_get("U_WMR60"); +} + +int U_WMR61_get(void){ + return U_WMRCORENONE_get("U_WMR61"); +} + +int U_WMR62_get(void){ + return U_WMRCORENONE_get("U_WMR62"); +} + +int U_WMR63_get(void){ + return U_WMRCORENONE_get("U_WMR63"); +} + +int U_WMR64_get(void){ + return U_WMRCORENONE_get("U_WMR64"); +} + +int U_WMR65_get(void){ + return U_WMRCORENONE_get("U_WMR65"); +} + +int U_WMR66_get(void){ + return U_WMRCORENONE_get("U_WMR66"); +} + +int U_WMR67_get(void){ + return U_WMRCORENONE_get("U_WMR67"); +} + +int U_WMR68_get(void){ + return U_WMRCORENONE_get("U_WMR68"); +} + +int U_WMR69_get(void){ + return U_WMRCORENONE_get("U_WMR69"); +} + +int U_WMR6A_get(void){ + return U_WMRCORENONE_get("U_WMR6A"); +} + +int U_WMR6B_get(void){ + return U_WMRCORENONE_get("U_WMR6B"); +} + +int U_WMR6C_get(void){ + return U_WMRCORENONE_get("U_WMR6C"); +} + +int U_WMR6D_get(void){ + return U_WMRCORENONE_get("U_WMR6D"); +} + +int U_WMR6E_get(void){ + return U_WMRCORENONE_get("U_WMR6E"); +} + +int U_WMR6F_get(void){ + return U_WMRCORENONE_get("U_WMR6F"); +} + +int U_WMR70_get(void){ + return U_WMRCORENONE_get("U_WMR70"); +} + +int U_WMR71_get(void){ + return U_WMRCORENONE_get("U_WMR71"); +} + +int U_WMR72_get(void){ + return U_WMRCORENONE_get("U_WMR72"); +} + +int U_WMR73_get(void){ + return U_WMRCORENONE_get("U_WMR73"); +} + +int U_WMR74_get(void){ + return U_WMRCORENONE_get("U_WMR74"); +} + +int U_WMR75_get(void){ + return U_WMRCORENONE_get("U_WMR75"); +} + +int U_WMR76_get(void){ + return U_WMRCORENONE_get("U_WMR76"); +} + +int U_WMR77_get(void){ + return U_WMRCORENONE_get("U_WMR77"); +} + +int U_WMR78_get(void){ + return U_WMRCORENONE_get("U_WMR78"); +} + +int U_WMR79_get(void){ + return U_WMRCORENONE_get("U_WMR79"); +} + +int U_WMR7A_get(void){ + return U_WMRCORENONE_get("U_WMR7A"); +} + +int U_WMR7B_get(void){ + return U_WMRCORENONE_get("U_WMR7B"); +} + +int U_WMR7C_get(void){ + return U_WMRCORENONE_get("U_WMR7C"); +} + +int U_WMR7D_get(void){ + return U_WMRCORENONE_get("U_WMR7D"); +} + +int U_WMR7E_get(void){ + return U_WMRCORENONE_get("U_WMR7E"); +} + +int U_WMR7F_get(void){ + return U_WMRCORENONE_get("U_WMR7F"); +} + +int U_WMR80_get(void){ + return U_WMRCORENONE_get("U_WMR80"); +} + +int U_WMR81_get(void){ + return U_WMRCORENONE_get("U_WMR81"); +} + +int U_WMR82_get(void){ + return U_WMRCORENONE_get("U_WMR82"); +} + +int U_WMR83_get(void){ + return U_WMRCORENONE_get("U_WMR83"); +} + +int U_WMR84_get(void){ + return U_WMRCORENONE_get("U_WMR84"); +} + +int U_WMR85_get(void){ + return U_WMRCORENONE_get("U_WMR85"); +} + +int U_WMR86_get(void){ + return U_WMRCORENONE_get("U_WMR86"); +} + +int U_WMR87_get(void){ + return U_WMRCORENONE_get("U_WMR87"); +} + +int U_WMR88_get(void){ + return U_WMRCORENONE_get("U_WMR88"); +} + +int U_WMR89_get(void){ + return U_WMRCORENONE_get("U_WMR89"); +} + +int U_WMR8A_get(void){ + return U_WMRCORENONE_get("U_WMR8A"); +} + +int U_WMR8B_get(void){ + return U_WMRCORENONE_get("U_WMR8B"); +} + +int U_WMR8C_get(void){ + return U_WMRCORENONE_get("U_WMR8C"); +} + +int U_WMR8D_get(void){ + return U_WMRCORENONE_get("U_WMR8D"); +} + +int U_WMR8E_get(void){ + return U_WMRCORENONE_get("U_WMR8E"); +} + +int U_WMR8F_get(void){ + return U_WMRCORENONE_get("U_WMR8F"); +} + +int U_WMR90_get(void){ + return U_WMRCORENONE_get("U_WMR90"); +} + +int U_WMR91_get(void){ + return U_WMRCORENONE_get("U_WMR91"); +} + +int U_WMR92_get(void){ + return U_WMRCORENONE_get("U_WMR92"); +} + +int U_WMR93_get(void){ + return U_WMRCORENONE_get("U_WMR93"); +} + +int U_WMR94_get(void){ + return U_WMRCORENONE_get("U_WMR94"); +} + +int U_WMR95_get(void){ + return U_WMRCORENONE_get("U_WMR95"); +} + +int U_WMR96_get(void){ + return U_WMRCORENONE_get("U_WMR96"); +} + +int U_WMR97_get(void){ + return U_WMRCORENONE_get("U_WMR97"); +} + +int U_WMR98_get(void){ + return U_WMRCORENONE_get("U_WMR98"); +} + +int U_WMR99_get(void){ + return U_WMRCORENONE_get("U_WMR99"); +} + +int U_WMR9A_get(void){ + return U_WMRCORENONE_get("U_WMR9A"); +} + +int U_WMR9B_get(void){ + return U_WMRCORENONE_get("U_WMR9B"); +} + +int U_WMR9C_get(void){ + return U_WMRCORENONE_get("U_WMR9C"); +} + +int U_WMR9D_get(void){ + return U_WMRCORENONE_get("U_WMR9D"); +} + +int U_WMR9E_get(void){ + return U_WMRCORENONE_get("U_WMR9E"); +} + +int U_WMR9F_get(void){ + return U_WMRCORENONE_get("U_WMR9F"); +} + +int U_WMRA0_get(void){ + return U_WMRCORENONE_get("U_WMRA0"); +} + +int U_WMRA1_get(void){ + return U_WMRCORENONE_get("U_WMRA1"); +} + +int U_WMRA2_get(void){ + return U_WMRCORENONE_get("U_WMRA2"); +} + +int U_WMRA3_get(void){ + return U_WMRCORENONE_get("U_WMRA3"); +} + +int U_WMRA4_get(void){ + return U_WMRCORENONE_get("U_WMRA4"); +} + +int U_WMRA5_get(void){ + return U_WMRCORENONE_get("U_WMRA5"); +} + +int U_WMRA6_get(void){ + return U_WMRCORENONE_get("U_WMRA6"); +} + +int U_WMRA7_get(void){ + return U_WMRCORENONE_get("U_WMRA7"); +} + +int U_WMRA8_get(void){ + return U_WMRCORENONE_get("U_WMRA8"); +} + +int U_WMRA9_get(void){ + return U_WMRCORENONE_get("U_WMRA9"); +} + +int U_WMRAA_get(void){ + return U_WMRCORENONE_get("U_WMRAA"); +} + +int U_WMRAB_get(void){ + return U_WMRCORENONE_get("U_WMRAB"); +} + +int U_WMRAC_get(void){ + return U_WMRCORENONE_get("U_WMRAC"); +} + +int U_WMRAD_get(void){ + return U_WMRCORENONE_get("U_WMRAD"); +} + +int U_WMRAE_get(void){ + return U_WMRCORENONE_get("U_WMRAE"); +} + +int U_WMRAF_get(void){ + return U_WMRCORENONE_get("U_WMRAF"); +} + +int U_WMRB0_get(void){ + return U_WMRCORENONE_get("U_WMRB0"); +} + +int U_WMRB1_get(void){ + return U_WMRCORENONE_get("U_WMRB1"); +} + +int U_WMRB2_get(void){ + return U_WMRCORENONE_get("U_WMRB2"); +} + +int U_WMRB3_get(void){ + return U_WMRCORENONE_get("U_WMRB3"); +} + +int U_WMRB4_get(void){ + return U_WMRCORENONE_get("U_WMRB4"); +} + +int U_WMRB5_get(void){ + return U_WMRCORENONE_get("U_WMRB5"); +} + +int U_WMRB6_get(void){ + return U_WMRCORENONE_get("U_WMRB6"); +} + +int U_WMRB7_get(void){ + return U_WMRCORENONE_get("U_WMRB7"); +} + +int U_WMRB8_get(void){ + return U_WMRCORENONE_get("U_WMRB8"); +} + +int U_WMRB9_get(void){ + return U_WMRCORENONE_get("U_WMRB9"); +} + +int U_WMRBA_get(void){ + return U_WMRCORENONE_get("U_WMRBA"); +} + +int U_WMRBB_get(void){ + return U_WMRCORENONE_get("U_WMRBB"); +} + +int U_WMRBC_get(void){ + return U_WMRCORENONE_get("U_WMRBC"); +} + +int U_WMRBD_get(void){ + return U_WMRCORENONE_get("U_WMRBD"); +} + +int U_WMRBE_get(void){ + return U_WMRCORENONE_get("U_WMRBE"); +} + +int U_WMRBF_get(void){ + return U_WMRCORENONE_get("U_WMRBF"); +} + +int U_WMRC0_get(void){ + return U_WMRCORENONE_get("U_WMRC0"); +} + +int U_WMRC1_get(void){ + return U_WMRCORENONE_get("U_WMRC1"); +} + +int U_WMRC2_get(void){ + return U_WMRCORENONE_get("U_WMRC2"); +} + +int U_WMRC3_get(void){ + return U_WMRCORENONE_get("U_WMRC3"); +} + +int U_WMRC4_get(void){ + return U_WMRCORENONE_get("U_WMRC4"); +} + +int U_WMRC5_get(void){ + return U_WMRCORENONE_get("U_WMRC5"); +} + +int U_WMRC6_get(void){ + return U_WMRCORENONE_get("U_WMRC6"); +} + +int U_WMRC7_get(void){ + return U_WMRCORENONE_get("U_WMRC7"); +} + +int U_WMRC8_get(void){ + return U_WMRCORENONE_get("U_WMRC8"); +} + +int U_WMRC9_get(void){ + return U_WMRCORENONE_get("U_WMRC9"); +} + +int U_WMRCA_get(void){ + return U_WMRCORENONE_get("U_WMRCA"); +} + +int U_WMRCB_get(void){ + return U_WMRCORENONE_get("U_WMRCB"); +} + +int U_WMRCC_get(void){ + return U_WMRCORENONE_get("U_WMRCC"); +} + +int U_WMRCD_get(void){ + return U_WMRCORENONE_get("U_WMRCD"); +} + +int U_WMRCE_get(void){ + return U_WMRCORENONE_get("U_WMRCE"); +} + +int U_WMRCF_get(void){ + return U_WMRCORENONE_get("U_WMRCF"); +} + +int U_WMRD0_get(void){ + return U_WMRCORENONE_get("U_WMRD0"); +} + +int U_WMRD1_get(void){ + return U_WMRCORENONE_get("U_WMRD1"); +} + +int U_WMRD2_get(void){ + return U_WMRCORENONE_get("U_WMRD2"); +} + +int U_WMRD3_get(void){ + return U_WMRCORENONE_get("U_WMRD3"); +} + +int U_WMRD4_get(void){ + return U_WMRCORENONE_get("U_WMRD4"); +} + +int U_WMRD5_get(void){ + return U_WMRCORENONE_get("U_WMRD5"); +} + +int U_WMRD6_get(void){ + return U_WMRCORENONE_get("U_WMRD6"); +} + +int U_WMRD7_get(void){ + return U_WMRCORENONE_get("U_WMRD7"); +} + +int U_WMRD8_get(void){ + return U_WMRCORENONE_get("U_WMRD8"); +} + +int U_WMRD9_get(void){ + return U_WMRCORENONE_get("U_WMRD9"); +} + +int U_WMRDA_get(void){ + return U_WMRCORENONE_get("U_WMRDA"); +} + +int U_WMRDB_get(void){ + return U_WMRCORENONE_get("U_WMRDB"); +} + +int U_WMRDC_get(void){ + return U_WMRCORENONE_get("U_WMRDC"); +} + +int U_WMRDD_get(void){ + return U_WMRCORENONE_get("U_WMRDD"); +} + +int U_WMRDE_get(void){ + return U_WMRCORENONE_get("U_WMRDE"); +} + +int U_WMRDF_get(void){ + return U_WMRCORENONE_get("U_WMRDF"); +} + +int U_WMRE0_get(void){ + return U_WMRCORENONE_get("U_WMRE0"); +} + +int U_WMRE1_get(void){ + return U_WMRCORENONE_get("U_WMRE1"); +} + +int U_WMRE2_get(void){ + return U_WMRCORENONE_get("U_WMRE2"); +} + +int U_WMRE3_get(void){ + return U_WMRCORENONE_get("U_WMRE3"); +} + +int U_WMRE4_get(void){ + return U_WMRCORENONE_get("U_WMRE4"); +} + +int U_WMRE5_get(void){ + return U_WMRCORENONE_get("U_WMRE5"); +} + +int U_WMRE6_get(void){ + return U_WMRCORENONE_get("U_WMRE6"); +} + +int U_WMRE7_get(void){ + return U_WMRCORENONE_get("U_WMRE7"); +} + +int U_WMRE8_get(void){ + return U_WMRCORENONE_get("U_WMRE8"); +} + +int U_WMRE9_get(void){ + return U_WMRCORENONE_get("U_WMRE9"); +} + +int U_WMREA_get(void){ + return U_WMRCORENONE_get("U_WMREA"); +} + +int U_WMREB_get(void){ + return U_WMRCORENONE_get("U_WMREB"); +} + +int U_WMREC_get(void){ + return U_WMRCORENONE_get("U_WMREC"); +} + +int U_WMRED_get(void){ + return U_WMRCORENONE_get("U_WMRED"); +} + +int U_WMREE_get(void){ + return U_WMRCORENONE_get("U_WMREE"); +} + +int U_WMREF_get(void){ + return U_WMRCORENONE_get("U_WMREF"); +} + +/** + \brief Get data from a U_WMRDELETEOBJECT record. + \return length of the U_WMRDELETEOBJECT record in bytes, or 0 on error + \param contents record to extract data from + \param Object Index of object which is made active. +*/ +int U_WMRDELETEOBJECT_get( + const char *contents, + uint16_t *Object + ){ + return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRDELETEOBJECT), Object); +} + +int U_WMRF1_get(void){ + return U_WMRCORENONE_get("U_WMRF1"); +} + +int U_WMRF2_get(void){ + return U_WMRCORENONE_get("U_WMRF2"); +} + +int U_WMRF3_get(void){ + return U_WMRCORENONE_get("U_WMRF3"); +} + +int U_WMRF4_get(void){ + return U_WMRCORENONE_get("U_WMRF4"); +} + +int U_WMRF5_get(void){ + return U_WMRCORENONE_get("U_WMRF5"); +} + +int U_WMRF6_get(void){ + return U_WMRCORENONE_get("U_WMRF6"); +} + +/** + \brief Retrieve values from a U_WMRCREATEPALETTE record + \return length of the U_WMRCREATEPALETTE record, or NULL on error + \param contents record to extract data from + \param Palette Create a Palette object. + \param PalEntries Array of Palette Entries +*/ +int U_WMRCREATEPALETTE_get( + const char *contents, + PU_PALETTE Palette, + const char **PalEntries + ){ + return U_WMRCORE_PALETTE_get(contents, (U_SIZE_WMRCREATEPALETTE), Palette, PalEntries); +} + +int U_WMRF8_get(void){ + return U_WMRCORENONE_get("U_WMRF8"); +} + +/** + \brief Get data from a U_WMRCREATEPATTERNBRUSH record. + Warning - application support for U_WMRCREATEPATTERNBRUSH is spotty, better to use U_WMRDIBCREATEPATTERNBRUSH. + \return length of the U_WMRCREATEPATTERNBRUSH record in bytes, or 0 on error + \param contents record to extract data from + \param Bm16 truncated Bitmap16 structure from record, only tge first 14 bytes hold data. + \param pasize Number of bytes in Pattern + \param Pattern byte array pattern, described by Bm16, for brush +*/ +int U_WMRCREATEPATTERNBRUSH_get( + const char *contents, + PU_BITMAP16 Bm16, + int *pasize, + const char **Pattern + ){ + int off = U_SIZE_METARECORD; + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETDIBTODEV)); + if(!size)return(0); + memset(Bm16, 0, U_SIZE_BITMAP16); + memcpy(Bm16, contents + off, 14); /* BM16 is truncated in this record type */ + *pasize = (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height; + off += 36; /* skip [truncated bitmap16 object and 18 bytes of reserved */ + *Pattern = (contents + off); + return(size); +} + +/** + \brief Get data from a U_WMRCREATEPENINDIRECT record. + \return length of the U_WMRCREATEPENINDIRECT record in bytes, or 0 on error + \param contents record to extract data from + \param pen pointer to a U_PEN object to fill. +*/ +int U_WMRCREATEPENINDIRECT_get( + const char *contents, + PU_PEN pen + ){ + int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRCREATEPENINDIRECT)); + if(!size)return(0); + memcpy(pen, contents + offsetof(U_WMRCREATEPENINDIRECT, pen), U_SIZE_PEN); + return(size); +} + +/** + \brief Get data from a U_WMRCREATEFONTINDIRECT record. + \return length of the U_WMRCREATEFONTINDIRECT record in bytes, or 0 on error + \param contents record to extract data from + \param font pointer to array of U_FONT structure in memory. Pointer may not be aligned properly for structure. +*/ +int U_WMRCREATEFONTINDIRECT_get( + const char *contents, + const char **font + ){ + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEFONTINDIRECT), NULL, NULL, font); +} + +/** + \brief Get data from a U_WMRCREATEBRUSHINDIRECT record. + \return length of the U_WMRCREATEBRUSHINDIRECT record in bytes, or 0 on error + \param contents record to extract data from + \param brush pointer to U_WLOGBRUSH structure in memory. Pointer may not be aligned properly for structure. +*/ +int U_WMRCREATEBRUSHINDIRECT_get( + const char *contents, + const char **brush + ){ + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEBRUSHINDIRECT), NULL, NULL, brush); +} + + /* in Wine, not in WMF PDF */ +int U_WMRCREATEBITMAPINDIRECT_get(void){ + return U_WMRCORENONE_get("U_WMRCREATEBITMAPINDIRECT"); +} + + /* in Wine, not in WMF PDF */ +int U_WMRCREATEBITMAP_get(void){ + return U_WMRCORENONE_get("U_WMRCREATEBITMAP"); +} + +/** + \brief Get data from a U_WMRCREATEREGION record. + \return length of the U_WMRCREATEREGION record in bytes, or 0 on error + \param contents record to extract data from + \param Region pointer to U_REGION structure in memory. Pointer may not be aligned properly for structure. +*/ +int U_WMRCREATEREGION_get( + const char *contents, + const char **Region + ){ + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEREGION), NULL, NULL, Region); +} + + + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uwmf.h b/src/extension/internal/uwmf.h new file mode 100644 index 000000000..a97648eb1 --- /dev/null +++ b/src/extension/internal/uwmf.h @@ -0,0 +1,2492 @@ +/** + @file uwmf.h Structures and functions prototypes for WMF files. + + WMF file Record structure information has been derived from Mingw and Wine header files, and from + Microsoft's WMF Information pdf, release date July 5,2012, link from here: + + http://msdn2.microsoft.com/en-us/library/250370.aspx + + If the direct link fails the document may be found + by searching for: "[MS-WMF]: Windows Metafile Format" + + *********************************** IMPORTANT!!! ********************************************** + WMF is a 16 bit file type that has some 32 bit integers embedded in it. In + a few cases these 32 bit fields are not aligned in the structures defined in uwmf.h, but + in most cases they are. So when creating the individual WMF records the functions in + uwmf.c can usually use a regular assignment operation for the 32 bit fields. However, once the + records are part of a WMF file in memory there is no guaranty that any 32 bit type will be correctly + aligned. Similarly, many WMF structures contain embedded other structures which would "naturally" + be passed by pointer, but since their alignment may not be what malloc() would have created for that + type, the outcome of that operation is not defined by the C standard. (Per Eric Sosman, section + 6.3.2.3p7 of the standard.) + + For this reason, the _print, _swap and any read operations must pass structures with unknown alignment + as a (char *), and pull out the data using memcpy() or some equivalent + that will not segfault when it tries to read a 32 bit value that is not aligned + on a 4 byte boundary. Failure to do so will result in nonportable code. You have been warned! + + Problem areas: + The Size16_4 field of all WMF records may NOT be assumed to 4 byte aligned. + DIB's U_BITMAPINFOHEADER 32 bit fields may not be aligned. + *********************************** IMPORTANT!!! ********************************************** + +*/ + +/* +File: uwmf.h +Version: 0.0.8 +Date: 27-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UWMF_ +#define _UWMF_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include "uemf.h" /* many structures/defs in common, pull in the EMF ones as a basis */ +#include "uemf_utf.h" +#include "uwmf_endian.h" + + + + + +// *********************************************************************************** +// Value enumerations and other predefined constants, alphabetical order by group + +/** RecordType Enumeration WMF PDF 2.1.1.1 + \defgroup U_WMR_RecordTypes WMR Record types + @{ +*/ +enum U_WMR_TYPES{ + U_WMR_EOF, //!< 0x0000 U_WMREOF record + U_WMR_SETBKCOLOR, //!< 0x0201 U_WMRSETBKCOLOR record + U_WMR_SETBKMODE, //!< 0x0102 U_WMRSETBKMODE record + U_WMR_SETMAPMODE, //!< 0x0103 U_WMRSETMAPMODE record + U_WMR_SETROP2, //!< 0x0104 U_WMRSETROP2 record + U_WMR_SETRELABS, //!< 0x0105 U_WMRSETRELABS record + U_WMR_SETPOLYFILLMODE, //!< 0x0106 U_WMRSETPOLYFILLMODE record + U_WMR_SETSTRETCHBLTMODE, //!< 0x0107 U_WMRSETSTRETCHBLTMODE record + U_WMR_SETTEXTCHAREXTRA, //!< 0x0108 U_WMRSETTEXTCHAREXTRA record + U_WMR_SETTEXTCOLOR, //!< 0x0209 U_WMRSETTEXTCOLOR record + U_WMR_SETTEXTJUSTIFICATION, //!< 0x020A U_WMRSETTEXTJUSTIFICATION record + U_WMR_SETWINDOWORG, //!< 0x020B U_WMRSETWINDOWORG record + U_WMR_SETWINDOWEXT, //!< 0x020C U_WMRSETWINDOWEXT record + U_WMR_SETVIEWPORTORG, //!< 0x020D U_WMRSETVIEWPORTORG record + U_WMR_SETVIEWPORTEXT, //!< 0x020E U_WMRSETVIEWPORTEXT record + U_WMR_OFFSETWINDOWORG, //!< 0x020F U_WMROFFSETWINDOWORG record + U_WMR_SCALEWINDOWEXT, //!< 0x0410 U_WMRSCALEWINDOWEXT record + U_WMR_OFFSETVIEWPORTORG, //!< 0x0211 U_WMROFFSETVIEWPORTORG record + U_WMR_SCALEVIEWPORTEXT, //!< 0x0412 U_WMRSCALEVIEWPORTEXT record + U_WMR_LINETO, //!< 0x0213 U_WMRLINETO record + U_WMR_MOVETO, //!< 0x0214 U_WMRMOVETO record + U_WMR_EXCLUDECLIPRECT, //!< 0x0415 U_WMREXCLUDECLIPRECT record + U_WMR_INTERSECTCLIPRECT, //!< 0x0416 U_WMRINTERSECTCLIPRECT record + U_WMR_ARC, //!< 0x0817 U_WMRARC record + U_WMR_ELLIPSE, //!< 0x0418 U_WMRELLIPSE record + U_WMR_FLOODFILL, //!< 0x0419 U_WMRFLOODFILL record + U_WMR_PIE, //!< 0x081A U_WMRPIE record + U_WMR_RECTANGLE, //!< 0x041B U_WMRRECTANGLE record + U_WMR_ROUNDRECT, //!< 0x061C U_WMRROUNDRECT record + U_WMR_PATBLT, //!< 0x061D U_WMRPATBLT record + U_WMR_SAVEDC, //!< 0x001E U_WMRSAVEDC record + U_WMR_SETPIXEL, //!< 0x041F U_WMRSETPIXEL record + U_WMR_OFFSETCLIPRGN, //!< 0x0220 U_WMROFFSETCLIPRGN record + U_WMR_TEXTOUT, //!< 0x0521 U_WMRTEXTOUT record + U_WMR_BITBLT, //!< 0x0922 U_WMRBITBLT record + U_WMR_STRETCHBLT, //!< 0x0B23 U_WMRSTRETCHBLT record + U_WMR_POLYGON, //!< 0x0324 U_WMRPOLYGON record + U_WMR_POLYLINE, //!< 0x0325 U_WMRPOLYLINE record + U_WMR_ESCAPE, //!< 0x0626 U_WMRESCAPE record + U_WMR_RESTOREDC, //!< 0x0127 U_WMRRESTOREDC record + U_WMR_FILLREGION, //!< 0x0228 U_WMRFILLREGION record + U_WMR_FRAMEREGION, //!< 0x0429 U_WMRFRAMEREGION record + U_WMR_INVERTREGION, //!< 0x012A U_WMRINVERTREGION record + U_WMR_PAINTREGION, //!< 0x012B U_WMRPAINTREGION record + U_WMR_SELECTCLIPREGION, //!< 0x012C U_WMRSELECTCLIPREGION record + U_WMR_SELECTOBJECT, //!< 0x012D U_WMRSELECTOBJECT record + U_WMR_SETTEXTALIGN, //!< 0x012E U_WMRSETTEXTALIGN record + U_WMR_DRAWTEXT, //!< 0x062F U_WMRDRAWTEXT record + U_WMR_CHORD, //!< 0x0830 U_WMRCHORD record + U_WMR_SETMAPPERFLAGS, //!< 0x0231 U_WMRSETMAPPERFLAGS record + U_WMR_EXTTEXTOUT, //!< 0x0A32 U_WMREXTTEXTOUT record + U_WMR_SETDIBTODEV, //!< 0x0D33 U_WMRSETDIBTODEV record + U_WMR_SELECTPALETTE, //!< 0x0234 U_WMRSELECTPALETTE record + U_WMR_REALIZEPALETTE, //!< 0x0035 U_WMRREALIZEPALETTE record + U_WMR_ANIMATEPALETTE, //!< 0x0436 U_WMRANIMATEPALETTE record + U_WMR_SETPALENTRIES, //!< 0x0037 U_WMRSETPALENTRIES record + U_WMR_POLYPOLYGON, //!< 0x0538 U_WMRPOLYPOLYGON record + U_WMR_RESIZEPALETTE, //!< 0x0139 U_WMRRESIZEPALETTE record + U_WMR_3A, //!< 0x003A U_WMR3A record + U_WMR_3B, //!< 0x003B U_WMR3B record + U_WMR_3C, //!< 0x003C U_WMR3C record + U_WMR_3D, //!< 0x003D U_WMR3D record + U_WMR_3E, //!< 0x003E U_WMR3E record + U_WMR_3F, //!< 0x003F U_WMR3F record + U_WMR_DIBBITBLT, //!< 0x0940 U_WMRDIBBITBLT record + U_WMR_DIBSTRETCHBLT, //!< 0x0B41 U_WMRDIBSTRETCHBLT record + U_WMR_DIBCREATEPATTERNBRUSH, //!< 0x0142 U_WMRDIBCREATEPATTERNBRUSH record + U_WMR_STRETCHDIB, //!< 0x0F43 U_WMRSTRETCHDIB record + U_WMR_44, //!< 0x0044 U_WMR44 record + U_WMR_45, //!< 0x0045 U_WMR45 record + U_WMR_46, //!< 0x0046 U_WMR46 record + U_WMR_47, //!< 0x0047 U_WMR47 record + U_WMR_EXTFLOODFILL, //!< 0x0548 U_WMREXTFLOODFILL record + U_WMR_49, //!< 0x0049 U_WMR49 record + U_WMR_4A, //!< 0x004A U_WMR4A record + U_WMR_4B, //!< 0x004B U_WMR4B record + U_WMR_4C, //!< 0x014C U_WMR4C record + U_WMR_4D, //!< 0x014D U_WMR4D record + U_WMR_4E, //!< 0x004E U_WMR4E record + U_WMR_4F, //!< 0x004F U_WMR4F record + U_WMR_50, //!< 0x0050 U_WMR50 record + U_WMR_51, //!< 0x0051 U_WMR51 record + U_WMR_52, //!< 0x0052 U_WMR52 record + U_WMR_53, //!< 0x0053 U_WMR53 record + U_WMR_54, //!< 0x0054 U_WMR54 record + U_WMR_55, //!< 0x0055 U_WMR55 record + U_WMR_56, //!< 0x0056 U_WMR56 record + U_WMR_57, //!< 0x0057 U_WMR57 record + U_WMR_58, //!< 0x0058 U_WMR58 record + U_WMR_59, //!< 0x0059 U_WMR59 record + U_WMR_5A, //!< 0x005A U_WMR5A record + U_WMR_5B, //!< 0x005B U_WMR5B record + U_WMR_5C, //!< 0x005C U_WMR5C record + U_WMR_5D, //!< 0x005D U_WMR5D record + U_WMR_5E, //!< 0x005E U_WMR5E record + U_WMR_5F, //!< 0x005F U_WMR5F record + U_WMR_60, //!< 0x0060 U_WMR60 record + U_WMR_61, //!< 0x0061 U_WMR61 record + U_WMR_62, //!< 0x0062 U_WMR62 record + U_WMR_63, //!< 0x0063 U_WMR63 record + U_WMR_64, //!< 0x0064 U_WMR64 record + U_WMR_65, //!< 0x0065 U_WMR65 record + U_WMR_66, //!< 0x0066 U_WMR66 record + U_WMR_67, //!< 0x0067 U_WMR67 record + U_WMR_68, //!< 0x0068 U_WMR68 record + U_WMR_69, //!< 0x0069 U_WMR69 record + U_WMR_6A, //!< 0x006A U_WMR6A record + U_WMR_6B, //!< 0x006B U_WMR6B record + U_WMR_6C, //!< 0x006C U_WMR6C record + U_WMR_6D, //!< 0x006D U_WMR6D record + U_WMR_6E, //!< 0x006E U_WMR6E record + U_WMR_6F, //!< 0x006F U_WMR6F record + U_WMR_70, //!< 0x0070 U_WMR70 record + U_WMR_71, //!< 0x0071 U_WMR71 record + U_WMR_72, //!< 0x0072 U_WMR72 record + U_WMR_73, //!< 0x0073 U_WMR73 record + U_WMR_74, //!< 0x0074 U_WMR74 record + U_WMR_75, //!< 0x0075 U_WMR75 record + U_WMR_76, //!< 0x0076 U_WMR76 record + U_WMR_77, //!< 0x0077 U_WMR77 record + U_WMR_78, //!< 0x0078 U_WMR78 record + U_WMR_79, //!< 0x0079 U_WMR79 record + U_WMR_7A, //!< 0x007A U_WMR7A record + U_WMR_7B, //!< 0x007B U_WMR7B record + U_WMR_7C, //!< 0x007C U_WMR7C record + U_WMR_7D, //!< 0x007D U_WMR7D record + U_WMR_7E, //!< 0x007E U_WMR7E record + U_WMR_7F, //!< 0x007F U_WMR7F record + U_WMR_80, //!< 0x0080 U_WMR80 record + U_WMR_81, //!< 0x0081 U_WMR81 record + U_WMR_82, //!< 0x0082 U_WMR82 record + U_WMR_83, //!< 0x0083 U_WMR83 record + U_WMR_84, //!< 0x0084 U_WMR84 record + U_WMR_85, //!< 0x0085 U_WMR85 record + U_WMR_86, //!< 0x0086 U_WMR86 record + U_WMR_87, //!< 0x0087 U_WMR87 record + U_WMR_88, //!< 0x0088 U_WMR88 record + U_WMR_89, //!< 0x0089 U_WMR89 record + U_WMR_8A, //!< 0x008A U_WMR8A record + U_WMR_8B, //!< 0x008B U_WMR8B record + U_WMR_8C, //!< 0x008C U_WMR8C record + U_WMR_8D, //!< 0x008D U_WMR8D record + U_WMR_8E, //!< 0x008E U_WMR8E record + U_WMR_8F, //!< 0x008F U_WMR8F record + U_WMR_90, //!< 0x0090 U_WMR90 record + U_WMR_91, //!< 0x0091 U_WMR91 record + U_WMR_92, //!< 0x0092 U_WMR92 record + U_WMR_93, //!< 0x0093 U_WMR93 record + U_WMR_94, //!< 0x0094 U_WMR94 record + U_WMR_95, //!< 0x0095 U_WMR95 record + U_WMR_96, //!< 0x0096 U_WMR96 record + U_WMR_97, //!< 0x0097 U_WMR97 record + U_WMR_98, //!< 0x0098 U_WMR98 record + U_WMR_99, //!< 0x0099 U_WMR99 record + U_WMR_9A, //!< 0x009A U_WMR9A record + U_WMR_9B, //!< 0x009B U_WMR9B record + U_WMR_9C, //!< 0x009C U_WMR9C record + U_WMR_9D, //!< 0x009D U_WMR9D record + U_WMR_9E, //!< 0x009E U_WMR9E record + U_WMR_9F, //!< 0x009F U_WMR9F record + U_WMR_A0, //!< 0x00A0 U_WMRA0 record + U_WMR_A1, //!< 0x00A1 U_WMRA1 record + U_WMR_A2, //!< 0x00A2 U_WMRA2 record + U_WMR_A3, //!< 0x00A3 U_WMRA3 record + U_WMR_A4, //!< 0x00A4 U_WMRA4 record + U_WMR_A5, //!< 0x00A5 U_WMRA5 record + U_WMR_A6, //!< 0x00A6 U_WMRA6 record + U_WMR_A7, //!< 0x00A7 U_WMRA7 record + U_WMR_A8, //!< 0x00A8 U_WMRA8 record + U_WMR_A9, //!< 0x00A9 U_WMRA9 record + U_WMR_AA, //!< 0x00AA U_WMRAA record + U_WMR_AB, //!< 0x00AB U_WMRAB record + U_WMR_AC, //!< 0x00AC U_WMRAC record + U_WMR_AD, //!< 0x00AD U_WMRAD record + U_WMR_AE, //!< 0x00AE U_WMRAE record + U_WMR_AF, //!< 0x00AF U_WMRAF record + U_WMR_B0, //!< 0x00B0 U_WMRB0 record + U_WMR_B1, //!< 0x00B1 U_WMRB1 record + U_WMR_B2, //!< 0x00B2 U_WMRB2 record + U_WMR_B3, //!< 0x00B3 U_WMRB3 record + U_WMR_B4, //!< 0x00B4 U_WMRB4 record + U_WMR_B5, //!< 0x00B5 U_WMRB5 record + U_WMR_B6, //!< 0x00B6 U_WMRB6 record + U_WMR_B7, //!< 0x00B7 U_WMRB7 record + U_WMR_B8, //!< 0x00B8 U_WMRB8 record + U_WMR_B9, //!< 0x00B9 U_WMRB9 record + U_WMR_BA, //!< 0x00BA U_WMRBA record + U_WMR_BB, //!< 0x00BB U_WMRBB record + U_WMR_BC, //!< 0x00BC U_WMRBC record + U_WMR_BD, //!< 0x00BD U_WMRBD record + U_WMR_BE, //!< 0x00BE U_WMRBE record + U_WMR_BF, //!< 0x00BF U_WMRBF record + U_WMR_C0, //!< 0x00C0 U_WMRC0 record + U_WMR_C1, //!< 0x00C1 U_WMRC1 record + U_WMR_C2, //!< 0x00C2 U_WMRC2 record + U_WMR_C3, //!< 0x00C3 U_WMRC3 record + U_WMR_C4, //!< 0x00C4 U_WMRC4 record + U_WMR_C5, //!< 0x00C5 U_WMRC5 record + U_WMR_C6, //!< 0x00C6 U_WMRC6 record + U_WMR_C7, //!< 0x00C7 U_WMRC7 record + U_WMR_C8, //!< 0x00C8 U_WMRC8 record + U_WMR_C9, //!< 0x00C9 U_WMRC9 record + U_WMR_CA, //!< 0x00CA U_WMRCA record + U_WMR_CB, //!< 0x00CB U_WMRCB record + U_WMR_CC, //!< 0x00CC U_WMRCC record + U_WMR_CD, //!< 0x00CD U_WMRCD record + U_WMR_CE, //!< 0x00CE U_WMRCE record + U_WMR_CF, //!< 0x00CF U_WMRCF record + U_WMR_D0, //!< 0x00D0 U_WMRD0 record + U_WMR_D1, //!< 0x00D1 U_WMRD1 record + U_WMR_D2, //!< 0x00D2 U_WMRD2 record + U_WMR_D3, //!< 0x00D3 U_WMRD3 record + U_WMR_D4, //!< 0x00D4 U_WMRD4 record + U_WMR_D5, //!< 0x00D5 U_WMRD5 record + U_WMR_D6, //!< 0x00D6 U_WMRD6 record + U_WMR_D7, //!< 0x00D7 U_WMRD7 record + U_WMR_D8, //!< 0x00D8 U_WMRD8 record + U_WMR_D9, //!< 0x00D9 U_WMRD9 record + U_WMR_DA, //!< 0x00DA U_WMRDA record + U_WMR_DB, //!< 0x00DB U_WMRDB record + U_WMR_DC, //!< 0x00DC U_WMRDC record + U_WMR_DD, //!< 0x00DD U_WMRDD record + U_WMR_DE, //!< 0x00DE U_WMRDE record + U_WMR_DF, //!< 0x00DF U_WMRDF record + U_WMR_E0, //!< 0x00E0 U_WMRE0 record + U_WMR_E1, //!< 0x00E1 U_WMRE1 record + U_WMR_E2, //!< 0x00E2 U_WMRE2 record + U_WMR_E3, //!< 0x00E3 U_WMRE3 record + U_WMR_E4, //!< 0x00E4 U_WMRE4 record + U_WMR_E5, //!< 0x00E5 U_WMRE5 record + U_WMR_E6, //!< 0x00E6 U_WMRE6 record + U_WMR_E7, //!< 0x00E7 U_WMRE7 record + U_WMR_E8, //!< 0x00E8 U_WMRE8 record + U_WMR_E9, //!< 0x00E9 U_WMRE9 record + U_WMR_EA, //!< 0x00EA U_WMREA record + U_WMR_EB, //!< 0x00EB U_WMREB record + U_WMR_EC, //!< 0x00EC U_WMREC record + U_WMR_ED, //!< 0x00ED U_WMRED record + U_WMR_EE, //!< 0x00EE U_WMREE record + U_WMR_EF, //!< 0x00EF U_WMREF record + U_WMR_DELETEOBJECT, //!< 0x01F0 U_WMRDELETEOBJECT record + U_WMR_F1, //!< 0x00F1 U_WMRF1 record + U_WMR_F2, //!< 0x00F2 U_WMRF2 record + U_WMR_F3, //!< 0x00F3 U_WMRF3 record + U_WMR_F4, //!< 0x00F4 U_WMRF4 record + U_WMR_F5, //!< 0x00F5 U_WMRF5 record + U_WMR_F6, //!< 0x00F6 U_WMRF6 record + U_WMR_CREATEPALETTE, //!< 0x00F7 U_WMRCREATEPALETTE record + U_WMR_F8 , //!< 0x00F8 U_WMRF8 record + U_WMR_CREATEPATTERNBRUSH, //!< 0x01F9 U_WMRCREATEPATTERNBRUSH record + U_WMR_CREATEPENINDIRECT, //!< 0x02FA U_WMRCREATEPENINDIRECT record + U_WMR_CREATEFONTINDIRECT, //!< 0x02FB U_WMRCREATEFONTINDIRECT record + U_WMR_CREATEBRUSHINDIRECT, //!< 0x02FC U_WMRCREATEBRUSHINDIRECT record + U_WMR_CREATEBITMAPINDIRECT, //!< 0x02FD U_WMRCREATEBITMAPINDIRECT record + U_WMR_CREATEBITMAP, //!< 0x06FE U_WMRCREATEBITMAP record + U_WMR_CREATEREGION, //!< 0x06FF U_WMRCREATEREGION record +}; +/** @} */ +#define U_WMR_MIN 0 //!< Minimum U_WMR_ value. +#define U_WMR_MAX 255 //!< Maximum U_WMR_ value. +#define U_WMR_MASK 0xFF //!< Mask for enumerator (lower) byte +#define U_WMR_INVALID 0xFFFFFFFF //!< Not any valid U_EMF_ valuee + + +/** BinaryRasterOperation Enumeration WMF PDF 2.1.1.2 + + Same as U_EMRSETROP2 in uemf.h +*/ + +/** BitCount Enumeration WMF PDF 2.1.1.3 + \defgroup AltBitCount_Qualifiers Alternate names for the values under U_BITMAPINFOHEADER_biBitCount_Qualifiers in uemf.h + @{ +*/ +#define BI_BITCOUNT_0 U_BCBM_EXPLICIT //!< Derived from JPG or PNG compressed image or ? +#define BI_BITCOUNT_1 U_BCBM_MONOCHROME //!< 2 colors. bmiColors array has two entries +#define BI_BITCOUNT_2 U_BCBM_COLOR4 //!< 2^4 colors. bmiColors array has 16 entries +#define BI_BITCOUNT_3 U_BCBM_COLOR8 //!< 2^8 colors. bmiColors array has 256 entries +#define BI_BITCOUNT_4 U_BCBM_COLOR16 //!< 2^16 colors. bmiColors is not used. Pixels are 5 bits B,G,R with 1 unused bit +#define BI_BITCOUNT_5 U_BCBM_COLOR24 //!< 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. +#define BI_BITCOUNT_6 U_BCBM_COLOR32 //!< 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. +/** @} */ + +/** BrushStyle Enumeration WMF PDF 2.1.1.4 + Same as "LB_Style Enumeration" in uemf.h +*/ + +/** CharacterSet Enumeration WMF PDF 2.1.1.5 + Same as "LF_CharSet Enumeration" in uemf.h +*/ + +/** ColorUsage Enumeration WMF PDF 2.1.1.6 + Same as "DIBColors Enumeration" in uemf.h, with one addition + \defgroup Extra_iUsageSrc_Qualifiers Extra DIBColors Enumeration + For cUsage fields in various DIB related records. + @{ +*/ +#define U_DIB_PAL_INDICES 2 //!< No color table, pixels are logical palette indices. +/** @} */ + +/** Compression Enumeration WMF PDF 2.1.1.7 + Same as "BI_Compression Enumeration" in uemf.h with these additions + \defgroup ExtraU_BITMAPINFOHEADER_biCompression_Qualifiers Extra BI_Compression Enumeration, none are implemented + @{ +*/ +#define U_BI_CMYK 0x000B //!< CMYK uncompressed +#define U_BI_CMYKRLE8 0x000C //!< CMYK RLE8 compression +#define U_BI_CMYKRLE4 = 0x000D //!< CMYK RLE4 compression +/** @} */ + +/** FamilyFont enumeration WMF PDF 2.1.1.8 + Only used in a PitchAndFamily object, defined there +*/ + +/** Floodfill enumeration WMF PDF 2.1.1.9 + Same as "FloodFill Enumeration" in uemf.h +*/ + +/** FontQuality enumeration WMF PDF 2.1.1.10 + Same as "LF_Quality Enumeration" in uemf.h +*/ + +/** GamutMappingIntent enumeration WMF PDF 2.1.1.11 + Same as "LCS_Intent Enumeration" in uemf.h +*/ + +/** HatchStyle enumeration WMF PDF 2.1.1.12 + Same as "HatchStyle Enumeration" in uemf.h +*/ + +/** Layout enumeration WMF PDF 2.1.1.13 + Same as "Mirroring Enumeration" in uemf.h +*/ + +/** LogicalColorSpace Enumeration WMF PDF 2.1.1.14 + Not used presently, applies in BitmapV4Header + @{ +*/ +//!< #define U_LCS_CALIBRATED_RGB 0x00000000 calibrated RGB +#define U_LCS_sRGB 0x73524742 //!< ASCII for "sRGB" +#define U_LCS_WINDOWS_COLOR_SPACE 0x57696E20 //!< ASCII for "Win " +/** @} */ + +/** LogicalColorSpaceV5 Enumeration WMF PDF 2.1.1.15 + Same as "Profile Enumeration" in uemf.h +*/ + +/** MapMode Enumeration WMF PDF 2.1.1.16 + Same as "MapMode Enumeration" in uemf.h +*/ + +/** MetaFilesEscape Enumeration WMF PDF 2.1.1.17 + \defgroup MFEscape_Qualifiers Metafile Escape record types + For U_WMRESCAPE eFunc field + @{ +*/ +#define U_MFE_NEWFRAME 0x0001 //!< NEWFRAME escape type +#define U_MFE_ABORTDOC 0x0002 //!< ABORTDOC escape type +#define U_MFE_NEXTBAND 0x0003 //!< NEXTBAND escape type +#define U_MFE_SETCOLORTABLE 0x0004 //!< SETCOLORTABLE escape type +#define U_MFE_GETCOLORTABLE 0x0005 //!< GETCOLORTABLE escape type +#define U_MFE_FLUSHOUT 0x0006 //!< FLUSHOUT escape type +#define U_MFE_DRAFTMODE 0x0007 //!< DRAFTMODE escape type +#define U_MFE_QUERYESCSUPPORT 0x0008 //!< QUERYESCSUPPORT escape type +#define U_MFE_SETABORTPROC 0x0009 //!< SETABORTPROC escape type +#define U_MFE_STARTDOC 0x000A //!< STARTDOC escape type +#define U_MFE_ENDDOC 0x000B //!< ENDDOC escape type +#define U_MFE_GETPHYSPAGESIZE 0x000C //!< GETPHYSPAGESIZE escape type +#define U_MFE_GETPRINTINGOFFSET 0x000D //!< GETPRINTINGOFFSET escape type +#define U_MFE_GETSCALINGFACTOR 0x000E //!< GETSCALINGFACTOR escape type +#define U_MFE_META_ESCAPE_ENHANCED_METAFILE 0x000F //!< META_ESCAPE_ENHANCED_METAFILE escape type +#define U_MFE_SETPENWIDTH 0x0010 //!< SETPENWIDTH escape type +#define U_MFE_SETCOPYCOUNT 0x0011 //!< SETCOPYCOUNT escape type +#define U_MFE_SETPAPERSOURCE 0x0012 //!< SETPAPERSOURCE escape type +#define U_MFE_PASSTHROUGH 0x0013 //!< PASSTHROUGH escape type +#define U_MFE_GETTECHNOLOGY 0x0014 //!< GETTECHNOLOGY escape type +#define U_MFE_SETLINECAP 0x0015 //!< SETLINECAP escape type +#define U_MFE_SETLINEJOIN 0x0016 //!< SETLINEJOIN escape type +#define U_MFE_SETMITERLIMIT 0x0017 //!< SETMITERLIMIT escape type +#define U_MFE_BANDINFO 0x0018 //!< BANDINFO escape type +#define U_MFE_DRAWPATTERNRECT 0x0019 //!< DRAWPATTERNRECT escape type +#define U_MFE_GETVECTORPENSIZE 0x001A //!< GETVECTORPENSIZE escape type +#define U_MFE_GETVECTORBRUSHSIZE 0x001B //!< GETVECTORBRUSHSIZE escape type +#define U_MFE_ENABLEDUPLEX 0x001C //!< ENABLEDUPLEX escape type +#define U_MFE_GETSETPAPERBINS 0x001D //!< GETSETPAPERBINS escape type +#define U_MFE_GETSETPRINTORIENT 0x001E //!< GETSETPRINTORIENT escape type +#define U_MFE_ENUMPAPERBINS 0x001F //!< ENUMPAPERBINS escape type +#define U_MFE_SETDIBSCALING 0x0020 //!< SETDIBSCALING escape type +#define U_MFE_EPSPRINTING 0x0021 //!< EPSPRINTING escape type +#define U_MFE_ENUMPAPERMETRICS 0x0022 //!< ENUMPAPERMETRICS escape type +#define U_MFE_GETSETPAPERMETRICS 0x0023 //!< GETSETPAPERMETRICS escape type +#define U_MFE_POSTSCRIPT_DATA 0x0025 //!< POSTSCRIPT_DATA escape type +#define U_MFE_POSTSCRIPT_IGNORE 0x0026 //!< POSTSCRIPT_IGNORE escape type +#define U_MFE_GETDEVICEUNITS 0x002A //!< GETDEVICEUNITS escape type +#define U_MFE_GETEXTENDEDTEXTMETRICS 0x0100 //!< GETEXTENDEDTEXTMETRICS escape type +#define U_MFE_GETPAIRKERNTABLE 0x0102 //!< GETPAIRKERNTABLE escape type +#define U_MFE_EXTTEXTOUT 0x0200 //!< EXTTEXTOUT escape type +#define U_MFE_GETFACENAME 0x0201 //!< GETFACENAME escape type +#define U_MFE_DOWNLOADFACE 0x0202 //!< DOWNLOADFACE escape type +#define U_MFE_METAFILE_DRIVER 0x0801 //!< METAFILE_DRIVER escape type +#define U_MFE_QUERYDIBSUPPORT 0x0C01 //!< QUERYDIBSUPPORT escape type +#define U_MFE_BEGIN_PATH 0x1000 //!< BEGIN_PATH escape type +#define U_MFE_CLIP_TO_PATH 0x1001 //!< CLIP_TO_PATH escape type +#define U_MFE_END_PATH 0x1002 //!< END_PATH escape type +#define U_MFE_OPEN_CHANNEL 0x100E //!< OPEN_CHANNEL escape type +#define U_MFE_DOWNLOADHEADER 0x100F //!< DOWNLOADHEADER escape type +#define U_MFE_CLOSE_CHANNEL 0x1010 //!< CLOSE_CHANNEL escape type +#define U_MFE_POSTSCRIPT_PASSTHROUGH 0x1013 //!< POSTSCRIPT_PASSTHROUGH escape type +#define U_MFE_ENCAPSULATED_POSTSCRIPT 0x1014 //!< ENCAPSULATED_POSTSCRIPT escape type +#define U_MFE_POSTSCRIPT_IDENTIFY 0x1015 //!< POSTSCRIPT_IDENTIFY escape type +#define U_MFE_POSTSCRIPT_INJECTION 0x1016 //!< POSTSCRIPT_INJECTION escape type +#define U_MFE_CHECKJPEGFORMAT 0x1017 //!< CHECKJPEGFORMAT escape type +#define U_MFE_CHECKPNGFORMAT 0x1018 //!< CHECKPNGFORMAT escape type +#define U_MFE_GET_PS_FEATURESETTING 0x1019 //!< GET_PS_FEATURESETTING escape type +#define U_MFE_MXDC_ESCAPE 0x101A //!< MXDC_ESCAPE escape type +#define U_MFE_SPCLPASSTHROUGH2 0x11D8 //!< SPCLPASSTHROUGH2 escape type +/** @} */ + +/** MetafileType Enumeration WMF PDF 2.1.1.18 + @{ +*/ +#define U_MEMORYMETAFILE 0x0001 //!< memory metafile (never used by libUWMF) +#define U_DISKMETAFILE 0x0002 //!< disk metafile (always used by libUWMF) +/** @} */ + +/** MetafileVersion Enumeration WMF PDF 2.1.1.19 + @{ +*/ + +#define U_METAVERSION100 0x0100 //!< DIBs not allowed +#define U_METAVERSION300 0x0300 //!< DIBs allowed +/** @} */ + +/** MixMode Enumeration WMF PDF 2.1.1.20 + Same as "BackgroundMode Enumeration" in uemf.h +*/ + +/** OutPrecision Enumeration WMF PDF 2.1.1.21 + Same as "LF_OutPrecision Enumeration" in uemf.h +*/ + +/** PaletteEntryFlag Enumeration WMF PDF 2.1.1.22 + @{ +*/ +#define U_PC_RESERVED 0x01 //!< used for animation +#define U_PC_EXPLICIT 0x02 //!< low order word is palette index +#define U_PC_NOCOLLAPSE 0x04 //!< store as new color in palette, do not match to existing color +/** @} */ + +/** PenStyle Enumeration WMF PDF 2.1.1.23 + Same as "PenStyle Enumeration" in uemf.h + EXCEPT no values >0xFFFF are used, in particular there is no U_PS_GEOMETRIC (ie, all are U_PS_COSMETIC). + Apparently because there is no U_PS_GEOMETRIC, U_PS_JOIN* and U_PS_ENDCAP* are also ignored by XP SP3 Preview + (which defaults to a rounded cap) and PowerPoint 2003 (which defaults to square cap). The behavior + was the same when escape records for JOIN and ENDCAP are used. Bottom line, WMF line formatting seems + to be very hit and miss from application to application. +*/ + +/** PitchFont Enumeration WMF PDF 2.1.1.24 + These are only used in PitchAndFamily object, defined there. +*/ + +/** PolyFillMode Enumeration WMF PDF 2.1.1.25 + These are the first twp emtries in "PolygonFillMode Enumeration" in uemf.h + +*/ + +/** PostScriptCap Enumeration WMF PDF 2.1.1.26 + These are used in Escape Cap + @{ +*/ +#define U_WPS_CAP_NOTSET -2 +#define U_WPS_CAP_FLAT 0 +#define U_WPS_CAP_ROUND 1 +#define U_WPS_CAP_SQUARE 2 +/** @} */ + +/** PostScriptClipping Enumeration WMF PDF 2.1.1.27 + PostFeatureSetting Enumeration WMF PDF 2.1.1.28 + + These are used by postscript drivers, not supported by libUWEMF. +*/ + +/** PostScrioptJoin Enumeration WMF PDF 2.1.1.29 + These are used in Escape Cap + @{ +*/ +#define U_WPS_JOIN_NOTSET -2 +#define U_WPS_JOIN_MITER 0 +#define U_WPS_JOIN_ROUND 1 +#define U_WPS_JOIN_BEVEL 2 +/** @} */ + +/** StretchMode Enumeration WMF PDF 2.1.1.30 + Same as "StretchMode Enumeration" in uemf.h + +*/ + +/** TernaryRasterOperation Enumeration WMF PDF 2.1.1.31 + Same as "Ternary Raster Operation Enumeration" in uemf.h + Only partially supported in libUWMF.h +*/ + +/** ClipPrecision Flags WMF PDF 2.1.2.1 + Same as "LF_ClipPrecision Enumeration" in uemf.h +*/ + +/** ExtTextOutOptions Flags WMF PDF 2.1.2.2 + These are a subset of "ExtTextOutOptions Enumeration" in uemf.h + Not defined for WMF: U_ETO_NONE, U_ETO_GRAYED, U_ETO_NORECT, + U_ETO_SMALL_CHARS,U_ETO_IGNORELANGUAGE,U_ETO_REVERSE_INDEX_MAP + Defined for WMF: U_ETO_OPAQUE, U_ETO_CLIPPED, U_ETO_GLYPH_INDEX, + U_ETO_RTLREADING,_ETO_NUMERICSLOCAL,U_ETO_NUMERICSLATIN, + U_ETO_PDY +*/ + +/** TextAlignment Enumeration WMF PDF 2.1.2.3 + VertialTextAlignment Enumeration WMF PDF 2.1.2.4 + These are both in "TextAlignment Enumeration" in uemf.h +*/ + + + +// *************************************************************************** +// Miscellaneous Values +/** TextAlignmentMode Flags WMF PDF 2.1.2.3 + VerticalTextAlignmentMode Flags WMF PDF 2.1.2.4 + Same as "TextAlignment Enumeration" in uemf.h +*/ + +/** \defgroup MinimumRecord_sizes Size in bytes of core record of each type. + These are USUALLY not the same + as the corresponding struct, so in general it is unsafe to use sizeof() with this code. + Always use the U_SIZE_x instead!!!! + Note that some records may actually be much, much longer than their minimum as they include strings, + bitmaps, and such. + @{ +*/ +/* Record sizeof (+ same, X differs) */ +#define U_SIZE_PAIRF 8 /* + 8 this might be different on 64 bit platform */ +#define U_SIZE_COLORREF 4 /* + 4 */ +#define U_SIZE_BRUSH 8 /* + 8 */ +#define U_SIZE_FONT 19 /* + 20 */ +#define U_SIZE_FONT_CORE 18 /* Minus the FaceName part */ +#define U_SIZE_PLTNTRY 4 /* + 4 */ +#define U_SIZE_PALETTE 8 /* + 8 */ +#define U_SIZE_PEN 10 /* + 10 */ +#define U_SIZE_POINT16 4 /* + 4 */ +#define U_SIZE_RECT16 8 /* + 8 */ +#define U_SIZE_REGION 20 /* X 22 20 is minums the variable part */ +#define U_SIZE_BITMAP16 10 /* + 10 */ +#define U_SIZE_BITMAPCOREHEADER 12 /* + 12 */ +#define U_SIZE_BITMAPINFOHEADER 40 /* + 40 */ +#define U_SIZE_BITMAPV4HEADER 108 /* ? 108 not tested */ +#define U_SIZE_BITMAPV5HEADER 124 /* ? 124 not tested */ +#define U_SIZE_WLOGBRUSH 8 /* + 8 */ +#define U_SIZE_POLYPOLYGON 4 /* + 4 */ +#define U_SIZE_SCAN 8 /* + 8 */ +#define U_SIZE_METARECORD 6 /* X 8 */ +#define U_SIZE_WMRPLACEABLE 22 /* X 24 */ +#define U_SIZE_WMRHEADER 18 /* X 20 */ +#define U_SIZE_WMREOF 6 /* X 8 */ +#define U_SIZE_WMRSETRELABS 6 /* X 8 */ +#define U_SIZE_WMRSAVEDC 6 /* X 8 */ +#define U_SIZE_WMRRESTOREDC 8 /* * 8 */ +#define U_SIZE_WMRREALIZEPALETTE 6 /* X 8 */ +#define U_SIZE_WMRSETBKCOLOR 10 /* X 12 */ +#define U_SIZE_WMRSETTEXTCOLOR 10 /* X 12 */ +#define U_SIZE_WMRSETBKMODE 8 /* X 12 last 2 bytes are optional */ +#define U_SIZE_WMRSETROP2 8 /* X 12 last 2 bytes are optional */ +#define U_SIZE_WMRSETPOLYFILLMODE 8 /* X 12 last 2 bytes are optional */ +#define U_SIZE_WMRSETSTRETCHBLTMODE 8 /* X 12 last 2 bytes are optional */ +#define U_SIZE_WMRSETTEXTALIGN 8 /* X 12 last 2 bytes are optional */ +#define U_SIZE_WMRSETMAPMODE 8 /* + 8 */ +#define U_SIZE_WMRSETTEXTCHAREXTRA 8 /* + 8 */ +#define U_SIZE_WMRSETTEXTJUSTIFICATION 10 /* X 12 */ +#define U_SIZE_WMRSETWINDOWORG 10 /* X 12 */ +#define U_SIZE_WMRSETWINDOWEXT 10 /* X 12 */ +#define U_SIZE_WMRSETVIEWPORTORG 10 /* X 12 */ +#define U_SIZE_WMRSETVIEWPORTEXT 10 /* X 12 */ +#define U_SIZE_WMROFFSETWINDOWORG 10 /* X 12 */ +#define U_SIZE_WMROFFSETVIEWPORTORG 10 /* X 12 */ +#define U_SIZE_WMRLINETO 10 /* X 12 */ +#define U_SIZE_WMRMOVETO 10 /* X 12 */ +#define U_SIZE_WMROFFSETCLIPRGN 10 /* X 12 */ +#define U_SIZE_WMRSCALEWINDOWEXT 14 /* X 16 */ +#define U_SIZE_WMRSCALEVIEWPORTEXT 14 /* X 16 */ +#define U_SIZE_WMREXCLUDECLIPRECT 14 /* X 16 */ +#define U_SIZE_WMRINTERSECTCLIPRECT 14 /* X 16 */ +#define U_SIZE_WMRARC 22 /* X 24 */ +#define U_SIZE_WMRELLIPSE 14 /* X 16 */ +#define U_SIZE_WMRRECTANGLE 14 /* X 16 */ +#define U_SIZE_WMRFLOODFILL 16 /* + 16 */ +#define U_SIZE_WMREXTFLOODFILL 16 /* + 16 */ +#define U_SIZE_WMRSETPIXEL 14 /* X 16 */ +#define U_SIZE_WMRPIE 22 /* X 24 */ +#define U_SIZE_WMRCHORD 22 /* X 24 */ +#define U_SIZE_WMRROUNDRECT 18 /* X 20 */ +#define U_SIZE_WMRPATBLT 18 /* X 20 */ +#define U_SIZE_WMRTEXTOUT 8 /* X 12 (not including String,y,x) */ +#define U_SIZE_WMRBITBLT_NOPX 24 /* + 24 */ +#define U_SIZE_WMRBITBLT_PX 22 /* X 32 */ +#define U_SIZE_WMRSTRETCHBLT_NOPX 28 /* + 28 */ +#define U_SIZE_WMRSTRETCHBLT_PX 26 /* X 36 */ +#define U_SIZE_WMRPOLYGON 10 /* X 12 */ +#define U_SIZE_WMRPOLYLINE 10 /* X 12 */ +#define U_SIZE_WMRESCAPE 10 /* X 12 Data field could be completely absent */ +#define U_SIZE_WMRFILLREGION 10 /* X 12 */ +#define U_SIZE_WMRFRAMEREGION 14 /* X 16 */ +#define U_SIZE_WMRINVERTREGION 8 /* + 8 */ +#define U_SIZE_WMRPAINTREGION 8 /* + 8 */ +#define U_SIZE_WMRSELECTCLIPREGION 8 /* + 8 */ +#define U_SIZE_WMRSELECTOBJECT 8 /* + 8 */ +#define U_SIZE_WMRSELECTPALETTE 8 /* + 8 */ +#define U_SIZE_WMRRESIZEPALETTE 8 /* + 8 */ +#define U_SIZE_WMRDELETEOBJECT 8 /* + 8 */ +#define U_SIZE_WMRDRAWTEXT 6 /* X 8 */ +#define U_SIZE_WMRCREATEBITMAPINDIRECT 6 /* X 8 */ +#define U_SIZE_WMRCREATEBITMAP 6 /* X 8 */ +#define U_SIZE_WMRSETMAPPERFLAGS 10 /* X 12 */ +#define U_SIZE_WMREXTTEXTOUT 14 /* X 16 */ +#define U_SIZE_WMRSETDIBTODEV 22 /* X 28 */ +#define U_SIZE_WMRANIMATEPALETTE 14 /* X 16 */ +#define U_SIZE_WMRSETPALENTRIES 14 /* X 16 */ +#define U_SIZE_WMRCREATEPALETTE 14 /* X 16 */ +#define U_SIZE_WMRPOLYPOLYGON 10 /* X 12 */ +#define U_SIZE_WMRDIBBITBLT_NOPX 24 /* + 24 */ +#define U_SIZE_WMRDIBBITBLT_PX 22 /* X 24 */ +#define U_SIZE_WMRDIBSTRETCHBLT_NOPX 28 /* + 28 */ +#define U_SIZE_WMRDIBSTRETCHBLT_PX 26 /* X 28 */ +#define U_SIZE_WMRDIBCREATEPATTERNBRUSH 10 /* X 12 */ +#define U_SIZE_WMRSTRETCHDIB 28 /* X 32 */ +#define U_SIZE_WMRCREATEPATTERNBRUSH 6 /* X 8 */ +#define U_SIZE_WMRCREATEPENINDIRECT 16 /* + 16 */ +#define U_SIZE_WMRCREATEFONTINDIRECT 26 /* X 28 */ +#define U_SIZE_WMRCREATEBRUSHINDIRECT 14 /* X 16 */ +#define U_SIZE_WMRCREATEREGION 26 /* X 28 */ +/** @} */ + + +// *************************************************************************** +// Macros + +/** \defgroup Common_macros Common Macros + @{ +*/ +/* Because Size16_4 may not be aligned no tests should dereference it directly from a pointer. +in NOPX tests cast causes uint8_t to promote to uint32_t, without it c++ compiler complains about +comparison of int with unsigned int */ +#define U_TEST_NOPX2(A,B) (A == (uint32_t) (B + 3)) /* A is Size16_4 (extracted and aligned), B = xb true if no bitmap associated with the structure, used with some BLT records*/ +#define U_TEST_NOPXB(A,B) (A/2 == (uint32_t) (B + 3)) /* A is Size16_4(extracted and aligned)*2, B - xb, true if no bitmap associated with the structure, used with some BLT records*/ +#define U_WMRTYPE(A) (((PU_METARECORD)A)->iType) //!< Get iType from U_WMR* record +#define U_WMRXB(A) (((PU_METARECORD)A)->xb) //!< Get xb from U_WMR* record +#define U_WMR_XB_FROM_TYPE(A) ((uint8_t) (U_wmr_values(A)>>8)) //!< Get xb from type value +#define U_U16(A) (*(uint16_t *)&A) /* interpret a 16 bit type as uint16_t */ +#define U_P16(A) ( (uint16_t *)&A) /* pass any 16 bit type as a pointer to a uint16_t */ +#define U_PP16(A) ( (uint16_t *) A) /* pass any pointer to a 16 bit type as a pointer to a uint16_t */ + +/** @} */ + +/* ************************************************************ + WMF structures OTHER than those corresponding to complete U_WMR_* records + ************************************************************ */ + +/** Brush Object WMF PDF 2.2.1.1 + + Documentation is muddy, bColor and bHatch fields have different meanings depending on + the value of bStyle. Unclear if bHatch bytes are present in some cases from the + documentation. + + style Color Data + U_BS_SOLID ColorRef Object Not used (bytes present???) + U_BS_NULL ignored ignored (bytes present???). + U_BS_PATTERN ignored Bitmap16 object holding patern + U_BS_DIBPATTERNPT ColorUsage Enum DIB object + U_BS_HATCHED ColorRef Object HatchStyle Enumeration +*/ + +typedef struct { + uint16_t Style; //!< BrushStyle enumeration + U_COLORREF Color; //!< Brush Color value, 32 bit value is not aligned. + uint8_t Data[1]; //!< Brush pattern information, variable size and format +} U_BRUSH, *PU_BRUSH; + + +/** Font Object WMF PDF 2.2.1.2 + Warning, only pass by pointer, passing by value will will truncate in Facename! +*/ +typedef struct { + int16_t Height; //!< Height in Logical units + int16_t Width; //!< Average Width in Logical units + int16_t Escapement; //!< Angle in 0.1 degrees betweem escapement vector and X axis + int16_t Orientation; //!< Angle in 0.1 degrees between baseline and X axis + int16_t Weight; //!< LF_Weight Enumeration + uint8_t Italic; //!< LF_Italic Enumeration + uint8_t Underline; //!< LF_Underline Enumeration + uint8_t StrikeOut; //!< LF_StrikeOut Enumeration + uint8_t CharSet; //!< LF_CharSet Enumeration + uint8_t OutPrecision; //!< LF_OutPrecision Enumeration + uint8_t ClipPrecision; //!< LF_ClipPrecision Enumeration + uint8_t Quality; //!< LF_Quality Enumeration + uint8_t PitchAndFamily; //!< LF_PitchAndFamily Enumeration + uint8_t FaceName[1]; //!< Name of font. ANSI Latin1, null terminated. +} U_FONT, *PU_FONT; + +/** PaletteEntry Object WMF PDF 2.2.2.13 + Note, NOT compatiable with U_LOGPLTNTRY + Out of PDF order because needed for next struture. +*/ +typedef struct { + uint8_t Value; //!< 0 or PaletteEntryFlag Enumeration + uint8_t Blue; //!< Palette entry Blue Intensity + uint8_t Green; //!< Palette entry Green Intensity + uint8_t Red; //!< Palette entry Red Intensity +} U_PLTNTRY, *PU_PLTNTRY; + +/** Palette Object WMF PDF 2.2.1.3 + NOT same as "LogPalette Object" in uemf.h because Palette Entries have reversed colors. + Values for palVersion are expanded + + Start must be 0x0300 (as for EMF) with U_WMRCREATEPALETTE but is an offset + for U_WMRSETPALENTRIES and U_ANIMATEPALETTE +*/ +typedef struct { + uint16_t Start; //!< Either 0x0300 or an offset into the Palette table + uint16_t NumEntries; //!< Number of U_LOGPLTNTRY objects + U_PLTNTRY PalEntries[1]; //!< Array of PaletteEntry Objects +} U_PALETTE, *PU_PALETTE; + +/** Pen Object WMF PDF 2.2.1.4 +*/ +typedef struct { + uint16_t Style; //!< PenStyle Enumeration + uint16_t Widthw[2]; //!< reassemble/store the Pen Width in object dimensions using Widthw, the 32 bit value is not aligned + U_COLORREF Color; //!< Pen Color, the 32 bit value is not aligned. +} U_PEN, *PU_PEN; + +/** Rect Object WMF PDF 2.2.2.18 + \brief Coordinates of the upper left, lower right corner. + Note that the coordinate system is 0,0 in the upper left corner + of the screen an N,M in the lower right corner. + Microsoft name: RECT Object COLLIDES with EMF Rect Object. + + This one is out of order because it is needed early. +*/ +typedef struct { + int16_t left; //!< left coordinate + int16_t top; //!< top coordinate + int16_t right; //!< right coordinate + int16_t bottom; //!< bottom coordinate +} U_RECT16, *PU_RECT16; + +#define U_RCL16_DEF (U_RECT16){0,0,-1,-1} //!< Use this when no bounds are needed. + +/** Region Object WMF PDF 2.2.1.5 +*/ +typedef struct { + uint16_t ignore1; //!< unused value + uint16_t Type; //!< must be 0x0006. + uint16_t ignore2; //!< unused value + int16_t Size; //!< aScans in bytes + regions size in bytes (size of this header plus all U_SCAN objects?) + int16_t sCount; //!< number of scanlines in region + int16_t sMax; //!< largest number of points in any scan + U_RECT16 sRect; //!< bounding rectangle + uint16_t aScans[1]; //!< series of appended U_SCAN objects +} U_REGION, *PU_REGION; + +/** Bitmap16 Object WMF PDF 2.2.2.1 + + The U_BITMAP16 core is always followed by + uint8_t Bits[1]; //!< bitmap pixel data. Bytes contained = (((Width * BitsPixel + 15) >> 4) << 1) * Height + Note that in U_WMRCREATEPATTERNBRUSH Bits is always [4]. + +*/ +typedef struct { + int16_t Type; //!< "bitmap type" MS PDF does not define this field beyond this. + int16_t Width; //!< bitmap width in pixels. + int16_t Height; //!< bitmap height in scan lines. + int16_t WidthBytes; //!< bytes per scan line. + uint8_t Planes; //!< must be 1. + uint8_t BitsPixel; //!< number of adjacent color bits on each plane (R bits + G bits + B bits ????) +} U_BITMAP16, *PU_BITMAP16; + +/** BitmapCoreHeader Object WMF PDF 2.2.2.2 +*/ +typedef struct { + uint16_t Size_4[2]; //!< size of U_BITMAPCOREHEADER in bytes. + uint16_t Width; //!< DIB width in pixels. + uint16_t Height; //!< DIB height in pixels. + uint16_t Planes; //!< must be 1 + uint16_t BitCount; //!< Pixel Format (BitCount Enumeration) +} U_BITMAPCOREHEADER, *PU_BITMAPCOREHEADER; + + +/** BitmapInfoHeader Object WMF PDF 2.2.2.3 + same as "BITMAPINFOHEADER Object" in uemf.h + use U_BITMAPINFOHEADER +*/ + +/** BitmapV4Header Object WMF PDF 2.2.2.4 +*/ +typedef struct { + uint32_t bV4Size; + int32_t bV4Width; + int32_t bV4Height; + uint16_t bV4Planes; + uint16_t bV4BitCount; + uint32_t bV4Compression; + uint32_t bV4SizeImage; + int32_t bV4XPelsPerMeter; + int32_t bV4YPelsPerMeter; + uint32_t bV4ClrUsed; + uint32_t bV4ClrImportant; + uint32_t bV4RedMask; + uint32_t bV4GreenMask; + uint32_t bV4BlueMask; + uint32_t bV4AlphaMask; + uint32_t bV4CSType; + U_CIEXYZTRIPLE bV4EndPoints; + uint32_t bV4GammaRed; + uint32_t bV4GammaGreen; + uint32_t bV4GammaBlue; +} U_BITMAPV4HEADER, *PU_BITMAPV4HEADER; //!< For ? + + +/** BitmapV5Header Object WMF PDF 2.2.2.5 +*/ +typedef struct { + uint32_t bV5Size; + int32_t bV5Width; + int32_t bV5Height; + uint16_t bV5Planes; + uint16_t bV5BitCount; + uint32_t bV5Compression; + uint32_t bV5SizeImage; + int32_t bV5XPelsPerMeter; + int32_t bV5YPelsPerMeter; + uint32_t bV5ClrUsed; + uint32_t bV5ClrImportant; + uint32_t bV5RedMask; + uint32_t bV5GreenMask; + uint32_t bV5BlueMask; + uint32_t bV5AlphaMask; + uint32_t bV5CSType; + U_CIEXYZTRIPLE bV5Endpoints; + uint32_t bV5GammaRed; + uint32_t bV5GammaGreen; + uint32_t bV5GammaBlue; + uint32_t bV5Intent; + uint32_t bV5ProfileData; + uint32_t bV5ProfileSize; + uint32_t bV5Reserved; +} U_BITMAPV5HEADER, *PU_BITMAPV5HEADER; //!< For ? + + + +/** CIEXYZ Object WMF PDF 2.2.2.6 + Same as "CIEXYZ Object" in uemf.h +*/ + +/** CIEXYZTriple Object WMF PDF 2.2.2.7 + Same as "CIEXYZTRIPLE Object" in uemf.h +*/ + +/** ColorRef Object WMF PDF 2.2.2.8 + Same as "COLORREF Object" in uemf.h +*/ + +/** DeviceIndependentBitmap Object WMF PDF 2.2.2.9 +This "object" has an organization, but not one that can be easily expressed with a C struct. It consists of +three parts, all of which have variable size: + + DIBHeaderInfo BitmapCoreHeader or BitmapInfoHeader Object + Colors Array of RGBQuad Objects or uint16_t that make a color table, as determined from the DIBHeaderInfo field. + BitMapBuffer Array of bytes containing the image. + +*/ + +/** WLogBrush Object WMF PDF 2.2.2.10 + Not compatible with EMF LogBrush object! + + style Color Hatch + U_BS_SOLID ColorRef Object Not used (bytes present???) + U_BS_NULL ignored ignored (bytes present???). + U_BS_PATTERN ignored not used (Action is not strictly defined) + U_BS_DIBPATTERN ignored not used (Action is not strictly defined) + U_BS_DIBPATTERNPT ignored not used (Action is not strictly defined) + U_BS_HATCHED ColorRef Object HatchStyle Enumeration +*/ +typedef struct { + uint16_t Style; //!< BrushStyle Enumeration + U_COLORREF Color; //!< Brush Color value, 32 bit value is not aligned. + uint16_t Hatch; //!< HatchStyle Enumeration +} U_WLOGBRUSH, *PU_WLOGBRUSH; + +/** LogColorSpace Object WMF PDF 2.2.2.11 + Same as "LOGCOLORSPACEA Object" in uemf.h + use U_LOGCOLORSPACEA +*/ + +/** LogColorSpaceW Object WMF PDF 2.2.2.12 + Same as "LOGCOLORSPACEW Object" in uemf.h + use U_LOGCOLORSPACEW +*/ + + +/** PaletteEntry Object WMF PDF 2.2.2.13 + moved up before Palette Object */ + +/** PitchAndFamily Enumerations WMF PDF 2.2.2.14 + Same as "LF_PitchAndFamily Enumeration" in uemf.h +*/ + +/** PointL Object WMF PDF 2.2.2.15 + Same as "Point Object" in uemf.h +*/ + +/** PointS Object WMF PDF 2.2.2.16 + Same as "POINTS Object" in uemf.h +*/ + +/** PolyPolygon Object WMF PDF 2.2.2.17 + There is an array "aPoints" of uint16_t after aPolyCounts that holds the coordinates. + Presumably it is in order [x1,y1],[x2,y2],etc. The documentation does not say, it might have + y then x. + aPoints starts at aPolyCounts[nPolys] +*/ +typedef struct { + uint16_t nPolys; //!< Number of polygons + uint16_t aPolyCounts[1]; //!< Number of points in each polygon (sequential) +} U_POLYPOLYGON, *PU_POLYPOLYGON; + +/** Rect Object WMF PDF 2.2.2.18 + This one is out of order, had to be created much earlier than this +*/ + +/** RectL Object WMF PDF 2.2.2.19 + Same as "RECT Object" in uemf.h +*/ + +/** RGBQuad Object WMF PDF 2.2.2.20 + Same as "RGBQUAD Object" in uemf.h +*/ + +/** Scan Object WMF PDF 2.2.2.21 + Field "count2" must follow ScanLines, but it cannot be placed into the struct. It is + an uint16_t value which must be the same as count. +*/ +typedef struct { + uint16_t count; //!< Number of entries in the ScanLines array + uint16_t top; //!< Y coordinate of the top scanline + uint16_t bottom; //!< Y coordinate of the bottom scanline + uint16_t ScanLines[1]; //!< Array of 16 bit left/right pairs +} U_SCAN, *PU_SCAN; + +/** SizeL Object WMF PDF 2.2.2.22 + Same as "SIZEL Object" in uemf.h +*/ + + +/** First three fields of MOST WMF records (not WMR_HEADER and WMR_PLACEABLE!) + Should only used for accessing size and type fields. + NOT used as a prefix like U_EMR in uemf.h because it may cause alignment issues. + Microsoft name: WMF Object +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type +} U_METARECORD, *PU_METARECORD; + +/** WMF PDF 2.3.2.3 META_PLACEABLE + If present this must immediately precede the header. + It is not enumerated as an WMR record type. + This only ever occurs at the start of a WMF file, so the two uint32_t values will always be aligned. +*/ +typedef struct { + uint32_t Key; //!< MUST be 0x9AC6CDD7 + uint16_t HWmf; //!< 0. (Always. Manual says total number of 16bit words in record, but no examples found like that) + U_RECT16 Dst; //!< Destination bounding box in logical units + uint16_t Inch; //!< Logical units/inch (convention if not specified: 1440 logical units/inch) + uint32_t Reserved; //!< must be 0 + uint16_t Checksum; //!< Checksum of preceding 10 16 bit values +} U_WMRPLACEABLE, *PU_WMRPLACEABLE; + +/** WMF PDF 2.3.2.2 META_HEADER +*/ +typedef struct { + uint8_t iType; //!< RecordType enumeration, must be 1 + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Size16w; //!< Total number of 16bit words in record + uint16_t version; //!< Metafile version enumeration + uint16_t Sizew[2]; //!< reassemble/store the Size (16 bit words in entire file) using Sizew, the 32 bit value is not aligned + uint16_t nObjects; //!< Total number of brushes, pens, and other graphics objects defined in this file + uint32_t maxSize; //!< Largest record in file, in number of 16bit words (This uint32_t is aligned) + uint16_t nMembers; //!< Unused, should be 0 +} U_WMRHEADER, *PU_WMRHEADER; + + +// *********************************************************************************** +// The following structures correspond to U_WMR_# records + +/* Index 00 U_WMREOF WMF PDF 2.3.2.1 META_EOF */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type +} U_WMREOF, *PU_WMREOF, + U_WMRSETRELABS, *PU_WMRSETRELABS, + U_WMRSAVEDC, *PU_WMRSAVEDC, + U_WMRREALIZEPALETTE, *PU_WMRREALIZEPALETTE; + +/* Index 01 U_WMRSETBKCOLOR WMF PDF 2.3.5.14 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_COLORREF Color; //!< Color value, the 32 bit value is not aligned. +} U_WMRSETBKCOLOR, *PU_WMRSETBKCOLOR, + U_WMRSETTEXTCOLOR, *PU_WMRSETTEXTCOLOR; + +/* Index 02 U_WMRSETBKMODE WMF PDF 2.3.5.15 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Mode; //!< Various Enumeraton. + uint16_t Reserved; //!< Ignore (ALSO OPTIONAL - FIELD MAY NOT BE PRESENT!!!!) +} U_WMRSETBKMODE, *PU_WMRSETBKMODE, //!< MixMode Enumeration. + U_WMRSETROP2, *PU_WMRSETROP2, //!< Binary Raster Operation Enumeration. + U_WMRSETPOLYFILLMODE, *PU_WMRSETPOLYFILLMODE, //!< PolyFillMode Enumeration. + U_WMRSETSTRETCHBLTMODE, *PU_WMRSETSTRETCHBLTMODE, //!< StretchMode Enumeration + U_WMRSETTEXTALIGN, *PU_WMRSETTEXTALIGN; //!< TextAlignment Enumeration. + +/* Index 03 U_WMRSETMAPMODE WMF PDF 2.3.5.17 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Mode; //!< Various Enumeraton and other +} U_WMRSETMAPMODE, *PU_WMRSETMAPMODE, //!< MapMode Enumeration. + U_WMRSETTEXTCHAREXTRA, *PU_WMRSETTEXTCHAREXTRA; //!< Extra space in logical units to add to each character + +/* Index 04 U_WMRSETROP2 WMF PDF 2.3.5.22 See Index 02 */ + +/* Index 05 U_WMRSETRELABS WMF PDF 2.3.5.21 See Index 00*/ + +/* Index 06 U_WMRSETPOLYFILLMODE WMF PDF 2.3.5.20 See Index 02 + Index 07 U_WMRSETSTRETCHBLTMODE WMF PDF 2.3.5.23 */ + +/* Index 08 U_WMRSETTEXTCHAREXTRA WMF PDF 2.3.5.25 See Index 03*/ + +/* Index 09 U_WMRSETTEXTCOLOR WMF PDF 2.3.5.26 see Index 01 */ + +/* Index 0A U_WMRSETTEXTJUSTIFICATION WMF PDF 2.3.5.27 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Count; //!< Number of space characters in the line + uint16_t Extra; //!< Number of extra space characters to add to the line +} U_WMRSETTEXTJUSTIFICATION, *PU_WMRSETTEXTJUSTIFICATION; + +/* Index 0B U_WMRSETWINDOWORG WMF PDF 2.3.5.31 + Index 0C U_WMRSETWINDOWEXT WMF PDF 2.3.5.30 + Index 0D U_WMRSETVIEWPORTORG WMF PDF 2.3.5.29 + Index 0E U_WMRSETVIEWPORTEXT WMF PDF 2.3.5.28 + Index 0F U_WMROFFSETWINDOWORG WMF PDF 2.3.5.7 + Index 13 U_WMRLINETO WMF PDF 2.3.3.10 + Index 14 U_WMRMOVETO WMF PDF 2.3.3.4 +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t y; //!< Y value (note order!) + int16_t x; //!< X value +} U_WMRSETWINDOWORG, *PU_WMRSETWINDOWORG, //!< Window X,Y origin + U_WMRSETWINDOWEXT, *PU_WMRSETWINDOWEXT, //!< Window X,Y extent + U_WMRSETVIEWPORTORG, *PU_WMRSETVIEWPORTORG, //!< Viewport X,Y origin + U_WMRSETVIEWPORTEXT, *PU_WMRSETVIEWPORTEXT, //!< Viewport X,Y extent + U_WMROFFSETWINDOWORG, *PU_WMROFFSETWINDOWORG, //!< Window X,Y offset in device units + U_WMROFFSETVIEWPORTORG, *PU_WMROFFSETVIEWPORTORG, //!< Viewport X,Y offset in device units + U_WMRLINETO, *PU_WMRLINETO, //!< Endpoint X,Y in logical units + U_WMRMOVETO, *PU_WMRMOVETO, //!< Destination X,Y in logical units + U_WMROFFSETCLIPRGN, *PU_WMROFFSETCLIPRGN; //!< ClipRegion X,Y offset in logical units + +/* Index 10 U_WMRSCALEWINDOWEXT WMF PDF 2.3.5.13 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t yDenom; //!< Y denominator + int16_t yNum; //!< Y numerator + int16_t xDenom; //!< X denominator + int16_t xNum; //!< X numerator +} U_WMRSCALEWINDOWEXT, *PU_WMRSCALEWINDOWEXT, + U_WMRSCALEVIEWPORTEXT, *PU_WMRSCALEVIEWPORTEXT; + +/* Index 11 U_WMROFFSETVIEWPORTORG WMF PDF 2.3.5.6 see Index 0B */ + +/* Index 12 U_WMRSCALEVIEWPORTEXT WMF PDF 2.3.5.12 see Index 10 */ + +/* Index 13 U_WMRLINETO WMF PDF 2.3.3.10 see index 0B + Index 14 U_WMRMOVETO WMF PDF 2.3.5.4 */ + +/* Index 15 U_WMREXCLUDECLIPRECT WMF PDF 2.3.5.2 + Index 16 U_WMRINTERSECTCLIPRECT WMF PDF 2.3.5.3 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t Bottom; //!< Coordinates in logical units + int16_t Right; //!< Coordinates in logical units + int16_t Top; //!< Coordinates in logical units + int16_t Left; //!< Coordinates in logical units +} U_WMREXCLUDECLIPRECT, *PU_WMREXCLUDECLIPRECT, + U_WMRINTERSECTCLIPRECT, *PU_WMRINTERSECTCLIPRECT; + +/* Index 17 U_WMRARC WMF PDF 2.3.3.1 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t yEndArc; //!< Coordinates in logical units + int16_t xEndArc; //!< Coordinates in logical units + int16_t yStartArc; //!< Coordinates in logical units + int16_t xStartArc; //!< Coordinates in logical units + int16_t Bottom; //!< Coordinates in logical units + int16_t Right; //!< Coordinates in logical units + int16_t Top; //!< Coordinates in logical units + int16_t Left; //!< Coordinates in logical units +} U_WMRARC, *PU_WMRARC; + +/* Index 18 U_WMRELLIPSE WMF PDF 2.3.3.3 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t Bottom; //!< Coordinates in logical units + int16_t Right; //!< Coordinates in logical units + int16_t Top; //!< Coordinates in logical units + int16_t Left; //!< Coordinates in logical units +} U_WMRELLIPSE, *PU_WMRELLIPSE, + U_WMRRECTANGLE, *PU_WMRRECTANGLE; + +/* Index 19 U_WMRFLOODFILL WMF PDF 2.3.3.7 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t Mode; //!< FloodFill Enumeration + U_COLORREF Color; //!< Color + int16_t y; //!< Y + int16_t x; //!< X +} U_WMRFLOODFILL, *PU_WMRFLOODFILL, + U_WMREXTFLOODFILL, *PU_WMREXTFLOODFILL; + +/* Index 1A U_WMRPIE WMF PDF 2.3.3.13 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t yRadial2; //!< in logical units + int16_t xRadial2; //!< in logical units + int16_t yRadial1; //!< in logical units + int16_t xRadial1; //!< in logical units + int16_t Bottom; //!< in logical units + int16_t Right; //!< in logical units + int16_t Top; //!< in logical units + int16_t Left; //!< in logical units +} U_WMRPIE, *PU_WMRPIE, + U_WMRCHORD, *PU_WMRCHORD; + +/* Index 1B U_WMRRECTANGLE WMF PDF 2.3.3.17 See Index 18 */ + +/* Index 1C U_WMRROUNDRECT WMF PDF 2.3.3.18 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t Height; //!< in logical units (rounded corner) + int16_t Width; //!< in logical units (rounded corner) + int16_t Bottom; //!< in logical units + int16_t Right; //!< in logical units + int16_t Top; //!< in logical units + int16_t Left; //!< in logical units +} U_WMRROUNDRECT, *PU_WMRROUNDRECT; + +/* Index 1D U_WMRPATBLT WMF PDF 2.3.3.12 +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the rop3 Ternary raster operation using rop3w, as the 32 bit value is not aligned + int16_t Height; //!< in logical units (of Rect to Fill) + int16_t Width; //!< in logical units (of Rect to Fill) + int16_t yDst; //!< in logical units (UL corner to fill) + int16_t xDst; //!< in logical units (UL corner to fill) +} U_WMRPATBLT, *PU_WMRPATBLT; + +/* Index 1E U_WMRSAVEDC WMF PDF 2.3.5.11 See Index 00*/ + +/* Index 1F U_WMRSETPIXEL WMF PDF 2.3.3.19 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_COLORREF Color; //!< Color + int16_t y; //!< Y + int16_t x; //!< X +} U_WMRSETPIXEL, *PU_WMRSETPIXEL; + +/* Index 20 U_WMROFFSETCLIPRGN WMF PDF 2.3.5.5 See Index 0B*/ + +/* Index 21 U_WMRTEXTOUT WMF PDF 2.3.3.20 + Also part of the record, but at variable positions + int16_t y; start position + int16_t x; start position +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t Length; //!< Stringlength in bytes + uint8_t String; //!< String to write, storage area must be 2n bytes. +} U_WMRTEXTOUT, *PU_WMRTEXTOUT; + +/* Index 22 U_WMRBITBLT WMF PDF 2.3.1.1 + This is a variable structure the core, invariant part extends to xSrc. + + if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form + Use Macro U_TEST_NOPX2 + +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t ignore; //!< ignore + int16_t Height; //!< in logical units (of Src and Dst rects) + int16_t Width; //!< in logical units (of Src and Dst rects) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) +} U_WMRBITBLT_NOPX, *PU_WMRBITBLT_NOPX; + +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t Height; //!< in logical units (of Src and Dst rects) + int16_t Width; //!< in logical units (of Src and Dst rects) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) + U_BITMAP16 bitmap; //!< Src bitmap +} U_WMRBITBLT_PX, *PU_WMRBITBLT_PX; + + +/* Index 23 U_WMRSTRETCHBLT WMF PDF 2.3.1.5 + This is a variable structure the core, invariant part extends to xSrc. + + if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form + Use Macro U_TEST_NOPX2. +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t hSrc; //!< Height in logical units of Src rect + int16_t wSrc; //!< Wdith in logical units of Dst rect + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t ignore; //!< ignored + int16_t hDst; //!< Height in logical units of Dst rect + int16_t wDst; //!< Wdith in logical units of Dst rect + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) +} U_WMRSTRETCHBLT_NOPX, *PU_WMRSTRETCHBLT_NOPX; + +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t hSrc; //!< Height in logical units of Src rect + int16_t wSrc; //!< Wdith in logical units of Dst rect + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t hDst; //!< Height in logical units of Dst rect + int16_t wDst; //!< Wdith in logical units of Dst rect + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) + U_BITMAP16 bitmap; //!< Src bitmap +} U_WMRSTRETCHBLT_PX, *PU_WMRSTRETCHBLT_PX; + +/* Index 24 U_WMRPOLYGON WMF PDF 2.3.3.15 + Index 25 U_WMRPOLYLINE WMF PDF 2.3.3.14 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t nPoints; //!< Number of points in aPoints + U_POINT16 aPoints[1]; //!< Array of points +} U_WMRPOLYGON, *PU_WMRPOLYGON, + U_WMRPOLYLINE, *PU_WMRPOLYLINE; + +/* Index 26 U_WMRESCAPE WMF PDF 2.3.6.1 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t eFunc; //!< Escape function + uint16_t nBytes; //!< bytes in the data array + uint8_t Data[1]; //!< data array +} U_WMRESCAPE, *PU_WMRESCAPE; + +/* Index 27 U_WMRRESTOREDC WMF PDF 2.3.5.10*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t DC; //!< DC to restore (negative is relative to current, positive is absolute) +} U_WMRRESTOREDC, *PU_WMRRESTOREDC; + +/* Index 28 U_WMRFILLREGION WMF PDF 2.3.3.6 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Region; //!< Index of region to fill in object table + uint16_t Brush; //!< Index of brush to use in object table +} U_WMRFILLREGION, *PU_WMRFILLREGION; + +/* Index 29 U_WMRFRAMEREGION WMF PDF 2.3.3.8 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Region; //!< Index of region to frame in object table + uint16_t Brush; //!< Index of brush to use in frame in object table + int16_t Height; //!< in logical units (of frame) + int16_t Width; //!< in logical units (of frame) +} U_WMRFRAMEREGION, *PU_WMRFRAMEREGION; + +/* Index 2A U_WMRINVERTREGION WMF PDF 2.3.3.9 + Index 2B U_WMRPAINTREGION WMF PDF 2.3.3.11 + Index 2C U_WMRSELECTCLIPREGION WMF PDF 2.3.4.9 + Index 2D U_WMRSELECTOBJECT WMF PDF 2.3.4.10 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t index; //!< (usually) index of region/object in object table +} U_WMRINVERTREGION, *PU_WMRINVERTREGION, //!< invert region + U_WMRPAINTREGION, *PU_WMRPAINTREGION, //!< paint region + U_WMRSELECTCLIPREGION, *PU_WMRSELECTCLIPREGION, //!< select as clip region + U_WMRSELECTOBJECT, *PU_WMRSELECTOBJECT, //!< select object + U_WMRSELECTPALETTE, *PU_WMRSELECTPALETTE, //!< select palette object + U_WMRRESIZEPALETTE, *PU_WMRRESIZEPALETTE, //!< resize the system palette to "index" + U_WMRDELETEOBJECT, *PU_WMRDELETEOBJECT; //!< delete object + +/* Index 2E U_WMRSETTEXTALIGN WMF PDF 2.3.5.24 See Index 02 */ + +/* Index 2F U_WMRDRAWTEXT in Wine, not in WMF PDF. + no documentation found, this part must be correct */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type +} U_WMRDRAWTEXT, *PU_WMRDRAWTEXT, + U_WMRCREATEBITMAPINDIRECT, *PU_WMRCREATEBITMAPINDIRECT, + U_WMRCREATEBITMAP, *PU_WMRCREATEBITMAP; + +/* Index 30 U_WMRCHORD WMF PDF 2.3.3.2 See Index 1A */ + +/* Index 31 U_WMRSETMAPPERFLAGS WMF PDF 2.3.5.18 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t valuew[2]; //!< if 1 bit set font mapper selects only matching aspect fonts. reassemble/store the value using valuew, the 32 bit value is not aligned. +} U_WMRSETMAPPERFLAGS, *PU_WMRSETMAPPERFLAGS; + +/* Index 32 U_WMREXTTEXTOUT WMF PDF 2.3.3.5 + Variable size structure. Common part is shown. + + U_RECT16 Rect; Only present when U_ETO_OPAQUE or U_ETO_CLIPPED bits are set in Opts + uint8_t String; String to write, storage area must be 2n bytes. + int16_t Dx; Kerning information. Must have same number of entries as Length. + Dx is present when + 2*Size16_4[2] -14 - 2*((Length + 1)/2)) - 8*(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)) == 2*Length +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + int16_t y; //!< in logical units (draw point) + int16_t x; //!< in logical units (draw point) + int16_t Length; //!< Stringlength in bytes + uint16_t Opts; //!< ExtTextOutOptions Flags +} U_WMREXTTEXTOUT, *PU_WMREXTTEXTOUT; + +/* Index 33 U_WMRSETDIBTODEV WMF PDF 2.3.1.4 + Constant part of record is showon. It is followed by a + DeviceIndependentBitmap Object +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t cUsage; //!< ColorUsage enumeration + uint16_t ScanCount; //!< Number of scan lines in Src + uint16_t StartScan; //!< First Scan line in Src + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t Height; //!< in logical units (of Src and Dst) + int16_t Width; //!< in logical units (of Src and Dst) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) + uint8_t dib[1]; //!< DeviceIndependentBitmap object +} U_WMRSETDIBTODEV, *PU_WMRSETDIBTODEV; + +/* Index 34 U_WMRSELECTPALETTE WMF PDF 2.3.4.11 See Index 2A */ + +/* Index 35 U_WMRREALIZEPALETTE WMF PDF 2.3.5.8 See Index 00 */ + +/* Index 36 U_WMRANIMATEPALETTE WMF PDF 2.3.5.1 + Index 37 U_WMRSETPALENTRIES WMF PDF 2.3.5.19 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_PALETTE Palette; //!< Palette object +} U_WMRANIMATEPALETTE, *PU_WMRANIMATEPALETTE, + U_WMRSETPALENTRIES, *PU_WMRSETPALENTRIES, + U_WMRCREATEPALETTE, *PU_WMRCREATEPALETTE; + +/* Index 38 U_WMRPOLYPOLYGON WMF PDF 2.3.3.16 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_POLYPOLYGON PPolygon; //!< PolyPolygon object (size is variable!) +} U_WMRPOLYPOLYGON, *PU_WMRPOLYPOLYGON; + +/* Index 39 U_WMRRESIZEPALETTE WMF PDF 2.3.5.9 See Index 2A */ + +/* Index 40 U_WMRDIBBITBLT WMF PDF 2.3.1.2 + The PX form is a variable structure the core, invariant part extends to xDst, and that is + followed by a DeviceInvariantBitmap object which starts at "dib". + The NOPX form is a constant structure. + + if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form + Use Macro U_TEST_NOPX2. +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + uint16_t ignore; //!< ignore + int16_t Height; //!< in logical units (of Src and Dst) + int16_t Width; //!< in logical units (of Src and Dst) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) +} U_WMRDIBBITBLT_NOPX, *PU_WMRDIBBITBLT_NOPX; + +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t Height; //!< in logical units (of Src and Dst) + int16_t Width; //!< in logical units (of Src and Dst) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) + uint8_t dib[1]; //!< DeviceIndependentBitmap object +} U_WMRDIBBITBLT_PX, *PU_WMRDIBBITBLT_PX; + +/* Index 41 U_WMRDIBSTRETCHBLT WMF PDF 2.3.1.3 + The PX form is a variable structure the core, invariant part extends to xDst, and that is + followed by a DeviceInvariantBitmap object which starts at "dib". + The NOPX form is a constant structure. + + if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form + Use Macro U_TEST_NOPX2. +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t hSrc; //!< in logical units (of Src) + int16_t wSrc; //!< in logical units (of Src) + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + uint16_t ignore; //!< ignore + int16_t hDst; //!< in logical units (of Dst) + int16_t wDst; //!< in logical units (of Dst) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) +} U_WMRDIBSTRETCHBLT_NOPX, *PU_WMRDIBSTRETCHBLT_NOPX; + +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + int16_t hSrc; //!< in logical units (of Src) + int16_t wSrc; //!< in logical units (of Src) + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t hDst; //!< in logical units (of Dst) + int16_t wDst; //!< in logical units (of Dst) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) + uint8_t dib[1]; //!< DeviceIndependentBitmap object +} U_WMRDIBSTRETCHBLT_PX, *PU_WMRDIBSTRETCHBLT_PX; + + +/* Index 42 U_WMRDIBCREATEPATTERNBRUSH WMF PDF 2.3.4.8 + + style cUsage Brush created + U_BS_SOLID like U_BS_DIBPATTERNPT + U_BS_NULL like U_BS_DIBPATTERNPT + U_BS_HATCHED like U_BS_DIBPATTERNPT + U_BS_DIBPATTERNPT ColorUsage enumer. U_BS_DIBPATTERNPT brush from DIB in Src + U_BS_PATTERN ColorUsage enumer. U_BS_PATTERN brush from Bitmap16 object in Src +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t Style; //!< BrushStyle Enumeration + uint16_t cUsage; //!< See table above + uint8_t Src[1]; //!< DeviceIndependentBitmap or Bitmap16 object +} U_WMRDIBCREATEPATTERNBRUSH, *PU_WMRDIBCREATEPATTERNBRUSH; + +/* Index 43 U_WMRSTRETCHDIB WMF PDF 2.3.1.6 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned. + uint16_t cUsage; //!< ColorUsage enumeration + int16_t hSrc; //!< in logical units (of Src) + int16_t wSrc; //!< in logical units (of Src) + int16_t ySrc; //!< in logical units (UL corner of Src rect) + int16_t xSrc; //!< in logical units (UL corner of Src rect) + int16_t hDst; //!< in logical units (of Dst) + int16_t wDst; //!< in logical units (of Dst) + int16_t yDst; //!< in logical units (UL corner of Dst rect) + int16_t xDst; //!< in logical units (UL corner of Dst rect) + uint8_t dib[1]; //!< DeviceIndependentBitmap object +} U_WMRSTRETCHDIB, *PU_WMRSTRETCHDIB; + +/* Index 48 U_WMREXTFLOODFILL WMF PDF 2.3.3.4 See Index 19*/ +/* Index 4C U_WMR4C */ +/* Index 4D U_WMR4D */ +/* Index 4F U_WMR4F */ +/* Index 50 U_WMR50 */ +/* Index 52 U_WMR52 */ +/* Index 5E U_WMR5E */ +/* Index 5F U_WMR5F */ +/* Index 60 U_WMR60 */ +/* Index 61 U_WMR61 */ +/* Index 62 U_WMR62 */ +/* Index 63 U_WMR63 */ +/* Index 64 U_WMR64 */ +/* Index 65 U_WMR65 */ +/* Index 66 U_WMR66 */ +/* Index 67 U_WMR67 */ +/* Index 68 U_WMR68 */ +/* Index 69 U_WMR69 */ +/* Index 6A U_WMR6A */ +/* Index 6B U_WMR6B */ +/* Index 6C U_WMR6C */ +/* Index 6D U_WMR6D */ +/* Index 6E U_WMR6E */ +/* Index 6F U_WMR6F */ +/* Index 70 U_WMR70 */ +/* Index 71 U_WMR71 */ +/* Index 72 U_WMR72 */ +/* Index 73 U_WMR73 */ +/* Index 74 U_WMR74 */ +/* Index 75 U_WMR75 */ +/* Index 76 U_WMR76 */ +/* Index 77 U_WMR77 */ +/* Index 78 U_WMR78 */ +/* Index 79 U_WMR79 */ +/* Index 7A U_WMR7A */ +/* Index 7B U_WMR7B */ +/* Index 7C U_WMR7C */ +/* Index 7D U_WMR7D */ +/* Index 7E U_WMR7E */ +/* Index 7F U_WMR7F */ +/* Index 80 U_WMR80 */ +/* Index 81 U_WMR81 */ +/* Index 82 U_WMR82 */ +/* Index 83 U_WMR83 */ +/* Index 84 U_WMR84 */ +/* Index 85 U_WMR85 */ +/* Index 86 U_WMR86 */ +/* Index 87 U_WMR87 */ +/* Index 88 U_WMR88 */ +/* Index 89 U_WMR89 */ +/* Index 8A U_WMR8A */ +/* Index 8B U_WMR8B */ +/* Index 8C U_WMR8C */ +/* Index 8D U_WMR8D */ +/* Index 8E U_WMR8E */ +/* Index 8F U_WMR8F */ +/* Index 90 U_WMR90 */ +/* Index 91 U_WMR91 */ +/* Index 92 U_WMR92 */ +/* Index 93 U_WMR93 */ +/* Index 94 U_WMR94 */ +/* Index 95 U_WMR95 */ +/* Index 96 U_WMR96 */ +/* Index 97 U_WMR97 */ +/* Index 98 U_WMR98 */ +/* Index 99 U_WMR99 */ +/* Index 9A U_WMR9A */ +/* Index 9B U_WMR9B */ +/* Index 9C U_WMR9C */ +/* Index 9D U_WMR9D */ +/* Index 9E U_WMR9E */ +/* Index 9F U_WMR9F */ +/* Index A0 U_WMRA0 */ +/* Index A1 U_WMRA1 */ +/* Index A2 U_WMRA2 */ +/* Index A3 U_WMRA3 */ +/* Index A4 U_WMRA4 */ +/* Index A5 U_WMRA5 */ +/* Index A6 U_WMRA6 */ +/* Index A7 U_WMRA7 */ +/* Index A8 U_WMRA8 */ +/* Index A9 U_WMRA9 */ +/* Index AA U_WMRAA */ +/* Index AB U_WMRAB */ +/* Index AC U_WMRAC */ +/* Index AD U_WMRAD */ +/* Index AE U_WMRAE */ +/* Index AF U_WMRAF */ +/* Index B0 U_WMRB0 */ +/* Index B1 U_WMRB1 */ +/* Index B2 U_WMRB2 */ +/* Index B3 U_WMRB3 */ +/* Index B4 U_WMRB4 */ +/* Index B5 U_WMRB5 */ +/* Index B6 U_WMRB6 */ +/* Index B7 U_WMRB7 */ +/* Index B8 U_WMRB8 */ +/* Index B9 U_WMRB9 */ +/* Index BA U_WMRBA */ +/* Index BB U_WMRBB */ +/* Index BC U_WMRBC */ +/* Index BD U_WMRBD */ +/* Index BE U_WMRBE */ +/* Index BF U_WMRBF */ +/* Index C0 U_WMRC0 */ +/* Index C1 U_WMRC1 */ +/* Index C2 U_WMRC2 */ +/* Index C3 U_WMRC3 */ +/* Index C4 U_WMRC4 */ +/* Index C5 U_WMRC5 */ +/* Index C6 U_WMRC6 */ +/* Index C7 U_WMRC7 */ +/* Index C8 U_WMRC8 */ +/* Index C9 U_WMRC9 */ +/* Index CA U_WMRCA */ +/* Index CB U_WMRCB */ +/* Index CC U_WMRCC */ +/* Index CD U_WMRCD */ +/* Index CE U_WMRCE */ +/* Index CF U_WMRCF */ +/* Index D0 U_WMRD0 */ +/* Index D1 U_WMRD1 */ +/* Index D2 U_WMRD2 */ +/* Index D3 U_WMRD3 */ +/* Index D4 U_WMRD4 */ +/* Index D5 U_WMRD5 */ +/* Index D6 U_WMRD6 */ +/* Index D7 U_WMRD7 */ +/* Index D8 U_WMRD8 */ +/* Index D9 U_WMRD9 */ +/* Index DA U_WMRDA */ +/* Index DB U_WMRDB */ +/* Index DC U_WMRDC */ +/* Index DD U_WMRDD */ +/* Index DE U_WMRDE */ +/* Index DF U_WMRDF */ +/* Index E0 U_WMRE0 */ +/* Index E1 U_WMRE1 */ +/* Index E2 U_WMRE2 */ +/* Index E3 U_WMRE3 */ +/* Index E4 U_WMRE4 */ +/* Index E5 U_WMRE5 */ +/* Index E6 U_WMRE6 */ +/* Index E7 U_WMRE7 */ +/* Index E8 U_WMRE8 */ +/* Index E9 U_WMRE9 */ +/* Index EA U_WMREA */ +/* Index EB U_WMREB */ +/* Index EC U_WMREC */ +/* Index ED U_WMRED */ +/* Index EE U_WMREE */ +/* Index EF U_WMREF */ +/* Index F0 U_WMRDELETEOBJECT WMF PDF 2.3.4.7 See Index 2A */ +/* Index F1 U_WMRF1 */ +/* Index F2 U_WMRF2 */ +/* Index F3 U_WMRF3 */ +/* Index F4 U_WMRF4 */ +/* Index F5 U_WMRF5 */ + +/* Index F7 U_WMRCREATEPALETTE WMF PDF 2.3.4.3 See Index 36*/ + +/* Index F8 U_WMRF8 */ +/* Index F9 U_WMRCREATEPATTERNBRUSH WMF PDF 2.3.4.4 + + This one is peculiar... + + After the core structure there is: + + 1. A truncated U_BITMAP16. Only the first 14 bytes are present, and the last 4 bytes (bits section) are ignored.\ + 2. 18 zero bytes (reserved) + 3. A pattern. The pattern is a byte array whose size is set by the fields in the U_BITMAP16 structure as follows: + + (((Width * BitsPixel + 15) >> 4) << 1) * Height + + brush created is BS_PATTERN + +*/ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type +} U_WMRCREATEPATTERNBRUSH, *PU_WMRCREATEPATTERNBRUSH; + +/* Index FA U_WMRCREATEPENINDIRECT WMF PDF 2.3.4.5 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_PEN pen; //!< Pen Object +} U_WMRCREATEPENINDIRECT, *PU_WMRCREATEPENINDIRECT; + +/* Index FB U_WMRCREATEFONTINDIRECT WMF PDF 2.3.4.2 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_FONT font; //!< Font Object +} U_WMRCREATEFONTINDIRECT, *PU_WMRCREATEFONTINDIRECT; + +/* Index FC U_WMRCREATEBRUSHINDIRECT WMF PDF 2.3.4.1 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_WLOGBRUSH brush; //!< WLogBrush Object +} U_WMRCREATEBRUSHINDIRECT, *PU_WMRCREATEBRUSHINDIRECT; + +/* Index FD U_WMRCREATEBITMAPINDIRECT in Wine, not in WMF PDF see index 2F */ + +/* Index FE U_WMRCREATEBITMAP in Wine, not in WMF PDF see index 2F */ + +/* Index FF U_WMRCREATEREGION WMF PDF 2.3.4.6 */ +typedef struct { + uint16_t Size16_4[2]; //!< Total number of 16bit words in record + uint8_t iType; //!< RecordType enumeration + uint8_t xb; //!< Extra high order byte associated with record type + U_REGION region; //!< Region Object +} U_WMRCREATEREGION, *PU_WMRCREATEREGION; + + + +// ************************************************************************************************ +// Utility function structures + +typedef struct { + FILE *fp; //!< Open file + size_t allocated; //!< Size of the buffer + size_t used; //!< Amount consumed + uint32_t records; //!< Number of records already contained + uint16_t ignore; //!< size padding,not used + uint32_t PalEntries; //!< Number of PalEntries (set from U_EMREOF) + uint32_t chunk; //!< Number of bytes to add when more space is needed + char *buf; //!< Buffer for constructing the EMF in memory + uint32_t largest; //!< Largest record size, in bytes (used by WMF, not by EMF) + uint32_t sumObjects; //!< Number of objects created (used by WMF, not by EMF) +} WMFTRACK; + +/** + The various create functions need a place to put their handles, these are stored in the table below. + We don't actually do anything much with these handles, that is up to whatever program finally plays back the WMF, but + we do need to keep track of the numbers so that they are not accidentally reused. (Also WMF files have rules + about how object handles must be numbered, for instance, the lowest possible number must always be used. These + are different from EMF object handles.) This structure is used for staying in conformance with these rules. + + There are no stock objects in WMF files. +*/ +typedef struct { + uint32_t *table; //!< Array Buffer for constructing the WMF in memory + size_t allocated; //!< Slots in the buffer + size_t chunk; //!< Number to add if a realloc is required + uint32_t lolimit; //!< Lowest unoccupied table slot, may be a hole created by a deleteobject. + uint32_t hilimit; //!< Highest table slot occupied (currently) + uint32_t peak; //!< Highest table slot occupied (ever) +} WMFHANDLES; + +// ************************************************************************************************ +// Prototypes (_set first, then _get) +char *wmr_dup(const char *wmr); +int wmf_start(const char *name, uint32_t initsize, uint32_t chunksize, WMFTRACK **wt); +int wmf_free(WMFTRACK **wt); +int wmf_finish(WMFTRACK *wt); +int wmf_append(PU_METARECORD rec, WMFTRACK *wt, int freerec); +int wmf_header_append(PU_METARECORD rec,WMFTRACK *et, int freerec); +int wmf_readdata(const char *filename, char **contents, size_t*length); +#define wmf_fopen emf_fopen +int wmf_htable_create(uint32_t initsize, uint32_t chunksize, WMFHANDLES **wht); +int wmf_htable_delete(uint32_t *ih, WMFHANDLES *wht); +int wmf_htable_insert(uint32_t *ih, WMFHANDLES *wht); +int wmf_htable_free(WMFHANDLES **wht); +int16_t U_16_checksum(int16_t *buf, int count); +int16_t *dx16_set( int32_t height, uint32_t weight, uint32_t members); +uint32_t U_wmr_properties(uint32_t type); + +uint32_t U_wmr_size(const U_METARECORD *record); +uint32_t U_wmr_values(int idx); +char *U_wmr_names(int idx); +char *U_wmr_escnames(int idx); + +void U_sanerect16(U_RECT16 rc, double *left, double *top, double *right, double *bottom); + + +PU_FONT U_FONT_set(int16_t Height, int16_t Width, int16_t Escapement, int16_t Orientation, + int16_t Weight, uint8_t Italic, uint8_t Underline, uint8_t StrikeOut, + uint8_t CharSet, uint8_t OutPrecision, uint8_t ClipPrecision, + uint8_t Quality, uint8_t PitchAndFamily, char *FaceName); +U_PLTNTRY U_PLTNTRY_set(U_COLORREF Color); +PU_PALETTE U_PLTENTRY_set(uint16_t Start, uint16_t NumEntries, PU_PLTNTRY Entries); +U_PEN U_PEN_set(uint16_t Style, uint16_t Width, U_COLORREF Color); +U_RECT16 U_RECT16_set(U_POINT16 ul,U_POINT16 lr); +PU_BITMAP16 U_BITMAP16_set(const int16_t Type, const int16_t Width, const int16_t Height, + const int16_t LineN, const uint8_t BitsPixel, const char *Bits); +PU_SCAN U_SCAN_set(uint16_t count, uint16_t top, uint16_t bottom, uint16_t *ScanLines); +PU_REGION U_REGION_set(int16_t Size, int16_t sCount, int16_t sMax, U_RECT16 sRect, uint16_t *aScans); +U_WLOGBRUSH U_WLOGBRUSH_set(uint16_t Style, U_COLORREF Color, uint16_t Hatch); +PU_PAIRF U_PAIRF_set(float x, float y); + +char *wdeleteobject_set(uint32_t *ihObject, WMFHANDLES *wht); +char *wselectobject_set(uint32_t ihObject, WMFHANDLES *wht ); +char *wcreatepenindirect_set(uint32_t *ihPen, WMFHANDLES *wht, U_PEN pen); +char *wcreatebrushindirect_set(uint32_t *ihBrush, WMFHANDLES *wht, U_WLOGBRUSH lb); +char *wcreatedibpatternbrush_srcdib_set(uint32_t *ihBrush, WMFHANDLES *wht, + uint32_t iUsage, const PU_BITMAPINFO Bmi, uint32_t cbPx, const char *Px); +char *wcreatedibpatternbrush_srcbm16_set(uint32_t *ihBrush, WMFHANDLES *wht, + uint32_t iUsage, const PU_BITMAP16 Bm16); +char *wcreatepatternbrush_set(uint32_t *ihBrush, WMFHANDLES *wht, PU_BITMAP16 Bm16, char *Pattern); +char *wcreatefontindirect_set(uint32_t *ihFont, WMFHANDLES *wht, PU_FONT uf); +char *wcreatepalette_set(uint32_t *ihPal, WMFHANDLES *wht, PU_PALETTE up); +char *wsetpaletteentries_set(uint32_t *ihPal, WMFHANDLES *wht, const PU_PALETTE Palletes); +char *wcreateregion_set(uint32_t *ihReg, WMFHANDLES *wht, const PU_REGION Region); +char *wbegin_path_set(void); +char *wend_path_set(void); +char *wlinecap_set(int32_t Type); +char *wlinejoin_set(int32_t Type); +char *wmiterlimit_set(int32_t limit); + + +char *U_WMRHEADER_set(PU_PAIRF size,unsigned int dpi); +char *U_WMREOF_set(void); +char *U_WMRSETBKCOLOR_set(U_COLORREF Color); +char *U_WMRSETBKMODE_set(uint16_t Mode); +char *U_WMRSETMAPMODE_set(uint16_t Mode); +char *U_WMRSETROP2_set(uint16_t Mode); +char *U_WMRSETRELABS_set(void); +char *U_WMRSETPOLYFILLMODE_set(uint16_t Mode); +char *U_WMRSETSTRETCHBLTMODE_set(uint16_t Mode); +char *U_WMRSETTEXTCHAREXTRA_set(uint16_t Mode); +char *U_WMRSETTEXTCOLOR_set(U_COLORREF Color); +char *U_WMRSETTEXTJUSTIFICATION_set(uint16_t Count, uint16_t Extra); +char *U_WMRSETWINDOWORG_set(U_POINT16 coord); +char *U_WMRSETWINDOWEXT_set(U_POINT16 extent); +char *U_WMRSETVIEWPORTORG_set(U_POINT16 coord); +char *U_WMRSETVIEWPORTEXT_set(U_POINT16 extent); +char *U_WMROFFSETWINDOWORG_set(U_POINT16 offset); +char *U_WMRSCALEWINDOWEXT_set(U_POINT16 Denom, U_POINT16 Num); +char *U_WMROFFSETVIEWPORTORG_set(U_POINT16 offset); +char *U_WMRSCALEVIEWPORTEXT_set(U_POINT16 Denom, U_POINT16 Num); +char *U_WMRLINETO_set(U_POINT16 coord); +char *U_WMRMOVETO_set(U_POINT16 coord); +char *U_WMREXCLUDECLIPRECT_set(U_RECT16 rect); +char *U_WMRINTERSECTCLIPRECT_set(U_RECT16 rect); +char *U_WMRARC_set(U_POINT16 StartArc, U_POINT16 EndArc, U_RECT16 rect); +char *U_WMRELLIPSE_set(U_RECT16 rect); +char *U_WMRFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord); +char *U_WMRPIE_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect); +char *U_WMRRECTANGLE_set(U_RECT16 rect); +char *U_WMRROUNDRECT_set(int16_t Width, int16_t Height, U_RECT16 rect); +char *U_WMRPATBLT_set(U_POINT16 Dst, U_POINT16 cwh, uint32_t dwRop3); +char *U_WMRSAVEDC_set(void); +char *U_WMRSETPIXEL_set(U_COLORREF Color, U_POINT16 coord); +char *U_WMROFFSETCLIPRGN_set(U_POINT16 offset); +char *U_WMRTEXTOUT_set(U_POINT16 Dst, char *string); +char *U_WMRBITBLT_set(U_POINT16 Dst, U_POINT16 cwh, U_POINT16 Src, + uint32_t dwRop3, const PU_BITMAP16 Bm16); +char *U_WMRSTRETCHBLT_set(U_POINT16 Dst, U_POINT16 cDst, U_POINT16 Src, + U_POINT16 cSrc, uint32_t dwRop3, const PU_BITMAP16 Bm16); +char *U_WMRPOLYGON_set(uint16_t Length, const PU_POINT16 Data); +char *U_WMRPOLYLINE_set(uint16_t Length, const PU_POINT16 Data); +char *U_WMRESCAPE_set(uint16_t Escape, uint16_t Length, const void *Data); +char *U_WMRRESTOREDC_set(int16_t DC); +char *U_WMRFILLREGION_set(uint16_t Region, uint16_t Brush); +char *U_WMRFRAMEREGION_set(uint16_t Region, uint16_t Brush, int16_t Height, int16_t Width); +char *U_WMRINVERTREGION_set(uint16_t Region); +char *U_WMRPAINTREGION_set(uint16_t Region); +char *U_WMRSELECTCLIPREGION_set(uint16_t Region); +char *U_WMRSELECTOBJECT_set(uint16_t object); +char *U_WMRSETTEXTALIGN_set(uint16_t Mode); +char *U_WMRDRAWTEXT_set(void); /* in Wine, not in WMF PDF. */ +char *U_WMRCHORD_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect); +char *U_WMRSETMAPPERFLAGS_set(uint32_t Mode); +char *U_WMREXTTEXTOUT_set(U_POINT16 Dst, int16_t Length, uint16_t Opts, const char *string, int16_t *dx, U_RECT16 rect); +char *U_WMRSETDIBTODEV_set(void); +char *U_WMRSELECTPALETTE_set(uint16_t Palette); +char *U_WMRREALIZEPALETTE_set(void); +char *U_WMRANIMATEPALETTE_set(PU_PALETTE Palette); +char *U_WMRSETPALENTRIES_set(PU_PALETTE Palette); +char *U_WMRPOLYPOLYGON_set(const uint16_t, const uint16_t *aPolyCounts, const PU_POINT16 points); +char *U_WMRRESIZEPALETTE_set(uint16_t Palette); +char *U_WMR3A_set(void); +char *U_WMR3B_set(void); +char *U_WMR3C_set(void); +char *U_WMR3D_set(void); +char *U_WMR3E_set(void); +char *U_WMR3F_set(void); +char *U_WMRDIBBITBLT_set(U_POINT16 Dst, U_POINT16 cwh, U_POINT16 Src, + uint32_t dwRop3, const PU_BITMAPINFO Bmi, uint32_t cbPx, const char *Px); +char *U_WMRDIBSTRETCHBLT_set(U_POINT16 Dst, U_POINT16 cDst, U_POINT16 Src, + U_POINT16 cSrc, uint32_t dwRop3, const PU_BITMAPINFO Bmi, uint32_t cbPx, const char *Px); +char *U_WMRDIBCREATEPATTERNBRUSH_set(const uint16_t Style, const uint16_t iUsage, + PU_BITMAPINFO Bmi, uint32_t cbPx, const char *Px, PU_BITMAP16 Bm16); +char *U_WMRSTRETCHDIB_set(U_POINT16 Dest, U_POINT16 cDest, U_POINT16 Src, U_POINT16 cSrc, + const uint16_t cUsage, uint32_t dwRop3, const PU_BITMAPINFO Bmi, uint32_t cbPx, const char *Px); +char *U_WMR44_set(void); +char *U_WMR45_set(void); +char *U_WMR46_set(void); +char *U_WMR47_set(void); +char *U_WMREXTFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord); +char *U_WMR49_set(void); +char *U_WMR4A_set(void); +char *U_WMR4B_set(void); +char *U_WMR4C_set(void); +char *U_WMR4D_set(void); +char *U_WMR4E_set(void); +char *U_WMR4F_set(void); +char *U_WMR50_set(void); +char *U_WMR51_set(void); +char *U_WMRABORTDOC_set(void); +char *U_WMR53_set(void); +char *U_WMR54_set(void); +char *U_WMR55_set(void); +char *U_WMR56_set(void); +char *U_WMR57_set(void); +char *U_WMR58_set(void); +char *U_WMR59_set(void); +char *U_WMR5A_set(void); +char *U_WMR5B_set(void); +char *U_WMR5C_set(void); +char *U_WMR5D_set(void); +char *U_WMR5E_set(void); +char *U_WMR5F_set(void); +char *U_WMR60_set(void); +char *U_WMR61_set(void); +char *U_WMR62_set(void); +char *U_WMR63_set(void); +char *U_WMR64_set(void); +char *U_WMR65_set(void); +char *U_WMR66_set(void); +char *U_WMR67_set(void); +char *U_WMR68_set(void); +char *U_WMR69_set(void); +char *U_WMR6A_set(void); +char *U_WMR6B_set(void); +char *U_WMR6C_set(void); +char *U_WMR6D_set(void); +char *U_WMR6E_set(void); +char *U_WMR6F_set(void); +char *U_WMR70_set(void); +char *U_WMR71_set(void); +char *U_WMR72_set(void); +char *U_WMR73_set(void); +char *U_WMR74_set(void); +char *U_WMR75_set(void); +char *U_WMR76_set(void); +char *U_WMR77_set(void); +char *U_WMR78_set(void); +char *U_WMR79_set(void); +char *U_WMR7A_set(void); +char *U_WMR7B_set(void); +char *U_WMR7C_set(void); +char *U_WMR7D_set(void); +char *U_WMR7E_set(void); +char *U_WMR7F_set(void); +char *U_WMR80_set(void); +char *U_WMR81_set(void); +char *U_WMR82_set(void); +char *U_WMR83_set(void); +char *U_WMR84_set(void); +char *U_WMR85_set(void); +char *U_WMR86_set(void); +char *U_WMR87_set(void); +char *U_WMR88_set(void); +char *U_WMR89_set(void); +char *U_WMR8A_set(void); +char *U_WMR8B_set(void); +char *U_WMR8C_set(void); +char *U_WMR8D_set(void); +char *U_WMR8E_set(void); +char *U_WMR8F_set(void); +char *U_WMR90_set(void); +char *U_WMR91_set(void); +char *U_WMR92_set(void); +char *U_WMR93_set(void); +char *U_WMR94_set(void); +char *U_WMR95_set(void); +char *U_WMR96_set(void); +char *U_WMR97_set(void); +char *U_WMR98_set(void); +char *U_WMR99_set(void); +char *U_WMR9A_set(void); +char *U_WMR9B_set(void); +char *U_WMR9C_set(void); +char *U_WMR9D_set(void); +char *U_WMR9E_set(void); +char *U_WMR9F_set(void); +char *U_WMRA0_set(void); +char *U_WMRA1_set(void); +char *U_WMRA2_set(void); +char *U_WMRA3_set(void); +char *U_WMRA4_set(void); +char *U_WMRA5_set(void); +char *U_WMRA6_set(void); +char *U_WMRA7_set(void); +char *U_WMRA8_set(void); +char *U_WMRA9_set(void); +char *U_WMRAA_set(void); +char *U_WMRAB_set(void); +char *U_WMRAC_set(void); +char *U_WMRAD_set(void); +char *U_WMRAE_set(void); +char *U_WMRAF_set(void); +char *U_WMRB0_set(void); +char *U_WMRB1_set(void); +char *U_WMRB2_set(void); +char *U_WMRB3_set(void); +char *U_WMRB4_set(void); +char *U_WMRB5_set(void); +char *U_WMRB6_set(void); +char *U_WMRB7_set(void); +char *U_WMRB8_set(void); +char *U_WMRB9_set(void); +char *U_WMRBA_set(void); +char *U_WMRBB_set(void); +char *U_WMRBC_set(void); +char *U_WMRBD_set(void); +char *U_WMRBE_set(void); +char *U_WMRBF_set(void); +char *U_WMRC0_set(void); +char *U_WMRC1_set(void); +char *U_WMRC2_set(void); +char *U_WMRC3_set(void); +char *U_WMRC4_set(void); +char *U_WMRC5_set(void); +char *U_WMRC6_set(void); +char *U_WMRC7_set(void); +char *U_WMRC8_set(void); +char *U_WMRC9_set(void); +char *U_WMRCA_set(void); +char *U_WMRCB_set(void); +char *U_WMRCC_set(void); +char *U_WMRCD_set(void); +char *U_WMRCE_set(void); +char *U_WMRCF_set(void); +char *U_WMRD0_set(void); +char *U_WMRD1_set(void); +char *U_WMRD2_set(void); +char *U_WMRD3_set(void); +char *U_WMRD4_set(void); +char *U_WMRD5_set(void); +char *U_WMRD6_set(void); +char *U_WMRD7_set(void); +char *U_WMRD8_set(void); +char *U_WMRD9_set(void); +char *U_WMRDA_set(void); +char *U_WMRDB_set(void); +char *U_WMRDC_set(void); +char *U_WMRDD_set(void); +char *U_WMRDE_set(void); +char *U_WMRDF_set(void); +char *U_WMRE0_set(void); +char *U_WMRE1_set(void); +char *U_WMRE2_set(void); +char *U_WMRE3_set(void); +char *U_WMRE4_set(void); +char *U_WMRE5_set(void); +char *U_WMRE6_set(void); +char *U_WMRE7_set(void); +char *U_WMRE8_set(void); +char *U_WMRE9_set(void); +char *U_WMREA_set(void); +char *U_WMREB_set(void); +char *U_WMREC_set(void); +char *U_WMRED_set(void); +char *U_WMREE_set(void); +char *U_WMREF_set(void); +char *U_WMRDELETEOBJECT_set(uint16_t object); +char *U_WMRF1_set(void); +char *U_WMRF2_set(void); +char *U_WMRF3_set(void); +char *U_WMRF4_set(void); +char *U_WMRF5_set(void); +char *U_WMRF6_set(void); +char *U_WMRCREATEPALETTE_set(PU_PALETTE Palette); +char *U_WMRF8_set(void); +char *U_WMRCREATEPATTERNBRUSH_set(PU_BITMAP16 Bm16, char *Pattern); +char *U_WMRCREATEPENINDIRECT_set(U_PEN pen); +char *U_WMRCREATEFONTINDIRECT_set(PU_FONT font); +char *U_WMRCREATEBRUSHINDIRECT_set(U_WLOGBRUSH brush); +char *U_WMRCREATEBITMAPINDIRECT_set(void); /* in Wine, not in WMF PDF*/ +char *U_WMRCREATEBITMAP_set(void); /* in Wine, not in WMF PDF */ +char *U_WMRCREATEREGION_set(PU_REGION region); + +int16_t *dx16_get( int32_t height, uint32_t weight, uint32_t members); +size_t U_WMRRECSAFE_get(const char *contents, const char *blimit); +int wmfheader_get(const char *contents, const char *blimit, PU_WMRPLACEABLE Placeable, PU_WMRHEADER Header); +int wmr_arc_points(U_RECT16 rclBox, U_POINT16 ArcStart, U_POINT16 ArcEnd, + int *f1, int f2, PU_PAIRF center, PU_PAIRF start, PU_PAIRF end, PU_PAIRF size ); +void U_BITMAPINFOHEADER_get(const char *Bmih, uint32_t *Size, int32_t *Width, int32_t *Height, + uint32_t *Planes, uint32_t *BitCount, uint32_t *Compression, uint32_t *SizeImage, + int32_t *XPelsPerMeter, int32_t *YPelsPerMeter, uint32_t *ClrUsed, uint32_t *ClrImportant); +void U_BITMAPCOREHEADER_get(const char *BmiCh, int32_t *Size, int32_t *Width, int32_t *Height, int32_t *BitCount); +int wget_DIB_params(const char *dib, const char **px, const U_RGBQUAD **ct, int32_t *numCt, + int32_t *width, int32_t *height, int32_t *colortype, int32_t *invert); +int U_WMREOF_get(const char *contents); +int U_WMRSETBKCOLOR_get(const char *contents, PU_COLORREF Color); +int U_WMRSETBKMODE_get(const char *contents, uint16_t *Mode); +int U_WMRSETMAPMODE_get(const char *contents, uint16_t *Mode); +int U_WMRSETROP2_get(const char *contents, uint16_t *Mode); +int U_WMRSETRELABS_get(const char *contents); +int U_WMRSETPOLYFILLMODE_get(const char *contents, uint16_t *Mode); +int U_WMRSETSTRETCHBLTMODE_get(const char *contents, uint16_t *Mode); +int U_WMRSETTEXTCHAREXTRA_get(const char *contents, uint16_t *Mode); +int U_WMRSETTEXTCOLOR_get(const char *contents, PU_COLORREF Color); +int U_WMRSETTEXTJUSTIFICATION_get(const char *contents, uint16_t *Count, uint16_t *Extra); +int U_WMRSETWINDOWORG_get(const char *contents, PU_POINT16 coord); +int U_WMRSETWINDOWEXT_get(const char *contents, PU_POINT16 extent); +int U_WMRSETVIEWPORTORG_get(const char *contents, PU_POINT16 coord); +int U_WMRSETVIEWPORTEXT_get(const char *contents, PU_POINT16 extent); +int U_WMROFFSETWINDOWORG_get(const char *contents, PU_POINT16 offset); +int U_WMRSCALEWINDOWEXT_get(const char *contents, PU_POINT16 Denom, PU_POINT16 Num); +int U_WMROFFSETVIEWPORTORG_get(const char *contents, PU_POINT16 offset); +int U_WMRSCALEVIEWPORTEXT_get(const char *contents, PU_POINT16 Denom, PU_POINT16 Num); +int U_WMRLINETO_get(const char *contents, PU_POINT16 coord); +int U_WMRMOVETO_get(const char *contents, PU_POINT16 coord); +int U_WMREXCLUDECLIPRECT_get(const char *contents, PU_RECT16 rect); +int U_WMRINTERSECTCLIPRECT_get(const char *contents, PU_RECT16 rect); +int U_WMRARC_get(const char *contents, PU_POINT16 StartArc, PU_POINT16 EndArc, PU_RECT16 rect); +int U_WMRELLIPSE_get(const char *contents, PU_RECT16 rect); +int U_WMRFLOODFILL_get(const char *contents, uint16_t *Mode, PU_COLORREF Color, PU_POINT16 coord); +int U_WMRPIE_get(const char *contents, PU_POINT16 Radial1, PU_POINT16 Radial2, PU_RECT16 rect); +int U_WMRRECTANGLE_get(const char *contents, PU_RECT16 rect); +int U_WMRROUNDRECT_get(const char *contents, int16_t *Width, int16_t *Height, PU_RECT16 rect); +int U_WMRPATBLT_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cwh, uint32_t *dwRop3); +int U_WMRSAVEDC_get(const char *contents); +int U_WMRSETPIXEL_get(const char *contents, PU_COLORREF Color, PU_POINT16 coord); +int U_WMROFFSETCLIPRGN_get(const char *contents, PU_POINT16 offset); +int U_WMRTEXTOUT_get(const char *contents, PU_POINT16 Dst, int16_t *Length, const char **string); +int U_WMRBITBLT_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cwh, PU_POINT16 Src, uint32_t *dwRop3, PU_BITMAP16 Bm16, const char **px); +int U_WMRSTRETCHBLT_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cDst, PU_POINT16 Src, PU_POINT16 cSrc, uint32_t *dwRop3, PU_BITMAP16 Bm16, const char **px); +int U_WMRPOLYGON_get(const char *contents, uint16_t *Length, const char **Data); +int U_WMRPOLYLINE_get(const char *contents, uint16_t *Length, const char **Data); +int U_WMRESCAPE_get(const char *contents, uint16_t *Escape, uint16_t *Length, const char **Data); +int U_WMRRESTOREDC_get(const char *contents, int16_t *DC); +int U_WMRFILLREGION_get(const char *contents, uint16_t *Region, uint16_t *Brush); +int U_WMRFRAMEREGION_get(const char *contents, uint16_t *Region, uint16_t *Brush, int16_t *Height, int16_t *Width); +int U_WMRINVERTREGION_get(const char *contents, uint16_t *Region); +int U_WMRPAINTREGION_get(const char *contents, uint16_t *Region); +int U_WMRSELECTCLIPREGION_get(const char *contents, uint16_t *Region); +int U_WMRSELECTOBJECT_get(const char *contents, uint16_t *Object); +int U_WMRSETTEXTALIGN_get(const char *contents, uint16_t *Mode); +int U_WMRDRAWTEXT_get(void); /* in Wine, not in WMF PDF. */ +int U_WMRCHORD_get(const char *contents, PU_POINT16 Radial1, PU_POINT16 Radial2, PU_RECT16 rect); +int U_WMRSETMAPPERFLAGS_get(const char *contents, uint32_t *Mode); +int U_WMREXTTEXTOUT_get(const char *contents, PU_POINT16 Dst, int16_t *Length, uint16_t *Opts, const char **string, const int16_t **dx, PU_RECT16 rect); +int U_WMRSETDIBTODEV_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cwh, PU_POINT16 Src, uint16_t *cUsage, uint16_t *ScanCount, uint16_t *StartScan, const char **dib); +int U_WMRSELECTPALETTE_get(const char *contents, uint16_t *Palette); +int U_WMRREALIZEPALETTE_get(const char *contents); +int U_WMRANIMATEPALETTE_get(const char *contents, PU_PALETTE Palette, const char **PalEntries); +int U_WMRSETPALENTRIES_get(const char *contents, PU_PALETTE Palette, const char **PalEntries); +int U_WMRPOLYPOLYGON_get(const char *contents, uint16_t *nPolys, const uint16_t **aPolyCounts, const char **Points); +int U_WMRRESIZEPALETTE_get(const char *contents, uint16_t *Palette); +int U_WMR3A_get(void); +int U_WMR3B_get(void); +int U_WMR3C_get(void); +int U_WMR3D_get(void); +int U_WMR3E_get(void); +int U_WMR3F_get(void); +int U_WMRDIBBITBLT_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cwh, PU_POINT16 Src, uint32_t *dwRop3, const char **dib); +int U_WMRDIBSTRETCHBLT_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cDst, PU_POINT16 Src, PU_POINT16 cSrc, uint32_t *dwRop3, const char **dib); +int U_WMRDIBCREATEPATTERNBRUSH_get(const char *contents, uint16_t *Style, uint16_t *cUsage, const char **Bm16, const char **dib); +int U_WMRSTRETCHDIB_get(const char *contents, PU_POINT16 Dst, PU_POINT16 cDst, PU_POINT16 Src, PU_POINT16 cSrc, uint16_t *cUsage, uint32_t *dwRop3, const char **dib); +int U_WMR44_get(void); +int U_WMR45_get(void); +int U_WMR46_get(void); +int U_WMR47_get(void); +int U_WMREXTFLOODFILL_get(const char *contents, uint16_t *Mode, PU_COLORREF Color, PU_POINT16 coord); +int U_WMR49_get(void); +int U_WMR4A_get(void); +int U_WMR4B_get(void); +int U_WMR4C_get(void); +int U_WMR4D_get(void); +int U_WMR4E_get(void); +int U_WMR4F_get(void); +int U_WMR50_get(void); +int U_WMR51_get(void); +int U_WMRABORTDOC_get(void); +int U_WMR53_get(void); +int U_WMR54_get(void); +int U_WMR55_get(void); +int U_WMR56_get(void); +int U_WMR57_get(void); +int U_WMR58_get(void); +int U_WMR59_get(void); +int U_WMR5A_get(void); +int U_WMR5B_get(void); +int U_WMR5C_get(void); +int U_WMR5D_get(void); +int U_WMR5E_get(void); +int U_WMR5F_get(void); +int U_WMR60_get(void); +int U_WMR61_get(void); +int U_WMR62_get(void); +int U_WMR63_get(void); +int U_WMR64_get(void); +int U_WMR65_get(void); +int U_WMR66_get(void); +int U_WMR67_get(void); +int U_WMR68_get(void); +int U_WMR69_get(void); +int U_WMR6A_get(void); +int U_WMR6B_get(void); +int U_WMR6C_get(void); +int U_WMR6D_get(void); +int U_WMR6E_get(void); +int U_WMR6F_get(void); +int U_WMR70_get(void); +int U_WMR71_get(void); +int U_WMR72_get(void); +int U_WMR73_get(void); +int U_WMR74_get(void); +int U_WMR75_get(void); +int U_WMR76_get(void); +int U_WMR77_get(void); +int U_WMR78_get(void); +int U_WMR79_get(void); +int U_WMR7A_get(void); +int U_WMR7B_get(void); +int U_WMR7C_get(void); +int U_WMR7D_get(void); +int U_WMR7E_get(void); +int U_WMR7F_get(void); +int U_WMR80_get(void); +int U_WMR81_get(void); +int U_WMR82_get(void); +int U_WMR83_get(void); +int U_WMR84_get(void); +int U_WMR85_get(void); +int U_WMR86_get(void); +int U_WMR87_get(void); +int U_WMR88_get(void); +int U_WMR89_get(void); +int U_WMR8A_get(void); +int U_WMR8B_get(void); +int U_WMR8C_get(void); +int U_WMR8D_get(void); +int U_WMR8E_get(void); +int U_WMR8F_get(void); +int U_WMR90_get(void); +int U_WMR91_get(void); +int U_WMR92_get(void); +int U_WMR93_get(void); +int U_WMR94_get(void); +int U_WMR95_get(void); +int U_WMR96_get(void); +int U_WMR97_get(void); +int U_WMR98_get(void); +int U_WMR99_get(void); +int U_WMR9A_get(void); +int U_WMR9B_get(void); +int U_WMR9C_get(void); +int U_WMR9D_get(void); +int U_WMR9E_get(void); +int U_WMR9F_get(void); +int U_WMRA0_get(void); +int U_WMRA1_get(void); +int U_WMRA2_get(void); +int U_WMRA3_get(void); +int U_WMRA4_get(void); +int U_WMRA5_get(void); +int U_WMRA6_get(void); +int U_WMRA7_get(void); +int U_WMRA8_get(void); +int U_WMRA9_get(void); +int U_WMRAA_get(void); +int U_WMRAB_get(void); +int U_WMRAC_get(void); +int U_WMRAD_get(void); +int U_WMRAE_get(void); +int U_WMRAF_get(void); +int U_WMRB0_get(void); +int U_WMRB1_get(void); +int U_WMRB2_get(void); +int U_WMRB3_get(void); +int U_WMRB4_get(void); +int U_WMRB5_get(void); +int U_WMRB6_get(void); +int U_WMRB7_get(void); +int U_WMRB8_get(void); +int U_WMRB9_get(void); +int U_WMRBA_get(void); +int U_WMRBB_get(void); +int U_WMRBC_get(void); +int U_WMRBD_get(void); +int U_WMRBE_get(void); +int U_WMRBF_get(void); +int U_WMRC0_get(void); +int U_WMRC1_get(void); +int U_WMRC2_get(void); +int U_WMRC3_get(void); +int U_WMRC4_get(void); +int U_WMRC5_get(void); +int U_WMRC6_get(void); +int U_WMRC7_get(void); +int U_WMRC8_get(void); +int U_WMRC9_get(void); +int U_WMRCA_get(void); +int U_WMRCB_get(void); +int U_WMRCC_get(void); +int U_WMRCD_get(void); +int U_WMRCE_get(void); +int U_WMRCF_get(void); +int U_WMRD0_get(void); +int U_WMRD1_get(void); +int U_WMRD2_get(void); +int U_WMRD3_get(void); +int U_WMRD4_get(void); +int U_WMRD5_get(void); +int U_WMRD6_get(void); +int U_WMRD7_get(void); +int U_WMRD8_get(void); +int U_WMRD9_get(void); +int U_WMRDA_get(void); +int U_WMRDB_get(void); +int U_WMRDC_get(void); +int U_WMRDD_get(void); +int U_WMRDE_get(void); +int U_WMRDF_get(void); +int U_WMRE0_get(void); +int U_WMRE1_get(void); +int U_WMRE2_get(void); +int U_WMRE3_get(void); +int U_WMRE4_get(void); +int U_WMRE5_get(void); +int U_WMRE6_get(void); +int U_WMRE7_get(void); +int U_WMRE8_get(void); +int U_WMRE9_get(void); +int U_WMREA_get(void); +int U_WMREB_get(void); +int U_WMREC_get(void); +int U_WMRED_get(void); +int U_WMREE_get(void); +int U_WMREF_get(void); +int U_WMRDELETEOBJECT_get(const char *contents, uint16_t *Object); +int U_WMRF1_get(void); +int U_WMRF2_get(void); +int U_WMRF3_get(void); +int U_WMRF4_get(void); +int U_WMRF5_get(void); +int U_WMRF6_get(void); +int U_WMRCREATEPALETTE_get(const char *contents, PU_PALETTE Palette, const char **PalEntries); +int U_WMRF8_get(void); +int U_WMRCREATEPATTERNBRUSH_get(const char *contents, PU_BITMAP16 Bm16, int *pasize, const char **Pattern); +int U_WMRCREATEPENINDIRECT_get(const char *contents, PU_PEN pen); +int U_WMRCREATEFONTINDIRECT_get(const char *contents, const char **font); +int U_WMRCREATEBRUSHINDIRECT_get(const char *contents, const char **brush); +int U_WMRCREATEBITMAPINDIRECT_get(void); +int U_WMRCREATEBITMAP_get(void); +int U_WMRCREATEREGION_get(const char *contents, const char **Region); + + +#ifdef __cplusplus +} +#endif + +#endif /* _UWMF_ */ diff --git a/src/extension/internal/uwmf_endian.c b/src/extension/internal/uwmf_endian.c new file mode 100644 index 000000000..e14c7aa77 --- /dev/null +++ b/src/extension/internal/uwmf_endian.c @@ -0,0 +1,1772 @@ +/** + @file uwmf_endian.c Functions for Swaping WMF records +*/ + +/* +File: uwmf_endian.c +Version: 0.1.2 +Date: 18-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> /* for offsetof() */ +#include <string.h> +#include "uwmf.h" +#include "uwmf_endian.h" + +// hide almost everything in this file from Doxygen +//! @cond +/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed +to be used in end user code. */ + +void U_swap2(void *ul, unsigned int count); +void U_swap4(void *ul, unsigned int count); +void bitmapinfo_swap(char *Bmi); + +/* ********************************************************************************************** + These functions Swap standard objects used in the WMR records. + The low level ones do not append EOL. +*********************************************************************************************** */ + +/** + \brief Swap U_BITMAP16 object + \param b U_BITMAP16 object +*/ +void bitmap16_swap( + char *b + ){ + U_swap2(b,4); /* Type, Width, Height, WidthBytes */ + /* Planes and BitsPixel are bytes, so no swap needed */ + /* Bits[] pixel data should already be in order */ +} + +/** + \brief Swap a U_BRUSH object. + \param b U_BRUSH object. + style bColor bHatch + U_BS_SOLID ColorRef Object Not used (bytes present???) + U_BS_NULL ignored ignored (bytes present???). + U_BS_PATTERN ignored Bitmap16 object holding patern + U_BS_DIBPATTERNPT ColorUsage Enum DIB object + U_BS_HATCHED ColorRef Object HatchStyle Enumeration +*/ +void brush_swap( + char *b, + int torev + ){ + int Style; + if(torev){ Style = *(uint16_t *)(b + offsetof(U_BRUSH,Style)); } + U_swap2(b + offsetof(U_BRUSH,Style),1); + if(!torev){ Style = *(uint16_t *)(b + offsetof(U_BRUSH,Style)); } + /* Color is already in the right order */ + switch(Style){ + case U_BS_SOLID: + /* no/ignored data field */ + break; + case U_BS_NULL: + /* no/ignored data field */ + break; + case U_BS_PATTERN: + bitmap16_swap(b + offsetof(U_BRUSH,Data)); + break; + case U_BS_DIBPATTERNPT: + bitmapinfo_swap(b + offsetof(U_BRUSH,Data)); + break; + case U_BS_HATCHED: + /* no/ignored data field */ + break; + } +} + +/** + \brief Swap a U_FONT object from pointer. + \param lf U_FONT object +*/ +void font_swap( + char *f + ){ + U_swap2(f + offsetof(U_FONT,Height),5); /*Height, Width, Escapement, Orientation, Weight */ + /* Other fields are single bytes */ +} + +/** + \brief Swap a pointer to a U_PALETTE object. + \param lp Pointer to a U_PALETTE object. +*/ +void palette_swap( + char *p + ){ + U_swap2(p + offsetof(U_PALETTE,Start),2); /* Start, NumEntries*/ + /* PalEntries[1] is byte ordered, so no need to swap */ +} + +/** + \brief Swap a U_PEN object. + \param p U_PEN object +*/ +void pen_swap( + char *p + ){ + U_swap2(p + offsetof(U_PEN,Style),3); /* Style,Widthw[0],Widthw[1] */ + /* Color already in order */ +} + +/* there are no + void rect16_ltrb_swap() + void rect16_brtl_swap() +because rectangles are swapped using U_swap2 as an array of 4 int16 values. +*/ + + +/** + \brief Swap U_REGION object + \param rect U_REGION object + \param torev + PARTIAL IMPLEMENTATION +*/ +void region_swap( + char *reg, + int torev + ){ + int Size; + if(torev){ Size = *(int16_t *)(reg + offsetof(U_REGION,Size)); } + U_swap2(reg,10); /* ignore1 through sRrect*/ + if(!torev){ Size = *(int16_t *)(reg + offsetof(U_REGION,Size)); } + U_swap2(reg + U_SIZE_REGION, (Size - U_SIZE_REGION)/2); /* aScans */ +} + + +/** + \brief Swap U_BITMAPCOREHEADER object + \param ch U_BITMAPCOREHEADER object +*/ +void bitmapcoreheader_swap( + char *ch + ){ + U_swap4(ch + offsetof(U_BITMAPCOREHEADER,Size_4), 1); /* Size_4, may not be aligned */ + U_swap2(ch + offsetof(U_BITMAPCOREHEADER,Width),4); /* Width, Height, Planes, BitCount, */ +} + +/** LogBrushW Object WMF PDF 2.2.2.10 + \brief Swap a U_WLOGBRUSH object. + \param lb U_WLOGBRUSH object. + + style Color Hatch + U_BS_SOLID ColorRef Object Not used (bytes present???) + U_BS_NULL ignored ignored (bytes present???). + U_BS_PATTERN ignored not used (Action is not strictly defined) + U_BS_DIBPATTERN ignored not used (Action is not strictly defined) + U_BS_DIBPATTERNPT ignored not used (Action is not strictly defined) + U_BS_HATCHED ColorRef Object HatchStyle Enumeration +*/ +void wlogbrush_swap( + char *lb + ){ + U_swap2(lb + offsetof(U_WLOGBRUSH,Style),1); + /* Color is already in order */ + U_swap2(lb + offsetof(U_WLOGBRUSH,Hatch),1); +} + +/** + \brief Swap U_POLYPOLY object from pointer + \param pp PU_POLYPOLY object +*/ +void polypolygon_swap( + char *pp, + int torev + ){ + int i,totPoints; + uint16_t nPolys; + uint16_t *aPolyCounts; + if(torev){ nPolys = *(uint16_t *)(pp + offsetof(U_POLYPOLYGON, nPolys)); } + U_swap2(pp + offsetof(U_POLYPOLYGON, nPolys),1); + if(!torev){ nPolys = *(uint16_t *)(pp + offsetof(U_POLYPOLYGON, nPolys)); } + aPolyCounts = (uint16_t *)(pp + offsetof(U_POLYPOLYGON, aPolyCounts)); + if(torev){ + for(totPoints=0,i=0;i<nPolys; i++){ totPoints += aPolyCounts[i]; } + } + U_swap2(aPolyCounts,nPolys); + if(!torev){ + for(totPoints=0,i=0;i<nPolys; i++){ totPoints += aPolyCounts[i]; } + } + U_swap2(&(aPolyCounts[nPolys]),2*totPoints); /* 2 coords/ point */ +} + +/** + \brief Swap U_SCAN object + \param pp U_SCAN object +*/ +void scan_swap( + char *sc, + int torev + ){ + int count; + if(torev){ count = *(uint16_t *)sc; } + U_swap2(sc,3); /*count, top, bottom */ + if(!torev){ count = *(uint16_t *)sc; } + U_swap2(sc + offsetof(U_SCAN,ScanLines),count); +} + +/** + \brief Swap a summary of a DIB header + A DIB header in an WMF may be either a BitmapCoreHeader or BitmapInfoHeader. + \param dh void pointer to DIB header +*/ +void dibheader_swap( + char *dh, + int torev + ){ + int Size; + memcpy(&Size, dh, 4); /* may not be aligned */ + if(!torev)U_swap4(&Size,1); + if(Size == 0xC){ + bitmapcoreheader_swap(dh); + } + else { + bitmapinfo_swap(dh); + } +} + +/** + \brief Swap WMF header object + \param head uint8_t pointer to header + \returns size of entire header structure + + If the header is preceded by a placeable struture, Swap that as well. +*/ +int wmfheader_swap( + char *contents, + int torev + ){ + uint32_t Key,Size16w; + int size=0; + Key=*(uint32_t *)(contents + offsetof(U_WMRPLACEABLE,Key)); + if(!torev)U_swap4(&Key,1); + if(Key == 0x9AC6CDD7){ + U_swap4(contents + offsetof(U_WMRPLACEABLE,Key ),1); + U_swap2(contents + offsetof(U_WMRPLACEABLE,HWmf ),1); + U_swap2(contents + offsetof(U_WMRPLACEABLE,Dst ),4); + U_swap2(contents + offsetof(U_WMRPLACEABLE,Inch ),1); + U_swap4(contents + offsetof(U_WMRPLACEABLE,Reserved),1); + U_swap2(contents + offsetof(U_WMRPLACEABLE,Checksum),1); + contents += U_SIZE_WMRPLACEABLE; + size += U_SIZE_WMRPLACEABLE; + } + if(torev){ Size16w = *(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w)); } + U_swap2(contents + offsetof(U_WMRHEADER,Size16w),2);/* Size16w, Version */ + if(!torev){ Size16w = *(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w)); } + U_swap4(contents + offsetof(U_WMRHEADER,Sizew ),1);/* Sizew */ + U_swap2(contents + offsetof(U_WMRHEADER,nObjects),1);/* nObjects */ + U_swap4(contents + offsetof(U_WMRHEADER,maxSize ),1);/* maxSize */ + U_swap2(contents + offsetof(U_WMRHEADER,nMembers),1);/* nMembers */ + size += 2*Size16w; + return(size); +} + + + +// hide these from Doxygen +//! @cond +/* ********************************************************************************************** +These functions contain shared code used by various U_WMR*_Swap functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. +*********************************************************************************************** */ + +/* Size16 EVERY record type should call this, directly or indirectly*/ +void U_WMRCORE_SIZE16_swap(char *record, int torev){ + torev = torev; // shuts up compiler warnings about unused parameters + U_swap4(record, 1); /* Size16_4 is at offset 0 in U_METARECORD */ +} + + +/* Size16, move to data, Single 32bit followed by array of N16 U_POINT16 */ +void U_WMRCORE_U32_N16_swap(char *record, int N16, int torev){ + int off=U_SIZE_METARECORD; + U_WMRCORE_SIZE16_swap(record, torev); + U_swap4(record + off, 1); off+=4; + U_swap2(record + off, N16); +} + +/* Single 16bit nPoints followed by array of nPoints U_POINT16 */ +void U_WMRCORE_U16_N16_swap(char *record, int torev){ + int nPoints; + U_WMRCORE_SIZE16_swap(record, torev); + if(torev){ nPoints = *(uint16_t *)(record + offsetof(U_WMRPOLYGON,nPoints)); } + U_swap2(record + offsetof(U_WMRPOLYGON,nPoints), 1); + if(!torev){ nPoints = *(uint16_t *)(record + offsetof(U_WMRPOLYGON,nPoints)); } + U_swap2(record + offsetof(U_WMRPOLYGON,aPoints), 2*nPoints); +} + +/* all records that specify palette objects */ +void U_WMRCORE_PALETTE_swap(char *record, int torev){ + torev = torev; // shuts up compiler warnings about unused parameters + U_WMRCORE_SIZE16_swap(record, torev); + palette_swap(record + offsetof(U_WMRANIMATEPALETTE,Palette)); +} + +/* all records that have N int16 values, unconditionally swapped */ +void U_WMRCORE_N16_swap(char *record, int N16, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + U_swap2(record+U_SIZE_METARECORD, N16); +} + + +/* like floodfill */ +void U_WMRCORE_U16_CR_2U16_swap(char *record, int torev){ + int off = U_SIZE_METARECORD; + U_WMRCORE_SIZE16_swap(record, torev); + U_swap2(record+off, 1); off += 2 + sizeof(U_COLORREF); + U_swap2(record+off, 2); +} + + +//! @endcond + +/* ********************************************************************************************** +These are the core WMR functions, each creates a particular type of record. +All return these records via a char* pointer, which is NULL if the call failed. +They are listed in order by the corresponding U_EMR_* index number. +*********************************************************************************************** */ + +/** + \brief Swap a pointer to a U_WMR_whatever record which has not been implemented. + \param name name of this type of record + \param contents pointer to a buffer holding all EMR records + \param recnum number of this record in contents + \param off offset to this record in contents +*/ +void U_WMRNOTIMPLEMENTED_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMREOF_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRSETBKCOLOR_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRSETBKMODE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETMAPMODE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETROP2_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETRELABS_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRSETPOLYFILLMODE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETSTRETCHBLTMODE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETTEXTCHAREXTRA_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETTEXTCOLOR_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRSETTEXTJUSTIFICATION_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRSETWINDOWORG_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRSETWINDOWEXT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRSETVIEWPORTORG_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRSETVIEWPORTEXT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMROFFSETWINDOWORG_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRSCALEWINDOWEXT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMROFFSETVIEWPORTORG_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRSCALEVIEWPORTEXT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMRLINETO_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRMOVETO_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMREXCLUDECLIPRECT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMRINTERSECTCLIPRECT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMRARC_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record, 8, torev); +} + +void U_WMRELLIPSE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMRFLOODFILL_swap(char *record, int torev){ + U_WMRCORE_U16_CR_2U16_swap(record, torev); +} + +void U_WMRPIE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record, 8, torev); +} + +void U_WMRRECTANGLE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMRROUNDRECT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,6,torev); +} + +void U_WMRPATBLT_swap(char *record, int torev){ + U_WMRCORE_U32_N16_swap(record,4,torev); +} + +void U_WMRSAVEDC_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRSETPIXEL_swap(char *record, int torev){ + int off = U_SIZE_METARECORD + sizeof(U_COLORREF); + U_WMRCORE_SIZE16_swap(record, torev); + U_swap2(record+off, 2); +} + +void U_WMROFFSETCLIPRGN_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRTEXTOUT_swap(char *record, int torev){ + int L2; + if(torev){ L2 = *(int16_t *)(record + U_SIZE_METARECORD); } /* Length field */ + U_WMRCORE_N16_swap(record,1,torev); /* Length */ + if(!torev){ L2 = *(int16_t *)(record + U_SIZE_METARECORD); } /* Length field */ + /* string is in bytes, do not swap that */ + U_swap2(record + U_SIZE_WMRTEXTOUT + L2, 2); /* y,x */ +} + +void U_WMRBITBLT_swap(char *record, int torev){ + uint32_t Size16; + uint8_t xb; + memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4); + if(!torev)U_swap4(&Size16,1); + xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb)); + if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */ + U_WMRCORE_U32_N16_swap(record,7,torev); + } + else { /* yes bitmap */ + U_WMRCORE_U32_N16_swap(record,6,torev); + bitmap16_swap(record + offsetof(U_WMRBITBLT_PX,bitmap)); + } +} + +void U_WMRSTRETCHBLT_swap(char *record, int torev){ + uint32_t Size16; + uint8_t xb; + memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4); + if(!torev)U_swap4(&Size16,1); + xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb)); + if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */ + U_WMRCORE_U32_N16_swap(record,9,torev); + } + else { /* yes bitmap */ + U_WMRCORE_U32_N16_swap(record,8,torev); + bitmap16_swap(record + offsetof(U_WMRSTRETCHBLT_PX,bitmap)); + } +} + +void U_WMRPOLYGON_swap(char *record, int torev){ + U_WMRCORE_U16_N16_swap(record, torev); +} + +void U_WMRPOLYLINE_swap(char *record, int torev){ + U_WMRCORE_U16_N16_swap(record, torev); +} + +void U_WMRESCAPE_swap(char *record, int torev){ + uint16_t eFunc; + + if(torev){ eFunc = *(uint16_t *)(record + offsetof(U_WMRESCAPE,eFunc)); } + U_WMRCORE_N16_swap(record,2,torev); + if(!torev){ eFunc = *(uint16_t *)(record + offsetof(U_WMRESCAPE,eFunc)); } + /* Handle data swapping for three types only, anything else end user code must handle */ + if((eFunc == U_MFE_SETLINECAP) || (eFunc == U_MFE_SETLINEJOIN) || (eFunc == U_MFE_SETMITERLIMIT)){ + U_swap4(record + offsetof(U_WMRESCAPE, Data),1); + } +} + +void U_WMRRESTOREDC_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRFILLREGION_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,2,torev); +} + +void U_WMRFRAMEREGION_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,4,torev); +} + +void U_WMRINVERTREGION_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRPAINTREGION_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSELECTCLIPREGION_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSELECTOBJECT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRSETTEXTALIGN_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRDRAWTEXT_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCHORD_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record, 8, torev); +} + +void U_WMRSETMAPPERFLAGS_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMREXTTEXTOUT_swap(char *record, int torev){ + int off,Length,Len2,Opts; + U_swap4(record + offsetof(U_WMREXTTEXTOUT,Size16_4),1); + if(torev){ + Length = *(int16_t *)( record + offsetof(U_WMREXTTEXTOUT,Length)); + Opts = *(uint16_t *)(record + offsetof(U_WMREXTTEXTOUT,Opts)); + } + U_swap2(record + offsetof(U_WMREXTTEXTOUT,y), 4); /* y,x,Length,Opts*/ + if(!torev){ + Length = *(int16_t *)( record + offsetof(U_WMREXTTEXTOUT,Length)); + Opts = *(uint16_t *)(record + offsetof(U_WMREXTTEXTOUT,Opts)); + } + off = U_SIZE_WMREXTTEXTOUT; + if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){ + U_swap2(record + off,4); off += 8; + } + Len2 = (Length & 1 ? Length + 1 : Length); + off += Len2; /* no need to swap string, it is a byte array */ + U_swap2(record+off,Length); /* swap the dx array */ +} + +void U_WMRSETDIBTODEV_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record, 9, torev); + dibheader_swap(record + offsetof(U_WMRSETDIBTODEV,dib), torev); +} + +void U_WMRSELECTPALETTE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRREALIZEPALETTE_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); +} + +void U_WMRANIMATEPALETTE_swap(char *record, int torev){ + U_WMRCORE_PALETTE_swap(record, torev); +} + +void U_WMRSETPALENTRIES_swap(char *record, int torev){ + U_WMRCORE_PALETTE_swap(record, torev); +} + +void U_WMRPOLYPOLYGON_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + polypolygon_swap(record + offsetof(U_WMRPOLYPOLYGON,PPolygon), torev); +} + +void U_WMRRESIZEPALETTE_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMR3A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR3B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR3C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR3D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR3E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR3F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDIBBITBLT_swap(char *record, int torev){ + uint32_t Size16; + uint8_t xb; + memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4); + if(!torev)U_swap4(&Size16,1); + xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb)); + if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */ + U_WMRCORE_U32_N16_swap(record,7,torev); + } + else { /* yes bitmap */ + U_WMRCORE_U32_N16_swap(record,6,torev); + dibheader_swap(record + offsetof(U_WMRDIBBITBLT_PX,dib), torev); + } +} + +void U_WMRDIBSTRETCHBLT_swap(char *record, int torev){ + uint32_t Size16; + uint8_t xb; + memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4); + if(!torev)U_swap4(&Size16,1); + xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb)); + if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */ + U_WMRCORE_U32_N16_swap(record,9,torev); + } + else { /* yes bitmap */ + U_WMRCORE_U32_N16_swap(record,8,torev); + dibheader_swap(record + offsetof(U_WMRDIBSTRETCHBLT_PX,dib), torev); + } +} + +void U_WMRDIBCREATEPATTERNBRUSH_swap(char *record, int torev){ + int Style; + if(torev){ Style = *(uint16_t *)(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Style)); } + U_WMRCORE_N16_swap(record,2,torev); /* Style and cUsage */ + if(!torev){ Style = *(uint16_t *)(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Style)); } + if(Style == U_BS_PATTERN){ + bitmap16_swap(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Src)); + } + else { + dibheader_swap(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Src), torev); + } +} + +void U_WMRSTRETCHDIB_swap(char *record, int torev){ + torev = torev; + U_WMRCORE_U32_N16_swap(record,9,torev); + dibheader_swap(record + offsetof(U_WMRSTRETCHDIB,dib), torev); +} + +void U_WMR44_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR45_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR46_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR47_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMREXTFLOODFILL_swap(char *record, int torev){ + U_WMRCORE_U16_CR_2U16_swap(record, torev); +} + +void U_WMR49_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR4A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR4B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR4C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR4D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR4E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR4F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR50_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR51_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR52_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR53_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR54_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR55_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR56_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR57_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR58_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR59_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR5A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR5B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR5C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR5D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR5E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR5F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR60_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR61_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR62_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR63_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR64_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR65_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR66_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR67_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR68_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR69_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR6A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR6B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR6C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR6D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR6E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR6F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR70_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR71_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR72_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR73_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR74_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR75_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR76_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR77_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR78_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR79_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR7A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR7B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR7C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR7D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR7E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR7F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR80_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR81_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR82_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR83_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR84_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR85_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR86_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR87_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR88_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR89_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR8A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR8B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR8C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR8D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR8E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR8F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR90_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR91_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR92_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR93_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR94_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR95_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR96_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR97_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR98_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR99_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR9A_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR9B_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR9C_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR9D_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR9E_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMR9F_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA0_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA1_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA2_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA3_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA4_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA5_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA6_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA7_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA8_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRA9_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRAA_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRAB_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRAC_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRAD_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRAE_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRAF_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB0_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB1_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB2_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB3_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB4_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB5_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB6_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB7_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB8_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRB9_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRBA_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRBB_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRBC_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRBD_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRBE_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRBF_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC0_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC1_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC2_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC3_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC4_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC5_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC6_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC7_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC8_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRC9_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCA_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCB_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCC_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCD_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCE_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCF_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD0_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD1_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD2_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD3_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD4_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD5_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD6_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD7_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD8_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRD9_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDA_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDB_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDC_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDD_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDE_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDF_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE0_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE1_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE2_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE3_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE4_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE5_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE6_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE7_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE8_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRE9_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMREA_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMREB_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMREC_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRED_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMREE_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMREF_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRDELETEOBJECT_swap(char *record, int torev){ + U_WMRCORE_N16_swap(record,1,torev); +} + +void U_WMRF1_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRF2_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRF3_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRF4_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRF5_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRF6_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCREATEPALETTE_swap(char *record, int torev){ + U_WMRCORE_PALETTE_swap(record, torev); +} + +void U_WMRF8_swap(char *record, int torev){ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCREATEPATTERNBRUSH_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + bitmap16_swap(record + U_SIZE_METARECORD); + /* pattern array byte order already correct? */ +} + +void U_WMRCREATEPENINDIRECT_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + pen_swap(record + offsetof(U_WMRCREATEPENINDIRECT,pen)); +} + +void U_WMRCREATEFONTINDIRECT_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + font_swap(record + offsetof(U_WMRCREATEFONTINDIRECT,font)); +} + +void U_WMRCREATEBRUSHINDIRECT_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + wlogbrush_swap(record + offsetof(U_WMRCREATEBRUSHINDIRECT,brush)); +} + +void U_WMRCREATEBITMAPINDIRECT_swap(char *record, int torev){ /* in Wine, not in WMF PDF */ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCREATEBITMAP_swap(char *record, int torev){ /* in Wine, not in WMF PDF */ + U_WMRNOTIMPLEMENTED_swap(record, torev); +} + +void U_WMRCREATEREGION_swap(char *record, int torev){ + U_WMRCORE_SIZE16_swap(record, torev); + region_swap(record + offsetof(U_WMRCREATEREGION,region), torev); +} +//! @endcond + +/** + \brief Convert an entire WMF in memory from Big Endian to Little Endian (or vice versa). + \return 0 on failure, 1 on success + \param contents pointer to the buffer holding the entire EMF in memory + \param length number of bytes in the buffer + \param torev 1 for native to reversed, 0 for reversed to native + + Normally this would be called immediately before writing the data to a file + or immediately after reading the data from a file. +*/ +int U_wmf_endian(char *contents, size_t length, int torev){ + size_t off; + uint32_t OK, Size16; + uint8_t iType; + char *record; + int recnum, offset; + + record = contents; + off = wmfheader_swap(record,torev); fflush(stdout); /* WMF header is not a normal record, handle it separately */ + record += off; + offset = off; + OK = 1; + recnum = 1; /* used when debugging */ + + while(OK){ + if(record > contents + length){ return(0); } // this is most likely a corrupt WMF + + memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4); /* This may not be aligned */ + if(!torev){ U_swap4(&Size16,1); } + iType = *(uint8_t *)(record + offsetof(U_METARECORD,iType)); + +//printf("DEBUG U_wmf_endian before switch record:%d offset:%d type:%d name:%s Size16:%d\n",recnum,offset,iType,U_wmr_names(iType),Size16);fflush(stdout); + switch (iType) + { + case U_WMR_EOF: U_WMREOF_swap(record, torev); OK=0; break; + case U_WMR_SETBKCOLOR: U_WMRSETBKCOLOR_swap(record, torev); break; + case U_WMR_SETBKMODE: U_WMRSETBKMODE_swap(record, torev); break; + case U_WMR_SETMAPMODE: U_WMRSETMAPMODE_swap(record, torev); break; + case U_WMR_SETROP2: U_WMRSETROP2_swap(record, torev); break; + case U_WMR_SETRELABS: U_WMRSETRELABS_swap(record, torev); break; + case U_WMR_SETPOLYFILLMODE: U_WMRSETPOLYFILLMODE_swap(record, torev); break; + case U_WMR_SETSTRETCHBLTMODE: U_WMRSETSTRETCHBLTMODE_swap(record, torev); break; + case U_WMR_SETTEXTCHAREXTRA: U_WMRSETTEXTCHAREXTRA_swap(record, torev); break; + case U_WMR_SETTEXTCOLOR: U_WMRSETTEXTCOLOR_swap(record, torev); break; + case U_WMR_SETTEXTJUSTIFICATION: U_WMRSETTEXTJUSTIFICATION_swap(record, torev); break; + case U_WMR_SETWINDOWORG: U_WMRSETWINDOWORG_swap(record, torev); break; + case U_WMR_SETWINDOWEXT: U_WMRSETWINDOWEXT_swap(record, torev); break; + case U_WMR_SETVIEWPORTORG: U_WMRSETVIEWPORTORG_swap(record, torev); break; + case U_WMR_SETVIEWPORTEXT: U_WMRSETVIEWPORTEXT_swap(record, torev); break; + case U_WMR_OFFSETWINDOWORG: U_WMROFFSETWINDOWORG_swap(record, torev); break; + case U_WMR_SCALEWINDOWEXT: U_WMRSCALEWINDOWEXT_swap(record, torev); break; + case U_WMR_OFFSETVIEWPORTORG: U_WMROFFSETVIEWPORTORG_swap(record, torev); break; + case U_WMR_SCALEVIEWPORTEXT: U_WMRSCALEVIEWPORTEXT_swap(record, torev); break; + case U_WMR_LINETO: U_WMRLINETO_swap(record, torev); break; + case U_WMR_MOVETO: U_WMRMOVETO_swap(record, torev); break; + case U_WMR_EXCLUDECLIPRECT: U_WMREXCLUDECLIPRECT_swap(record, torev); break; + case U_WMR_INTERSECTCLIPRECT: U_WMRINTERSECTCLIPRECT_swap(record, torev); break; + case U_WMR_ARC: U_WMRARC_swap(record, torev); break; + case U_WMR_ELLIPSE: U_WMRELLIPSE_swap(record, torev); break; + case U_WMR_FLOODFILL: U_WMRFLOODFILL_swap(record, torev); break; + case U_WMR_PIE: U_WMRPIE_swap(record, torev); break; + case U_WMR_RECTANGLE: U_WMRRECTANGLE_swap(record, torev); break; + case U_WMR_ROUNDRECT: U_WMRROUNDRECT_swap(record, torev); break; + case U_WMR_PATBLT: U_WMRPATBLT_swap(record, torev); break; + case U_WMR_SAVEDC: U_WMRSAVEDC_swap(record, torev); break; + case U_WMR_SETPIXEL: U_WMRSETPIXEL_swap(record, torev); break; + case U_WMR_OFFSETCLIPRGN: U_WMROFFSETCLIPRGN_swap(record, torev); break; + case U_WMR_TEXTOUT: U_WMRTEXTOUT_swap(record, torev); break; + case U_WMR_BITBLT: U_WMRBITBLT_swap(record, torev); break; + case U_WMR_STRETCHBLT: U_WMRSTRETCHBLT_swap(record, torev); break; + case U_WMR_POLYGON: U_WMRPOLYGON_swap(record, torev); break; + case U_WMR_POLYLINE: U_WMRPOLYLINE_swap(record, torev); break; + case U_WMR_ESCAPE: U_WMRESCAPE_swap(record, torev); break; + case U_WMR_RESTOREDC: U_WMRRESTOREDC_swap(record, torev); break; + case U_WMR_FILLREGION: U_WMRFILLREGION_swap(record, torev); break; + case U_WMR_FRAMEREGION: U_WMRFRAMEREGION_swap(record, torev); break; + case U_WMR_INVERTREGION: U_WMRINVERTREGION_swap(record, torev); break; + case U_WMR_PAINTREGION: U_WMRPAINTREGION_swap(record, torev); break; + case U_WMR_SELECTCLIPREGION: U_WMRSELECTCLIPREGION_swap(record, torev); break; + case U_WMR_SELECTOBJECT: U_WMRSELECTOBJECT_swap(record, torev); break; + case U_WMR_SETTEXTALIGN: U_WMRSETTEXTALIGN_swap(record, torev); break; + case U_WMR_DRAWTEXT: U_WMRDRAWTEXT_swap(record, torev); break; + case U_WMR_CHORD: U_WMRCHORD_swap(record, torev); break; + case U_WMR_SETMAPPERFLAGS: U_WMRSETMAPPERFLAGS_swap(record, torev); break; + case U_WMR_EXTTEXTOUT: U_WMREXTTEXTOUT_swap(record, torev); break; + case U_WMR_SETDIBTODEV: U_WMRSETDIBTODEV_swap(record, torev); break; + case U_WMR_SELECTPALETTE: U_WMRSELECTPALETTE_swap(record, torev); break; + case U_WMR_REALIZEPALETTE: U_WMRREALIZEPALETTE_swap(record, torev); break; + case U_WMR_ANIMATEPALETTE: U_WMRANIMATEPALETTE_swap(record, torev); break; + case U_WMR_SETPALENTRIES: U_WMRSETPALENTRIES_swap(record, torev); break; + case U_WMR_POLYPOLYGON: U_WMRPOLYPOLYGON_swap(record, torev); break; + case U_WMR_RESIZEPALETTE: U_WMRRESIZEPALETTE_swap(record, torev); break; + case U_WMR_3A: U_WMR3A_swap(record, torev); break; + case U_WMR_3B: U_WMR3B_swap(record, torev); break; + case U_WMR_3C: U_WMR3C_swap(record, torev); break; + case U_WMR_3D: U_WMR3D_swap(record, torev); break; + case U_WMR_3E: U_WMR3E_swap(record, torev); break; + case U_WMR_3F: U_WMR3F_swap(record, torev); break; + case U_WMR_DIBBITBLT: U_WMRDIBBITBLT_swap(record, torev); break; + case U_WMR_DIBSTRETCHBLT: U_WMRDIBSTRETCHBLT_swap(record, torev); break; + case U_WMR_DIBCREATEPATTERNBRUSH: U_WMRDIBCREATEPATTERNBRUSH_swap(record, torev); break; + case U_WMR_STRETCHDIB: U_WMRSTRETCHDIB_swap(record, torev); break; + case U_WMR_44: U_WMR44_swap(record, torev); break; + case U_WMR_45: U_WMR45_swap(record, torev); break; + case U_WMR_46: U_WMR46_swap(record, torev); break; + case U_WMR_47: U_WMR47_swap(record, torev); break; + case U_WMR_EXTFLOODFILL: U_WMREXTFLOODFILL_swap(record, torev); break; + case U_WMR_49: U_WMR49_swap(record, torev); break; + case U_WMR_4A: U_WMR4A_swap(record, torev); break; + case U_WMR_4B: U_WMR4B_swap(record, torev); break; + case U_WMR_4C: U_WMR4C_swap(record, torev); break; + case U_WMR_4D: U_WMR4D_swap(record, torev); break; + case U_WMR_4E: U_WMR4E_swap(record, torev); break; + case U_WMR_4F: U_WMR4F_swap(record, torev); break; + case U_WMR_50: U_WMR50_swap(record, torev); break; + case U_WMR_51: U_WMR51_swap(record, torev); break; + case U_WMR_52: U_WMR52_swap(record, torev); break; + case U_WMR_53: U_WMR53_swap(record, torev); break; + case U_WMR_54: U_WMR54_swap(record, torev); break; + case U_WMR_55: U_WMR55_swap(record, torev); break; + case U_WMR_56: U_WMR56_swap(record, torev); break; + case U_WMR_57: U_WMR57_swap(record, torev); break; + case U_WMR_58: U_WMR58_swap(record, torev); break; + case U_WMR_59: U_WMR59_swap(record, torev); break; + case U_WMR_5A: U_WMR5A_swap(record, torev); break; + case U_WMR_5B: U_WMR5B_swap(record, torev); break; + case U_WMR_5C: U_WMR5C_swap(record, torev); break; + case U_WMR_5D: U_WMR5D_swap(record, torev); break; + case U_WMR_5E: U_WMR5E_swap(record, torev); break; + case U_WMR_5F: U_WMR5F_swap(record, torev); break; + case U_WMR_60: U_WMR60_swap(record, torev); break; + case U_WMR_61: U_WMR61_swap(record, torev); break; + case U_WMR_62: U_WMR62_swap(record, torev); break; + case U_WMR_63: U_WMR63_swap(record, torev); break; + case U_WMR_64: U_WMR64_swap(record, torev); break; + case U_WMR_65: U_WMR65_swap(record, torev); break; + case U_WMR_66: U_WMR66_swap(record, torev); break; + case U_WMR_67: U_WMR67_swap(record, torev); break; + case U_WMR_68: U_WMR68_swap(record, torev); break; + case U_WMR_69: U_WMR69_swap(record, torev); break; + case U_WMR_6A: U_WMR6A_swap(record, torev); break; + case U_WMR_6B: U_WMR6B_swap(record, torev); break; + case U_WMR_6C: U_WMR6C_swap(record, torev); break; + case U_WMR_6D: U_WMR6D_swap(record, torev); break; + case U_WMR_6E: U_WMR6E_swap(record, torev); break; + case U_WMR_6F: U_WMR6F_swap(record, torev); break; + case U_WMR_70: U_WMR70_swap(record, torev); break; + case U_WMR_71: U_WMR71_swap(record, torev); break; + case U_WMR_72: U_WMR72_swap(record, torev); break; + case U_WMR_73: U_WMR73_swap(record, torev); break; + case U_WMR_74: U_WMR74_swap(record, torev); break; + case U_WMR_75: U_WMR75_swap(record, torev); break; + case U_WMR_76: U_WMR76_swap(record, torev); break; + case U_WMR_77: U_WMR77_swap(record, torev); break; + case U_WMR_78: U_WMR78_swap(record, torev); break; + case U_WMR_79: U_WMR79_swap(record, torev); break; + case U_WMR_7A: U_WMR7A_swap(record, torev); break; + case U_WMR_7B: U_WMR7B_swap(record, torev); break; + case U_WMR_7C: U_WMR7C_swap(record, torev); break; + case U_WMR_7D: U_WMR7D_swap(record, torev); break; + case U_WMR_7E: U_WMR7E_swap(record, torev); break; + case U_WMR_7F: U_WMR7F_swap(record, torev); break; + case U_WMR_80: U_WMR80_swap(record, torev); break; + case U_WMR_81: U_WMR81_swap(record, torev); break; + case U_WMR_82: U_WMR82_swap(record, torev); break; + case U_WMR_83: U_WMR83_swap(record, torev); break; + case U_WMR_84: U_WMR84_swap(record, torev); break; + case U_WMR_85: U_WMR85_swap(record, torev); break; + case U_WMR_86: U_WMR86_swap(record, torev); break; + case U_WMR_87: U_WMR87_swap(record, torev); break; + case U_WMR_88: U_WMR88_swap(record, torev); break; + case U_WMR_89: U_WMR89_swap(record, torev); break; + case U_WMR_8A: U_WMR8A_swap(record, torev); break; + case U_WMR_8B: U_WMR8B_swap(record, torev); break; + case U_WMR_8C: U_WMR8C_swap(record, torev); break; + case U_WMR_8D: U_WMR8D_swap(record, torev); break; + case U_WMR_8E: U_WMR8E_swap(record, torev); break; + case U_WMR_8F: U_WMR8F_swap(record, torev); break; + case U_WMR_90: U_WMR90_swap(record, torev); break; + case U_WMR_91: U_WMR91_swap(record, torev); break; + case U_WMR_92: U_WMR92_swap(record, torev); break; + case U_WMR_93: U_WMR93_swap(record, torev); break; + case U_WMR_94: U_WMR94_swap(record, torev); break; + case U_WMR_95: U_WMR95_swap(record, torev); break; + case U_WMR_96: U_WMR96_swap(record, torev); break; + case U_WMR_97: U_WMR97_swap(record, torev); break; + case U_WMR_98: U_WMR98_swap(record, torev); break; + case U_WMR_99: U_WMR99_swap(record, torev); break; + case U_WMR_9A: U_WMR9A_swap(record, torev); break; + case U_WMR_9B: U_WMR9B_swap(record, torev); break; + case U_WMR_9C: U_WMR9C_swap(record, torev); break; + case U_WMR_9D: U_WMR9D_swap(record, torev); break; + case U_WMR_9E: U_WMR9E_swap(record, torev); break; + case U_WMR_9F: U_WMR9F_swap(record, torev); break; + case U_WMR_A0: U_WMRA0_swap(record, torev); break; + case U_WMR_A1: U_WMRA1_swap(record, torev); break; + case U_WMR_A2: U_WMRA2_swap(record, torev); break; + case U_WMR_A3: U_WMRA3_swap(record, torev); break; + case U_WMR_A4: U_WMRA4_swap(record, torev); break; + case U_WMR_A5: U_WMRA5_swap(record, torev); break; + case U_WMR_A6: U_WMRA6_swap(record, torev); break; + case U_WMR_A7: U_WMRA7_swap(record, torev); break; + case U_WMR_A8: U_WMRA8_swap(record, torev); break; + case U_WMR_A9: U_WMRA9_swap(record, torev); break; + case U_WMR_AA: U_WMRAA_swap(record, torev); break; + case U_WMR_AB: U_WMRAB_swap(record, torev); break; + case U_WMR_AC: U_WMRAC_swap(record, torev); break; + case U_WMR_AD: U_WMRAD_swap(record, torev); break; + case U_WMR_AE: U_WMRAE_swap(record, torev); break; + case U_WMR_AF: U_WMRAF_swap(record, torev); break; + case U_WMR_B0: U_WMRB0_swap(record, torev); break; + case U_WMR_B1: U_WMRB1_swap(record, torev); break; + case U_WMR_B2: U_WMRB2_swap(record, torev); break; + case U_WMR_B3: U_WMRB3_swap(record, torev); break; + case U_WMR_B4: U_WMRB4_swap(record, torev); break; + case U_WMR_B5: U_WMRB5_swap(record, torev); break; + case U_WMR_B6: U_WMRB6_swap(record, torev); break; + case U_WMR_B7: U_WMRB7_swap(record, torev); break; + case U_WMR_B8: U_WMRB8_swap(record, torev); break; + case U_WMR_B9: U_WMRB9_swap(record, torev); break; + case U_WMR_BA: U_WMRBA_swap(record, torev); break; + case U_WMR_BB: U_WMRBB_swap(record, torev); break; + case U_WMR_BC: U_WMRBC_swap(record, torev); break; + case U_WMR_BD: U_WMRBD_swap(record, torev); break; + case U_WMR_BE: U_WMRBE_swap(record, torev); break; + case U_WMR_BF: U_WMRBF_swap(record, torev); break; + case U_WMR_C0: U_WMRC0_swap(record, torev); break; + case U_WMR_C1: U_WMRC1_swap(record, torev); break; + case U_WMR_C2: U_WMRC2_swap(record, torev); break; + case U_WMR_C3: U_WMRC3_swap(record, torev); break; + case U_WMR_C4: U_WMRC4_swap(record, torev); break; + case U_WMR_C5: U_WMRC5_swap(record, torev); break; + case U_WMR_C6: U_WMRC6_swap(record, torev); break; + case U_WMR_C7: U_WMRC7_swap(record, torev); break; + case U_WMR_C8: U_WMRC8_swap(record, torev); break; + case U_WMR_C9: U_WMRC9_swap(record, torev); break; + case U_WMR_CA: U_WMRCA_swap(record, torev); break; + case U_WMR_CB: U_WMRCB_swap(record, torev); break; + case U_WMR_CC: U_WMRCC_swap(record, torev); break; + case U_WMR_CD: U_WMRCD_swap(record, torev); break; + case U_WMR_CE: U_WMRCE_swap(record, torev); break; + case U_WMR_CF: U_WMRCF_swap(record, torev); break; + case U_WMR_D0: U_WMRD0_swap(record, torev); break; + case U_WMR_D1: U_WMRD1_swap(record, torev); break; + case U_WMR_D2: U_WMRD2_swap(record, torev); break; + case U_WMR_D3: U_WMRD3_swap(record, torev); break; + case U_WMR_D4: U_WMRD4_swap(record, torev); break; + case U_WMR_D5: U_WMRD5_swap(record, torev); break; + case U_WMR_D6: U_WMRD6_swap(record, torev); break; + case U_WMR_D7: U_WMRD7_swap(record, torev); break; + case U_WMR_D8: U_WMRD8_swap(record, torev); break; + case U_WMR_D9: U_WMRD9_swap(record, torev); break; + case U_WMR_DA: U_WMRDA_swap(record, torev); break; + case U_WMR_DB: U_WMRDB_swap(record, torev); break; + case U_WMR_DC: U_WMRDC_swap(record, torev); break; + case U_WMR_DD: U_WMRDD_swap(record, torev); break; + case U_WMR_DE: U_WMRDE_swap(record, torev); break; + case U_WMR_DF: U_WMRDF_swap(record, torev); break; + case U_WMR_E0: U_WMRE0_swap(record, torev); break; + case U_WMR_E1: U_WMRE1_swap(record, torev); break; + case U_WMR_E2: U_WMRE2_swap(record, torev); break; + case U_WMR_E3: U_WMRE3_swap(record, torev); break; + case U_WMR_E4: U_WMRE4_swap(record, torev); break; + case U_WMR_E5: U_WMRE5_swap(record, torev); break; + case U_WMR_E6: U_WMRE6_swap(record, torev); break; + case U_WMR_E7: U_WMRE7_swap(record, torev); break; + case U_WMR_E8: U_WMRE8_swap(record, torev); break; + case U_WMR_E9: U_WMRE9_swap(record, torev); break; + case U_WMR_EA: U_WMREA_swap(record, torev); break; + case U_WMR_EB: U_WMREB_swap(record, torev); break; + case U_WMR_EC: U_WMREC_swap(record, torev); break; + case U_WMR_ED: U_WMRED_swap(record, torev); break; + case U_WMR_EE: U_WMREE_swap(record, torev); break; + case U_WMR_EF: U_WMREF_swap(record, torev); break; + case U_WMR_DELETEOBJECT: U_WMRDELETEOBJECT_swap(record, torev); break; + case U_WMR_F1: U_WMRF1_swap(record, torev); break; + case U_WMR_F2: U_WMRF2_swap(record, torev); break; + case U_WMR_F3: U_WMRF3_swap(record, torev); break; + case U_WMR_F4: U_WMRF4_swap(record, torev); break; + case U_WMR_F5: U_WMRF5_swap(record, torev); break; + case U_WMR_F6: U_WMRF6_swap(record, torev); break; + case U_WMR_CREATEPALETTE: U_WMRCREATEPALETTE_swap(record, torev); break; + case U_WMR_F8: U_WMRF8_swap(record, torev); break; + case U_WMR_CREATEPATTERNBRUSH: U_WMRCREATEPATTERNBRUSH_swap(record, torev); break; + case U_WMR_CREATEPENINDIRECT: U_WMRCREATEPENINDIRECT_swap(record, torev); break; + case U_WMR_CREATEFONTINDIRECT: U_WMRCREATEFONTINDIRECT_swap(record, torev); break; + case U_WMR_CREATEBRUSHINDIRECT: U_WMRCREATEBRUSHINDIRECT_swap(record, torev); break; + case U_WMR_CREATEBITMAPINDIRECT: U_WMRCREATEBITMAPINDIRECT_swap(record, torev); break; + case U_WMR_CREATEBITMAP: U_WMRCREATEBITMAP_swap(record, torev); break; + case U_WMR_CREATEREGION: U_WMRCREATEREGION_swap(record, torev); break; + default: U_WMRNOTIMPLEMENTED_swap(record, torev); break; + } //end of switch + record += 2*Size16; + offset += 2*Size16; + recnum++; + } //end of while + return(1); +} + + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uwmf_endian.h b/src/extension/internal/uwmf_endian.h new file mode 100644 index 000000000..dc01c0d07 --- /dev/null +++ b/src/extension/internal/uwmf_endian.h @@ -0,0 +1,39 @@ +/** + @file uemf_endian.h Prototype for function for converting EMF records between Big Endian and Little Endian +*/ + +/* +File: uwmf_endian.h +Version: 0.0.1 +Date: 10-JAN-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UWMF_ENDIAN_ +#define _UWMF_ENDIAN_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "uemf_endian.h" + +/* There is no way for the preprocessor, in general, to figure out endianness. So the command line must define + WORDS_BIGENDIAN for a big endian machine. Otherwise we assume is is little endian. If it is something + else this code won't work in any case. */ +#ifdef WORDS_BIGENDIAN +#define U_BYTE_SWAP 1 +#else +#define U_BYTE_SWAP 0 +#endif + +// prototypes +int U_wmf_endian(char *contents, size_t length, int torev); + +#ifdef __cplusplus +} +#endif + +#endif /* _UWMF_ENDIAN_ */ diff --git a/src/extension/internal/uwmf_print.c b/src/extension/internal/uwmf_print.c new file mode 100644 index 000000000..bb9f3eb36 --- /dev/null +++ b/src/extension/internal/uwmf_print.c @@ -0,0 +1,1616 @@ +/** + @file uwmf_print.c Functions for printing WMF records +*/ + +/* +File: uwmf_print.c +Version: 0.0.2 +Date: 18-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> /* for offsetof() macro */ +#include <string.h> +#include "uwmf_print.h" + +/* ********************************************************************************************** + These functions print standard objects used in the WMR records. + The low level ones do not append EOL. +*********************************************************************************************** */ + +/* many of these are implemented in uemf_print.c and not replicated here */ + + + +/** + \brief Print a U_BRUSH object. + \param b U_BRUSH object. + style bColor bHatch + U_BS_SOLID ColorRef Object Not used (bytes present???) + U_BS_NULL ignored ignored (bytes present???). + U_BS_PATTERN ignored Bitmap16 object holding patern + U_BS_DIBPATTERNPT ColorUsage Enum DIB object + U_BS_HATCHED ColorRef Object HatchStyle Enumeration +*/ +void brush_print( + U_BRUSH b + ){ + U_COLORREF Color; + switch(b.Style){ + case U_BS_SOLID: + memcpy(&Color, &b.Color, sizeof(U_COLORREF)); + printf("Color:"); colorref_print(Color); + break; + case U_BS_NULL: + printf("Null"); + break; + case U_BS_PATTERN: + printf("Pattern:(not shown)"); + break; + case U_BS_DIBPATTERNPT: + printf("DIBPattern:(not shown)"); + break; + case U_BS_HATCHED: + printf("Hatch:0x%4.4X ", *(uint16_t *)(b.Data)); + break; + } +} + +/** + \brief Print a U_FONT object from a char *pointer. + The U_FONT struct object may not be properly aligned, but all of the fields within it will + OK for alignment. + \param font U_FONT object (as a char * pointer) +*/ +void font_print( + const char *font + ){ + printf("Height:%d ", *(int16_t *)(font + offsetof(U_FONT,Height ))); + printf("Width:%d ", *(int16_t *)(font + offsetof(U_FONT,Width ))); + printf("Escapement:%d ", *(int16_t *)(font + offsetof(U_FONT,Escapement ))); + printf("Orientation:%d ", *(int16_t *)(font + offsetof(U_FONT,Orientation ))); + printf("Weight:%d ", *(int16_t *)(font + offsetof(U_FONT,Weight ))); + printf("Italic:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,Italic ))); + printf("Underline:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,Underline ))); + printf("StrikeOut:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,StrikeOut ))); + printf("CharSet:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,CharSet ))); + printf("OutPrecision:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,OutPrecision ))); + printf("ClipPrecision:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,ClipPrecision ))); + printf("Quality:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,Quality ))); + printf("PitchAndFamily:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,PitchAndFamily))); + printf("FaceName:%s ", (font + offsetof(U_FONT,FaceName ))); +} + + +/** + \brief Print a U_PLTNTRY object. + \param pny U_PLTNTRY object. +*/ +void pltntry_print( + U_PLTNTRY pny + ){ + printf("Value:%u ", pny.Value); + printf("Red:%u ", pny.Red ); + printf("Green:%u ", pny.Green); + printf("Blue:%u ", pny.Blue ); +} + + +/** + \brief Print a pointer to a U_PALETTE object. + \param p Pointer to a U_PALETTE object + \param PalEntries Array of Palette Entries +*/ +void palette_print( + const PU_PALETTE p, + const char *PalEntries + ){ + int i; + U_PLTNTRY pny; + + printf("Start:%X ", p->Start ); + printf("NumEntries:%u ",p->NumEntries ); + if(p->NumEntries && PalEntries){ + for(i=0; i < p->NumEntries; i++, PalEntries += sizeof(U_PLTNTRY)){ + memcpy(&pny, PalEntries, sizeof(U_PLTNTRY)); + printf("%d:",i); pltntry_print(pny); + } + } +} + +/** + \brief Print a U_PEN object. + \param p U_PEN object + uint16_t Style; //!< PenStyle Enumeration + uint16_t Width; //!< Pen Width in object dimensions + uint16_t unused; //!< unused + union { + U_COLORREF Color; //!< Pen color (NOT aligned on 4n byte boundary!) + uint16_t Colorw[2]; //!< reassemble/store the Color value using these, NOT Color. + }; +*/ +void pen_print( + U_PEN p + ){ + U_COLORREF Color; + printf("Style:0x%8.8X " ,p.Style ); + printf("Width:%u " ,p.Widthw[0] ); + memcpy(&Color, &p.Color, sizeof(U_COLORREF)); + printf("Color"); colorref_print(Color); +} + +/** + \brief Print U_RECT16 object + Prints in order left, top, right, bottom + \param rect U_RECT16 object +*/ +void rect16_ltrb_print( + U_RECT16 rect + ){ + printf("LTRB{%d,%d,%d,%d} ",rect.left,rect.top,rect.right,rect.bottom); +} + +/** + \brief Print U_RECT16 object + Some WMF rects use the order bottom, right, top, left. These are passed in using + the same structure as for a normal U_RECT16 so: + position holds + left bottom + top right + right top + bottom left + This is used by WMR_RECTANGLE and many others. + \param rect U_RECT16 object +*/ +void rect16_brtl_print( + U_RECT16 rect + ){ + printf("BRTL{%d,%d,%d,%d} ",rect.bottom,rect.right,rect.top,rect.left); +} + + + +/** + \brief Print U_REGION object from a char * pointer. + \param region U_REGION object +*/ +void region_print( + const char *region + ){ + U_RECT16 rect16; + printf("Type:%d ", *(uint16_t *)(region + offsetof(U_REGION,Type ))); + printf("Size:%d ", *( int16_t *)(region + offsetof(U_REGION,Size ))); + printf("sCount:%d ",*( int16_t *)(region + offsetof(U_REGION,sCount))); + printf("sMax:%d ", *( int16_t *)(region + offsetof(U_REGION,sMax ))); + memcpy(&rect16, (region + offsetof(U_REGION,sRect )), sizeof(U_RECT16)); + printf("sRect: "); rect16_ltrb_print(rect16); +} + + +/** + \brief Print U_BITMAP16 object + \param b U_BITMAP16 object +*/ +void bitmap16_print( + U_BITMAP16 b + ){ + printf("Type:%d ", b.Type ); + printf("Width:%d ", b.Width ); + printf("Height:%d ", b.Height ); + printf("WidthBytes:%d ", b.WidthBytes); + printf("Planes:%d ", b.Planes ); + printf("BitsPixel:%d ", b.BitsPixel ); + printf("BitsBytes:%d ", (((b.Width * b.BitsPixel + 15) >> 4) << 1) * b.Height ); +} + +/** + \brief Print U_BITMAPCOREHEADER object + \param ch U_BITMAPCOREHEADER object +*/ +void bitmapcoreheader_print( + U_BITMAPCOREHEADER ch + ){ + uint32_t Size; + memcpy(&Size, &(ch.Size_4), 4); /* will be aligned, but is in two pieces */ + printf("Size:%d ", Size); + printf("Width:%d ", ch.Width); + printf("Height:%d ", ch.Height); + printf("Planes:%d ", ch.Planes); + printf("BitCount:%d ", ch.BitCount); +} + +/** LogBrushW Object WMF PDF 2.2.2.10 + \brief Print a U_LOGBRUSHW object. + \param lb U_LOGBRUSHW object. + + style Color Hatch + U_BS_SOLID ColorRef Object Not used (bytes present???) + U_BS_NULL ignored ignored (bytes present???). + U_BS_PATTERN ignored not used (Action is not strictly defined) + U_BS_DIBPATTERN ignored not used (Action is not strictly defined) + U_BS_DIBPATTERNPT ignored not used (Action is not strictly defined) + U_BS_HATCHED ColorRef Object HatchStyle Enumeration +*/ +void wlogbrush_print( + const char *lb + ){ + U_COLORREF Color; + uint16_t Style = *(uint16_t *)(lb + offsetof(U_WLOGBRUSH,Style)); + uint16_t Hatch = *(uint16_t *)(lb + offsetof(U_WLOGBRUSH,Hatch)); + memcpy(&Color, lb + offsetof(U_WLOGBRUSH,Color), sizeof(U_COLORREF)); + printf("Style:0x%4.4X ",Style); + switch(Style){ + case U_BS_SOLID: + printf("Color:"); colorref_print(Color); + break; + case U_BS_NULL: + printf("Null"); + break; + case U_BS_PATTERN: + printf("Pattern:(not implemented)"); + break; + case U_BS_DIBPATTERN: + printf("DIBPattern:(not implemented)"); + break; + case U_BS_DIBPATTERNPT: + printf("DIBPatternPt:(not implemented)"); + break; + case U_BS_HATCHED: + printf("Color:"); colorref_print(Color); + printf("Hatch:0x%4.4X ", Hatch); + break; + } +} + + +/** + \brief Print U_POLYPOLY object from pointer + \param nPolys Number of elements in aPolyCounts + \param aPolyCounts Number of points in each poly (sequential) + \param Points pointer to array of U_POINT16 in memory. Probably not aligned. +*/ +void polypolygon_print( + uint16_t nPolys, + const uint16_t *aPolyCounts, + const char *Points + ){ + int i,j; + U_POINT16 pt; + for(i=0; i<nPolys; i++, aPolyCounts++){ + printf(" Polygon[%d]: ",i); + for(j=0; j < *aPolyCounts; j++, Points += sizeof(U_POINT16)){ + memcpy(&pt, Points, sizeof(U_POINT16)); /* may not be aligned */ + point16_print(pt); + } + } +} + +/** + \brief Print U_SCAN object + \param sc U_SCAN object +*/ +void scan_print( + U_SCAN sc + ){ + printf("Count:%d ", sc.count); + printf("Top:%d ", sc.top); + printf("Bottom:%d ", sc.bottom); + printf("data:(not shown)"); +} + +/** + \brief Print a summary of a DIB header + \param dh void pointer to DIB header + A DIB header in an WMF may be either a BitmapCoreHeader or BitmapInfoHeader. +*/ +void dibheader_print(const void *dh){ + uint32_t Size; + memcpy(&Size, dh, 4); /* may not be aligned */ + if(Size == 0xC ){ + printf("(BitmapCoreHeader) "); + U_BITMAPCOREHEADER bmch; + memcpy(&bmch, dh, sizeof(U_BITMAPCOREHEADER)); /* may not be aligned */ + bitmapcoreheader_print(bmch); + } + else { + printf(" (BitmapInfoHeader) "); + bitmapinfo_print(dh); /* may not be aligned, called routine must handle it */ + } +} + +/** + \brief Print WMF header object + \returns size of entire header structure + \param contents pointer to the first byte in the buffer holding the entire WMF file in memory + \param blimit pointer to the byte after the last byte in contents + + If the header is preceded by a placeable struture, print that as well. +*/ +int wmfheader_print( + const char *contents, + const char *blimit + ){ + U_WMRPLACEABLE Placeable; + U_WMRHEADER Header; + int size = wmfheader_get(contents, blimit, &Placeable, &Header); + uint32_t utmp4; + U_RECT16 rect16; + uint32_t Key; + memcpy(&Key, contents + offsetof(U_WMRPLACEABLE,Key), 4); + if(Placeable.Key == 0x9AC6CDD7){ + printf("WMF, Placeable: "); + printf("HWmf:%u ", Placeable.HWmf); + memcpy(&rect16, &(Placeable.Dst), sizeof(U_RECT16)); + printf("Box:"); rect16_ltrb_print(rect16); + printf("Inch:%u ", Placeable.Inch); + printf("Checksum:%d ", Placeable.Checksum); + printf("Calculated_Checksum:%d\n",U_16_checksum((int16_t *)contents,10)); + } + else { + printf("WMF, Not Placeable\n"); + } + printf(" RecType:%d\n", Header.iType); + printf(" 16bit words in record:%d\n", Header.Size16w); + printf(" Version:%d\n", Header.version); + memcpy(&utmp4, &(Header.Sizew),4); + printf(" 16bit words in file:%d\n",utmp4); + printf(" Objects:%d\n", Header.nObjects); + memcpy(&utmp4, &(Header.maxSize),4); + printf(" Largest Record:%d\n", utmp4); + printf(" nMembers:%d\n", Header.nMembers); + + return(size); +} + + + +// hide these from Doxygen +//! @cond +/* ********************************************************************************************** +These functions contain shared code used by various U_WMR*_print functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. +*********************************************************************************************** */ + + +void wcore_points_print(uint16_t nPoints, const char *aPoints){ + int i; + U_POINT16 pt; + printf(" Points: "); + for(i=0;i<nPoints; i++){ + memcpy(&pt, aPoints + i*4, sizeof(U_POINT16)); /* aPoints U_POINT16 structure may not be aligned, so copy it out */ + printf("[%d]:",i); point16_print(pt); + } + printf("\n"); +} + + + +//! @endcond + +/* ********************************************************************************************** +These are the core WMR functions, each creates a particular type of record. +All return these records via a char* pointer, which is NULL if the call failed. +They are listed in order by the corresponding U_WMR_* index number. +*********************************************************************************************** */ + +/** + \brief Print a pointer to a U_WMR_whatever record which has not been implemented. + \param contents pointer to a buffer holding a WMR record +*/ +void U_WMRNOTIMPLEMENTED_print(const char *contents){ + printf(" Not Implemented!\n"); +} + +void U_WMREOF_print(const char *contents){ +} + +void U_WMRSETBKCOLOR_print(const char *contents){ + U_COLORREF Color; + int size = U_WMRSETBKCOLOR_get(contents, &Color); + if(size>0){ + printf(" %-15s ","Color:"); colorref_print(Color); printf("\n"); + } +} + +void U_WMRSETBKMODE_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETBKMODE_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +void U_WMRSETMAPMODE_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETMAPMODE_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +void U_WMRSETROP2_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETROP2_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +void U_WMRSETRELABS_print(const char *contents){ + /* This record type has only the common 6 bytes, so nothing (else) to print */ +} + +void U_WMRSETPOLYFILLMODE_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETPOLYFILLMODE_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +void U_WMRSETSTRETCHBLTMODE_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETSTRETCHBLTMODE_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +void U_WMRSETTEXTCHAREXTRA_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETTEXTCHAREXTRA_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +void U_WMRSETTEXTCOLOR_print(const char *contents){ + U_COLORREF Color; + int size = U_WMRSETTEXTCOLOR_get(contents, &Color); + if(size>0){ + printf(" %-15s ","Color:"); colorref_print(Color); printf("\n"); + } +} + +void U_WMRSETTEXTJUSTIFICATION_print(const char *contents){ + uint16_t Count; + uint16_t Extra; + int size = U_WMRSETTEXTJUSTIFICATION_get(contents, &Count, &Extra); + if(size){ + printf(" %-15s %d\n","Count", Count); + printf(" %-15s %d\n","Extra", Extra); + } +} + +void U_WMRSETWINDOWORG_print(const char *contents){ + U_POINT16 coord; + int size = U_WMRSETWINDOWORG_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMRSETWINDOWEXT_print(const char *contents){ + U_POINT16 coord; + int size = U_WMRSETWINDOWEXT_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","W,H",coord.x, coord.y); + } +} + +void U_WMRSETVIEWPORTORG_print(const char *contents){ + U_POINT16 coord; + int size = U_WMRSETVIEWPORTORG_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMRSETVIEWPORTEXT_print(const char *contents){ + U_POINT16 coord; + int size = U_WMRSETVIEWPORTEXT_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","W,H",coord.x, coord.y); + } +} + +void U_WMROFFSETWINDOWORG_print(const char *contents){ + U_POINT16 coord; + int size = U_WMROFFSETWINDOWORG_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMRSCALEWINDOWEXT_print(const char *contents){ + U_POINT16 Denom, Num; + int size = U_WMRSCALEWINDOWEXT_get(contents, &Denom, &Num); + if(size > 0){ + printf(" yDenom:%d\n", Denom.y); + printf(" yNum:%d\n", Num.y ); + printf(" xDenom:%d\n", Denom.x); + printf(" xNum:%d\n", Num.x ); + } +} + +void U_WMROFFSETVIEWPORTORG_print(const char *contents){ + U_POINT16 coord; + int size = U_WMROFFSETVIEWPORTORG_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMRSCALEVIEWPORTEXT_print(const char *contents){ + U_POINT16 Denom, Num; + int size = U_WMRSCALEVIEWPORTEXT_get(contents, &Denom, &Num); + if(size > 0){ + printf(" yDenom:%d\n", Denom.y); + printf(" yNum:%d\n", Num.y ); + printf(" xDenom:%d\n", Denom.x); + printf(" xNum:%d\n", Num.x ); + } +} + +void U_WMRLINETO_print(const char *contents){ + U_POINT16 coord; + int size = U_WMRLINETO_get(contents, &coord); + if(size){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMRMOVETO_print(const char *contents){ + U_POINT16 coord; + int size = U_WMRMOVETO_get(contents, &coord); + if(size > 0){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMREXCLUDECLIPRECT_print(const char *contents){ + U_RECT16 rect16; + int size = U_WMREXCLUDECLIPRECT_get(contents, &rect16); + if(size > 0){ + printf(" Rect:"); + rect16_ltrb_print(rect16); + printf("\n"); + } +} + +void U_WMRINTERSECTCLIPRECT_print(const char *contents){ + U_RECT16 rect16; + int size = U_WMRINTERSECTCLIPRECT_get(contents, &rect16); + if(size > 0){ + printf(" Rect:"); + rect16_ltrb_print(rect16); + printf("\n"); + } +} + +void U_WMRARC_print(const char *contents){ + U_POINT16 StartArc, EndArc; + U_RECT16 rect16; + int size = U_WMRARC_get(contents, &StartArc, &EndArc, &rect16); + if(size > 0){ + printf(" yRadial2:%d\n", EndArc.y); + printf(" xRadial2:%d\n", EndArc.x); + printf(" yRadial1:%d\n", StartArc.y); + printf(" xRadial1:%d\n", StartArc.x); + printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n"); + } +} + +void U_WMRELLIPSE_print(const char *contents){ + U_RECT16 rect16; + int size = U_WMRELLIPSE_get(contents, &rect16); + if(size > 0){ + printf(" Rect:"); + rect16_ltrb_print(rect16); + printf("\n"); + } +} + +void U_WMRFLOODFILL_print(const char *contents){ + uint16_t Mode; + U_COLORREF Color; + U_POINT16 coord; + int size = U_WMRFLOODFILL_get(contents, &Mode, &Color, &coord); + if(size > 0){ + printf(" Mode 0x%4.4X\n", Mode); + printf(" Color:"); colorref_print(Color); printf("\n"); + printf(" X,Y {%d,%d}\n", coord.x, coord.y); + } +} + +void U_WMRPIE_print(const char *contents){ + U_POINT16 StartArc, EndArc; + U_RECT16 rect16; + int size = U_WMRPIE_get(contents, &StartArc, &EndArc, &rect16); + if(size > 0){ + printf(" yRadial2:%d\n", EndArc.y); + printf(" xRadial2:%d\n", EndArc.x); + printf(" yRadial1:%d\n", StartArc.y); + printf(" xRadial1:%d\n", StartArc.x); + printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n"); + } +} + +void U_WMRRECTANGLE_print(const char *contents){ + U_RECT16 rect16; + int size = U_WMRRECTANGLE_get(contents, &rect16); + if(size > 0){ + printf(" Rect:"); + rect16_ltrb_print(rect16); + printf("\n"); + } +} + +void U_WMRROUNDRECT_print(const char *contents){ + int16_t Height, Width; + U_RECT16 rect16; + int size = U_WMRROUNDRECT_get(contents, &Width, &Height, &rect16); + if(size > 0){ + printf(" Width:%d\n", Width); + printf(" Height:%d\n", Height); + printf(" Rect:"); + rect16_ltrb_print(rect16); + printf("\n"); + } +} + +void U_WMRPATBLT_print(const char *contents){ + uint32_t dwRop3; + U_POINT16 Dst; + U_POINT16 cwh; + int size = U_WMRPATBLT_get(contents, &Dst, &cwh, &dwRop3); + if(size > 0){ + printf(" Rop3:%8.8X\n", dwRop3 ); + printf(" W,H:%d,%d\n", cwh.x, cwh.y ); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); + } +} + +void U_WMRSAVEDC_print(const char *contents){ + /* This record type has only the common 6 bytes, so nothing (else) to print */ +} + +void U_WMRSETPIXEL_print(const char *contents){ + U_COLORREF Color; + U_POINT16 coord; + int size = U_WMRSETPIXEL_get(contents, &Color, &coord); + if(size > 0){ + printf(" Color:"); colorref_print(Color); printf("\n"); + printf(" X,Y {%d,%d}\n", coord.x, coord.y); + } +} + +void U_WMROFFSETCLIPRGN_print(const char *contents){ + U_POINT16 coord; + int size = U_WMROFFSETCLIPRGN_get(contents, &coord); + if(size > 0){ + printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y); + } +} + +void U_WMRTEXTOUT_print(const char *contents){ + int16_t Length; + const char *string; + U_POINT16 Dst; + int size = U_WMRTEXTOUT_get(contents, &Dst, &Length, &string); + if(size > 0){ + printf(" X,Y:{%d,%d}\n", Dst.y,Dst.x); /* y/x order in record is reversed, fix that here */ + printf(" Length:%d\n", Length); + printf(" String:<%.*s>\n", Length, string); /* May not be null terminated */ + } +} + +void U_WMRBITBLT_print(const char *contents){ + uint32_t dwRop3; + U_POINT16 Dst, Src, cwh; + U_BITMAP16 Bm16; + const char *px; + int size = U_WMRBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &Bm16, &px); + if(size > 0){ + printf(" Rop3:%8.8X\n", dwRop3 ); + printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y); + printf(" W,H:%d,%d\n", cwh.x, cwh.y); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y); + if(px){ printf(" Bitmap16:"); bitmap16_print(Bm16); printf("\n"); } + else { printf(" Bitmap16: none\n"); } + } +} + +void U_WMRSTRETCHBLT_print(const char *contents){ + uint32_t dwRop3; + U_POINT16 Dst, Src, cDst, cSrc; + U_BITMAP16 Bm16; + const char *px; + int size = U_WMRSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &Bm16, &px); + if(size > 0){ + printf(" Rop3:%8.8X\n", dwRop3 ); + printf(" Src W,H:%d,%d\n", cSrc.x, cSrc.y); + printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y ); + printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); + if(px){ printf(" Bitmap16:"); bitmap16_print(Bm16); printf("\n"); } + else { printf(" Bitmap16: none\n"); } + } +} + +void U_WMRPOLYGON_print(const char *contents){ + uint16_t Length; + const char *Data; + int size = U_WMRPOLYGON_get(contents, &Length, &Data); + if(size > 0){ + wcore_points_print(Length, Data); + } +} + +void U_WMRPOLYLINE_print(const char *contents){ + uint16_t Length; + const char *Data; + int size = U_WMRPOLYLINE_get(contents, &Length, &Data); + if(size > 0){ + wcore_points_print(Length, Data); + } +} + +void U_WMRESCAPE_print(const char *contents){ + uint32_t utmp4; + uint16_t Escape; + uint16_t Length; + const char *Data; + int size = U_WMRESCAPE_get(contents, &Escape, &Length, &Data); + if(size > 0){ + printf(" EscType:%s\n",U_wmr_escnames(Escape)); + printf(" nBytes:%d\n",Length); + if((Escape == U_MFE_SETLINECAP) || (Escape == U_MFE_SETLINEJOIN) || (Escape == U_MFE_SETMITERLIMIT)){ + memcpy(&utmp4, Data ,4); + printf(" Data:%d\n", utmp4); + } + else { + printf(" Data: (not shown)\n"); + } + } +} + +void U_WMRRESTOREDC_print(const char *contents){ + /* This record type has only the common 6 bytes, so nothing (else) to print */ +} + +void U_WMRFILLREGION_print(const char *contents){ + uint16_t Region; + uint16_t Brush; + int size = U_WMRFILLREGION_get(contents, &Region, &Brush); + if(size > 0){ + printf(" %-15s %d\n","Region", Region); + printf(" %-15s %d\n","Brush", Brush); + } +} + +void U_WMRFRAMEREGION_print(const char *contents){ + uint16_t Region; + uint16_t Brush; + int16_t Height; + int16_t Width; + int size = U_WMRFRAMEREGION_get(contents, &Region, &Brush, &Height, &Width); + if(size > 0){ + printf(" Region:%d\n",Region); + printf(" Brush:%d\n", Brush ); + printf(" Height:%d\n",Height); + printf(" Width:%d\n", Width ); + } +} + +void U_WMRINVERTREGION_print(const char *contents){ + uint16_t Region; + int size = U_WMRSETTEXTALIGN_get(contents, &Region); + if(size > 0){ + printf(" %-15s %d\n","Region:", Region); + } +} + +void U_WMRPAINTREGION_print(const char *contents){ + uint16_t Region; + int size = U_WMRPAINTREGION_get(contents, &Region); + if(size>0){ + printf(" %-15s %d\n","Region:", Region); + } +} + +void U_WMRSELECTCLIPREGION_print(const char *contents){ + uint16_t Region; + int size = U_WMRSELECTCLIPREGION_get(contents, &Region); + if(size>0){ + printf(" %-15s %d\n","Region:", Region); + } +} + +void U_WMRSELECTOBJECT_print(const char *contents){ + uint16_t Object; + int size = U_WMRSELECTOBJECT_get(contents, &Object); + if(size>0){ + printf(" %-15s %d\n","Object:", Object); + } +} + +void U_WMRSETTEXTALIGN_print(const char *contents){ + uint16_t iMode; + int size = U_WMRSETTEXTALIGN_get(contents, &iMode); + if(size>0){ + printf(" %-15s 0x%4.4X\n","iMode:", iMode); + } +} + +#define U_WMRDRAWTEXT_print U_WMRNOTIMPLEMENTED_print + +void U_WMRCHORD_print(const char *contents){ + U_POINT16 StartArc, EndArc; + U_RECT16 rect16; + int size = U_WMRCHORD_get(contents, &StartArc, &EndArc, &rect16); + if(size > 0){ + printf(" yRadial2:%d\n", EndArc.y); + printf(" xRadial2:%d\n", EndArc.x); + printf(" yRadial1:%d\n", StartArc.y); + printf(" xRadial1:%d\n", StartArc.x); + printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n"); + } +} + +void U_WMRSETMAPPERFLAGS_print(const char *contents){ + uint32_t Flags4; + int size = U_WMRSETMAPPERFLAGS_get(contents, &Flags4); + if(size > 0){ + printf(" %-15s 0x%8.8X\n","Flags4:", Flags4); + } +} + +void U_WMREXTTEXTOUT_print(const char *contents){ + U_RECT16 rect16; + U_POINT16 Dst; + int16_t Length; + uint16_t Opts; + const int16_t *dx; + const char *string; + int i; + int size = U_WMREXTTEXTOUT_get(contents, &Dst, &Length, &Opts, &string, &dx, &rect16); + if(size > 0){ + printf(" X,Y:{%d,%d}\n", Dst.x, Dst.y); + printf(" Length:%d\n", Length ); + printf(" Opts:%4.4X\n", Opts ); + if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){ + printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n"); + } + printf(" String:<%.*s>\n",Length, string); + printf(" Dx:"); + for(i=0; i<Length; i++,dx++){ printf("%d:", *dx ); } + printf("\n"); + } +} + +void U_WMRSETDIBTODEV_print(const char *contents){ + uint16_t cUsage; + uint16_t ScanCount; + uint16_t StartScan; + U_POINT16 Dst; + U_POINT16 cwh; + U_POINT16 Src; + const char *dib; + int size = U_WMRSETDIBTODEV_get(contents, &Dst, &cwh, &Src, &cUsage, &ScanCount, &StartScan, &dib); + if(size > 0){ + printf(" cUsage:%d\n", cUsage ); + printf(" ScanCount:%d\n", ScanCount ); + printf(" StartScan:%d\n", StartScan ); + printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y ); + printf(" W,H:%d,%d\n", cwh.x, cwh.y ); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); + printf(" DIB:"); dibheader_print(dib); printf("\n"); + } +} + +void U_WMRSELECTPALETTE_print(const char *contents){ + uint16_t Palette; + int size = U_WMRSELECTPALETTE_get(contents, &Palette); + if(size > 0){ + printf(" %-15s %d\n","Palette:", Palette); + } +} + +void U_WMRREALIZEPALETTE_print(const char *contents){ + /* This record type has only the common 6 bytes, so nothing (else) to print */ +} + +void U_WMRANIMATEPALETTE_print(const char *contents){ + U_PALETTE Palette; + const char *PalEntries; + int size = U_WMRANIMATEPALETTE_get(contents, &Palette, &PalEntries); + if(size > 0){ + printf(" Palette:"); palette_print(&Palette, PalEntries); printf("\n"); + + } +} + +void U_WMRSETPALENTRIES_print(const char *contents){ + U_PALETTE Palette; + const char *PalEntries; + int size = U_WMRSETPALENTRIES_get(contents, &Palette, &PalEntries); + if(size > 0){ + printf(" Palette:"); palette_print(&Palette, PalEntries); printf("\n"); + } +} + +void U_WMRPOLYPOLYGON_print(const char *contents){ + uint16_t nPolys; + const uint16_t *aPolyCounts; + const char *Points; + int size = U_WMRPOLYPOLYGON_get(contents, &nPolys, &aPolyCounts, &Points); + if(size > 0){ + printf(" Polygons:"); polypolygon_print(nPolys, aPolyCounts, Points); printf("\n"); + } +} + +void U_WMRRESIZEPALETTE_print(const char *contents){ + uint16_t Palette; + int size = U_WMRSELECTCLIPREGION_get(contents, &Palette); + if(size>0){ + printf(" %-15s %d\n","Palette:", Palette); + } +} + +#define U_WMR3A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR3B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR3C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR3D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR3E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR3F_print U_WMRNOTIMPLEMENTED_print + +void U_WMRDIBBITBLT_print(const char *contents){ + U_POINT16 Dst, cwh, Src; + uint32_t dwRop3; + const char *dib; + int size = U_WMRDIBBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &dib); + if(size > 0){ + printf(" Rop3:%8.8X\n", dwRop3 ); + printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x ); + printf(" W,H:%d,%d\n", cwh.x, cwh.y ); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); + if(dib){ printf(" DIB:"); dibheader_print(dib); printf("\n"); } + else { printf(" DIB: none\n"); } + } +} + +void U_WMRDIBSTRETCHBLT_print(const char *contents){ + U_POINT16 Dst, cDst, Src, cSrc; + uint32_t dwRop3; + const char *dib; + int size = U_WMRDIBSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &dib); + if(size > 0){ + printf(" Rop3:%8.8X\n", dwRop3 ); + printf(" Src W,H:%d,%d\n", cSrc.x, cSrc.y ); + printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x ); + printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y ); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); + if(dib){ printf(" DIB:"); dibheader_print(dib); printf("\n"); } + else { printf(" DIB: none\n"); } + } +} + +void U_WMRDIBCREATEPATTERNBRUSH_print(const char *contents){ + uint16_t Style, cUsage; + const char *TBm16; + const char *dib; + int size = U_WMRDIBCREATEPATTERNBRUSH_get(contents, &Style, &cUsage, &TBm16, &dib); + if(size > 0){ + U_BITMAP16 Bm16; + printf(" Style:%d\n", Style ); + printf(" cUsage:%d\n", cUsage); + if(TBm16){ + memcpy(&Bm16, TBm16, U_SIZE_BITMAP16); + printf(" Src:Bitmap16:"); bitmap16_print(Bm16); printf("\n"); + } + else { /* from DIB */ + printf(" Src:DIB:"); dibheader_print(dib); printf("\n"); + } + } +} + +void U_WMRSTRETCHDIB_print(const char *contents){ + U_POINT16 Dst, cDst, Src, cSrc; + uint32_t dwRop3; + uint16_t cUsage; + const char *dib; + int size = U_WMRSTRETCHDIB_get(contents, &Dst, &cDst, &Src, &cSrc, &cUsage, &dwRop3, &dib); + if(size > 0){ + printf(" Rop3:%8.8X\n", dwRop3 ); + printf(" cUsage:%d\n", cUsage ); + printf(" Src W,H:%d,%d\n", cSrc.x, cSrc.y ); + printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x ); + printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y ); + printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); + if(dib){ printf(" DIB:"); dibheader_print(dib); printf("\n"); } + else { printf(" DIB: none\n"); } + } +} + +#define U_WMR44_print U_WMRNOTIMPLEMENTED_print +#define U_WMR45_print U_WMRNOTIMPLEMENTED_print +#define U_WMR46_print U_WMRNOTIMPLEMENTED_print +#define U_WMR47_print U_WMRNOTIMPLEMENTED_print + +void U_WMREXTFLOODFILL_print(const char *contents){ + uint16_t Mode; + U_COLORREF Color; + U_POINT16 coord; + int size = U_WMREXTFLOODFILL_get(contents, &Mode, &Color, &coord); + if(size > 0){ + printf(" Mode 0x%4.4X\n", Mode); + printf(" Color:"); colorref_print(Color); printf("\n"); + printf(" X,Y {%d,%d}\n", coord.x, coord.y); + } +} + +#define U_WMR49_print U_WMRNOTIMPLEMENTED_print +#define U_WMR4A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR4B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR4C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR4D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR4E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR4F_print U_WMRNOTIMPLEMENTED_print +#define U_WMR50_print U_WMRNOTIMPLEMENTED_print +#define U_WMR51_print U_WMRNOTIMPLEMENTED_print +#define U_WMR52_print U_WMRNOTIMPLEMENTED_print +#define U_WMR53_print U_WMRNOTIMPLEMENTED_print +#define U_WMR54_print U_WMRNOTIMPLEMENTED_print +#define U_WMR55_print U_WMRNOTIMPLEMENTED_print +#define U_WMR56_print U_WMRNOTIMPLEMENTED_print +#define U_WMR57_print U_WMRNOTIMPLEMENTED_print +#define U_WMR58_print U_WMRNOTIMPLEMENTED_print +#define U_WMR59_print U_WMRNOTIMPLEMENTED_print +#define U_WMR5A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR5B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR5C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR5D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR5E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR5F_print U_WMRNOTIMPLEMENTED_print +#define U_WMR60_print U_WMRNOTIMPLEMENTED_print +#define U_WMR61_print U_WMRNOTIMPLEMENTED_print +#define U_WMR62_print U_WMRNOTIMPLEMENTED_print +#define U_WMR63_print U_WMRNOTIMPLEMENTED_print +#define U_WMR64_print U_WMRNOTIMPLEMENTED_print +#define U_WMR65_print U_WMRNOTIMPLEMENTED_print +#define U_WMR66_print U_WMRNOTIMPLEMENTED_print +#define U_WMR67_print U_WMRNOTIMPLEMENTED_print +#define U_WMR68_print U_WMRNOTIMPLEMENTED_print +#define U_WMR69_print U_WMRNOTIMPLEMENTED_print +#define U_WMR6A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR6B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR6C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR6D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR6E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR6F_print U_WMRNOTIMPLEMENTED_print +#define U_WMR70_print U_WMRNOTIMPLEMENTED_print +#define U_WMR71_print U_WMRNOTIMPLEMENTED_print +#define U_WMR72_print U_WMRNOTIMPLEMENTED_print +#define U_WMR73_print U_WMRNOTIMPLEMENTED_print +#define U_WMR74_print U_WMRNOTIMPLEMENTED_print +#define U_WMR75_print U_WMRNOTIMPLEMENTED_print +#define U_WMR76_print U_WMRNOTIMPLEMENTED_print +#define U_WMR77_print U_WMRNOTIMPLEMENTED_print +#define U_WMR78_print U_WMRNOTIMPLEMENTED_print +#define U_WMR79_print U_WMRNOTIMPLEMENTED_print +#define U_WMR7A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR7B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR7C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR7D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR7E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR7F_print U_WMRNOTIMPLEMENTED_print +#define U_WMR80_print U_WMRNOTIMPLEMENTED_print +#define U_WMR81_print U_WMRNOTIMPLEMENTED_print +#define U_WMR82_print U_WMRNOTIMPLEMENTED_print +#define U_WMR83_print U_WMRNOTIMPLEMENTED_print +#define U_WMR84_print U_WMRNOTIMPLEMENTED_print +#define U_WMR85_print U_WMRNOTIMPLEMENTED_print +#define U_WMR86_print U_WMRNOTIMPLEMENTED_print +#define U_WMR87_print U_WMRNOTIMPLEMENTED_print +#define U_WMR88_print U_WMRNOTIMPLEMENTED_print +#define U_WMR89_print U_WMRNOTIMPLEMENTED_print +#define U_WMR8A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR8B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR8C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR8D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR8E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR8F_print U_WMRNOTIMPLEMENTED_print +#define U_WMR90_print U_WMRNOTIMPLEMENTED_print +#define U_WMR91_print U_WMRNOTIMPLEMENTED_print +#define U_WMR92_print U_WMRNOTIMPLEMENTED_print +#define U_WMR93_print U_WMRNOTIMPLEMENTED_print +#define U_WMR94_print U_WMRNOTIMPLEMENTED_print +#define U_WMR95_print U_WMRNOTIMPLEMENTED_print +#define U_WMR96_print U_WMRNOTIMPLEMENTED_print +#define U_WMR97_print U_WMRNOTIMPLEMENTED_print +#define U_WMR98_print U_WMRNOTIMPLEMENTED_print +#define U_WMR99_print U_WMRNOTIMPLEMENTED_print +#define U_WMR9A_print U_WMRNOTIMPLEMENTED_print +#define U_WMR9B_print U_WMRNOTIMPLEMENTED_print +#define U_WMR9C_print U_WMRNOTIMPLEMENTED_print +#define U_WMR9D_print U_WMRNOTIMPLEMENTED_print +#define U_WMR9E_print U_WMRNOTIMPLEMENTED_print +#define U_WMR9F_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA0_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA1_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA2_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA3_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA4_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA5_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA6_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA7_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA8_print U_WMRNOTIMPLEMENTED_print +#define U_WMRA9_print U_WMRNOTIMPLEMENTED_print +#define U_WMRAA_print U_WMRNOTIMPLEMENTED_print +#define U_WMRAB_print U_WMRNOTIMPLEMENTED_print +#define U_WMRAC_print U_WMRNOTIMPLEMENTED_print +#define U_WMRAD_print U_WMRNOTIMPLEMENTED_print +#define U_WMRAE_print U_WMRNOTIMPLEMENTED_print +#define U_WMRAF_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB0_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB1_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB2_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB3_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB4_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB5_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB6_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB7_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB8_print U_WMRNOTIMPLEMENTED_print +#define U_WMRB9_print U_WMRNOTIMPLEMENTED_print +#define U_WMRBA_print U_WMRNOTIMPLEMENTED_print +#define U_WMRBB_print U_WMRNOTIMPLEMENTED_print +#define U_WMRBC_print U_WMRNOTIMPLEMENTED_print +#define U_WMRBD_print U_WMRNOTIMPLEMENTED_print +#define U_WMRBE_print U_WMRNOTIMPLEMENTED_print +#define U_WMRBF_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC0_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC1_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC2_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC3_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC4_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC5_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC6_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC7_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC8_print U_WMRNOTIMPLEMENTED_print +#define U_WMRC9_print U_WMRNOTIMPLEMENTED_print +#define U_WMRCA_print U_WMRNOTIMPLEMENTED_print +#define U_WMRCB_print U_WMRNOTIMPLEMENTED_print +#define U_WMRCC_print U_WMRNOTIMPLEMENTED_print +#define U_WMRCD_print U_WMRNOTIMPLEMENTED_print +#define U_WMRCE_print U_WMRNOTIMPLEMENTED_print +#define U_WMRCF_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD0_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD1_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD2_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD3_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD4_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD5_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD6_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD7_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD8_print U_WMRNOTIMPLEMENTED_print +#define U_WMRD9_print U_WMRNOTIMPLEMENTED_print +#define U_WMRDA_print U_WMRNOTIMPLEMENTED_print +#define U_WMRDB_print U_WMRNOTIMPLEMENTED_print +#define U_WMRDC_print U_WMRNOTIMPLEMENTED_print +#define U_WMRDD_print U_WMRNOTIMPLEMENTED_print +#define U_WMRDE_print U_WMRNOTIMPLEMENTED_print +#define U_WMRDF_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE0_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE1_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE2_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE3_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE4_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE5_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE6_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE7_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE8_print U_WMRNOTIMPLEMENTED_print +#define U_WMRE9_print U_WMRNOTIMPLEMENTED_print +#define U_WMREA_print U_WMRNOTIMPLEMENTED_print +#define U_WMREB_print U_WMRNOTIMPLEMENTED_print +#define U_WMREC_print U_WMRNOTIMPLEMENTED_print +#define U_WMRED_print U_WMRNOTIMPLEMENTED_print +#define U_WMREE_print U_WMRNOTIMPLEMENTED_print +#define U_WMREF_print U_WMRNOTIMPLEMENTED_print + +void U_WMRDELETEOBJECT_print(const char *contents){ + uint16_t Object; + int size = U_WMRDELETEOBJECT_get(contents, &Object); + if(size>0){ + printf(" %-15s %d\n","Object:", Object); + } +} + +#define U_WMRF1_print U_WMRNOTIMPLEMENTED_print +#define U_WMRF2_print U_WMRNOTIMPLEMENTED_print +#define U_WMRF3_print U_WMRNOTIMPLEMENTED_print +#define U_WMRF4_print U_WMRNOTIMPLEMENTED_print +#define U_WMRF5_print U_WMRNOTIMPLEMENTED_print +#define U_WMRF6_print U_WMRNOTIMPLEMENTED_print + +void U_WMRCREATEPALETTE_print(const char *contents){ + U_PALETTE Palette; + const char *PalEntries; + int size = U_WMRCREATEPALETTE_get(contents, &Palette, &PalEntries); + if(size > 0){ + printf(" Palette:"); palette_print(&Palette, PalEntries); printf("\n"); + + } +} + +#define U_WMRF8_print U_WMRNOTIMPLEMENTED_print + +void U_WMRCREATEPATTERNBRUSH_print(const char *contents){ + U_BITMAP16 Bm16; + int pasize; + int i; + const char *Pattern; + + int size = U_WMRCREATEPATTERNBRUSH_get(contents, &Bm16, &pasize, &Pattern); + if(size > 0){ + /* BM16 is truncated, but bitmap16_print does not get into the part that was omitted */ + printf(" BitMap16: "); bitmap16_print(Bm16); printf("\n"); + printf(" Pattern: "); + for(i=0;i<pasize;i++){ + printf("%2.2X ",Pattern[i]); + } + printf("\n"); + } +} + +void U_WMRCREATEPENINDIRECT_print(const char *contents){ + U_PEN pen; + int size = U_WMRCREATEPENINDIRECT_get(contents, &pen); + if(size > 0){ + printf(" Pen:"); pen_print(pen); printf("\n"); + } +} + +void U_WMRCREATEFONTINDIRECT_print(const char *contents){ + const char *font; /* Note, because of possible struct alignment issue have to use char * to reference the data */ + int size = U_WMRCREATEFONTINDIRECT_get(contents, &font); + if(size > 0){ + printf(" Font:"); + font_print(font); + printf("\n"); + } +} + +void U_WMRCREATEBRUSHINDIRECT_print(const char *contents){ + const char *brush; /* Note, because of possible struct alignment issue have to use char * to reference the data */ + int size = U_WMRCREATEBRUSHINDIRECT_get(contents, &brush); + if(size > 0){ + printf(" Brush:"); + wlogbrush_print(brush); + printf("\n"); + } +} + +void U_WMRCREATEBITMAPINDIRECT_print(const char *contents){ /* in Wine, not in WMF PDF */ + U_WMRNOTIMPLEMENTED_print(contents); +} + +void U_WMRCREATEBITMAP_print(const char *contents){ /* in Wine, not in WMF PDF */ + U_WMRNOTIMPLEMENTED_print(contents); +} + +void U_WMRCREATEREGION_print(const char *contents){ + const char *region; /* Note, because of possible struct alignment issue have to use char * to reference the data */ + int size = U_WMRCREATEBRUSHINDIRECT_get(contents, ®ion); + if(size > 0){ + printf(" Brush:"); + printf(" Region: "); region_print(region); printf("\n"); + } +} + +/** + \brief Print any record in a wmf + \returns record length for a normal record, 0 for WMREOF, -1 for a bad record + \param contents pointer to a buffer holding all WMR records + \param blimit one byte past the last WMF record in memory. + \param recnum number of this record in contents + \param off offset to this record in contents +*/ +int U_wmf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off){ + + + uint8_t iType; + size_t size; + + contents += off; + + /* Check that the record size is OK, abort if not. + Pointer math might wrap, so check both sides of the range */ + size = U_WMRRECSAFE_get(contents, blimit); + if(!size)return(-1); + + iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) ); + +#if 1 /* show record checksums, this is NOT portable, result changes with endian type, useful for debugging */ + printf("%-30srecord:%5d type:%3u offset:%8d size:%8u\n", + U_wmr_names(iType), recnum, iType, (int) off, (int) size); +#else + printf("%-30srecord:%5d type:%3u offset:%8d size:%8u recchecksum:%u\n", + U_wmr_names(iType), recnum, iType, (int) off, (int) size, U_16_checksum((int16_t *)contents, size)); +#endif + + switch (iType) + { + case U_WMR_EOF: U_WMREOF_print(contents); size=0; break; + case U_WMR_SETBKCOLOR: U_WMRSETBKCOLOR_print(contents); break; + case U_WMR_SETBKMODE: U_WMRSETBKMODE_print(contents); break; + case U_WMR_SETMAPMODE: U_WMRSETMAPMODE_print(contents); break; + case U_WMR_SETROP2: U_WMRSETROP2_print(contents); break; + case U_WMR_SETRELABS: U_WMRSETRELABS_print(contents); break; + case U_WMR_SETPOLYFILLMODE: U_WMRSETPOLYFILLMODE_print(contents); break; + case U_WMR_SETSTRETCHBLTMODE: U_WMRSETSTRETCHBLTMODE_print(contents); break; + case U_WMR_SETTEXTCHAREXTRA: U_WMRSETTEXTCHAREXTRA_print(contents); break; + case U_WMR_SETTEXTCOLOR: U_WMRSETTEXTCOLOR_print(contents); break; + case U_WMR_SETTEXTJUSTIFICATION: U_WMRSETTEXTJUSTIFICATION_print(contents); break; + case U_WMR_SETWINDOWORG: U_WMRSETWINDOWORG_print(contents); break; + case U_WMR_SETWINDOWEXT: U_WMRSETWINDOWEXT_print(contents); break; + case U_WMR_SETVIEWPORTORG: U_WMRSETVIEWPORTORG_print(contents); break; + case U_WMR_SETVIEWPORTEXT: U_WMRSETVIEWPORTEXT_print(contents); break; + case U_WMR_OFFSETWINDOWORG: U_WMROFFSETWINDOWORG_print(contents); break; + case U_WMR_SCALEWINDOWEXT: U_WMRSCALEWINDOWEXT_print(contents); break; + case U_WMR_OFFSETVIEWPORTORG: U_WMROFFSETVIEWPORTORG_print(contents); break; + case U_WMR_SCALEVIEWPORTEXT: U_WMRSCALEVIEWPORTEXT_print(contents); break; + case U_WMR_LINETO: U_WMRLINETO_print(contents); break; + case U_WMR_MOVETO: U_WMRMOVETO_print(contents); break; + case U_WMR_EXCLUDECLIPRECT: U_WMREXCLUDECLIPRECT_print(contents); break; + case U_WMR_INTERSECTCLIPRECT: U_WMRINTERSECTCLIPRECT_print(contents); break; + case U_WMR_ARC: U_WMRARC_print(contents); break; + case U_WMR_ELLIPSE: U_WMRELLIPSE_print(contents); break; + case U_WMR_FLOODFILL: U_WMRFLOODFILL_print(contents); break; + case U_WMR_PIE: U_WMRPIE_print(contents); break; + case U_WMR_RECTANGLE: U_WMRRECTANGLE_print(contents); break; + case U_WMR_ROUNDRECT: U_WMRROUNDRECT_print(contents); break; + case U_WMR_PATBLT: U_WMRPATBLT_print(contents); break; + case U_WMR_SAVEDC: U_WMRSAVEDC_print(contents); break; + case U_WMR_SETPIXEL: U_WMRSETPIXEL_print(contents); break; + case U_WMR_OFFSETCLIPRGN: U_WMROFFSETCLIPRGN_print(contents); break; + case U_WMR_TEXTOUT: U_WMRTEXTOUT_print(contents); break; + case U_WMR_BITBLT: U_WMRBITBLT_print(contents); break; + case U_WMR_STRETCHBLT: U_WMRSTRETCHBLT_print(contents); break; + case U_WMR_POLYGON: U_WMRPOLYGON_print(contents); break; + case U_WMR_POLYLINE: U_WMRPOLYLINE_print(contents); break; + case U_WMR_ESCAPE: U_WMRESCAPE_print(contents); break; + case U_WMR_RESTOREDC: U_WMRRESTOREDC_print(contents); break; + case U_WMR_FILLREGION: U_WMRFILLREGION_print(contents); break; + case U_WMR_FRAMEREGION: U_WMRFRAMEREGION_print(contents); break; + case U_WMR_INVERTREGION: U_WMRINVERTREGION_print(contents); break; + case U_WMR_PAINTREGION: U_WMRPAINTREGION_print(contents); break; + case U_WMR_SELECTCLIPREGION: U_WMRSELECTCLIPREGION_print(contents); break; + case U_WMR_SELECTOBJECT: U_WMRSELECTOBJECT_print(contents); break; + case U_WMR_SETTEXTALIGN: U_WMRSETTEXTALIGN_print(contents); break; + case U_WMR_DRAWTEXT: U_WMRDRAWTEXT_print(contents); break; + case U_WMR_CHORD: U_WMRCHORD_print(contents); break; + case U_WMR_SETMAPPERFLAGS: U_WMRSETMAPPERFLAGS_print(contents); break; + case U_WMR_EXTTEXTOUT: U_WMREXTTEXTOUT_print(contents); break; + case U_WMR_SETDIBTODEV: U_WMRSETDIBTODEV_print(contents); break; + case U_WMR_SELECTPALETTE: U_WMRSELECTPALETTE_print(contents); break; + case U_WMR_REALIZEPALETTE: U_WMRREALIZEPALETTE_print(contents); break; + case U_WMR_ANIMATEPALETTE: U_WMRANIMATEPALETTE_print(contents); break; + case U_WMR_SETPALENTRIES: U_WMRSETPALENTRIES_print(contents); break; + case U_WMR_POLYPOLYGON: U_WMRPOLYPOLYGON_print(contents); break; + case U_WMR_RESIZEPALETTE: U_WMRRESIZEPALETTE_print(contents); break; + case U_WMR_3A: U_WMR3A_print(contents); break; + case U_WMR_3B: U_WMR3B_print(contents); break; + case U_WMR_3C: U_WMR3C_print(contents); break; + case U_WMR_3D: U_WMR3D_print(contents); break; + case U_WMR_3E: U_WMR3E_print(contents); break; + case U_WMR_3F: U_WMR3F_print(contents); break; + case U_WMR_DIBBITBLT: U_WMRDIBBITBLT_print(contents); break; + case U_WMR_DIBSTRETCHBLT: U_WMRDIBSTRETCHBLT_print(contents); break; + case U_WMR_DIBCREATEPATTERNBRUSH: U_WMRDIBCREATEPATTERNBRUSH_print(contents); break; + case U_WMR_STRETCHDIB: U_WMRSTRETCHDIB_print(contents); break; + case U_WMR_44: U_WMR44_print(contents); break; + case U_WMR_45: U_WMR45_print(contents); break; + case U_WMR_46: U_WMR46_print(contents); break; + case U_WMR_47: U_WMR47_print(contents); break; + case U_WMR_EXTFLOODFILL: U_WMREXTFLOODFILL_print(contents); break; + case U_WMR_49: U_WMR49_print(contents); break; + case U_WMR_4A: U_WMR4A_print(contents); break; + case U_WMR_4B: U_WMR4B_print(contents); break; + case U_WMR_4C: U_WMR4C_print(contents); break; + case U_WMR_4D: U_WMR4D_print(contents); break; + case U_WMR_4E: U_WMR4E_print(contents); break; + case U_WMR_4F: U_WMR4F_print(contents); break; + case U_WMR_50: U_WMR50_print(contents); break; + case U_WMR_51: U_WMR51_print(contents); break; + case U_WMR_52: U_WMR52_print(contents); break; + case U_WMR_53: U_WMR53_print(contents); break; + case U_WMR_54: U_WMR54_print(contents); break; + case U_WMR_55: U_WMR55_print(contents); break; + case U_WMR_56: U_WMR56_print(contents); break; + case U_WMR_57: U_WMR57_print(contents); break; + case U_WMR_58: U_WMR58_print(contents); break; + case U_WMR_59: U_WMR59_print(contents); break; + case U_WMR_5A: U_WMR5A_print(contents); break; + case U_WMR_5B: U_WMR5B_print(contents); break; + case U_WMR_5C: U_WMR5C_print(contents); break; + case U_WMR_5D: U_WMR5D_print(contents); break; + case U_WMR_5E: U_WMR5E_print(contents); break; + case U_WMR_5F: U_WMR5F_print(contents); break; + case U_WMR_60: U_WMR60_print(contents); break; + case U_WMR_61: U_WMR61_print(contents); break; + case U_WMR_62: U_WMR62_print(contents); break; + case U_WMR_63: U_WMR63_print(contents); break; + case U_WMR_64: U_WMR64_print(contents); break; + case U_WMR_65: U_WMR65_print(contents); break; + case U_WMR_66: U_WMR66_print(contents); break; + case U_WMR_67: U_WMR67_print(contents); break; + case U_WMR_68: U_WMR68_print(contents); break; + case U_WMR_69: U_WMR69_print(contents); break; + case U_WMR_6A: U_WMR6A_print(contents); break; + case U_WMR_6B: U_WMR6B_print(contents); break; + case U_WMR_6C: U_WMR6C_print(contents); break; + case U_WMR_6D: U_WMR6D_print(contents); break; + case U_WMR_6E: U_WMR6E_print(contents); break; + case U_WMR_6F: U_WMR6F_print(contents); break; + case U_WMR_70: U_WMR70_print(contents); break; + case U_WMR_71: U_WMR71_print(contents); break; + case U_WMR_72: U_WMR72_print(contents); break; + case U_WMR_73: U_WMR73_print(contents); break; + case U_WMR_74: U_WMR74_print(contents); break; + case U_WMR_75: U_WMR75_print(contents); break; + case U_WMR_76: U_WMR76_print(contents); break; + case U_WMR_77: U_WMR77_print(contents); break; + case U_WMR_78: U_WMR78_print(contents); break; + case U_WMR_79: U_WMR79_print(contents); break; + case U_WMR_7A: U_WMR7A_print(contents); break; + case U_WMR_7B: U_WMR7B_print(contents); break; + case U_WMR_7C: U_WMR7C_print(contents); break; + case U_WMR_7D: U_WMR7D_print(contents); break; + case U_WMR_7E: U_WMR7E_print(contents); break; + case U_WMR_7F: U_WMR7F_print(contents); break; + case U_WMR_80: U_WMR80_print(contents); break; + case U_WMR_81: U_WMR81_print(contents); break; + case U_WMR_82: U_WMR82_print(contents); break; + case U_WMR_83: U_WMR83_print(contents); break; + case U_WMR_84: U_WMR84_print(contents); break; + case U_WMR_85: U_WMR85_print(contents); break; + case U_WMR_86: U_WMR86_print(contents); break; + case U_WMR_87: U_WMR87_print(contents); break; + case U_WMR_88: U_WMR88_print(contents); break; + case U_WMR_89: U_WMR89_print(contents); break; + case U_WMR_8A: U_WMR8A_print(contents); break; + case U_WMR_8B: U_WMR8B_print(contents); break; + case U_WMR_8C: U_WMR8C_print(contents); break; + case U_WMR_8D: U_WMR8D_print(contents); break; + case U_WMR_8E: U_WMR8E_print(contents); break; + case U_WMR_8F: U_WMR8F_print(contents); break; + case U_WMR_90: U_WMR90_print(contents); break; + case U_WMR_91: U_WMR91_print(contents); break; + case U_WMR_92: U_WMR92_print(contents); break; + case U_WMR_93: U_WMR93_print(contents); break; + case U_WMR_94: U_WMR94_print(contents); break; + case U_WMR_95: U_WMR95_print(contents); break; + case U_WMR_96: U_WMR96_print(contents); break; + case U_WMR_97: U_WMR97_print(contents); break; + case U_WMR_98: U_WMR98_print(contents); break; + case U_WMR_99: U_WMR99_print(contents); break; + case U_WMR_9A: U_WMR9A_print(contents); break; + case U_WMR_9B: U_WMR9B_print(contents); break; + case U_WMR_9C: U_WMR9C_print(contents); break; + case U_WMR_9D: U_WMR9D_print(contents); break; + case U_WMR_9E: U_WMR9E_print(contents); break; + case U_WMR_9F: U_WMR9F_print(contents); break; + case U_WMR_A0: U_WMRA0_print(contents); break; + case U_WMR_A1: U_WMRA1_print(contents); break; + case U_WMR_A2: U_WMRA2_print(contents); break; + case U_WMR_A3: U_WMRA3_print(contents); break; + case U_WMR_A4: U_WMRA4_print(contents); break; + case U_WMR_A5: U_WMRA5_print(contents); break; + case U_WMR_A6: U_WMRA6_print(contents); break; + case U_WMR_A7: U_WMRA7_print(contents); break; + case U_WMR_A8: U_WMRA8_print(contents); break; + case U_WMR_A9: U_WMRA9_print(contents); break; + case U_WMR_AA: U_WMRAA_print(contents); break; + case U_WMR_AB: U_WMRAB_print(contents); break; + case U_WMR_AC: U_WMRAC_print(contents); break; + case U_WMR_AD: U_WMRAD_print(contents); break; + case U_WMR_AE: U_WMRAE_print(contents); break; + case U_WMR_AF: U_WMRAF_print(contents); break; + case U_WMR_B0: U_WMRB0_print(contents); break; + case U_WMR_B1: U_WMRB1_print(contents); break; + case U_WMR_B2: U_WMRB2_print(contents); break; + case U_WMR_B3: U_WMRB3_print(contents); break; + case U_WMR_B4: U_WMRB4_print(contents); break; + case U_WMR_B5: U_WMRB5_print(contents); break; + case U_WMR_B6: U_WMRB6_print(contents); break; + case U_WMR_B7: U_WMRB7_print(contents); break; + case U_WMR_B8: U_WMRB8_print(contents); break; + case U_WMR_B9: U_WMRB9_print(contents); break; + case U_WMR_BA: U_WMRBA_print(contents); break; + case U_WMR_BB: U_WMRBB_print(contents); break; + case U_WMR_BC: U_WMRBC_print(contents); break; + case U_WMR_BD: U_WMRBD_print(contents); break; + case U_WMR_BE: U_WMRBE_print(contents); break; + case U_WMR_BF: U_WMRBF_print(contents); break; + case U_WMR_C0: U_WMRC0_print(contents); break; + case U_WMR_C1: U_WMRC1_print(contents); break; + case U_WMR_C2: U_WMRC2_print(contents); break; + case U_WMR_C3: U_WMRC3_print(contents); break; + case U_WMR_C4: U_WMRC4_print(contents); break; + case U_WMR_C5: U_WMRC5_print(contents); break; + case U_WMR_C6: U_WMRC6_print(contents); break; + case U_WMR_C7: U_WMRC7_print(contents); break; + case U_WMR_C8: U_WMRC8_print(contents); break; + case U_WMR_C9: U_WMRC9_print(contents); break; + case U_WMR_CA: U_WMRCA_print(contents); break; + case U_WMR_CB: U_WMRCB_print(contents); break; + case U_WMR_CC: U_WMRCC_print(contents); break; + case U_WMR_CD: U_WMRCD_print(contents); break; + case U_WMR_CE: U_WMRCE_print(contents); break; + case U_WMR_CF: U_WMRCF_print(contents); break; + case U_WMR_D0: U_WMRD0_print(contents); break; + case U_WMR_D1: U_WMRD1_print(contents); break; + case U_WMR_D2: U_WMRD2_print(contents); break; + case U_WMR_D3: U_WMRD3_print(contents); break; + case U_WMR_D4: U_WMRD4_print(contents); break; + case U_WMR_D5: U_WMRD5_print(contents); break; + case U_WMR_D6: U_WMRD6_print(contents); break; + case U_WMR_D7: U_WMRD7_print(contents); break; + case U_WMR_D8: U_WMRD8_print(contents); break; + case U_WMR_D9: U_WMRD9_print(contents); break; + case U_WMR_DA: U_WMRDA_print(contents); break; + case U_WMR_DB: U_WMRDB_print(contents); break; + case U_WMR_DC: U_WMRDC_print(contents); break; + case U_WMR_DD: U_WMRDD_print(contents); break; + case U_WMR_DE: U_WMRDE_print(contents); break; + case U_WMR_DF: U_WMRDF_print(contents); break; + case U_WMR_E0: U_WMRE0_print(contents); break; + case U_WMR_E1: U_WMRE1_print(contents); break; + case U_WMR_E2: U_WMRE2_print(contents); break; + case U_WMR_E3: U_WMRE3_print(contents); break; + case U_WMR_E4: U_WMRE4_print(contents); break; + case U_WMR_E5: U_WMRE5_print(contents); break; + case U_WMR_E6: U_WMRE6_print(contents); break; + case U_WMR_E7: U_WMRE7_print(contents); break; + case U_WMR_E8: U_WMRE8_print(contents); break; + case U_WMR_E9: U_WMRE9_print(contents); break; + case U_WMR_EA: U_WMREA_print(contents); break; + case U_WMR_EB: U_WMREB_print(contents); break; + case U_WMR_EC: U_WMREC_print(contents); break; + case U_WMR_ED: U_WMRED_print(contents); break; + case U_WMR_EE: U_WMREE_print(contents); break; + case U_WMR_EF: U_WMREF_print(contents); break; + case U_WMR_DELETEOBJECT: U_WMRDELETEOBJECT_print(contents); break; + case U_WMR_F1: U_WMRF1_print(contents); break; + case U_WMR_F2: U_WMRF2_print(contents); break; + case U_WMR_F3: U_WMRF3_print(contents); break; + case U_WMR_F4: U_WMRF4_print(contents); break; + case U_WMR_F5: U_WMRF5_print(contents); break; + case U_WMR_F6: U_WMRF6_print(contents); break; + case U_WMR_CREATEPALETTE: U_WMRCREATEPALETTE_print(contents); break; + case U_WMR_F8: U_WMRF8_print(contents); break; + case U_WMR_CREATEPATTERNBRUSH: U_WMRCREATEPATTERNBRUSH_print(contents); break; + case U_WMR_CREATEPENINDIRECT: U_WMRCREATEPENINDIRECT_print(contents); break; + case U_WMR_CREATEFONTINDIRECT: U_WMRCREATEFONTINDIRECT_print(contents); break; + case U_WMR_CREATEBRUSHINDIRECT: U_WMRCREATEBRUSHINDIRECT_print(contents); break; + case U_WMR_CREATEBITMAPINDIRECT: U_WMRCREATEBITMAPINDIRECT_print(contents); break; + case U_WMR_CREATEBITMAP: U_WMRCREATEBITMAP_print(contents); break; + case U_WMR_CREATEREGION: U_WMRCREATEREGION_print(contents); break; + default: U_WMRNOTIMPLEMENTED_print(contents); break; + } //end of switch + return(size); +} + + +#ifdef __cplusplus +} +#endif diff --git a/src/extension/internal/uwmf_print.h b/src/extension/internal/uwmf_print.h new file mode 100644 index 000000000..31a8df5dc --- /dev/null +++ b/src/extension/internal/uwmf_print.h @@ -0,0 +1,48 @@ +/** + @file uwmf_print.h Functions for printing records from WMF files. +*/ + +/* +File: uwmf_print.h +Version: 0.0.2 +Date: 14-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UWMF_PRINT_ +#define _UWMF_PRINT_ + +#ifdef __cplusplus +extern "C" { +#endif +#include "uwmf.h" +#include "uemf_print.h" + +/* prototypes for objects used in WMR records (other than those defined in uemf_print.h) */ +void brush_print(U_BRUSH b); +void font_print(const char *font); +void pltntry_print(U_PLTNTRY pny); +void palette_print(const PU_PALETTE p, const char *PalEntries); +void pen_print(U_PEN p); +void rect16_ltrb_print(U_RECT16 rect); +void rect16_brtl_print(U_RECT16 rect); +void region_print(const char *region); +void bitmap16_print(U_BITMAP16 b); +void bitmapcoreheader_print(U_BITMAPCOREHEADER ch); +void logbrushw_print(U_WLOGBRUSH lb); +void polypolygon_print(uint16_t nPolys, const uint16_t *aPolyCounts, const char *Points); +void scan_print(U_SCAN sc); +void dibheader_print(const void *dh); + +/* prototypes for WMF records */ +int wmfheader_print(const char *contents, const char *blimit); +void U_WMRNOTIMPLEMENTED_print(const char *contents); +int U_wmf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off); + +#ifdef __cplusplus +} +#endif + +#endif /* _UWMF_PRINT_ */ diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp new file mode 100644 index 000000000..7147b3433 --- /dev/null +++ b/src/extension/internal/wmf-inout.cpp @@ -0,0 +1,3235 @@ +/** @file + * @brief Windows-only Enhanced Metafile input and output. + */ +/* Authors: + * Ulf Erikson <ulferikson@users.sf.net> + * Jon A. Cruz <jon@joncruz.org> + * Abhishek Sharma + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + * + * References: + * - How to Create & Play Enhanced Metafiles in Win32 + * http://support.microsoft.com/kb/q145999/ + * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles + * http://support.microsoft.com/kb/q66949/ + * - Metafile Functions + * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp + * - Metafile Structures + * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#define EMF_DRIVER //work around SPStyle issue, MUST be EMF, not WMF +#include "sp-root.h" +#include "sp-path.h" +#include "style.h" +#include "print.h" +#include "extension/system.h" +#include "extension/print.h" +#include "extension/db.h" +#include "extension/input.h" +#include "extension/output.h" +#include "display/drawing.h" +#include "display/drawing-item.h" +#include "util/units.h" +#include "clear-n_.h" +#include "document.h" +#include "libunicode-convert/unicode-convert.h" + + +#include "wmf-inout.h" +#include "wmf-print.h" + +#define PRINT_WMF "org.inkscape.print.wmf" + +#ifndef U_PS_JOIN_MASK +#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND) +#endif + +namespace Inkscape { +namespace Extension { +namespace Internal { + + +static U_RECT16 rc_old; +static bool clipset = false; +static uint32_t BLTmode=0; + +/** Construct a PNG in memory from an RGB from the WMF file + +from: +http://www.lemoda.net/c/write-png/ + +which was based on: +http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng + +gcc -Wall -o testpng testpng.c -lpng + +Originally here, but moved up + +#include <png.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +*/ + + +/* Given "bitmap", this returns the pixel of bitmap at the point + ("x", "y"). */ + +pixel_t * Wmf::pixel_at (bitmap_t * bitmap, int x, int y) +{ + return bitmap->pixels + bitmap->width * y + x; +} + + +/* Write "bitmap" to a PNG file specified by "path"; returns 0 on + success, non-zero on error. */ + +void +Wmf::my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + PMEMPNG p=(PMEMPNG)png_get_io_ptr(png_ptr); + + size_t nsize = p->size + length; + + /* allocate or grow buffer */ + if(p->buffer){ p->buffer = (char *) realloc(p->buffer, nsize); } + else{ p->buffer = (char *) malloc(nsize); } + + if(!p->buffer){ png_error(png_ptr, "Write Error"); } + + /* copy new bytes to end of buffer */ + memcpy(p->buffer + p->size, data, length); + p->size += length; +} + +void Wmf::toPNG(PMEMPNG accum, int width, int height, const char *px){ + bitmap_t bmStore; + bitmap_t *bitmap = &bmStore; + accum->buffer=NULL; // PNG constructed in memory will end up here, caller must free(). + accum->size=0; + bitmap->pixels=(pixel_t *)px; + bitmap->width = width; + bitmap->height = height; + + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + size_t x, y; + png_byte ** row_pointers = NULL; + /* The following number is set by trial and error only. I cannot + see where it it is documented in the libpng manual. + */ + int pixel_size = 3; + int depth = 8; + + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL){ + accum->buffer=NULL; + return; + } + + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL){ + png_destroy_write_struct (&png_ptr, &info_ptr); + accum->buffer=NULL; + return; + } + + /* Set up error handling. */ + + if (setjmp (png_jmpbuf (png_ptr))) { + png_destroy_write_struct (&png_ptr, &info_ptr); + accum->buffer=NULL; + return; + } + + /* Set image attributes. */ + + png_set_IHDR ( + png_ptr, + info_ptr, + bitmap->width, + bitmap->height, + depth, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT + ); + + /* Initialize rows of PNG. */ + + row_pointers = (png_byte **) png_malloc (png_ptr, bitmap->height * sizeof (png_byte *)); + for (y = 0; y < bitmap->height; ++y) { + png_byte *row = + (png_byte *) png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size); + row_pointers[bitmap->height - y - 1] = row; // Row order in WMF is reversed. + for (x = 0; x < bitmap->width; ++x) { + pixel_t * pixel = pixel_at (bitmap, x, y); + *row++ = pixel->red; // R & B channels were set correctly by DIB_to_RGB + *row++ = pixel->green; + *row++ = pixel->blue; + } + } + + /* Write the image data to memory */ + + png_set_rows (png_ptr, info_ptr, row_pointers); + + png_set_write_fn(png_ptr, accum, my_png_write_data, NULL); + + png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + for (y = 0; y < bitmap->height; y++) { + png_free (png_ptr, row_pointers[y]); + } + png_free (png_ptr, row_pointers); + png_destroy_write_struct(&png_ptr, &info_ptr); + +} + + +/* convert an WMF RGB(A) color to 0RGB +inverse of gethexcolor() in emf-print.cpp +*/ +uint32_t Wmf::sethexcolor(U_COLORREF color){ + + uint32_t out; + out = (U_RGBAGetR(color) << 16) + + (U_RGBAGetG(color) << 8 ) + + (U_RGBAGetB(color) ); + return(out); +} + + +Wmf::Wmf (void) // The null constructor +{ + return; +} + + +Wmf::~Wmf (void) //The destructor +{ + return; +} + + +bool +Wmf::check (Inkscape::Extension::Extension * /*module*/) +{ + if (NULL == Inkscape::Extension::db.get(PRINT_WMF)) + return FALSE; + return TRUE; +} + + +void +Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) +{ + Inkscape::Extension::Print *mod; + SPPrintContext context; + const gchar *oldconst; + gchar *oldoutput; + unsigned int ret; + + doc->ensureUpToDate(); + + mod = Inkscape::Extension::get_print(PRINT_WMF); + oldconst = mod->get_param_string("destination"); + oldoutput = g_strdup(oldconst); + mod->set_param_string("destination", filename); + +/* Start */ + context.module = mod; + /* fixme: This has to go into module constructor somehow */ + /* Create new arena */ + mod->base = doc->getRoot(); + Inkscape::Drawing drawing; + mod->dkey = SPItem::display_key_new(1); + mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(mod->root); + /* Print document */ + ret = mod->begin(doc); + if (ret) { + g_free(oldoutput); + throw Inkscape::Extension::Output::save_failed(); + } + mod->base->invoke_print(&context); + ret = mod->finish(); + /* Release arena */ + mod->base->invoke_hide(mod->dkey); + mod->base = NULL; + mod->root = NULL; // deleted by invoke_hide +/* end */ + + mod->set_param_string("destination", oldoutput); + g_free(oldoutput); + + return; +} + + +void +Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) +{ + Inkscape::Extension::Extension * ext; + + ext = Inkscape::Extension::db.get(PRINT_WMF); + if (ext == NULL) + return; + + bool new_val = mod->get_param_bool("textToPath"); + bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug + // reserve FixPPT2 for opacity bug. Currently WMF does not export opacity values + bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug + bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug + bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard WMF hatch + + TableGen( //possibly regenerate the unicode-convert tables + mod->get_param_bool("TnrToSymbol"), + mod->get_param_bool("TnrToWingdings"), + mod->get_param_bool("TnrToZapfDingbats"), + mod->get_param_bool("UsePUA") + ); + + ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintWmf::init or a mysterious failure will result! + ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine); + ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys); + ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch); + ext->set_param_bool("textToPath", new_val); + + print_document_to_file(doc, filename); + + return; +} + + +enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE}; // apply to either fill or stroke + + +/* WMF has no worldTranform, so this always returns 1.0. Retain it to keep WMF and WMF in sync as much as possible.*/ +double Wmf::current_scale(PWMF_CALLBACK_DATA d){ + return 1.0; +} + +/* WMF has no worldTranform, so this always returns an Identity rotation matrix, but the offsets may have values.*/ +std::string Wmf::current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset){ + std::stringstream cxform; + double scale = current_scale(d); + cxform << "\"matrix("; + cxform << 1.0/scale; cxform << ","; + cxform << 0.0; cxform << ","; + cxform << 0.0; cxform << ","; + cxform << 1.0/scale; cxform << ","; + if(useoffset){ cxform << x; cxform << ","; cxform << y; } + else { cxform << "0,0"; } + cxform << ")\""; + return(cxform.str()); +} + +/* WMF has no worldTranform, so this always returns 0. Retain it to keep WMF and WMF in sync as much as possible.*/ +double Wmf::current_rotation(PWMF_CALLBACK_DATA d){ + return 0.0; +} + +/* Add another 100 blank slots to the hatches array. +*/ +void Wmf::enlarge_hatches(PWMF_CALLBACK_DATA d){ + d->hatches.size += 100; + d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *)); +} + +/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) +*/ +int Wmf::in_hatches(PWMF_CALLBACK_DATA d, char *test){ + int i; + for(i=0; i<d->hatches.count; i++){ + if(strcmp(test,d->hatches.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one + does not exist it is added to the hatches list and also entered into <defs>. + This is also used to add the path part of the hatches, which they reference with a xlink:href +*/ +uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){ + char hatchname[64]; // big enough + char hpathname[64]; // big enough + char hbkname[64]; // big enough + char tmpcolor[8]; + char bkcolor[8]; + uint32_t idx; + + switch(hatchType){ + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor)); + break; + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor)); + break; + default: + sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor)); + break; + } + + /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch. + This will be used late to compose, or recompose the transparent or opaque final hatch.*/ + + std::string refpath; // used to reference later the path pieces which are about to be created + sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor); + idx = in_hatches(d,hpathname); + if(!idx){ // add path/color if not already present + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hpathname); + + *(d->defs) += "\n"; + switch(hatchType){ + case U_HS_HORIZONTAL: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_VERTICAL: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_FDIAGONAL: + *(d->defs) += " <line id=\"sub"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + break; + case U_HS_BDIAGONAL: + *(d->defs) += " <line id=\"sub"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + break; + case U_HS_CROSS: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_DIAGCROSS: + *(d->defs) += " <line id=\"subfd"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + *(d->defs) += " <line id=\"subbd"; + *(d->defs) += hpathname; + *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\"/>\n"; + break; + case U_HS_SOLIDCLR: + case U_HS_DITHEREDCLR: + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + default: + *(d->defs) += " <path id=\""; + *(d->defs) += hpathname; + *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; + *(d->defs) += tmpcolor; + *(d->defs) += ";stroke:none"; + *(d->defs) += "\" />\n"; + break; + } + } + + // References to paths possibly just created above. These will be used in the actual patterns. + switch(hatchType){ + case U_HS_HORIZONTAL: + case U_HS_VERTICAL: + case U_HS_CROSS: + case U_HS_SOLIDCLR: + case U_HS_DITHEREDCLR: + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + default: + refpath += " <use xlink:href=\"#"; + refpath += hpathname; + refpath += "\" />\n"; + break; + case U_HS_FDIAGONAL: + case U_HS_BDIAGONAL: + refpath += " <use xlink:href=\"#sub"; + refpath += hpathname; + refpath += "\" />\n"; + refpath += " <use xlink:href=\"#sub"; + refpath += hpathname; + refpath += "\" transform=\"translate(6,0)\" />\n"; + refpath += " <use xlink:href=\"#sub"; + refpath += hpathname; + refpath += "\" transform=\"translate(-6,0)\" />\n"; + break; + case U_HS_DIAGCROSS: + refpath += " <use xlink:href=\"#subfd"; + refpath += hpathname; + refpath += "\" />\n"; + refpath += " <use xlink:href=\"#subfd"; + refpath += hpathname; + refpath += "\" transform=\"translate(6,0)\"/>\n"; + refpath += " <use xlink:href=\"#subfd"; + refpath += hpathname; + refpath += "\" transform=\"translate(-6,0)\"/>\n"; + refpath += " <use xlink:href=\"#subbd"; + refpath += hpathname; + refpath += "\" />\n"; + refpath += " <use xlink:href=\"#subbd"; + refpath += hpathname; + refpath += "\" transform=\"translate(6,0)\"/>\n"; + refpath += " <use xlink:href=\"#subbd"; + refpath += hpathname; + refpath += "\" transform=\"translate(-6,0)\"/>\n"; + break; + } + + if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){ + sprintf(hatchname,"WMFhatch%d_%s",hatchType,tmpcolor); + sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor); + idx = in_hatches(d,hatchname); + if(!idx){ // add it if not already present + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hatchname); + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += hatchname; + *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n"; + *(d->defs) += refpath; + *(d->defs) += " </pattern>\n"; + idx = d->hatches.count; + } + } + else { // bkMode==U_OPAQUE + /* Set up an object in the defs for this background, if there is not one already there */ + sprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor)); + sprintf(hbkname,"WMFhbkclr_%s",bkcolor); + idx = in_hatches(d,hbkname); + if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name. + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hbkname); + + *(d->defs) += "\n"; + *(d->defs) += " <rect id=\""; + *(d->defs) += hbkname; + *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#"; + *(d->defs) += bkcolor; + *(d->defs) += "\" />\n"; + } + + // this is the pattern, its name will show up in Inkscape's pattern selector + sprintf(hatchname,"WMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor); + idx = in_hatches(d,hatchname); + if(!idx){ // add it if not already present + if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } + d->hatches.strings[d->hatches.count++]=strdup(hatchname); + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += hatchname; + *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n"; + *(d->defs) += " <use xlink:href=\"#"; + *(d->defs) += hbkname; + *(d->defs) += "\" />\n"; + *(d->defs) += refpath; + *(d->defs) += " </pattern>\n"; + idx = d->hatches.count; + } + } + return(idx-1); +} + +/* Add another 100 blank slots to the images array. +*/ +void Wmf::enlarge_images(PWMF_CALLBACK_DATA d){ + d->images.size += 100; + d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *)); +} + +/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1) +*/ +int Wmf::in_images(PWMF_CALLBACK_DATA d, char *test){ + int i; + for(i=0; i<d->images.count; i++){ + if(strcmp(test,d->images.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add an image from a DIB. If a matching image already exists nothing happens. If one + does not exist it is added to the images list and also entered into <defs>. + +*/ +uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage){ + + uint32_t idx; + char imagename[64]; // big enough + char xywh[64]; // big enough + int dibparams; + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px = NULL; // RGBA pixels + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // DIB color table + int32_t width, height, colortype, numCt, invert; + if((iUsage != U_DIB_RGB_COLORS) || + !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory + dib, + &px, + &ct, + &numCt, + &width, + &height, + &colortype, + &invert + )) + ){ + + if(!DIB_to_RGBA( + px, // DIB pixel array + ct, // DIB color table + numCt, // DIB color table number of entries + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array in record + height, // Height of pixel array in record + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + ) && + rgba_px + ){ + toPNG( // Get the image from the RGBA px into mempng + &mempng, + width, height, // of the SRC bitmap + rgba_px + ); + free(rgba_px); + } + } + gchar *base64String; + if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ + base64String = g_base64_encode((guchar*) px, numCt ); + idx = in_images(d, (char *) base64String); + } + else if(mempng.buffer){ + base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + idx = in_images(d, (char *) base64String); + } + else { + // insert a random 3x4 blotch otherwise + width = 3; + height = 4; + base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); + idx = in_images(d, (char *) base64String); + } + if(!idx){ // add it if not already present - we looked at the actual data for comparison + if(d->images.count == d->images.size){ enlarge_images(d); } + idx = d->images.count; + d->images.strings[d->images.count++]=strdup(base64String); + + sprintf(imagename,"WMFimage%d",idx++); + sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer + + *(d->defs) += "\n"; + *(d->defs) += " <image id=\""; + *(d->defs) += imagename; + *(d->defs) += "\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n"; + if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; } + else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; } + *(d->defs) += base64String; + *(d->defs) += "\"\n"; + *(d->defs) += " />\n"; + + + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += imagename; + *(d->defs) += "_ref\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; + *(d->defs) += " >\n"; + *(d->defs) += " <use id=\""; + *(d->defs) += imagename; + *(d->defs) += "_ign\" "; + *(d->defs) += " xlink:href=\"#"; + *(d->defs) += imagename; + *(d->defs) += "\" />\n"; + *(d->defs) += " "; + *(d->defs) += " </pattern>\n"; + } + g_free(base64String); + return(idx-1); +} + +/* (Conditionally) add an image from a Bitmap16. If a matching image already exists nothing happens. If one + does not exist it is added to the images list and also entered into <defs>. + +*/ +uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px){ + + uint32_t idx; + char imagename[64]; // big enough + char xywh[64]; // big enough + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px = NULL; // RGBA pixels + const U_RGBQUAD *ct = NULL; // color table, always NULL here + int32_t width, height, colortype, numCt, invert; + numCt = 0; + width = Bm16.Width; // bitmap width in pixels. + height = Bm16.Height; // bitmap height in scan lines. + colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration + invert = 0; + if(colortype < 16)return(0xFFFFFFFF); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. + + if(!DIB_to_RGBA(// This is not really a dib, but close enough... + px, // DIB pixel array + ct, // DIB color table (always NULL here) + numCt, // DIB color table number of entries (always 0) + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array + height, // Height of pixel array + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + ) && rgba_px) + { + toPNG( // Get the image from the RGBA px into mempng + &mempng, + width, height, // of the SRC bitmap + rgba_px + ); + free(rgba_px); + } + gchar *base64String; + if(mempng.buffer){ + base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + } + else { + // insert a random 3x4 blotch otherwise + width = 3; + height = 4; + base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); + } + idx = in_images(d, (char *) base64String); + if(!idx){ // add it if not already present - we looked at the actual data for comparison + if(d->images.count == d->images.size){ enlarge_images(d); } + idx = d->images.count; + d->images.strings[d->images.count++]=g_strdup(base64String); + + sprintf(imagename,"WMFimage%d",idx++); + sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer + + *(d->defs) += "\n"; + *(d->defs) += " <image id=\""; + *(d->defs) += imagename; + *(d->defs) += "\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n"; + *(d->defs) += " xlink:href=\"data:image/png;base64,"; + *(d->defs) += base64String; + *(d->defs) += "\"\n"; + *(d->defs) += " />\n"; + + + *(d->defs) += "\n"; + *(d->defs) += " <pattern id=\""; + *(d->defs) += imagename; + *(d->defs) += "_ref\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; + *(d->defs) += " >\n"; + *(d->defs) += " <use id=\""; + *(d->defs) += imagename; + *(d->defs) += "_ign\" "; + *(d->defs) += " xlink:href=\"#"; + *(d->defs) += imagename; + *(d->defs) += "\" />\n"; + *(d->defs) += " </pattern>\n"; + } + g_free(base64String); + return(idx-1); +} + +void +Wmf::output_style(PWMF_CALLBACK_DATA d) +{ +// SVGOStringStream tmp_id; + SVGOStringStream tmp_style; + char tmp[1024] = {0}; + + float fill_rgb[3]; + sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb ); + float stroke_rgb[3]; + sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb); + + // for U_WMR_BITBLT with no image, try to approximate some of these operations/ + // Assume src color is "white" + if(d->dwRop3){ + switch(d->dwRop3){ + case U_PATINVERT: // treat all of these as black + case U_SRCINVERT: + case U_DSTINVERT: + case U_BLACKNESS: + case U_SRCERASE: + case U_NOTSRCCOPY: + fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0; + break; + case U_SRCCOPY: // treat all of these as white + case U_NOTSRCERASE: + case U_PATCOPY: + case U_WHITENESS: + fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0; + break; + case U_SRCPAINT: // use the existing color + case U_SRCAND: + case U_MERGECOPY: + case U_MERGEPAINT: + case U_PATPAINT: + default: + break; + } + d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT + } + + // Implement some of these, the ones where the original screen color does not matter. + // The options that merge screen and pen colors cannot be done correctly because we + // have no way of knowing what color is already on the screen. For those just pass the + // pen color through. + switch(d->dwRop2){ + case U_R2_BLACK: + fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0; + stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0; + break; + case U_R2_NOTMERGEPEN: + case U_R2_MASKNOTPEN: + break; + case U_R2_NOTCOPYPEN: + fill_rgb[0] = 1.0 - fill_rgb[0]; + fill_rgb[1] = 1.0 - fill_rgb[1]; + fill_rgb[2] = 1.0 - fill_rgb[2]; + stroke_rgb[0] = 1.0 - stroke_rgb[0]; + stroke_rgb[1] = 1.0 - stroke_rgb[1]; + stroke_rgb[2] = 1.0 - stroke_rgb[2]; + break; + case U_R2_MASKPENNOT: + case U_R2_NOT: + case U_R2_XORPEN: + case U_R2_NOTMASKPEN: + case U_R2_NOTXORPEN: + case U_R2_NOP: + case U_R2_MERGENOTPEN: + case U_R2_COPYPEN: + case U_R2_MASKPEN: + case U_R2_MERGEPENNOT: + case U_R2_MERGEPEN: + break; + case U_R2_WHITE: + fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0; + stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0; + break; + default: + break; + } + + +// tmp_id << "\n\tid=\"" << (d->id++) << "\""; +// *(d->outsvg) += tmp_id.str().c_str(); + *(d->outsvg) += "\n\tstyle=\""; + if (!d->dc[d->level].fill_set || ( d->mask & U_DRAW_NOFILL)) { // nofill are lines and arcs + tmp_style << "fill:none;"; + } else { + switch(d->dc[d->level].fill_mode){ + // both of these use the url(#) method + case DRAW_PATTERN: + snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]); + tmp_style << tmp; + break; + case DRAW_IMAGE: + snprintf(tmp, 1023, "fill:url(#WMFimage%d_ref); ",d->dc[d->level].fill_idx); + tmp_style << tmp; + break; + case DRAW_PAINT: + default: // <-- this should never happen, but just in case... + snprintf( + tmp, 1023, + "fill:#%02x%02x%02x;", + SP_COLOR_F_TO_U(fill_rgb[0]), + SP_COLOR_F_TO_U(fill_rgb[1]), + SP_COLOR_F_TO_U(fill_rgb[2]) + ); + tmp_style << tmp; + break; + } + snprintf( + tmp, 1023, + "fill-rule:%s;", + (d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero") + ); + tmp_style << tmp; + tmp_style << "fill-opacity:1;"; + + // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately + if( + (d->dc[d->level].fill_set ) && + (d->dc[d->level].stroke_set ) && + (d->dc[d->level].style.stroke_width.value == 1 ) && + (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) && + ( + (d->dc[d->level].fill_mode != DRAW_PAINT) || + ( + (fill_rgb[0]==stroke_rgb[0]) && + (fill_rgb[1]==stroke_rgb[1]) && + (fill_rgb[2]==stroke_rgb[2]) + ) + ) + ){ + d->dc[d->level].stroke_set = false; + } + } + + if (!d->dc[d->level].stroke_set) { + tmp_style << "stroke:none;"; + } else { + switch(d->dc[d->level].stroke_mode){ + // both of these use the url(#) method + case DRAW_PATTERN: + snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]); + tmp_style << tmp; + break; + case DRAW_IMAGE: + snprintf(tmp, 1023, "stroke:url(#WMFimage%d_ref); ",d->dc[d->level].stroke_idx); + tmp_style << tmp; + break; + case DRAW_PAINT: + default: // <-- this should never happen, but just in case... + snprintf( + tmp, 1023, + "stroke:#%02x%02x%02x;", + SP_COLOR_F_TO_U(stroke_rgb[0]), + SP_COLOR_F_TO_U(stroke_rgb[1]), + SP_COLOR_F_TO_U(stroke_rgb[2]) + ); + tmp_style << tmp; + break; + } + if(d->dc[d->level].style.stroke_width.value){ + tmp_style << "stroke-width:" << + MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;"; + } + else { // In a WMF a 0 width pixel means "1 pixel" + tmp_style << "stroke-width:" << pix_to_abs_size( d, 1 ) << "px;"; + } + + tmp_style << "stroke-linecap:" << + ( + d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" : + d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" : + d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" : + "unknown" + ) << ";"; + + tmp_style << "stroke-linejoin:" << + ( + d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" : + d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" : + d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" : + "unknown" + ) << ";"; + + // Set miter limit if known, even if it is not needed immediately (not miter) + tmp_style << "stroke-miterlimit:" << + MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; + + if (d->dc[d->level].style.stroke_dasharray_set && + d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) + { + tmp_style << "stroke-dasharray:"; + for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) { + if (i) + tmp_style << ","; + tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; + } + tmp_style << ";"; + tmp_style << "stroke-dashoffset:0;"; + } else { + tmp_style << "stroke-dasharray:none;"; + } + tmp_style << "stroke-opacity:1;"; + } + tmp_style << "\" "; + if (clipset) + tmp_style << "\n\tclip-path=\"url(#clipWmfPath" << d->id << ")\" "; + clipset = false; + + *(d->outsvg) += tmp_style.str().c_str(); +} + + +double +Wmf::_pix_x_to_point(PWMF_CALLBACK_DATA d, double px) +{ + double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); + double tmp; + tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX; + tmp -= d->ulCornerOutX; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner + return(tmp); +} + +double +Wmf::_pix_y_to_point(PWMF_CALLBACK_DATA d, double py) +{ + double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0); + double tmp; + tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY; + tmp -= d->ulCornerOutY; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner + return(tmp); +} + + +double +Wmf::pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py) +{ + double x = _pix_x_to_point(d, px); + + return x; +} + +double +Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py) +{ + + double y = _pix_y_to_point(d, py); + + return y; + +} + +double +Wmf::pix_to_abs_size(PWMF_CALLBACK_DATA d, double px) +{ + double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d)); + return ppx; +} + +/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of WMF x,y coordinates +*/ +std::string Wmf::pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y){ + std::stringstream cxform; + cxform << pix_to_x_point(d,x,y); + cxform << ","; + cxform << pix_to_y_point(d,x,y); + return(cxform.str()); +} + + +void +Wmf::select_pen(PWMF_CALLBACK_DATA d, int index) +{ + int width; + char *record = NULL; + U_PEN up; + + if (index < 0 && index >= d->n_obj){ return; } + record = d->wmf_obj[index].record; + if(!record){ return; } + d->dc[d->level].active_pen = index; + + (void) U_WMRCREATEPENINDIRECT_get(record, &up); + width = up.Widthw[0]; // width is stored in the first 16 bits of the 32. + + switch (up.Style & U_PS_STYLE_MASK) { + case U_PS_DASH: + case U_PS_DOT: + case U_PS_DASHDOT: + case U_PS_DASHDOTDOT: + { + int i = 0; + int penstyle = (up.Style & U_PS_STYLE_MASK); + d->dc[d->level].style.stroke_dash.n_dash = + penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 3; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + if (penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + + d->dc[d->level].style.stroke_dasharray_set = 1; + break; + } + + case U_PS_SOLID: + default: + { + d->dc[d->level].style.stroke_dasharray_set = 0; + break; + } + } + + switch (up.Style & U_PS_ENDCAP_MASK) { + case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; } + case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; } + case U_PS_ENDCAP_FLAT: + default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; } + } + + switch (up.Style & U_PS_JOIN_MASK) { + case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; } + case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; } + case U_PS_JOIN_ROUND: + default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; } + } + + + double pen_width; + if (up.Style == U_PS_NULL) { + d->dc[d->level].stroke_set = false; + pen_width =0.0; + } else if (width) { + d->dc[d->level].stroke_set = true; + int cur_level = d->level; + d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC. + pen_width = pix_to_abs_size( d, width ); + d->level = cur_level; + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + d->dc[d->level].stroke_set = true; + int cur_level = d->level; + d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC. + pen_width = pix_to_abs_size( d, 1 ); + d->level = cur_level; + } + d->dc[d->level].style.stroke_width.value = pen_width; + + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(up.Color) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(up.Color) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(up.Color) ); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); +} + + +void +Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) +{ + uint8_t iType; + char *record; + const char *membrush; + + if (index < 0 || index >= d->n_obj)return; + record = d->wmf_obj[index].record; + if(!record)return; + d->dc[d->level].active_brush = index; + + iType = *(uint8_t *)(record + offsetof(U_METARECORD, iType ) ); + if(iType == U_WMR_CREATEBRUSHINDIRECT){ + U_WLOGBRUSH lb; + (void) U_WMRCREATEBRUSHINDIRECT_get(record, &membrush); + memcpy(&lb, membrush, U_SIZE_WLOGBRUSH); + if(lb.Style == U_BS_SOLID){ + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(lb.Color) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(lb.Color) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(lb.Color) ); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = true; + } + else if(lb.Style == U_BS_HATCHED){ + d->dc[d->level].fill_idx = add_hatch(d, lb.Hatch, lb.Color); + d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes + d->dc[d->level].fill_mode = DRAW_PATTERN; + d->dc[d->level].fill_set = true; + } + else if(lb.Style == U_BS_NULL){ + d->dc[d->level].fill_mode = DRAW_PAINT; // set it to something + d->dc[d->level].fill_set = false; + } + } + else if(iType == U_WMR_DIBCREATEPATTERNBRUSH){ + uint32_t tidx; + uint16_t Style; + uint16_t cUsage; + const char *Bm16h; // Pointer to Bitmap16 header (px follows) + const char *dib; // Pointer to DIB + (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib); + // Bm16 not handled yet + if(dib || Bm16h){ + if(dib){ tidx = add_dib_image(d, dib, cUsage); } + else if(Bm16h){ + U_BITMAP16 Bm16; + const char *px; + memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16); + px = Bm16h + U_SIZE_BITMAP16; + tidx = add_bm16_image(d, Bm16, px); + } + if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + } + else { + d->dc[d->level].fill_idx = tidx; + d->dc[d->level].fill_mode = DRAW_IMAGE; + } + d->dc[d->level].fill_set = true; + } + else { + g_message("Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled"); + } + } +} + + +void +Wmf::select_font(PWMF_CALLBACK_DATA d, int index) +{ + char *record = NULL; + const char *memfont; + const char *facename; + U_FONT font; + + if (index < 0 || index >= d->n_obj)return; + record = d->wmf_obj[index].record; + if (!record)return; + d->dc[d->level].active_font = index; + + + (void) U_WMRCREATEFONTINDIRECT_get(record, &memfont); + memcpy(&font,memfont,U_SIZE_FONT_CORE); //make sure it is in a properly aligned structure before touching it + facename = memfont + U_SIZE_FONT_CORE; + + /* The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT + is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont + is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored + */ + int cur_level = d->level; + d->level = d->wmf_obj[index].level; + double font_size = pix_to_abs_size( d, font.Height ); + /* snap the font_size to the nearest 1/32nd of a point. + (The size is converted from Pixels to points, snapped, and converted back.) + See the notes where d->D2Pscale[XY] are set for the reason why. + Typically this will set the font to the desired exact size. If some peculiar size + was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */ + font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8); + d->level = cur_level; + d->dc[d->level].style.font_size.computed = font_size; + d->dc[d->level].style.font_weight.value = + font.Weight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 : + font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : + font.Weight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : + font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : + font.Weight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : + font.Weight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : + font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : + font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : + font.Weight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : + font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : + font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : + font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : + font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : + U_FW_NORMAL; + d->dc[d->level].style.font_style.value = (font.Italic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); + d->dc[d->level].style.text_decoration_line.underline = font.Underline; + d->dc[d->level].style.text_decoration_line.line_through = font.StrikeOut; + d->dc[d->level].style.text_decoration_line.set = true; + d->dc[d->level].style.text_decoration_line.inherit = false; + + // malformed WMF with empty filename may exist, ignore font change if encountered + if(d->dc[d->level].font_name)free(d->dc[d->level].font_name); + if(*facename){ + d->dc[d->level].font_name = strdup(facename); + } + else { // Malformed WMF might specify an empty font name + d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants + } + d->dc[d->level].style.baseline_shift.value = round((double)((font.Escapement + 3600) % 3600) / 10.0); // use baseline_shift instead of text_transform to avoid overflow +} + +/* Find the first free hole where an object may be stored. + If there are not any return -1. This is a big error, possibly from a corrupt WMF file. +*/ +int Wmf::insertable_object(PWMF_CALLBACK_DATA d) +{ + int index = d->low_water; // Start looking from here, it may already have been filled + while(index < d->n_obj && d->wmf_obj[index].record != NULL){ index++; } + if(index >= d->n_obj)return(-1); // this is a big problem, percolate it back up so the program can get out of this gracefully + d->low_water = index; // Could probably be index+1 + return(index); +} + +void +Wmf::delete_object(PWMF_CALLBACK_DATA d, int index) +{ + if (index >= 0 && index < d->n_obj) { + // If the active object is deleted set default draw values + if(index == d->dc[d->level].active_pen){ // Use default pen: solid, black, 1 pixel wide + d->dc[d->level].active_pen = -1; + d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE + d->dc[d->level].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; + d->dc[d->level].stroke_set = true; + d->dc[d->level].style.stroke_width.value = 1.0; + d->dc[d->level].style.stroke.value.color.set( 0, 0, 0 ); + } + else if(index == d->dc[d->level].active_brush){ + d->dc[d->level].active_brush = -1; + d->dc[d->level].fill_set = false; + } + else if(index == d->dc[d->level].active_font){ + d->dc[d->level].active_font = -1; + if(d->dc[d->level].font_name){ free(d->dc[d->level].font_name);} + d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants + d->dc[d->level].style.font_size.computed = 16.0; + d->dc[d->level].style.font_weight.value = SP_CSS_FONT_WEIGHT_400; + d->dc[d->level].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL; + d->dc[d->level].style.text_decoration_line.underline = 0; + d->dc[d->level].style.text_decoration_line.line_through = 0; + d->dc[d->level].style.baseline_shift.value = 0; + } + + + d->wmf_obj[index].type = 0; +// We are keeping a copy of the WMR rather than just a structure. Currently that is not necessary as the entire +// WMF is read in at once and is stored in a big malloc. However, in past versions it was handled +// reord by record, and we might need to do that again at some point in the future if we start running into WMF +// files too big to fit into memory. + if (d->wmf_obj[index].record) + free(d->wmf_obj[index].record); + d->wmf_obj[index].record = NULL; + if(index < d->low_water)d->low_water = index; + } +} + + +// returns the new index, or -1 on error. +int Wmf::insert_object(PWMF_CALLBACK_DATA d, int type, const char *record) +{ + int index = insertable_object(d); + if(index>=0){ + d->wmf_obj[index].type = type; + d->wmf_obj[index].level = d->level; + d->wmf_obj[index].record = wmr_dup(record); + } + return(index); +} + + +/** + \fn create a UTF-32LE buffer and fill it with UNICODE unknown character + \param count number of copies of the Unicode unknown character to fill with +*/ +uint32_t *Wmf::unknown_chars(size_t count){ + uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1)); + if(!res)throw "Inkscape fatal memory allocation error - cannot continue"; + for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; } + res[count]=0; + return res; +} + +/** + \brief store SVG for an image given the pixmap and various coordinate information + \param d + \param dib packed DIB in memory + \param dx (double) destination x in inkscape pixels + \param dy (double) destination y in inkscape pixels + \param dw (double) destination width in inkscape pixels + \param dh (double) destination height in inkscape pixels + \param sx (int) source x in src image pixels + \param sy (int) source y in src image pixels + \param iUsage +*/ +void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, + double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage){ + + SVGOStringStream tmp_image; + int dibparams; + + tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; + + // The image ID is filled in much later when tmp_image is converted + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px = NULL; // RGBA pixels + char *sub_px = NULL; // RGBA pixels, subarray + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // color table + int32_t width, height, colortype, numCt, invert; + if( (iUsage != U_DIB_RGB_COLORS) || + !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory + dib, + &px, + &ct, + &numCt, + &width, + &height, + &colortype, + &invert + )) + ){ + if(sw == 0 || sh == 0){ + sw = width; + sh = height; + } + + if(!DIB_to_RGBA( + px, // DIB pixel array + ct, // DIB color table + numCt, // DIB color table number of entries + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array + height, // Height of pixel array + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + ) && + rgba_px + ){ + sub_px = RGBA_to_RGBA( + rgba_px, // full pixel array from DIB + width, // Width of pixel array + height, // Height of pixel array + sx,sy, // starting point in pixel array + &sw,&sh // columns/rows to extract from the pixel array (output array size) + ); + + if(!sub_px)sub_px=rgba_px; + toPNG( // Get the image from the RGBA px into mempng + &mempng, + sw, sh, // size of the extracted pixel array + sub_px + ); + free(sub_px); + } + } + gchar *base64String; + if(dibparams == U_BI_JPEG){ + tmp_image << " xlink:href=\"data:image/jpeg;base64,"; + base64String = g_base64_encode((guchar*) px, numCt ); + tmp_image << base64String ; + g_free(base64String); + } + else if(dibparams==U_BI_PNG){ + tmp_image << " xlink:href=\"data:image/png;base64,"; + base64String = g_base64_encode((guchar*) px, numCt ); + tmp_image << base64String ; + g_free(base64String); + } + else if(mempng.buffer){ + tmp_image << " xlink:href=\"data:image/png;base64,"; + gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + tmp_image << base64String ; + g_free(base64String); + } + else { + tmp_image << " xlink:href=\"data:image/png;base64,"; + // insert a random 3x4 blotch otherwise + tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; + } + + tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; + + tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets. + *(d->outsvg) += "\n\t <image\n"; + *(d->outsvg) += tmp_image.str().c_str(); + + *(d->outsvg) += "/> \n"; + *(d->path) = ""; +} + +/** + \brief store SVG for an image given the pixmap and various coordinate information + \param d + \param Bm16 core Bitmap16 header + \param px pointer to Bitmap16 image data + \param dx (double) destination x in inkscape pixels + \param dy (double) destination y in inkscape pixels + \param dw (double) destination width in inkscape pixels + \param dh (double) destination height in inkscape pixels + \param sx (int) source x in src image pixels + \param sy (int) source y in src image pixels + \param iUsage +*/ +void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px, + double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh){ + + SVGOStringStream tmp_image; + + tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; + + // The image ID is filled in much later when tmp_image is converted + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px = NULL; // RGBA pixels + char *sub_px = NULL; // RGBA pixels, subarray + const U_RGBQUAD *ct = NULL; // color table + int32_t width, height, colortype, numCt, invert; + + numCt = 0; + width = Bm16.Width; // bitmap width in pixels. + height = Bm16.Height; // bitmap height in scan lines. + colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration + invert = 0; + + if(sw == 0 || sh == 0){ + sw = width; + sh = height; + } + + if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. + if(!DIB_to_RGBA( // This is not really a dib, but close enough... + px, // DIB pixel array + ct, // DIB color table (always NULL here) + numCt, // DIB color table number of entries (always 0) + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array + height, // Height of pixel array + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + ) && + rgba_px + ){ + sub_px = RGBA_to_RGBA( + rgba_px, // full pixel array from DIB + width, // Width of pixel array + height, // Height of pixel array + sx,sy, // starting point in pixel array + &sw,&sh // columns/rows to extract from the pixel array (output array size) + ); + + if(!sub_px)sub_px=rgba_px; + toPNG( // Get the image from the RGBA px into mempng + &mempng, + sw, sh, // size of the extracted pixel array + sub_px + ); + free(sub_px); + } + if(mempng.buffer){ + tmp_image << " xlink:href=\"data:image/png;base64,"; + gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + tmp_image << base64String; + g_free(base64String); + } + else { + tmp_image << " xlink:href=\"data:image/png;base64,"; + // insert a random 3x4 blotch otherwise + tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; + } + + tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; + + tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets. + *(d->outsvg) += "\n\t <image\n"; + *(d->outsvg) += tmp_image.str().c_str(); + + *(d->outsvg) += "/> \n"; + *(d->path) = ""; +} + +/** + \fn myMetaFileProc(char *contents, unsigned int length, PWMF_CALLBACK_DATA lpData) + \returns 1 on success, 0 on error + \param contents binary contents of an WMF file + \param length length in bytes of contents + \param d Inkscape data structures returned by this call +*/ +//THis was a callback, just build it into a normal function +int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d) +{ + uint32_t off=0; + uint32_t wmr_mask; + int OK =1; + TCHUNK_SPECS tsp; + uint8_t iType; + int nSize; // size of the current record, in bytes, or an error value if <=0 + const char *blimit = contents + length; // 1 byte past the end of the last record + + /* variables used to retrieve data from WMF records */ + uint16_t utmp16; + U_POINT16 pt16; // any point + U_RECT16 rc; // any rectangle, usually a bounding rectangle + U_POINT16 Dst; // Destination coordinates + U_POINT16 cDst; // Destination w,h, if different from Src + U_POINT16 Src; // Source coordinates + U_POINT16 cSrc; // Source w,h, if different from Dst + U_POINT16 cwh; // w,h, if Src and Dst use the same values + uint16_t cUsage; // colorusage enumeration + uint32_t dwRop3; // raster operations, these are only barely supported here + const char *dib; // DIB style image structure + U_BITMAP16 Bm16; // Bitmap16 style image structure + const char *px; // Image for Bm16 + uint16_t cPts; // number of points in the next variable + const char *points; // any list of U_POINT16, may not be aligned + int16_t tlen; // length of returned text, in bytes + const char *text; // returned text, Latin1 encoded + uint16_t Opts; + const int16_t *dx; // character spacing for one text mode, inkscape ignores this + double left, right, top, bottom; // values used, because a bounding rect can have values reversed L<->R, T<->B + + uint16_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written + U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor + + /* initialize the tsp for text reassembly */ + tsp.string = NULL; + tsp.ori = 0.0; /* degrees */ + tsp.fs = 12.0; /* font size */ + tsp.x = 0.0; + tsp.y = 0.0; + tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/ + tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ + tsp.taln = ALILEFT + ALIBASE; + tsp.ldir = LDIR_LR; + tsp.color.Red = 0; /* RGB Black */ + tsp.color.Green = 0; /* RGB Black */ + tsp.color.Blue = 0; /* RGB Black */ + tsp.color.Reserved = 0; /* not used */ + tsp.italics = 0; + tsp.weight = 80; + tsp.decoration = TXTDECOR_NONE; + tsp.condensed = 100; + tsp.co = 0; + tsp.fi_idx = -1; /* set to an invalid */ + + SVGOStringStream dbg_str; + + /* There is very little information in WMF headers, get what is there. In many cases pretty much everything will have to + default. If there is no placeable header we know pretty much nothing about the size of the page, in which case + assume that it is 1440 WMF pixels/inch and make the page A4 landscape. That is almost certainly the wrong page size + but it has to be set to something, and nothing horrible happens if the drawing goes off the page. */ + { + + U_WMRPLACEABLE Placeable; + U_WMRHEADER Header; + off = 0; + nSize = wmfheader_get(contents, blimit, &Placeable, &Header); + if(!nSize)return(0); + if(!Header.nObjects){ Header.nObjects = 256; }// there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway. + d->n_obj = Header.nObjects; + d->wmf_obj = new WMF_OBJECT[d->n_obj]; + d->low_water = 0; // completely empty at this point, so start searches at 0 + + // Init the new wmf_obj list elements to null, provided the + // dynamic allocation succeeded. + if ( d->wmf_obj != NULL ) + { + for( int i=0; i < d->n_obj; ++i ) + d->wmf_obj[i].record = NULL; + } //if + + if(!Placeable.Inch){ Placeable.Inch= 1440; } + if(!Placeable.Dst.right && !Placeable.Dst.left){ // no page size has been supplied + // This is gross, scan forward looking for a SETWINDOWEXT record, use the first one found to + // define the page size + int hold_nSize = off = nSize; + Placeable.Dst.left = 0; + Placeable.Dst.top = 0; + while(OK){ + nSize = U_WMRRECSAFE_get(contents + off, blimit); + if(nSize){ + iType = *(uint8_t *)(contents + off + offsetof(U_METARECORD, iType ) ); + if(iType == U_WMR_SETWINDOWEXT){ + OK=0; + nSize = U_WMRSETWINDOWEXT_get(contents + off, &Dst); + Placeable.Dst.right = Dst.x; + Placeable.Dst.bottom = Dst.y; + } + else if(iType == U_WMR_EOF){ + OK=0; + // Really messed up WMF, have to set the page to something, make it A4 horizontal + Placeable.Dst.right = round(((double) Placeable.Inch) * 297.0/25.4); + Placeable.Dst.bottom = round(((double) Placeable.Inch) * 210.0/25.4); + } + else { + off += nSize; + } + } + } + off=0; + nSize = hold_nSize; + OK=1; + } + + // drawing size in WMF pixels + d->PixelsInX = Placeable.Dst.right - Placeable.Dst.left + 1; + d->PixelsInY = Placeable.Dst.bottom - Placeable.Dst.top + 1; + + /* + Set values for Window and ViewPort extents to 0 - not defined yet. + */ + d->dc[d->level].sizeView.x = d->dc[d->level].sizeWnd.x = 0; + d->dc[d->level].sizeView.y = d->dc[d->level].sizeWnd.y = 0; + + // Upper left corner in device units, usually both 0, but not always + d->ulCornerInX = Placeable.Dst.left; + d->ulCornerInY = Placeable.Dst.top; + + d->E2IdirY = 1.0; // assume MM_ANISOTROPIC, if not, this will be changed later + d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "in", "px")/(double) Placeable.Inch; + trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */ + + // drawing size in Inkscape pixels + d->PixelsOutX = d->PixelsInX * d->D2PscaleX; + d->PixelsOutY = d->PixelsInY * d->D2PscaleY; + + // Upper left corner in Inkscape units + d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX; + d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY; + + d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known + dbg_str << "<!-- U_WMR_HEADER -->\n"; + + *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"; + + SVGOStringStream tmp_outdef; + tmp_outdef << "<svg\n"; + tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n"; + tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n"; + tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"; + tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role + tmp_outdef << " version=\"1.0\"\n"; + + tmp_outdef << + " width=\"" << d->PixelsOutX/ Inkscape::Util::Quantity::convert(1, "mm", "px") << "mm\"\n" << + " height=\"" << d->PixelsOutY/ Inkscape::Util::Quantity::convert(1, "mm", "px") << "mm\">\n"; + *(d->outdef) += tmp_outdef.str().c_str(); + *(d->outdef) += "<defs>"; // temporary end of header + + // d->defs holds any defines which are read in. + + + } + + + + while(OK){ + if(off>=length)return(0); //normally should exit from while after WMREOF sets OK to false. + contents += nSize; // pointer to the start of the next record + off += nSize; // offset from beginning of buffer to the start of the next record + + SVGOStringStream tmp_path; + SVGOStringStream tmp_str; + + /* Check that the current record size is OK, abort if not. + Pointer math might wrap, so check both sides of the range. + Some of the records will reset this with the same value,others will not + return a value at this time. */ + nSize = U_WMRRECSAFE_get(contents, blimit); + if(!nSize)break; + + iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) ); + +// Uncomment the following to track down toxic records +// std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl; + + wmr_mask = U_wmr_properties(iType); + if(wmr_mask == U_WMR_INVALID){ throw "Inkscape fatal programming error at U_wmr_properties"; } + +/* Uncomment the following to track down text problems */ +//std::cout << "tri->dirty:"<< d->tri->dirty << " wmr_mask: " << std::hex << wmr_mask << std::dec << std::endl; + + // incompatible change to text drawing detected (color or background change) forces out existing text + // OR + // next record is valid type and forces pending text to be drawn immediately + if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){ + TR_layout_analyze(d->tri); + TR_layout_2_svg(d->tri); + SVGOStringStream ts; + ts << d->tri->out; + *(d->outsvg) += ts.str().c_str(); + d->tri = trinfo_clear(d->tri); + } + if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag + d->dc[d->level].bkMode = tbkMode; + memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF)); + + if(d->dc[d->level].dirty & DIRTY_TEXT){ + // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing... + if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); } + else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque + } + + /* It is possible to have a series of EMF records that would result in + the following creating hash patterns which are never used. For instance, if + there were a series of records that changed the background color but did nothing + else. + */ + if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){ + select_brush(d, d->dc[d->level].fill_recidx); + } + + d->dc[d->level].dirty = 0; + } + +//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl; +/* +std::cout << "BEFORE DRAW" + << " test0 " << ( d->mask & U_DRAW_VISIBLE) + << " test1 " << ( d->mask & U_DRAW_FORCE) + << " test2 " << (wmr_mask & U_DRAW_ALTERS) + << " test3 " << (wmr_mask & U_DRAW_VISIBLE) + << " test4 " << !(d->mask & U_DRAW_ONLYTO) + << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) ) + << std::endl; +*/ + + if( + (wmr_mask != 0xFFFFFFFF) && // next record is valid type + (d->mask & U_DRAW_VISIBLE) && // This record is drawable + ( + (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH + (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way + ( (wmr_mask & U_DRAW_VISIBLE) && // Next record is visible... + ( + ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible + ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records + ) + ) + ) + ){ +// std::cout << "PATH DRAW at TOP <<+++++++++++++++++++++++++++++++++++++" << std::endl; + *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!! + output_style(d); + *(d->outsvg) += "\n\t"; + *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! + *(d->outsvg) += *(d->path); + *(d->outsvg) += " \" /> \n"; + *(d->path) = ""; //reset the path + // reset the flags + d->mask = 0; + d->drawtype = 0; + } +// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl; + switch (iType) + { + case U_WMR_EOF: + { + dbg_str << "<!-- U_WMR_EOF -->\n"; + + *(d->outsvg) = *(d->outdef) + *(d->defs) + "\n</defs>\n\n" + *(d->outsvg) + "</svg>\n"; + OK=0; + break; + } + case U_WMR_SETBKCOLOR: + { + dbg_str << "<!-- U_WMR_SETBKCOLOR -->\n"; + nSize = U_WMRSETBKCOLOR_get(contents, &tbkColor); + if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){ + d->dc[d->level].dirty |= DIRTY_TEXT; + if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; } + tbkMode = d->dc[d->level].bkMode; + } + break; + } + case U_WMR_SETBKMODE:{ + dbg_str << "<!-- U_WMR_SETBKMODE -->\n"; + nSize = U_WMRSETBKMODE_get(contents, &tbkMode); + if(tbkMode != d->dc[d->level].bkMode){ + d->dc[d->level].dirty |= DIRTY_TEXT; + if(tbkMode != d->dc[d->level].bkMode){ + if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; } + } + memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF)); + } + break; + } + case U_WMR_SETMAPMODE: + { + dbg_str << "<!-- U_WMR_SETMAPMODE -->\n"; + nSize = U_WMRSETMAPMODE_get(contents, &utmp16); + switch (utmp16){ + case U_MM_TEXT: + default: + // Use all values from the header. + break; + /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex + and show up in ScaleIn[XY] + */ + case U_MM_LOMETRIC: // 1 LU = 0.1 mm, + case U_MM_HIMETRIC: // 1 LU = 0.01 mm + case U_MM_LOENGLISH: // 1 LU = 0.1 in + case U_MM_HIENGLISH: // 1 LU = 0.01 in + case U_MM_TWIPS: // 1 LU = 1/1440 in + d->E2IdirY = -1.0; + // Use d->D2Pscale[XY] values from the header. + break; + case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX + case U_MM_ANISOTROPIC: + break; + } + break; + } + case U_WMR_SETROP2: + { + dbg_str << "<!-- U_WMR_SETROP2 -->\n"; + nSize = U_WMRSETROP2_get(contents, &utmp16); + d->dwRop2 = utmp16; + break; + } + case U_WMR_SETRELABS: dbg_str << "<!-- U_WMR_SETRELABS -->\n"; break; + case U_WMR_SETPOLYFILLMODE: + { + dbg_str << "<!-- U_WMR_SETPOLYFILLMODE -->\n"; + nSize = U_WMRSETPOLYFILLMODE_get(contents, &utmp16); + d->dc[d->level].style.fill_rule.value = (utmp16 == U_ALTERNATE ? 0 : utmp16 == U_WINDING ? 1 : 0); + break; + } + case U_WMR_SETSTRETCHBLTMODE: + { + dbg_str << "<!-- U_WMR_SETSTRETCHBLTMODE -->\n"; + nSize = U_WMRSETSTRETCHBLTMODE_get(contents, &utmp16); + BLTmode = utmp16; + break; + } + case U_WMR_SETTEXTCHAREXTRA: dbg_str << "<!-- U_WMR_SETTEXTCHAREXTRA -->\n"; break; + case U_WMR_SETTEXTCOLOR: + { + dbg_str << "<!-- U_WMR_SETTEXTCOLOR -->\n"; + nSize = U_WMRSETTEXTCOLOR_get(contents, &(d->dc[d->level].textColor)); + if(tbkMode != d->dc[d->level].bkMode){ + if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; } + } + // not text_dirty, because multicolored complex text is supported in libTERE + break; + } + case U_WMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_WMR_SETTEXTJUSTIFICATION -->\n"; break; + case U_WMR_SETWINDOWORG: + { + dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n"; + nSize = U_WMRSETWINDOWORG_get(contents, &d->dc[d->level].winorg); + break; + } + case U_WMR_SETWINDOWEXT: + { + dbg_str << "<!-- U_WMR_SETWINDOWEXT -->\n"; + + nSize = U_WMRSETWINDOWEXT_get(contents, &d->dc[d->level].sizeWnd); + + if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) { + d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; + if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) { + d->dc[d->level].sizeWnd.x = d->PixelsOutX; + d->dc[d->level].sizeWnd.y = d->PixelsOutY; + } + } + + if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) { + d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; + } + + /* scales logical to WMF pixels, transfer a negative sign on Y, if any */ + if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y; + if(d->dc[d->level].ScaleInY < 0){ + d->dc[d->level].ScaleInY *= -1.0; + d->E2IdirY = -1.0; + } + } + else { + d->dc[d->level].ScaleInX = 1; + d->dc[d->level].ScaleInY = 1; + } + break; + } + case U_WMR_SETVIEWPORTORG: + { + dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n"; + nSize = U_WMRSETVIEWPORTORG_get(contents, &d->dc[d->level].vieworg); + break; + } + case U_WMR_SETVIEWPORTEXT: + { + dbg_str << "<!-- U_WMR_SETVIEWPORTEXTEX -->\n"; + + nSize = U_WMRSETVIEWPORTEXT_get(contents, &d->dc[d->level].sizeView); + + if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) { + d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; + if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) { + d->dc[d->level].sizeView.x = d->PixelsOutX; + d->dc[d->level].sizeView.y = d->PixelsOutY; + } + } + + if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) { + d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; + } + + /* scales logical to WMF pixels, transfer a negative sign on Y, if any */ + if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y; + if(d->dc[d->level].ScaleInY < 0){ + d->dc[d->level].ScaleInY *= -1.0; + d->E2IdirY = -1.0; + } + } + else { + d->dc[d->level].ScaleInX = 1; + d->dc[d->level].ScaleInY = 1; + } + break; + } + case U_WMR_OFFSETWINDOWORG: dbg_str << "<!-- U_WMR_OFFSETWINDOWORG -->\n"; break; + case U_WMR_SCALEWINDOWEXT: dbg_str << "<!-- U_WMR_SCALEWINDOWEXT -->\n"; break; + case U_WMR_OFFSETVIEWPORTORG: dbg_str << "<!-- U_WMR_OFFSETVIEWPORTORG -->\n"; break; + case U_WMR_SCALEVIEWPORTEXT: dbg_str << "<!-- U_WMR_SCALEVIEWPORTEXT -->\n"; break; + case U_WMR_LINETO: + { + dbg_str << "<!-- U_WMR_LINETO -->\n"; + + nSize = U_WMRLINETO_get(contents, &pt16); + + d->mask |= wmr_mask; + + tmp_path << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " "; + break; + } + case U_WMR_MOVETO: + { + dbg_str << "<!-- U_WMR_MOVETO -->\n"; + + nSize = U_WMRLINETO_get(contents, &pt16); + + d->mask |= wmr_mask; + + d->dc[d->level].cur = pt16; + + tmp_path << + "\n\tM " << pix_to_xy( d, pt16.x, pt16.y ) << " "; + break; + } + case U_WMR_EXCLUDECLIPRECT: dbg_str << "<!-- U_WMR_EXCLUDECLIPRECT -->\n"; break; + case U_WMR_INTERSECTCLIPRECT: + { + dbg_str << "<!-- U_WMR_INTERSECTCLIPRECT -->\n"; + + nSize = U_WMRINTERSECTCLIPRECT_get(contents, &rc); + clipset = true; + if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) + break; + rc_old = rc; + + double dx = pix_to_x_point( d, rc.left, rc.top ); + double dy = pix_to_y_point( d, rc.left, rc.top ); + double dw = pix_to_abs_size( d, rc.right - rc.left + 1); + double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n<clipPath\n\tclipPathUnits=\"userSpaceOnUse\" "; + tmp_rectangle << "\nid=\"clipWmfPath" << ++(d->id) << "\" >"; + tmp_rectangle << "\n<rect "; + tmp_rectangle << "\n x=\"" << dx << "\" "; + tmp_rectangle << "\n y=\"" << dy << "\" "; + tmp_rectangle << "\n width=\"" << dw << "\" "; + tmp_rectangle << "\n height=\"" << dh << "\" />"; + tmp_rectangle << "\n</clipPath>"; + + *(d->outdef) += tmp_rectangle.str().c_str(); + *(d->path) = ""; + break; + } + case U_WMR_ARC: + { + dbg_str << "<!-- U_WMR_ARC -->\n"; + U_POINT16 ArcStart, ArcEnd; + nSize = U_WMRARC_get(contents, &ArcStart, &ArcEnd, &rc); + + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + int stat = wmr_arc_points(rc, ArcStart, ArcEnd,&f1, f2, ¢er, &start, &end, &size); + if(!stat){ + tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; + d->mask |= wmr_mask; + } + else { + dbg_str << "<!-- ARC record is invalid -->\n"; + } + break; + } + case U_WMR_ELLIPSE: + { + dbg_str << "<!-- U_WMR_ELLIPSE -->\n"; + + nSize = U_WMRELLIPSE_get(contents, &rc); + + double cx = pix_to_x_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 ); + double cy = pix_to_y_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 ); + double rx = pix_to_abs_size( d, fabs(rc.right - rc.left )/2.0 ); + double ry = pix_to_abs_size( d, fabs(rc.top - rc.bottom)/2.0 ); + + SVGOStringStream tmp_ellipse; + tmp_ellipse << "cx=\"" << cx << "\" "; + tmp_ellipse << "cy=\"" << cy << "\" "; + tmp_ellipse << "rx=\"" << rx << "\" "; + tmp_ellipse << "ry=\"" << ry << "\" "; + + d->mask |= wmr_mask; + + *(d->outsvg) += " <ellipse "; + output_style(d); + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_ellipse.str().c_str(); + *(d->outsvg) += "/> \n"; + *(d->path) = ""; + break; + } + case U_WMR_FLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break; + case U_WMR_PIE: + { + dbg_str << "<!-- U_WMR_PIE -->\n"; + U_POINT16 ArcStart, ArcEnd; + nSize = U_WMRPIE_get(contents, &ArcStart, &ArcEnd, &rc); + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y); + tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; + tmp_path << " z "; + d->mask |= wmr_mask; + } + else { + dbg_str << "<!-- PIE record is invalid -->\n"; + } + break; + } + case U_WMR_RECTANGLE: + { + dbg_str << "<!-- U_WMR_RECTANGLE -->\n"; + + nSize = U_WMRRECTANGLE_get(contents, &rc); + U_sanerect16(rc, &left, &top, &right, &bottom); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, left , top ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, right, top ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, right, bottom ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, left, bottom ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= wmr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_WMR_ROUNDRECT: + { + dbg_str << "<!-- U_WMR_ROUNDRECT -->\n"; + + int16_t Height,Width; + nSize = U_WMRROUNDRECT_get(contents, &Width, &Height, &rc); + U_sanerect16(rc, &left, &top, &right, &bottom); + double f = 4.*(sqrt(2) - 1)/3; + double f1 = 1.0 - f; + double cnx = Width/2; + double cny = Height/2; + + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n" + << " M " + << pix_to_xy(d, left , top + cny ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, left , top + cny*f1 ) + << " " + << pix_to_xy(d, left + cnx*f1 , top ) + << " " + << pix_to_xy(d, left + cnx , top ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, right - cnx , top ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, right - cnx*f1 , top ) + << " " + << pix_to_xy(d, right , top + cny*f1 ) + << " " + << pix_to_xy(d, right , top + cny ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, right , bottom - cny ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, right , bottom - cny*f1 ) + << " " + << pix_to_xy(d, right - cnx*f1 , bottom ) + << " " + << pix_to_xy(d, right - cnx , bottom ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, left + cnx , bottom ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, left + cnx*f1 , bottom ) + << " " + << pix_to_xy(d, left , bottom - cny*f1 ) + << " " + << pix_to_xy(d, left , bottom - cny ) + << "\n"; + tmp_rectangle << " z\n"; + + + d->mask |= wmr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_WMR_PATBLT: + { + dbg_str << "<!-- U_WMR_PATBLT -->\n"; + // Treat this like any other rectangle, ie, ignore the dwRop3 + nSize = U_WMRPATBLT_get(contents, &Dst, &cwh, &dwRop3); + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, Dst.x , Dst.y ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y + cwh.y ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x, Dst.y + cwh.y ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= wmr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_WMR_SAVEDC: + { + dbg_str << "<!-- U_WMR_SAVEDC -->\n"; + + if (d->level < WMF_MAX_DC) { + d->dc[d->level + 1] = d->dc[d->level]; + if(d->dc[d->level].font_name){ + d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated + } + d->level = d->level + 1; + } + break; + } + case U_WMR_SETPIXEL: dbg_str << "<!-- U_WMR_SETPIXEL -->\n"; break; + case U_WMR_OFFSETCLIPRGN: dbg_str << "<!-- U_WMR_OFFSETCLIPRGN/POLYLINE -->\n"; break; + // U_WMR_TEXTOUT should be here, but has been moved down to merge with U_WMR_EXTTEXTOUT + case U_WMR_BITBLT: + { + dbg_str << "<!-- U_WMR_BITBLT -->\n"; + nSize = U_WMRBITBLT_get(contents,&Dst,&cwh,&Src,&dwRop3,&Bm16,&px); + if(!px){ + int32_t dx = Dst.x; + int32_t dy = Dst.y; + int32_t dw = cwh.x; + int32_t dh = cwh.y; + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= wmr_mask; + d->dwRop3 = dwRop3; // we will try to approximate SOME of these + d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that + + tmp_path << tmp_rectangle.str().c_str(); + } + else { /* Not done yet, Bm16 image present */ } + double dx = pix_to_x_point( d, Dst.x, Dst.y); + double dy = pix_to_y_point( d, Dst.x, Dst.y); + double dw = pix_to_abs_size( d, cwh.x); + double dh = pix_to_abs_size( d, cwh.y); + //source position within the bitmap, in pixels + int sx = Src.x; + int sy = Src.y; + int sw = 0; // extract all of the image + int sh = 0; + if(sx<0)sx=0; + if(sy<0)sy=0; + common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh); + break; + } + case U_WMR_STRETCHBLT: + { + dbg_str << "<!-- U_WMR_STRETCHBLT -->\n"; + nSize = U_WMRSTRETCHBLT_get(contents,&Dst,&cDst,&Src,&cSrc,&dwRop3,&Bm16,&px); + if(!px){ + int32_t dx = Dst.x; + int32_t dy = Dst.y; + int32_t dw = cDst.x; + int32_t dh = cDst.y; + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= wmr_mask; + d->dwRop3 = dwRop3; // we will try to approximate SOME of these + d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that + + tmp_path << tmp_rectangle.str().c_str(); + } + else { /* Not done yet, Bm16 image present */ } + double dx = pix_to_x_point( d, Dst.x, Dst.y); + double dy = pix_to_y_point( d, Dst.x, Dst.y); + double dw = pix_to_abs_size( d, cDst.x); + double dh = pix_to_abs_size( d, cDst.y); + //source position within the bitmap, in pixels + int sx = Src.x; + int sy = Src.y; + int sw = cSrc.x; // extract the specified amount of the image + int sh = cSrc.y; + if(sx<0)sx=0; + if(sy<0)sy=0; + common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh); + break; + } + case U_WMR_POLYGON: + case U_WMR_POLYLINE: + { + dbg_str << "<!-- U_WMR_POLYGON/POLYLINE -->\n"; + nSize = U_WMRPOLYGON_get(contents, &cPts, &points); + uint32_t i; + + if (cPts < 2)break; + + d->mask |= wmr_mask; + memcpy(&pt16,points,U_SIZE_POINT16); points += U_SIZE_POINT16; + + tmp_str << "\n\tM " << pix_to_xy( d, pt16.x, pt16.y) << " "; + + for (i=1; i<cPts; i++) { + memcpy(&pt16,points,U_SIZE_POINT16); points+=U_SIZE_POINT16; + tmp_str << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " "; + } + + tmp_path << tmp_str.str().c_str(); + if(iType==U_WMR_POLYGON){ tmp_path << " z"; } + + break; + } + case U_WMR_ESCAPE: // only 3 types of escape are implemented + { + dbg_str << "<!-- U_WMR_ESCAPE -->\n"; + uint16_t Escape, elen; + nSize = U_WMRESCAPE_get(contents, &Escape, &elen, &text); + if(elen>=4){ + uint32_t utmp4; + memcpy(&utmp4, text ,4); + if(Escape == U_MFE_SETLINECAP){ + switch (utmp4 & U_PS_ENDCAP_MASK) { + case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; } + case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; } + case U_PS_ENDCAP_FLAT: + default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; } + } + } + else if(Escape == U_MFE_SETLINEJOIN){ + switch (utmp4 & U_PS_JOIN_MASK) { + case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; } + case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; } + case U_PS_JOIN_ROUND: + default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; } + } + } + else if(Escape == U_MFE_SETMITERLIMIT){ + //The function takes a float but uses a 32 bit int in the record. + float miterlimit = utmp4; + d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size + if (d->dc[d->level].style.stroke_miterlimit.value < 2) + d->dc[d->level].style.stroke_miterlimit.value = 2.0; + } + } + break; + } + case U_WMR_RESTOREDC: + { + dbg_str << "<!-- U_WMR_RESTOREDC -->\n"; + + int16_t DC; + nSize = U_WMRRESTOREDC_get(contents, &DC); + int old_level = d->level; + if (DC >= 0) { + if (DC < d->level) + d->level = DC; + } + else { + if (d->level + DC >= 0) + d->level = d->level + DC; + } + while (old_level > d->level) { + if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))){ + delete[] d->dc[old_level].style.stroke_dash.dash; + } + if(d->dc[old_level].font_name){ + free(d->dc[old_level].font_name); // else memory leak + d->dc[old_level].font_name = NULL; + } + old_level--; + } + break; + } + case U_WMR_FILLREGION: dbg_str << "<!-- U_WMR_FILLREGION -->\n"; break; + case U_WMR_FRAMEREGION: dbg_str << "<!-- U_WMR_FRAMEREGION -->\n"; break; + case U_WMR_INVERTREGION: dbg_str << "<!-- U_WMR_INVERTREGION -->\n"; break; + case U_WMR_PAINTREGION: dbg_str << "<!-- U_WMR_PAINTREGION -->\n"; break; + case U_WMR_SELECTCLIPREGION: + { + dbg_str << "<!-- U_WMR_EXTSELECTCLIPRGN -->\n"; + nSize = U_WMRSELECTCLIPREGION_get(contents, &utmp16); + if (utmp16 == U_RGN_COPY) + clipset = false; + break; + } + case U_WMR_SELECTOBJECT: + { + dbg_str << "<!-- U_WMR_SELECTOBJECT -->\n"; + + nSize = U_WMRSELECTOBJECT_get(contents, &utmp16); + unsigned int index = utmp16; + + // WMF has no stock objects + if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) { + switch (d->wmf_obj[index].type) + { + case U_WMR_CREATEPENINDIRECT: + select_pen(d, index); + break; + case U_WMR_CREATEBRUSHINDIRECT: + case U_WMR_DIBCREATEPATTERNBRUSH: + select_brush(d, index); + break; + case U_WMR_CREATEFONTINDIRECT: + select_font(d, index); + break; + case U_WMR_CREATEPATTERNBRUSH: // <- this one did not display properly on XP, DIBCREATEPATTERNBRUSH works + case U_WMR_CREATEPALETTE: + case U_WMR_CREATEBITMAPINDIRECT: + case U_WMR_CREATEBITMAP: + case U_WMR_CREATEREGION: + /* these do not do anything, but their objects must be kept in the count */ + break; + } + } + break; + } + case U_WMR_SETTEXTALIGN: + { + dbg_str << "<!-- U_WMR_SETTEXTALIGN -->\n"; + nSize = U_WMRSETTEXTALIGN_get(contents, &(d->dc[d->level].textAlign)); + break; + } + case U_WMR_DRAWTEXT: dbg_str << "<!-- U_WMR_DRAWTEXT -->\n"; break; + case U_WMR_CHORD: + { + dbg_str << "<!-- U_WMR_CHORD -->\n"; + U_POINT16 ArcStart, ArcEnd; + nSize = U_WMRCHORD_get(contents, &ArcStart, &ArcEnd, &rc); + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; + tmp_path << " z "; + d->mask |= wmr_mask; + } + else { + dbg_str << "<!-- CHORD record is invalid -->\n"; + } + break; + } + case U_WMR_SETMAPPERFLAGS: dbg_str << "<!-- U_WMR_SETMAPPERFLAGS -->\n"; break; + case U_WMR_TEXTOUT: + case U_WMR_EXTTEXTOUT: + { + if(iType == U_WMR_TEXTOUT){ + dbg_str << "<!-- U_WMR_TEXTOUT -->\n"; + nSize = U_WMRTEXTOUT_get(contents, &Dst, &tlen, &text); + } + else { + dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n"; + nSize = U_WMREXTTEXTOUT_get(contents, &Dst, &tlen, &Opts, &text, &dx, &rc ); + } + uint32_t fOptions = Opts; + + double x1,y1; + int cChars; + x1 = Dst.x; + y1 = Dst.y; + cChars = tlen; + + if (d->dc[d->level].textAlign & U_TA_UPDATECP) { + x1 = d->dc[d->level].cur.x; + y1 = d->dc[d->level].cur.y; + } + + double x = pix_to_x_point(d, x1, y1); + double y = pix_to_y_point(d, x1, y1); + + /* Rotation issues are handled entirely in libTERE now */ + + uint32_t *dup_wt = NULL; + + dup_wt = U_Latin1ToUtf32le(text, cChars, NULL); + if(!dup_wt)dup_wt = unknown_chars(cChars); + + msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats + + if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){ + free(d->dc[d->level].font_name); + d->dc[d->level].font_name = strdup("Times New Roman"); + } + + char *ansi_text; + ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, NULL); + free(dup_wt); + // Empty text or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse + if(*((uint8_t *)ansi_text) <= 0x1F){ + free(ansi_text); + ansi_text=NULL; + } + + if (ansi_text) { + + SVGOStringStream ts; + + gchar *escaped_text = g_markup_escape_text(ansi_text, -1); + + tsp.x = x*0.8; // TERE expects sizes in points + tsp.y = y*0.8; + tsp.color.Red = d->dc[d->level].textColor.Red; + tsp.color.Green = d->dc[d->level].textColor.Green; + tsp.color.Blue = d->dc[d->level].textColor.Blue; + tsp.color.Reserved = 0; + switch(d->dc[d->level].style.font_style.value){ + case SP_CSS_FONT_STYLE_OBLIQUE: + tsp.italics = FC_SLANT_OBLIQUE; break; + case SP_CSS_FONT_STYLE_ITALIC: + tsp.italics = FC_SLANT_ITALIC; break; + default: + case SP_CSS_FONT_STYLE_NORMAL: + tsp.italics = FC_SLANT_ROMAN; break; + } + switch(d->dc[d->level].style.font_weight.value){ + case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break; + case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; + case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break; + case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break; + case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break; + case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break; + case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break; + case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; + case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break; + case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break; + case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break; + case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; + case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; + default: tsp.weight = FC_WEIGHT_NORMAL ; break; + } + // WMF only supports two types of text decoration + tsp.decoration = TXTDECOR_NONE; + if(d->dc[d->level].style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; } + if(d->dc[d->level].style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;} + + // WMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left + tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER : + (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT : + ALIRIGHT); + tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE : + ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT : + ALITOP)); + + // language direction can be encoded two ways, U_TA_RTLREADING is preferred + if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; } + else{ tsp.ldir = LDIR_LR; } + + tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet) + tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement + // There is no world transform, so ori need not be further rotated + tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear(). + tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points + char *fontspec = TR_construct_fontspec(&tsp, d->dc[d->level].font_name); + tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec); + free(fontspec); + // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though + // as the metrics from fontconfig may not match, or the font may not be present. + if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; } + else { tsp.co=0; } + + int status; + + status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement + if(status==-1){ // change of escapement, emit what we have and reset + TR_layout_analyze(d->tri); + TR_layout_2_svg(d->tri); + ts << d->tri->out; + *(d->outsvg) += ts.str().c_str(); + d->tri = trinfo_clear(d->tri); + (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work + } + + g_free(escaped_text); + free(ansi_text); + } + + break; + } + case U_WMR_SETDIBTODEV: dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n"; break; + case U_WMR_SELECTPALETTE: dbg_str << "<!-- U_WMR_SELECTPALETTE -->\n"; break; + case U_WMR_REALIZEPALETTE: dbg_str << "<!-- U_WMR_REALIZEPALETTE -->\n"; break; + case U_WMR_ANIMATEPALETTE: dbg_str << "<!-- U_WMR_ANIMATEPALETTE -->\n"; break; + case U_WMR_SETPALENTRIES: dbg_str << "<!-- U_WMR_SETPALENTRIES -->\n"; break; + case U_WMR_POLYPOLYGON: + { + dbg_str << "<!-- U_WMR_POLYPOLYGON16 -->\n"; + uint16_t nPolys; + const uint16_t *aPolyCounts; + const char *Points; + int cpts; /* total number of points in Points*/ + nSize = U_WMRPOLYPOLYGON_get(contents, &nPolys, &aPolyCounts, &Points); + int n, i, j; + + d->mask |= wmr_mask; + + U_POINT16 apt; + for (n=cpts=0; n < nPolys; n++) { cpts += aPolyCounts[n]; } + i = 0; // offset in BYTES + cpts *= U_SIZE_POINT16; // limit for offset i, in BYTES + + for (n=0; n < nPolys && i<cpts; n++) { + SVGOStringStream poly_path; + + memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way + + poly_path << "\n\tM " << pix_to_xy( d, apt.x, apt.y) << " "; + i += U_SIZE_POINT16; + + for (j=1; j < aPolyCounts[n] && i < cpts; j++) { + memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way + poly_path << "\n\tL " << pix_to_xy( d, apt.x, apt.y) << " "; + i += U_SIZE_POINT16; + } + + tmp_str << poly_path.str().c_str(); + tmp_str << " z"; + tmp_str << " \n"; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_WMR_RESIZEPALETTE: dbg_str << "<!-- U_WMR_RESIZEPALETTE -->\n"; break; + case U_WMR_3A: + case U_WMR_3B: + case U_WMR_3C: + case U_WMR_3D: + case U_WMR_3E: + case U_WMR_3F: + { + dbg_str << "<!-- U_WMR_3A..3F -->\n"; + break; + } + case U_WMR_DIBBITBLT: + { + dbg_str << "<!-- U_WMR_DIBBITBLT -->\n"; + nSize = U_WMRDIBBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &dib); + + // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at + // least it leaves objects where the operations should have been. + if (!dib) { + // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead + + int32_t dx = Dst.x; + int32_t dy = Dst.y; + int32_t dw = cwh.x; + int32_t dh = cwh.y; + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= wmr_mask; + d->dwRop3 = dwRop3; // we will try to approximate SOME of these + d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that + + tmp_path << tmp_rectangle.str().c_str(); + } + else { + double dx = pix_to_x_point( d, Dst.x, Dst.y); + double dy = pix_to_y_point( d, Dst.x, Dst.y); + double dw = pix_to_abs_size( d, cDst.x); + double dh = pix_to_abs_size( d, cDst.y); + //source position within the bitmap, in pixels + int sx = Src.x; + int sy = Src.y; + int sw = 0; // extract all of the image + int sh = 0; + if(sx<0)sx=0; + if(sy<0)sy=0; + // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS + common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,U_DIB_RGB_COLORS); + } + break; + } + case U_WMR_DIBSTRETCHBLT: + { + dbg_str << "<!-- U_WMR_DIBSTRETCHBLT -->\n"; + nSize = U_WMRDIBSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &dib); + // Always grab image, ignore modes. + if (dib) { + double dx = pix_to_x_point( d, Dst.x, Dst.y); + double dy = pix_to_y_point( d, Dst.x, Dst.y); + double dw = pix_to_abs_size( d, cDst.x); + double dh = pix_to_abs_size( d, cDst.y); + //source position within the bitmap, in pixels + int sx = Src.x; + int sy = Src.y; + int sw = cSrc.x; // extract the specified amount of the image + int sh = cSrc.y; + // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS + common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh, U_DIB_RGB_COLORS); + } + break; + } + case U_WMR_DIBCREATEPATTERNBRUSH: + { + dbg_str << "<!-- U_WMR_DIBCREATEPATTERNBRUSH -->\n"; + insert_object(d, U_WMR_DIBCREATEPATTERNBRUSH, contents); + break; + } + case U_WMR_STRETCHDIB: + { + dbg_str << "<!-- U_WMR_STRETCHDIB -->\n"; + nSize = U_WMRSTRETCHDIB_get(contents, &Dst, &cDst, &Src, &cSrc, &cUsage, &dwRop3, &dib); + double dx = pix_to_x_point( d, Dst.x, Dst.y ); + double dy = pix_to_y_point( d, Dst.x, Dst.y ); + double dw = pix_to_abs_size( d, cDst.x); + double dh = pix_to_abs_size( d, cDst.y); + int sx = Src.x; //source position within the bitmap, in pixels + int sy = Src.y; + int sw = cSrc.x; // extract the specified amount of the image + int sh = cSrc.y; + uint32_t iUsageSrc; + iUsageSrc = cUsage; + common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,iUsageSrc); + + break; + } + case U_WMR_44: + case U_WMR_45: + case U_WMR_46: + case U_WMR_47: + { + dbg_str << "<!-- U_WMR_44..47 -->\n"; + break; + } + case U_WMR_EXTFLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break; + case U_WMR_49: + case U_WMR_4A: + case U_WMR_4B: + case U_WMR_4C: + case U_WMR_4D: + case U_WMR_4E: + case U_WMR_4F: + case U_WMR_50: + case U_WMR_51: + case U_WMR_52: + case U_WMR_53: + case U_WMR_54: + case U_WMR_55: + case U_WMR_56: + case U_WMR_57: + case U_WMR_58: + case U_WMR_59: + case U_WMR_5A: + case U_WMR_5B: + case U_WMR_5C: + case U_WMR_5D: + case U_WMR_5E: + case U_WMR_5F: + case U_WMR_60: + case U_WMR_61: + case U_WMR_62: + case U_WMR_63: + case U_WMR_64: + case U_WMR_65: + case U_WMR_66: + case U_WMR_67: + case U_WMR_68: + case U_WMR_69: + case U_WMR_6A: + case U_WMR_6B: + case U_WMR_6C: + case U_WMR_6D: + case U_WMR_6E: + case U_WMR_6F: + case U_WMR_70: + case U_WMR_71: + case U_WMR_72: + case U_WMR_73: + case U_WMR_74: + case U_WMR_75: + case U_WMR_76: + case U_WMR_77: + case U_WMR_78: + case U_WMR_79: + case U_WMR_7A: + case U_WMR_7B: + case U_WMR_7C: + case U_WMR_7D: + case U_WMR_7E: + case U_WMR_7F: + case U_WMR_80: + case U_WMR_81: + case U_WMR_82: + case U_WMR_83: + case U_WMR_84: + case U_WMR_85: + case U_WMR_86: + case U_WMR_87: + case U_WMR_88: + case U_WMR_89: + case U_WMR_8A: + case U_WMR_8B: + case U_WMR_8C: + case U_WMR_8D: + case U_WMR_8E: + case U_WMR_8F: + case U_WMR_90: + case U_WMR_91: + case U_WMR_92: + case U_WMR_93: + case U_WMR_94: + case U_WMR_95: + case U_WMR_96: + case U_WMR_97: + case U_WMR_98: + case U_WMR_99: + case U_WMR_9A: + case U_WMR_9B: + case U_WMR_9C: + case U_WMR_9D: + case U_WMR_9E: + case U_WMR_9F: + case U_WMR_A0: + case U_WMR_A1: + case U_WMR_A2: + case U_WMR_A3: + case U_WMR_A4: + case U_WMR_A5: + case U_WMR_A6: + case U_WMR_A7: + case U_WMR_A8: + case U_WMR_A9: + case U_WMR_AA: + case U_WMR_AB: + case U_WMR_AC: + case U_WMR_AD: + case U_WMR_AE: + case U_WMR_AF: + case U_WMR_B0: + case U_WMR_B1: + case U_WMR_B2: + case U_WMR_B3: + case U_WMR_B4: + case U_WMR_B5: + case U_WMR_B6: + case U_WMR_B7: + case U_WMR_B8: + case U_WMR_B9: + case U_WMR_BA: + case U_WMR_BB: + case U_WMR_BC: + case U_WMR_BD: + case U_WMR_BE: + case U_WMR_BF: + case U_WMR_C0: + case U_WMR_C1: + case U_WMR_C2: + case U_WMR_C3: + case U_WMR_C4: + case U_WMR_C5: + case U_WMR_C6: + case U_WMR_C7: + case U_WMR_C8: + case U_WMR_C9: + case U_WMR_CA: + case U_WMR_CB: + case U_WMR_CC: + case U_WMR_CD: + case U_WMR_CE: + case U_WMR_CF: + case U_WMR_D0: + case U_WMR_D1: + case U_WMR_D2: + case U_WMR_D3: + case U_WMR_D4: + case U_WMR_D5: + case U_WMR_D6: + case U_WMR_D7: + case U_WMR_D8: + case U_WMR_D9: + case U_WMR_DA: + case U_WMR_DB: + case U_WMR_DC: + case U_WMR_DD: + case U_WMR_DE: + case U_WMR_DF: + case U_WMR_E0: + case U_WMR_E1: + case U_WMR_E2: + case U_WMR_E3: + case U_WMR_E4: + case U_WMR_E5: + case U_WMR_E6: + case U_WMR_E7: + case U_WMR_E8: + case U_WMR_E9: + case U_WMR_EA: + case U_WMR_EB: + case U_WMR_EC: + case U_WMR_ED: + case U_WMR_EE: + case U_WMR_EF: + { + dbg_str << "<!-- U_WMR_EXTFLOODFILL..EF -->\n"; + break; + } + case U_WMR_DELETEOBJECT: + { + dbg_str << "<!-- U_WMR_DELETEOBJECT -->\n"; + nSize = U_WMRDELETEOBJECT_get(contents, &utmp16); + delete_object(d, utmp16); + break; + } + case U_WMR_F1: + case U_WMR_F2: + case U_WMR_F3: + case U_WMR_F4: + case U_WMR_F5: + case U_WMR_F6: + { + dbg_str << "<!-- F1..F6 -->\n"; + break; + } + case U_WMR_CREATEPALETTE: + { + dbg_str << "<!-- U_WMR_CREATEPALETTE -->\n"; + insert_object(d, U_WMR_CREATEPALETTE, contents); + break; + } + case U_WMR_F8: dbg_str << "<!-- F8 -->\n"; break; + case U_WMR_CREATEPATTERNBRUSH: + { + dbg_str << "<!-- U_WMR_CREATEPATTERNBRUSH -->\n"; + insert_object(d, U_WMR_CREATEPATTERNBRUSH, contents); + break; + } + case U_WMR_CREATEPENINDIRECT: + { + dbg_str << "<!-- U_WMR_EXTCREATEPEN -->\n"; + insert_object(d, U_WMR_CREATEPENINDIRECT, contents); + break; + } + case U_WMR_CREATEFONTINDIRECT: + { + dbg_str << "<!-- U_WMR_CREATEFONTINDIRECT -->\n"; + insert_object(d, U_WMR_CREATEFONTINDIRECT, contents); + break; + } + case U_WMR_CREATEBRUSHINDIRECT: + { + dbg_str << "<!-- U_WMR_CREATEBRUSHINDIRECT -->\n"; + insert_object(d, U_WMR_CREATEBRUSHINDIRECT, contents); + break; + } + case U_WMR_CREATEBITMAPINDIRECT: + { + dbg_str << "<!-- U_WMR_CREATEBITMAPINDIRECT -->\n"; + insert_object(d, U_WMR_CREATEBITMAPINDIRECT, contents); + break; + } + case U_WMR_CREATEBITMAP: + { + dbg_str << "<!-- U_WMR_CREATEBITMAP -->\n"; + insert_object(d, U_WMR_CREATEBITMAP, contents); + break; + } + case U_WMR_CREATEREGION: + { + dbg_str << "<!-- U_WMR_CREATEREGION -->\n"; + insert_object(d, U_WMR_CREATEREGION, contents); + break; + } + default: + dbg_str << "<!-- U_WMR_??? -->\n"; + break; + } //end of switch +// When testing, uncomment the following to place a comment for each processed WMR record in the SVG +// *(d->outsvg) += dbg_str.str().c_str(); + *(d->path) += tmp_path.str().c_str(); + if(!nSize){ OK=0; std::cout << "nSize == 0, oops!!!" << std::endl; } // There was some problem with this record, it is not safe to continue + + } //end of while +// When testing, uncomment the following to show the final SVG derived from the WMF +// std::cout << *(d->outsvg) << std::endl; + (void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant + + return 1; +} + +void Wmf::free_wmf_strings(WMF_STRINGS name){ + if(name.count){ + for(int i=0; i< name.count; i++){ free(name.strings[i]); } + free(name.strings); + } +} + +SPDocument * +Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) +{ + + WMF_CALLBACK_DATA d; + + memset(&d, 0, sizeof(WMF_CALLBACK_DATA)); + + for(int i = 0; i < WMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with + memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT)); + } + // set default drawing objects, these are active if no object has been selected + d.dc[0].active_pen = -1; // -1 when the default is used instead of a selected object + d.dc[0].active_brush = -1; + d.dc[0].active_font = -1; + // Default font, WMF spec says device can pick whatever it wants. WMF files that do not specify a font are unlikely to look very good! + d.dc[0].font_name = strdup("Arial"); + d.dc[0].style.font_size.computed = 16.0; + d.dc[0].style.font_weight.value = SP_CSS_FONT_WEIGHT_400; + d.dc[0].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL; + d.dc[0].style.text_decoration_line.underline = 0; + d.dc[0].style.text_decoration_line.line_through = 0; + d.dc[0].style.baseline_shift.value = 0; + d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black) + d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white) + d.dc[0].bkMode = U_TRANSPARENT; + d.dc[0].dirty = 0; + // Default pen, WMF files that do not specify a pen are unlikely to look very good! + d.dc[0].style.stroke_dasharray_set = 0; + d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE; + d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; + d.dc[0].stroke_set = true; + d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known + d.dc[0].style.stroke.value.color.set( 0, 0, 0 ); + // Default brush = none, WMF files that do not specify a brush are unlikely to look very good! + d.dc[0].fill_set = false; + + if (uri == NULL) { + return NULL; + } + + d.outsvg = new Glib::ustring(""); + d.path = new Glib::ustring(""); + d.outdef = new Glib::ustring(""); + d.defs = new Glib::ustring(""); + d.mask = 0; + d.drawtype = 0; + d.arcdir = U_AD_COUNTERCLOCKWISE; + d.dwRop2 = U_R2_COPYPEN; + d.dwRop3 = 0; + d.E2IdirY = 1.0; + d.D2PscaleX = 1.0; + d.D2PscaleY = 1.0; + d.hatches.size = 0; + d.hatches.count = 0; + d.hatches.strings = NULL; + d.images.size = 0; + d.images.count = 0; + d.images.strings = NULL; + + // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. + + *(d.defs) += "\n"; + *(d.defs) += " <pattern id=\"WMFhbasepattern\" \n"; + *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n"; + *(d.defs) += " width=\"6\" \n"; + *(d.defs) += " height=\"6\" \n"; + *(d.defs) += " x=\"0\" \n"; + *(d.defs) += " y=\"0\"> \n"; + *(d.defs) += " </pattern> \n"; + + + size_t length; + char *contents; + if(wmf_readdata(uri, &contents, &length))return(NULL); + + // set up the text reassembly system + if(!(d.tri = trinfo_init(NULL)))return(NULL); + (void) trinfo_load_ft_opts(d.tri, 1, + FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, + FT_KERNING_UNSCALED); + + (void) myMetaFileProc(contents,length, &d); + free(contents); + +// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; + + SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); + + delete d.outsvg; + delete d.path; + delete d.outdef; + delete d.defs; + free_wmf_strings(d.hatches); + free_wmf_strings(d.images); + + if (d.wmf_obj) { + int i; + for (i=0; i<d.n_obj; i++) + delete_object(&d, i); + delete[] d.wmf_obj; + } + + if (d.dc[0].style.stroke_dash.dash) + delete[] d.dc[0].style.stroke_dash.dash; + + for(int i=0; i<=d.level;i++){ + if(d.dc[i].font_name)free(d.dc[i].font_name); + } + + d.tri = trinfo_release_except_FC(d.tri); + + return doc; +} + + +void +Wmf::init (void) +{ + /* WMF in */ + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("WMF Input") "</name>\n" + "<id>org.inkscape.input.wmf</id>\n" + "<input>\n" + "<extension>.wmf</extension>\n" + "<mimetype>image/x-wmf</mimetype>\n" + "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n" + "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n" + "<output_extension>org.inkscape.output.wmf</output_extension>\n" + "</input>\n" + "</inkscape-extension>", new Wmf()); + + /* WMF out */ + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("WMF Output") "</name>\n" + "<id>org.inkscape.output.wmf</id>\n" + "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n" + "<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"boolean\">true</param>\n" + "<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"boolean\">true</param>\n" + "<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"boolean\">true</param>\n" + "<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard WMF hatches") "\" type=\"boolean\">false</param>\n" + "<output>\n" + "<extension>.wmf</extension>\n" + "<mimetype>image/x-wmf</mimetype>\n" + "<filetypename>" N_("Windows Metafile (*.wmf)") "</filetypename>\n" + "<filetypetooltip>" N_("Windows Metafile") "</filetypetooltip>\n" + "</output>\n" + "</inkscape-extension>", new Wmf()); + + return; +} + + +} } } /* namespace Inkscape, Extension, Implementation */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h new file mode 100644 index 000000000..07543e940 --- /dev/null +++ b/src/extension/internal/wmf-inout.h @@ -0,0 +1,213 @@ +/** @file + * @brief Windows Metafile Input/Output + */ +/* Authors: + * Ulf Erikson <ulferikson@users.sf.net> + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef SEEN_EXTENSION_INTERNAL_WMF_H +#define SEEN_EXTENSION_INTERNAL_WMF_H + +#define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler +#include <png.h> +#include "extension/implementation/implementation.h" +#include "style.h" +#include "uwmf.h" +#include "text_reassemble.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { + +#define DIRTY_NONE 0x00 +#define DIRTY_TEXT 0x01 +#define DIRTY_FILL 0x02 +#define DIRTY_STROKE 0x04 // not used currently + +typedef struct { + int type; + int level; + char *record; +} WMF_OBJECT, *PWMF_OBJECT; + +typedef struct { + int size; // number of slots allocated in strings + int count; // number of slots used in strings + char **strings; // place to store strings +} WMF_STRINGS, *PWMF_STRINGS; + +typedef struct wmf_device_context { + struct SPStyle style; + char *font_name; + bool stroke_set; + int stroke_mode; // enumeration from drawmode, not used if fill_set is not True + int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill + int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change + bool fill_set; + int fill_mode; // enumeration from drawmode, not used if fill_set is not True + int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill + int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change + int dirty; // holds the dirty bits for text, stroke, fill + int active_pen; // used when the active object is deleted to set the default values, -1 is none active + int active_brush; // ditto + int active_font; // ditto. also used to hold object number in case font needs to be remade due to textcolor change. + U_POINT16 sizeWnd; + U_POINT16 sizeView; + U_POINT16 winorg; + U_POINT16 vieworg; + double ScaleInX, ScaleInY; + double ScaleOutX, ScaleOutY; + uint16_t bkMode; + U_COLORREF bkColor; + U_COLORREF textColor; + uint16_t textAlign; + U_POINT16 cur; +} WMF_DEVICE_CONTEXT, *PWMF_DEVICE_CONTEXT; + +#define WMF_MAX_DC 128 + +/* + both emf-inout.h and wmf-inout.h are included by init.cpp, so whichever one goes in first defines these ommon types +*/ +#ifndef SEEN_EXTENSION_INTERNAL_METAFILECOMMON_ +#define SEEN_EXTENSION_INTERNAL_METAFILECOMMON_ +/* A coloured pixel. */ +typedef struct { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t opacity; +} pixel_t; + +/* A picture. */ + +typedef struct { + pixel_t *pixels; + size_t width; + size_t height; +} bitmap_t; + +/* structure to store PNG image bytes */ +typedef struct { + char *buffer; + size_t size; +} MEMPNG, *PMEMPNG; +#endif + + + +// like this causes a mysterious crash on the return from Wmf::open +//typedef struct emf_callback_data { +// this fixes it, so some confusion between this struct and the one in emf-inout??? +//typedef struct wmf_callback_data { +// as does this +typedef struct { + Glib::ustring *outsvg; + Glib::ustring *path; + Glib::ustring *outdef; + Glib::ustring *defs; + + WMF_DEVICE_CONTEXT dc[WMF_MAX_DC+1]; // FIXME: This should be dynamic.. + int level; + + double E2IdirY; // WMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc. + double D2PscaleX,D2PscaleY; // WMF device to Inkscape Page scale. + float PixelsInX, PixelsInY; // size of the drawing, in WMF device pixels + float PixelsOutX, PixelsOutY; // size of the drawing, in Inkscape pixels + double ulCornerInX,ulCornerInY; // Upper left corner, from header rclBounds, in logical units + double ulCornerOutX,ulCornerOutY; // Upper left corner, in Inkscape pixels + uint32_t mask; // Draw properties + int arcdir; // U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 + + uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested) + uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested) + + unsigned int id; + unsigned int drawtype; // one of 0 or U_WMR_FILLPATH, U_WMR_STROKEPATH, U_WMR_STROKEANDFILLPATH + // both of these end up in <defs> under the names shown here. These structures allow duplicates to be avoided. + WMF_STRINGS hatches; // hold pattern names, all like WMFhatch#_$$$$$$ where # is the WMF hatch code and $$$$$$ is the color + WMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives. + TR_INFO *tri; // Text Reassembly data structure + + + int n_obj; + int low_water; // first object slot which _might_ be unoccupied. Everything below is filled. + PWMF_OBJECT wmf_obj; +} WMF_CALLBACK_DATA, *PWMF_CALLBACK_DATA; + +class Wmf : Inkscape::Extension::Implementation::Implementation { //This is a derived class + +public: + Wmf(); // Empty constructor + + virtual ~Wmf();//Destructor + + bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) + + void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename + SPDocument *doc, + gchar const *filename); + + virtual SPDocument *open( Inkscape::Extension::Input *mod, + const gchar *uri ); + + static void init(void);//Initialize the class + +private: +protected: + static pixel_t *pixel_at (bitmap_t * bitmap, int x, int y); + static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); + static void toPNG(PMEMPNG accum, int width, int height, const char *px); + static uint32_t sethexcolor(U_COLORREF color); + static void print_document_to_file(SPDocument *doc, const gchar *filename); + static double current_scale(PWMF_CALLBACK_DATA d); + static std::string current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset); + static double current_rotation(PWMF_CALLBACK_DATA d); + static void enlarge_hatches(PWMF_CALLBACK_DATA d); + static int in_hatches(PWMF_CALLBACK_DATA d, char *test); + static uint32_t add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor); + static void enlarge_images(PWMF_CALLBACK_DATA d); + static int in_images(PWMF_CALLBACK_DATA d, char *test); + static uint32_t add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage); + static uint32_t add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px); + static void output_style(PWMF_CALLBACK_DATA d); + static double _pix_x_to_point(PWMF_CALLBACK_DATA d, double px); + static double _pix_y_to_point(PWMF_CALLBACK_DATA d, double py); + static double pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py); + static double pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py); + static double pix_to_abs_size(PWMF_CALLBACK_DATA d, double px); + static std::string pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y); + static void select_brush(PWMF_CALLBACK_DATA d, int index); + static void select_font(PWMF_CALLBACK_DATA d, int index); + static void select_pen(PWMF_CALLBACK_DATA d, int index); + static int insertable_object(PWMF_CALLBACK_DATA d); + static void delete_object(PWMF_CALLBACK_DATA d, int index); + static int insert_object(PWMF_CALLBACK_DATA d, int type, const char *record); + static uint32_t *unknown_chars(size_t count); + static void common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, + double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage); + static void common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px, + double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh); + static int myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d); + static void free_wmf_strings(WMF_STRINGS name); + +}; + +} } } /* namespace Inkscape, Extension, Implementation */ + + +#endif /* EXTENSION_INTERNAL_WMF_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp new file mode 100644 index 000000000..b7ab49b57 --- /dev/null +++ b/src/extension/internal/wmf-print.cpp @@ -0,0 +1,1994 @@ +/** @file + * @brief Windows Metafile printing + */ +/* Authors: + * Ulf Erikson <ulferikson@users.sf.net> + * Jon A. Cruz <jon@joncruz.org> + * Abhishek Sharma + * David Mathog + * + * Copyright (C) 2006-2009 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +/* + * References: + * - How to Create & Play Enhanced Metafiles in Win32 + * http://support.microsoft.com/kb/q145999/ + * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles + * http://support.microsoft.com/kb/q66949/ + * - Metafile Functions + * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp + * - Metafile Structures + * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include "2geom/sbasis-to-bezier.h" +#include "2geom/svg-elliptical-arc.h" + +#include "2geom/path.h" +#include "2geom/pathvector.h" +#include "2geom/rect.h" +#include "2geom/bezier-curve.h" +#include "2geom/hvlinesegment.h" +#include "helper/geom.h" +#include "helper/geom-curves.h" +#include "sp-item.h" + +#include "style.h" +#include "inkscape-version.h" +#include "sp-root.h" + +#include "util/units.h" + +#include "extension/system.h" +#include "extension/print.h" +#include "document.h" +#include "path-prefix.h" +#include "sp-pattern.h" +#include "sp-image.h" +#include "sp-gradient.h" +#include "sp-radial-gradient.h" +#include "sp-linear-gradient.h" + +#include "splivarot.h" // pieces for union on shapes +#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path +#include "display/canvas-bpath.h" // for SPWindRule + +#include "wmf-print.h" + + +#include <string.h> +extern "C" { +#include "libunicode-convert/unicode-convert.h" +} + + +namespace Inkscape { +namespace Extension { +namespace Internal { + +#define PXPERMETER 2835 +#define MAXDISP 2.0 // This should be set in the output dialog. This is ok for experimenting, no more than 2 pixel deviation. Not actually used at present + +enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT}; + +struct FFNEXUS { + char *fontname; //Font name + FFNEXUS *next; //link to next nexus, NULL if this is the last + double f1; //Vertical (rotating) offset factor (* font height) + double f2; //Vertical (nonrotating) offset factor (* font height) + double f3; //Horizontal (nonrotating) offset factor (* font height) +}; + +struct GRADVALUES{ + Geom::Point p1; // center or start + Geom::Point p2; // xhandle or end + Geom::Point p3; // yhandle or unused + double r; // radius or unused + void *grad; // to access the stops information + int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value + U_COLORREF bgc; // document background color, this is as good a place as any to keep it + float rgb[3]; // also background color, but as 0-1 float. +}; + +/* globals */ +static double PX2WORLD = 1200.0/90.0; // inkscape is 90 dpi, WMF file is 1200 +static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch; +static FFNEXUS *wmf_short_fflist = NULL; //only those fonts so far encountered +static FFNEXUS *wmf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf +static WMFTRACK *wt = NULL; +static WMFHANDLES *wht = NULL; +static GRADVALUES gv; + +void PrintWmf::read_system_fflist(void){ //this is not called by any other source files + FFNEXUS *temp=NULL; + FFNEXUS *ptr=NULL; + std::fstream fffile; + std::string instr; + char fontname[128]; + double f1,f2,f3; + std::string path_to_ffconf; + + if(wmf_long_fflist)return; + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + + path_to_ffconf=INKSCAPE_EXTENSIONDIR; +#ifdef WIN32 + path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax +#else + path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax +#endif + //open the input + fffile.open(path_to_ffconf.c_str(), std::ios::in); + if(!fffile.is_open()){ + g_error("Unable to open file: %s\n", path_to_ffconf.c_str()); + } + while (std::getline(fffile,instr)){ + if(instr[0]=='#')continue; + // not a comment, get the 4 values from the line + int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]); + if(elements!=4){ + g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str()); + } + temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed + temp->f1=f1; + temp->f2=f2; + temp->f3=f3; + temp->fontname=strdup(fontname); //This will never be freed + temp->next=NULL; //just to be explicit, it is already 0 + if(ptr){ + ptr->next=temp; + ptr=temp; + } + else { + wmf_long_fflist=ptr=temp; + } + } + fffile.close(); + + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); +} + +/* Looks for the fontname in the long list. If it does not find it, it adds the default values +to the short list with this fontname. If it does find it, then it adds the specified values. +*/ +void PrintWmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files + FFNEXUS *ptr=NULL; + FFNEXUS *tmp=wmf_long_fflist; + if(!wmf_long_fflist){ + g_error("Programming error search_long_fflist called before read_system_fflist\n"); + } + ptr=wmf_long_fflist; + while(ptr){ + if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; } + ptr=ptr->next; + } + //tmp points at either the found name, or the default, the first entry in wmf_long_fflist + if(!wmf_short_fflist){ + ptr=wmf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS)); + } + else { + ptr=wmf_short_fflist; + while(ptr->next){ ptr=ptr->next; } + ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS)); + ptr=ptr->next; + } + ptr->fontname=strdup(tmp->fontname); + *f1 = ptr->f1 = tmp->f1; + *f2 = ptr->f2 = tmp->f2; + *f3 = ptr->f3 = tmp->f3; + ptr->next=NULL; +} + +/* Looks for the fontname in the short list. If it does not find it, it looks in the wmf_long_fflist. +Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default. +*/ +void PrintWmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files + FFNEXUS *ptr=NULL; + static FFNEXUS *last=NULL; + + if(!wmf_long_fflist){ + g_error("Programming error search_short_fflist called before read_system_fflist\n"); + } + // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately + if(last && !strcmp(last->fontname,fontname)){ ptr=last; } + else { ptr=wmf_short_fflist; } // wmf_short_fflist may still be NULL + while(ptr){ + if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; } + ptr=ptr->next; + } + //reach this point only if there is no match + search_long_fflist(fontname, f1, f2, f3); +} + +void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale){ + float fdx; + int i; + int16_t *ladx; + const char *cptr=&string[strlen(string)+1]; // this works because of the first fake terminator + + *adx = NULL; + *ky = 0.0; // set a default value + sscanf(cptr,"%7d",ndx); + if(!*ndx)return; // this could happen with an empty string + cptr += 7; + ladx = (int16_t *) malloc(*ndx * sizeof(int16_t) ); + if(!ladx)g_error("Out of memory"); + *adx=ladx; + for(i=0; i<*ndx; i++,cptr+=7, ladx++){ + sscanf(cptr,"%7f",&fdx); + *ladx=(int16_t) round(fdx * scale); + } + cptr++; // skip 2nd fake terminator + sscanf(cptr,"%7f",&fdx); + *ky=fdx; + cptr += 7; // advance over ky and its space + sscanf(cptr,"%07d",rtl); +} + +/* convert an 0RGB color to EMF U_COLORREF. +inverse of sethexcolor() in wmf-inout.cpp +*/ +U_COLORREF PrintWmf::gethexcolor(uint32_t color){ + U_COLORREF out; + out = U_RGB( + (color >> 16) & 0xFF, + (color >> 8) & 0xFF, + (color >> 0) & 0xFF + ); + return(out); +} + + +/* Translate inkscape weights to WMF weights. +*/ +uint32_t PrintWmf::transweight(const unsigned int inkweight){ + if(inkweight == SP_CSS_FONT_WEIGHT_400)return(U_FW_NORMAL); + if(inkweight == SP_CSS_FONT_WEIGHT_100)return(U_FW_THIN); + if(inkweight == SP_CSS_FONT_WEIGHT_200)return(U_FW_EXTRALIGHT); + if(inkweight == SP_CSS_FONT_WEIGHT_300)return(U_FW_LIGHT); + // 400 is tested first, as it is the most common case + if(inkweight == SP_CSS_FONT_WEIGHT_500)return(U_FW_MEDIUM); + if(inkweight == SP_CSS_FONT_WEIGHT_600)return(U_FW_SEMIBOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_700)return(U_FW_BOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_800)return(U_FW_EXTRABOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_900)return(U_FW_HEAVY); + return(U_FW_NORMAL); +} + +PrintWmf::PrintWmf (void) +{ + // all of the class variables are initialized elsewhere, many in PrintWmf::Begin, +} + + +PrintWmf::~PrintWmf (void) +{ + + /* restore default signal handling for SIGPIPE */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_DFL); +#endif + return; +} + + +unsigned int PrintWmf::setup (Inkscape::Extension::Print * /*mod*/) +{ + return TRUE; +} + + +unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) +{ + char *rec; + gchar const *utf8_fn = mod->get_param_string("destination"); + + FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); + FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); + FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); + FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); + + (void) wmf_start(utf8_fn, 1000000, 250000, &wt); // Initialize the wt structure + (void) wmf_htable_create(128, 128, &wht); // Initialize the wht structure + + // WMF header the only things that can be set are the page size in inches (w,h) and the dpi + // width and height in px + _width = doc->getWidth(); + _height = doc->getHeight(); + + // initialize a few global variables + hbrush = hpen = 0; + htextalignment = U_TA_BASELINE | U_TA_LEFT; + use_stroke = use_fill = simple_shape = usebk = false; + + Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview"); + if(nv){ + const char *p1 = nv->attribute("pagecolor"); + char *p2; + uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123" + if(*p2)lc=0; + gv.bgc = gethexcolor(lc); + gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0; + gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0; + gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0; + } + + bool pageBoundingBox; + pageBoundingBox = mod->get_param_bool("pageBoundingBox"); + + Geom::Rect d; + if (pageBoundingBox) { + d = Geom::Rect::from_xywh(0, 0, _width, _height); + } else { + SPItem* doc_item = doc->getRoot(); + Geom::OptRect bbox = doc_item->desktopVisualBounds(); + if (bbox) d = *bbox; + } + + d *= Geom::Scale(Inkscape::Util::Quantity::convert(1, "px", "in")); // 90 dpi inside inkscape, wmf file will be 1200 dpi + + /* -1/1200 in next two lines so that WMF read in will write out again at exactly the same size */ + float dwInchesX = d.width() - 1.0/1200.0; + float dwInchesY = d.height() - 1.0/1200.0; + int dwPxX = round(dwInchesX * 1200.0); + int dwPxY = round(dwInchesY * 1200.0); +#if 0 + float dwInchesX = d.width(); + float dwInchesY = d.height(); + int dwPxX = round(d.width() * 1200.0); + int dwPxY = round(d.height() * 1200.0); +#endif + + PU_PAIRF ps = U_PAIRF_set(dwInchesX, dwInchesY); + rec = U_WMRHEADER_set(ps,1200); // Example: drawing is A4 horizontal, 1200 dpi + if(!rec){ + g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"); + } + (void) wmf_header_append((PU_METARECORD)rec, wt, 1); + free(ps); + + rec = U_WMRSETWINDOWEXT_set(point16_set( dwPxX, dwPxY)); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWEXT"); + } + + rec = U_WMRSETWINDOWORG_set(point16_set(0,0)); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWORG"); + } + + rec = U_WMRSETMAPMODE_set(U_MM_ANISOTROPIC); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"); + } + + /* set some parameters, else the program that reads the WMF may default to other values */ + + rec = U_WMRSETBKMODE_set(U_TRANSPARENT); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at U_WMRSETBKMODE"); + } + + hpolyfillmode=U_WINDING; + rec = U_WMRSETPOLYFILLMODE_set(U_WINDING); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE"); + } + + // Text alignment: (only changed if RTL text is encountered ) + // - (x,y) coordinates received by this filter are those of the point where the text + // actually starts, and already takes into account the text object's alignment; + // - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT. + rec = U_WMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTALIGN_set"); + } + + htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; + rec = U_WMRSETTEXTCOLOR_set(U_RGB(0,0,0)); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTCOLOR_set"); + } + + rec = U_WMRSETROP2_set(U_R2_COPYPEN); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at U_WMRSETROP2"); + } + + hmiterlimit=5; + rec = wmiterlimit_set(5); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at wmiterlimit_set"); + } + + + // create a pen as object 0. We never use it (except by mistake). Its purpose it to make all of the other object indices >=1 + U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0,0,0)); + uint32_t Pen; + rec = wcreatepenindirect_set(&Pen, wht, up); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set"); + } + + // create a null pen. If no specific pen is set, this is used + up = U_PEN_set(U_PS_NULL, 1, colorref_set(0,0,0)); + rec = wcreatepenindirect_set(&hpen_null, wht, up); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set"); + } + destroy_pen(); // make this pen active + + // create a null brush. If no specific brush is set, this is used + U_WLOGBRUSH lb = U_WLOGBRUSH_set(U_BS_NULL, U_RGB(0, 0, 0), U_HS_HORIZONTAL); + rec = wcreatebrushindirect_set(&hbrush_null, wht, lb); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set"); + } + destroy_brush(); // make this brush active + + return 0; +} + + +unsigned int PrintWmf::finish (Inkscape::Extension::Print * /*mod*/) +{ + char *rec; + if (!wt) return 0; + + // get rid of null brush + rec = wdeleteobject_set(&hbrush_null, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null brush"); + } + + // get rid of null pen + rec = wdeleteobject_set(&hpen_null, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null pen"); + } + + // get rid of object 0, which was a pen that was used to shift the other object indices to >=1. + hpen=0; + rec = wdeleteobject_set(&hpen, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set filler object"); + } + + rec = U_WMREOF_set(); // generate the EOF record + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::finish"); + } + (void) wmf_finish(wt); // Finalize and write out the WMF + wmf_free(&wt); // clean up + wmf_htable_free(&wht); // clean up + + return 0; +} + + +unsigned int PrintWmf::comment ( Inkscape::Extension::Print * /*module*/, const char * /*comment*/) +{ + if (!wt) return 0; + + // earlier versions had flush of fill here, but it never executed and was removed + + return 0; +} + +// Extract hatchType, hatchColor from a name like +// *MFhatch<hatchType>_<hatchColor>[_<bkcolor>] (WMF or EMF hatches are the same) +// Where the first one is a number and the second (and third) a color in hex. +// hatchType, hatchColor, bkColor have been set with defaults before this is called. +// +void PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ + int val; + uint32_t hcolor=0; + uint32_t bcolor=0; + + // name should be EMFhatch or WMFhatch but *MFhatch will be accepted + if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse + name += 8; // WMFhatch already detected + val = 0; + while(*name && isdigit(*name)){ + val = 10*val + *name - '0'; + name++; + } + *hatchType = val; + if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify + *hatchType = -1; + } + else { + name++; + if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background + if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify + *hatchColor = gethexcolor(hcolor); + } + else { + *hatchColor = gethexcolor(hcolor); + *bkColor = gethexcolor(bcolor); + usebk = true; + } + } + /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */ + if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR; +} + +// +// Recurse down from a brush pattern, try to figure out what it is. +// If an image is found set a pointer to the epixbuf, else set that to NULL +// If a pattern is found with a name like [EW]MFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t), +// otherwise hatchType is set to -1 and hatchColor is not defined. +// + +void PrintWmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){ + if(depth==0){ + *epixbuf = NULL; + *hatchType = -1; + *hatchColor = U_RGB(0,0,0); + *bkColor = U_RGB(255,255,255); + } + depth++; + // first look along the pattern chain, if there is one + if(SP_IS_PATTERN(parent)){ + for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + if(SP_IS_IMAGE(pat_i)){ + *epixbuf = ((SPImage *)pat_i)->pixbuf; + return; + } + char temp[32]; // large enough + temp[31]='\0'; + strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_###### + hatch_classify(temp, hatchType, hatchColor, bkColor); + if(*hatchType != -1)return; + + // still looking? Look at this pattern's children, if there are any + SPObject *child = pat_i->firstChild(); + while(child && !(*epixbuf) && (*hatchType == -1)){ + brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); + child = child->getNext(); + } + } + } + else if(SP_IS_IMAGE(parent)){ + *epixbuf = ((SPImage *)parent)->pixbuf; + return; + } + else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either. + SPObject *child = parent->firstChild(); + while(child && !(*epixbuf) && (*hatchType == -1)){ + brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor); + child = child->getNext(); + } + } +} + +//swap R/B in 4 byte pixel +void PrintWmf::swapRBinRGBA(char *px, int pixels){ + char tmp; + for(int i=0;i<pixels*4;px+=4,i+=4){ + tmp=px[2]; + px[2]=px[0]; + px[0]=tmp; + } +} + +/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */ +inline float opweight(float v1, float v2, float op){ + return v1*op + v2*(1.0-op); +} + +U_COLORREF PrintWmf::avg_stop_color(SPGradient *gr){ + U_COLORREF cr; + int last = gr->vector.stops.size() -1; + if(last>=1){ + float rgbs[3]; + float rgbe[3]; + float ops,ope; + + ops = gr->vector.stops[0 ].opacity; + ope = gr->vector.stops[last].opacity; + sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs); + sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe); + + /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */ + cr = U_RGB( + 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0), + 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0), + 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0) + ); + } + else { + cr = U_RGB(0, 0, 0); // The default fill + } + return cr; +} + +int PrintWmf::hold_gradient(void *gr, int mode){ + gv.mode = mode; + gv.grad = gr; + if(mode==DRAW_RADIAL_GRADIENT){ + SPRadialGradient *rg = (SPRadialGradient *) gr; + gv.r = rg->r.computed; // radius, but of what??? + gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center + gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle + gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle + if (rg->gradientTransform_set) { + gv.p1 = gv.p1 * rg->gradientTransform; + gv.p2 = gv.p2 * rg->gradientTransform; + gv.p3 = gv.p3 * rg->gradientTransform; + } + } + else if(mode==DRAW_LINEAR_GRADIENT){ + SPLinearGradient *lg = (SPLinearGradient *) gr; + gv.r = 0; // unused + gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start + gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end + gv.p3 = Geom::Point (0, 0); // unused + if (lg->gradientTransform_set) { + gv.p1 = gv.p1 * lg->gradientTransform; + gv.p2 = gv.p2 * lg->gradientTransform; + } + } + else { + g_error("Fatal programming error, hold_gradient() in wmf-print.cpp called with invalid draw mode"); + } + return 1; +} + +// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring. +int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) +{ + float rgb[3]; + char *rec; + U_WLOGBRUSH lb; + uint32_t brush, fmode; + enum drawmode fill_mode; + GdkPixbuf *pixbuf; + uint32_t brushStyle; + int hatchType; + U_COLORREF hatchColor; + U_COLORREF bkColor; + uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required. + uint32_t height = 0; + + if (!wt) return 0; + + // set a default fill in case we can't figure out a better way to do it + fmode = U_ALTERNATE; + fill_mode = DRAW_PAINT; + brushStyle = U_BS_SOLID; + hatchType = U_HS_SOLIDCLR; + bkColor = U_RGB(0, 0, 0); + if(fcolor){ hatchColor = *fcolor; } + else { hatchColor = U_RGB(0, 0, 0); } + + if (!fcolor && style) { + if(style->fill.isColor()){ + fill_mode = DRAW_PAINT; + float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); + if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill + + sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); + hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + + fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE); + } + else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server + SPPaintServer *paintserver = style->fill.value.href->getObject(); + SPPattern *pat = SP_PATTERN (paintserver); + double dwidth = pattern_width(pat); + double dheight = pattern_height(pat); + width = dwidth; + height = dheight; + brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor); + if(pixbuf){ fill_mode = DRAW_IMAGE; } + else { // pattern + fill_mode = DRAW_PATTERN; + if(hatchType == -1){ // Not a standard hatch, so force it to something + hatchType = U_HS_CROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + if(FixPPTPatternAsHatch){ + if(hatchType == -1){ // image or unclassified + fill_mode = DRAW_PATTERN; + hatchType = U_HS_DIAGCROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + brushStyle = U_BS_HATCHED; + } + else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient + // currently we do not do anything with gradients, the code below just sets the color to the average of the stops + SPPaintServer *paintserver = style->fill.value.href->getObject(); + SPLinearGradient *lg = NULL; + SPRadialGradient *rg = NULL; + + if (SP_IS_LINEARGRADIENT (paintserver)) { + lg = SP_LINEARGRADIENT(paintserver); + SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built + fill_mode = DRAW_LINEAR_GRADIENT; + } + else if (SP_IS_RADIALGRADIENT (paintserver)) { + rg = SP_RADIALGRADIENT(paintserver); + SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built + fill_mode = DRAW_RADIAL_GRADIENT; + } + else { + // default fill + } + + if(rg){ + if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); } + else { hatchColor = avg_stop_color(rg); } + } + else if(lg){ + if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); } + else { hatchColor = avg_stop_color(lg); } + } + } + } + else { // if (!style) + // default fill + } + + switch(fill_mode){ + case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices + case DRAW_RADIAL_GRADIENT: // ditto + case DRAW_PAINT: + case DRAW_PATTERN: + // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. + if(usebk){ + rec = U_WMRSETBKCOLOR_set(bkColor); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set"); + } + rec = U_WMRSETBKMODE_set(U_OPAQUE); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set"); + } + } + lb = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType); + rec = wcreatebrushindirect_set(&brush, wht, lb); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set"); + } + break; + case DRAW_IMAGE: + char *px; + char *rgba_px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width*height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set"); + } + free(px); + free(Bmi); // ct will be NULL because of colortype + break; + } + + hbrush = brush; // need this later for destroy_brush + rec = wselectobject_set(brush, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_brush at wselectobject_set"); + } + + if(fmode != hpolyfillmode){ + hpolyfillmode=fmode; + rec = U_WMRSETPOLYFILLMODE_set(fmode); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set"); + } + } + + return 0; +} + + +void PrintWmf::destroy_brush() +{ + char *rec; + // WMF lets any object be deleted whenever, and the chips fall where they may... + if (hbrush){ + rec = wdeleteobject_set(&hbrush, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::destroy_brush"); + } + hbrush = 0; + } + + // (re)select the null brush + + rec = wselectobject_set(hbrush_null, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::destroy_brush"); + } +} + + +int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) +{ + char *rec = NULL; + uint32_t pen; + uint32_t penstyle; + U_COLORREF penColor; + U_PEN up; + int modstyle; + + if (!wt) return 0; + + // set a default stroke in case we can't figure out a better way to do it + penstyle = U_PS_SOLID; + modstyle = 0; + penColor = U_RGB(0, 0, 0); + uint32_t linewidth = 1; + + if (style) { // override some or all of the preceding + float rgb[3]; + + // WMF does not support hatched, bitmap, or gradient pens, just set the color. + sp_color_get_rgb_floatv( &style->stroke.value.color, rgb ); + penColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + + using Geom::X; + using Geom::Y; + + Geom::Point zero(0, 0); + Geom::Point one(1, 1); + Geom::Point p0(zero * transform); + Geom::Point p1(one * transform); + Geom::Point p(p1 - p0); + + double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); + + if(!style->stroke_width.computed){return 0;} //if width is 0 do not (reset) the pen, it should already be NULL_PEN + linewidth = MAX( 1, (uint32_t) round(scale * style->stroke_width.computed * PX2WORLD) ); + + // most WMF readers will ignore linecap and linejoin, but set them anyway. Inkscape itself can read them back in. + + if ( style->stroke_linecap.computed == 0) { modstyle |= U_PS_ENDCAP_FLAT; } + else if (style->stroke_linecap.computed == 1) { modstyle |= U_PS_ENDCAP_ROUND; } + else { modstyle |= U_PS_ENDCAP_SQUARE; } + + if (style->stroke_linejoin.computed == 0) { + float miterlimit = style->stroke_miterlimit.value; // This is a ratio. + if (miterlimit < 1)miterlimit = 1; + + // most WMF readers will ignore miterlimit, but set it anyway. Inkscape itself can read it back in + if((uint32_t)miterlimit != hmiterlimit){ + hmiterlimit = (uint32_t)miterlimit; + rec = wmiterlimit_set((uint32_t) miterlimit); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_pen at wmiterlimit_set"); + } + } + modstyle |= U_PS_JOIN_MITER; + } + else if (style->stroke_linejoin.computed == 1) { modstyle |= U_PS_JOIN_ROUND; } + else { modstyle |= U_PS_JOIN_BEVEL; } + + if (style->stroke_dash.n_dash && + style->stroke_dash.dash ) + { + if(!FixPPTDashLine){ // if this is set code elsewhere will break dots/dashes into many smaller lines. + penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash + } + } + + } + + up = U_PEN_set(penstyle | modstyle, linewidth, penColor); + rec = wcreatepenindirect_set(&pen, wht, up); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_pen at wcreatepenindirect_set"); + } + + rec = wselectobject_set(pen, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::create_pen at wselectobject_set"); + } + hpen = pen; // need this later for destroy_pen + + return 0; +} + +// delete the defined pen object +void PrintWmf::destroy_pen() +{ + char *rec = NULL; + // WMF lets any object be deleted whenever, and the chips fall where they may... + if (hpen){ + rec = wdeleteobject_set(&hpen, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::destroy_pen"); + } + hpen = 0; + } + + // (re)select the null pen + + rec = wselectobject_set(hpen_null, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::destroy_pen"); + } +} + + + +unsigned int PrintWmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) +{ + if (!m_tr_stack.empty()) { + Geom::Affine tr_top = m_tr_stack.top(); + m_tr_stack.push(transform * tr_top); + } else { + m_tr_stack.push(transform); + } + + return 1; +} + +unsigned int PrintWmf::release(Inkscape::Extension::Print * /*mod*/) +{ + m_tr_stack.pop(); + return 1; +} + +#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) +inline U_COLORREF PrintWmf::weight_opacity(U_COLORREF c1){ + float opa = c1.Reserved/255.0; + U_COLORREF result = U_RGB( + 255*opweight((float)c1.Red /255.0, gv.rgb[0], opa), + 255*opweight((float)c1.Green/255.0, gv.rgb[1], opa), + 255*opweight((float)c1.Blue /255.0, gv.rgb[2], opa) + ); + return result; +} + + +// return the color between c1 and c2, c1 for t=0, c2 for t=1.0 +U_COLORREF PrintWmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){ + U_COLORREF result; + result.Red = clrweight(c1.Red, c2.Red, t); + result.Green = clrweight(c1.Green, c2.Green, t); + result.Blue = clrweight(c1.Blue, c2.Blue, t); + result.Reserved = clrweight(c1.Reserved, c2.Reserved, t); + + // now handle the opacity, mix the RGB with background at the weighted opacity + + if(result.Reserved != 255)result = weight_opacity(result); + + return result; +} + +/* convert from center ellipse to SVGEllipticalArc ellipse + + From: + http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter + A point (x,y) on the arc can be found by: + + {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT} + + where + {cx,cy} is the center of the ellipse + F is the rotation angle of the X axis of the ellipse from the true X axis + T is the rotation angle around the ellipse + {,,,} is the rotation matrix + rx,ry are the radii of the ellipse's axes + + For SVG parameterization need two points. + Arbitrarily we can use T=0 and T=pi + Since the sweep is 180 the flags are always 0: + + F is in RADIANS, but the SVGEllipticalArc needs degrees! + +*/ +Geom::PathVector PrintWmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ + using Geom::X; + using Geom::Y; + double x1,y1,x2,y2; + Geom::Path SVGep; + + x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); + y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); + x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); + y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); + + char text[256]; + sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + return outres; +} + + +/* rx2,ry2 must be larger than rx1,ry1! + angle is in RADIANS +*/ +Geom::PathVector PrintWmf::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F){ + using Geom::X; + using Geom::Y; + double x11,y11,x12,y12; + double x21,y21,x22,y22; + double degrot = F*360./(2.*M_PI); + + x11 = ctr[X] + cos(F) * rx1 * cos(0) + sin(-F) * ry1 * sin(0); + y11 = ctr[Y] + sin(F) * rx1 * cos(0) + cos(F) * ry1 * sin(0); + x12 = ctr[X] + cos(F) * rx1 * cos(M_PI) + sin(-F) * ry1 * sin(M_PI); + y12 = ctr[Y] + sin(F) * rx1 * cos(M_PI) + cos(F) * ry1 * sin(M_PI); + + x21 = ctr[X] + cos(F) * rx2 * cos(0) + sin(-F) * ry2 * sin(0); + y21 = ctr[Y] + sin(F) * rx2 * cos(0) + cos(F) * ry2 * sin(0); + x22 = ctr[X] + cos(F) * rx2 * cos(M_PI) + sin(-F) * ry2 * sin(M_PI); + y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI); + + char text[512]; + sprintf(text," M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", + x11,y11, rx1,ry1,degrot,x12,y12, rx1,ry1,degrot,x11,y11, + x21,y21, rx2,ry2,degrot,x22,y22, rx2,ry2,degrot,x21,y21 + ); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + + return outres; +} + +/* Elliptical hole in a large square extending from -50k to +50k */ +Geom::PathVector PrintWmf::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ + using Geom::X; + using Geom::Y; + double x1,y1,x2,y2; + Geom::Path SVGep; + + x1 = ctr[X] + cos(F) * rx * cos(0) + sin(-F) * ry * sin(0); + y1 = ctr[Y] + sin(F) * rx * cos(0) + cos(F) * ry * sin(0); + x2 = ctr[X] + cos(F) * rx * cos(M_PI) + sin(-F) * ry * sin(M_PI); + y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); + + char text[256]; + sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", + x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1); + std::vector<Geom::Path> outres = Geom::parse_svg_path(text); + return outres; +} + +/* rectangular cutter. +ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges +pos vector from center to leading edge +neg vector from center to trailing edge +width vector to side edge +*/ +Geom::PathVector PrintWmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){ + std::vector<Geom::Path> outres; + Geom::Path cutter; + cutter.start( ctr + pos - width); + cutter.appendNew<Geom::LineSegment>(ctr + pos + width); + cutter.appendNew<Geom::LineSegment>(ctr + neg + width); + cutter.appendNew<Geom::LineSegment>(ctr + neg - width); + cutter.close(); + outres.push_back(cutter); + return outres; +} + +/* Convert from SPWindRule to livarot's FillRule + This is similar to what sp_selected_path_boolop() does +*/ +FillRule PrintWmf::SPWR_to_LVFR(SPWindRule wr){ + FillRule fr; + if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; } + else { fr = fill_nonZero; } + return fr; +} + + +unsigned int PrintWmf::fill( + Inkscape::Extension::Print * /*mod*/, + Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, + Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) +{ + using Geom::X; + using Geom::Y; + + Geom::Affine tf = m_tr_stack.top(); + + use_fill = true; + use_stroke = false; + + fill_transform = tf; + + if (create_brush(style, NULL)){ + /* + Handle gradients. Uses modified livarot as 2geom boolops is currently broken. + Can handle gradients with multiple stops. + + The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries. + There is an inevitable loss of accuracy saving through an WMF file because of the integer coordinate system. + Keep the overlap quite large so that loss of accuracy does not remove an overlap. + */ + destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below + Geom::Path cutter; + float rgb[3]; + U_COLORREF wc,c1,c2; + FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed); + double doff,doff_base,doff_range; + double divisions= 128.0; + int nstops; + int istop = 1; + float opa; // opacity at stop + + SPRadialGradient *tg = (SPRadialGradient *) (gv.grad); // linear/radial are the same here + nstops = tg->vector.stops.size(); + sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb); + opa = tg->vector.stops[0].opacity; + c1 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + sp_color_get_rgb_floatv(&tg->vector.stops[nstops-1].color, rgb); + opa = tg->vector.stops[nstops-1].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + doff = 0.0; + doff_base = 0.0; + doff_range = tg->vector.stops[1].offset; // next or last stop + + if(gv.mode==DRAW_RADIAL_GRADIENT){ + Geom::Point xv = gv.p2 - gv.p1; // X' vector + Geom::Point yv = gv.p3 - gv.p1; // Y' vector + Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector + double rx = hypot(xv[X],xv[Y]); + double ry = hypot(yv[X],yv[Y]); + double range = fmax(rx,ry); // length along the gradient + double step = range/divisions; // adequate approximation for gradient + double overlap = step/4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity". + Do this first so that outer colored ring will overlay it. + */ + pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y])); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb); + wc = weight_opacity(c2); + (void) create_brush(style, &wc); + print_pathv(pathvr, fill_transform); + + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + for(start = 0.0; start < range; start += step, doff += 1./divisions){ + stop = start + step + overlap; + if(stop > range)stop=range; + wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + (void) create_brush(style, &wc); + + pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y])); + + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if(doff >= doff_range - doff_base){ + istop++; + if(istop >= nstops)continue; // could happen on a rounding error + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1=c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + } + } + } + else if(gv.mode == DRAW_LINEAR_GRADIENT){ + Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector + Geom::Point puv = uv.cw(); // perp. to unit vector + double range = Geom::distance(gv.p1,gv.p2); // length along the gradient + double step = range/divisions; // adequate approximation for gradient + double overlap = step/4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* before lower end of gradient, overlap first slice position */ + wc = weight_opacity(c1); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p1, uv*(overlap), uv*(-50000.0), puv*50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); + + /* after high end of gradient, overlap last slice poosition */ + wc = weight_opacity(c2); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p2, uv*(-overlap), uv*(50000.0), puv*50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); + + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + for(start = 0.0; start < range; start += step, doff += 1./divisions){ + stop = start + step + overlap; + if(stop > range)stop=range; + pathvc = rect_cutter(gv.p1, uv*start, uv*stop, puv*50000.0); + + wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + (void) create_brush(style, &wc); + Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if(doff >= doff_range - doff_base){ + istop++; + if(istop >= nstops)continue; // could happen on a rounding error + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1=c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + } + } + } + else { + g_error("Fatal programming error in PrintWmf::fill, invalid gradient type detected"); + } + use_fill = false; // gradients handled, be sure stroke does not use stroke and fill + } + else { + /* + Inkscape was not calling create_pen for objects with no border. + This was because it never called stroke() (next method). + PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can + become a visible border. + To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill. + */ + if (style->stroke.noneSet || style->stroke_width.computed == 0.0){ + destroy_pen(); //this sets the NULL_PEN + } + + /* postpone fill in case stroke also required AND all stroke paths closed + Dashes converted to line segments will "open" a closed path. + */ + bool all_closed = true; + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){ + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){ + if (pit->end_default() != pit->end_closed()) { all_closed=false; } + } + } + if ( + (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) || + (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) || + !all_closed + ){ + print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv + use_fill = false; + } + } + + return 0; +} + + +unsigned int PrintWmf::stroke ( + Inkscape::Extension::Print * /*mod*/, + Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, + Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) +{ + + char *rec = NULL; + Geom::Affine tf = m_tr_stack.top(); + + use_stroke = true; + // use_fill was set in ::fill, if it is needed, if not, the null brush is used, it should be already set + + if (create_pen(style, tf))return 0; + + if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine ){ + // convert the path, gets its complete length, and then make a new path with parameter length instead of t + Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis + Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter + Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes + Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end + int n_dash = style->stroke_dash.n_dash; + int i=0; //dash index + double tlength; // length of tmp_pathpw + double slength=0.0; // start of gragment + double elength; // end of gragment + for (unsigned int i=0; i < pathv.size(); i++) { + tmp_pathpw.concat(pathv[i].toPwSb()); + } + tlength = length(tmp_pathpw,0.1); + tmp_pathpw2 = arc_length_parametrization(tmp_pathpw); + + // go around the dash array repeatedly until the entire path is consumed (but not beyond). + while(slength < tlength){ + elength = slength + style->stroke_dash.dash[i++]; + if(elength > tlength)elength = tlength; + Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength)); + if(slength){ tmp_pathpw3.concat(fragment); } + else { first_frag = fragment; } + slength = elength; + slength += style->stroke_dash.dash[i++]; // the gap + if(i>=n_dash)i=0; + } + tmp_pathpw3.concat(first_frag); // may merge line around start point + Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01); + print_pathv(out_pathv, tf); + } + else { + print_pathv(pathv, tf); + } + + use_stroke = false; + use_fill = false; + + if(usebk){ // OPAQUE was set, revert to TRANSPARENT + usebk = false; + rec = U_WMRSETBKMODE_set(U_TRANSPARENT); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::stroke at U_WMRSETBKMODE_set"); + } + } + + return 0; +} + + +// Draws simple_shapes, those with closed WMR_* primitives, like polygons, rectangles and ellipses. +// These use whatever the current pen/brush are and need not be followed by a FILLPATH or STROKEPATH. +// For other paths it sets a few flags and returns. +bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ + + Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP ); + + int nodes = 0; + int moves = 0; + int lines = 0; + int curves = 0; + char *rec = NULL; + + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + moves++; + nodes++; + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + nodes++; + + if ( is_straight_curve(*cit) ) { lines++; } + else if (&*cit) { curves++; } + } + } + + if (!nodes) + return false; + + U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves*3]; + int i = 0; + + /** For all Subpaths in the <path> */ + + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + using Geom::X; + using Geom::Y; + + Geom::Point p0 = pit->initialPoint(); + + p0[X] = (p0[X] * PX2WORLD); + p0[Y] = (p0[Y] * PX2WORLD); + + int32_t const x0 = (int32_t) round(p0[X]); + int32_t const y0 = (int32_t) round(p0[Y]); + + lpPoints[i].x = x0; + lpPoints[i].y = y0; + i = i + 1; + + /** For all segments in the subpath */ + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + if ( is_straight_curve(*cit) ) + { + //Geom::Point p0 = cit->initialPoint(); + Geom::Point p1 = cit->finalPoint(); + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + + lpPoints[i].x = x1; + lpPoints[i].y = y1; + i = i + 1; + } + else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) + { + std::vector<Geom::Point> points = cubic->points(); + //Geom::Point p0 = points[0]; + Geom::Point p1 = points[1]; + Geom::Point p2 = points[2]; + Geom::Point p3 = points[3]; + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + p2[X] = (p2[X] * PX2WORLD); + p3[X] = (p3[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + p2[Y] = (p2[Y] * PX2WORLD); + p3[Y] = (p3[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + int32_t const x2 = (int32_t) round(p2[X]); + int32_t const y2 = (int32_t) round(p2[Y]); + int32_t const x3 = (int32_t) round(p3[X]); + int32_t const y3 = (int32_t) round(p3[Y]); + + lpPoints[i].x = x1; + lpPoints[i].y = y1; + lpPoints[i+1].x = x2; + lpPoints[i+1].y = y2; + lpPoints[i+2].x = x3; + lpPoints[i+2].y = y3; + i = i + 3; + } + } + } + + bool done = false; + bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); + bool polygon = false; + bool rectangle = false; + bool ellipse = false; + + if (moves == 1 && moves+lines == nodes && closed) { + polygon = true; +// if (nodes==5) { // disable due to LP Bug 407394 +// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && +// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) +// { +// rectangle = true; +// } +// } + } + else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { +// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && +// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && +// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && +// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && +// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && +// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) +// { // disable due to LP Bug 407394 +// ellipse = true; +// } + } + + if (polygon || ellipse) { + // pens and brushes already set by caller, do not touch them + + if (polygon) { + if (rectangle){ + U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[0].x, lpPoints[0].y}, (U_POINT16) {lpPoints[2].x, lpPoints[2].y}); + rec = U_WMRRECTANGLE_set(rcl); + } + else { + rec = U_WMRPOLYGON_set(nodes, lpPoints); + } + } + else if (ellipse) { + U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[6].x, lpPoints[3].y}, (U_POINT16) {lpPoints[0].x, lpPoints[9].y}); + rec = U_WMRELLIPSE_set(rcl); + } + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon"); + } + + done = true; + + } + + delete[] lpPoints; + + return done; +} + +/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape + in the past (or will be in the future?) Not in current trunk. (4/19/2012) + + Limitations of this code: + 1. Images lose their rotation, one corner stays in the same place. + 2. Transparency is lost on export. (A limitation of the WMF format.) + 3. Probably messes up if row stride != w*4 + 4. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine + that calls this one and passes px, but never removes the rest of the pixbuf. The first time + this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more. + If this routine is reduced to + if(1)return(0); + and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the + size of two bitmaps. +*/ + +unsigned int PrintWmf::image( + Inkscape::Extension::Print * /* module */, /** not used */ + unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */ + unsigned int w, /** width of bitmap */ + unsigned int h, /** height of bitmap */ + unsigned int rs, /** row stride (normally w*4) */ + Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */ + SPStyle const *style) /** provides indirect link to image object */ +{ + double x1,y1,dw,dh; + char *rec = NULL; + Geom::Affine tf = m_tr_stack.top(); + + rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::image at EMRHEADER"); + } + + x1= atof(style->object->getAttribute("x")); + y1= atof(style->object->getAttribute("y")); + dw= atof(style->object->getAttribute("width")); + dh= atof(style->object->getAttribute("height")); + Geom::Point pLL(x1,y1); + Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates + + char *px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w*4, colortype, 0, 1); + Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + + U_POINT16 Dest = point16_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD)); + U_POINT16 cDest = point16_set(round(dw * PX2WORLD), round(dh * PX2WORLD)); + U_POINT16 Src = point16_set(0,0); + U_POINT16 cSrc = point16_set(w,h); + rec = U_WMRSTRETCHDIB_set( + Dest, //! Destination UL corner in logical units + cDest, //! Destination W & H in logical units + Src, //! Source UL corner in logical units + cSrc, //! Source W & H in logical units + U_DIB_RGB_COLORS, //! DIBColors Enumeration + U_SRCCOPY, //! RasterOPeration Enumeration + Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) + h*rs, //! size in bytes of px + px //! (Optional) bitmapbuffer (U_BITMAPINFO section) + ); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set"); + } + free(px); + free(Bmi); + if(numCt)free(ct); + return 0; +} + +// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything +unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ + char *rec = NULL; + PU_POINT16 pt16hold, pt16ptr; + uint16_t *n16hold; + uint16_t *n16ptr; + + simple_shape = print_simple_shape(pathv, transform); + if (!simple_shape && !pathv.empty()){ + // WMF does not have beziers, need to convert to ONLY linears with something like this: + Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP ); + + /** For all Subpaths in the <path> */ + + /* If the path consists entirely of closed subpaths use one polypolygon. + Otherwise use a mix of polygon or polyline separately on each path. + If the polyline turns out to be single line segments, use a series of MOVETO/LINETO instead, + because WMF has no POLYPOLYLINE. + The former allows path delimited donuts and the like, which + cannot be represented in WMF with polygon or polyline because there is no external way to combine paths + as there is in EMF or SVG. + For polygons specify the last point the same as the first. The WMF/EMF manuals say that the + reading program SHOULD close the path, which allows a conforming program not to, potentially rendering + a closed path as an open one. */ + int nPolys=0; + int totPoints = 0; + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + totPoints += 1 + pit->size_default(); // big array, will hold all points, for all polygons. Size_default ignores first point in each path. + if (pit->end_default() == pit->end_closed()) { nPolys++; } + else { nPolys=0; break; } + } + + if(nPolys > 1){ // a single polypolygon, a single polygon falls through to the else + pt16hold = pt16ptr = (PU_POINT16) malloc(totPoints * sizeof(U_POINT16)); + if(!pt16ptr)return(false); + + n16hold = n16ptr = (uint16_t *) malloc(nPolys * sizeof(uint16_t)); + if(!n16ptr){ free(pt16hold); return(false); } + + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + using Geom::X; + using Geom::Y; + + + *n16ptr++ = pit->size_default(); // points in the subpath + + /** For each segment in the subpath */ + + Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator + + p1[X] = (p1[X] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + Geom::Point p1 = cit->finalPoint(); + + p1[X] = (p1[X] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); + } + + } + rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold,pt16hold); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set"); + } + free(pt16hold); + free(n16hold); + } + else { // one or more polyline or polygons (but not all polygons, that would be the preceding case) + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + using Geom::X; + using Geom::Y; + + /* Malformatted Polylines with a sequence like M L M M L have been seen, the 2nd M does nothing + and that point must not go into the output. */ + if(!(pit->size_default())){ continue; } + /* Figure out how many points there are, make an array big enough to hold them, and store + all the points. This is the same for open or closed path. This gives the upper bound for + the number of points. The actual number used is calculated on the fly. + */ + int nPoints = 1 + pit->size_default(); + + pt16hold = pt16ptr = (PU_POINT16) malloc(nPoints * sizeof(U_POINT16)); + if(!pt16ptr)break; + + /** For each segment in the subpath */ + + Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator + + p1[X] = (p1[X] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); + nPoints = 1; + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit, nPoints++) + { + Geom::Point p1 = cit->finalPoint(); + + p1[X] = (p1[X] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); + } + + if (pit->end_default() == pit->end_closed()) { + rec = U_WMRPOLYGON_set(nPoints, pt16hold); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON_set"); + } + } + else if(nPoints>2) { + rec = U_WMRPOLYLINE_set(nPoints, pt16hold); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::print_pathv at U_POLYLINE_set"); + } + } + else if(nPoints == 2) { + rec = U_WMRMOVETO_set(pt16hold[0]); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRMOVETO_set"); + } + rec = U_WMRLINETO_set(pt16hold[1]); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRLINETO_set"); + } + } + free(pt16hold); + } + } + } + + // WMF has no fill or stroke commands, the draw does it with active pen/brush + + // clean out brush and pen, but only after all parts of the draw complete + if (use_fill){ destroy_brush(); } + if (use_stroke){ destroy_pen(); } + + return TRUE; +} + + +bool PrintWmf::textToPath(Inkscape::Extension::Print * ext) +{ + return ext->get_param_bool("textToPath"); +} + +unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, + SPStyle const *const style) +{ + if (!wt) return 0; + + char *rec = NULL; + int ccount,newfont; + int fix90n=0; + uint32_t hfont = 0; + Geom::Affine tf = m_tr_stack.top(); + double rot = -1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation, - sign for MM_TEXT + double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below + double dx,dy; + double f1,f2,f3; + double ky; + + // the dx array is smuggled in like: text<nul>w1 w2 w3 ...wn<nul><nul>, where the widths are floats 7 characters wide, including the space + int ndx, rtl; + int16_t *adx; + smuggle_adxky_out(text, &adx, &ky, &rtl, &ndx, PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); // side effect: free() adx + + uint32_t textalignment; + if(rtl > 0){ textalignment = U_TA_BASELINE | U_TA_LEFT; } + else { textalignment = U_TA_BASELINE | U_TA_RIGHT | U_TA_RTLREADING; } + if(textalignment != htextalignment){ + htextalignment = textalignment; + rec = U_WMRSETTEXTALIGN_set(textalignment); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTALIGN_set"); + } + } + + char *text2 = strdup(text); // because U_Utf8ToUtf16le calls iconv which does not like a const char * + uint16_t *unicode_text = U_Utf8ToUtf16le( text2, 0, NULL ); + free(text2); + //translates Unicode as Utf16le to NonUnicode, if possible. If any translate, all will, and all to + //the same font, because of code in Layout::print + UnicodeToNon(unicode_text, &ccount, &newfont); + // The preceding hopefully handled conversions to symbol, wingdings or zapf dingbats. Now slam everything + // else down into latin1, which is all WMF can handle. If the language isn't English expect terrible results. + char *latin1_text = U_Utf16leToLatin1( unicode_text, 0, NULL ); + free(unicode_text); + + //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value + //Some funky ones: Arial, Times New Roman + //Some not funky ones: Symbol and Verdana. + //Without a huge table we cannot catch them all, so just the most common problem ones. + if(FixPPTCharPos){ + switch(newfont){ + case CVTSYM: + search_short_fflist("Convert To Symbol", &f1, &f2, &f3); + break; + case CVTZDG: + search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3); + break; + case CVTWDG: + search_short_fflist("Convert To Wingdings", &f1, &f2, &f3); + break; + default: //also CVTNON + search_short_fflist(style->text->font_family.value, &f1, &f2, &f3); + break; + } + if(f2 || f3){ + int irem = ((int) round(rot)) % 900 ; + if(irem <=9 && irem >= -9){ + fix90n=1; //assume vertical + rot = (double) (((int) round(rot)) - irem); + rotb = rot*M_PI/1800.0; + if( abs(rot) == 900.0 ){ fix90n = 2; } + } + } + } + + /* + Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision. + The WMF output files produced here have been designed so that the integer valued pt sizes + land right on an integer value in the WMF file, so those are exact. However, something like 18.1 pt will be + somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) + */ + int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); + if (!hfont) { + + // Get font face name. Use changed font name if unicode mapped to one + // of the special fonts. + char *facename; + if(!newfont){ facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL); } + else { facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL); } + + // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if + // it was streteched asymmetrically.) Few applications support text from WMF which is scaled + // differently by height/width, so leave lfWidth alone. + + PU_FONT puf = U_FONT_set( + textheight, + 0, + round(rot), + round(rot), + transweight(style->font_weight.computed), + (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), + style->text_decoration_line.underline, + style->text_decoration_line.line_through, + U_DEFAULT_CHARSET, + U_OUT_DEFAULT_PRECIS, + U_CLIP_DEFAULT_PRECIS, + U_DEFAULT_QUALITY, + U_DEFAULT_PITCH | U_FF_DONTCARE, + facename); + free(facename); + + rec = wcreatefontindirect_set( &hfont, wht, puf); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::text at wcreatefontindirect_set"); + } + free(puf); + } + + rec = wselectobject_set(hfont, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::text at wselectobject_set"); + } + + float rgb[3]; + sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); + // only change the text color when it needs to be changed + if(memcmp(htextcolor_rgb,rgb,3*sizeof(float))){ + memcpy(htextcolor_rgb,rgb,3*sizeof(float)); + rec = U_WMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set"); + } + } + + + // Text alignment: + // - (x,y) coordinates received by this filter are those of the point where the text + // actually starts, and already takes into account the text object's alignment; + // - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT. + // this is set at the beginning of the file and never changed + + // Transparent text background, never changes, set at the beginning of the file + + Geom::Point p2 = p * tf; + + //Handle super/subscripts and vertical kerning +/* Previously used this, but vertical kerning was not supported + p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); + p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); +*/ + p2[Geom::X] += ky * std::sin( rotb ); + p2[Geom::Y] += ky * std::cos( rotb ); + + //Conditionally handle compensation for PPT WMF import bug (affects PPT 2003-2010, at least) + if(FixPPTCharPos){ + if(fix90n==1){ //vertical + dx= 0.0; + dy= f3 * style->font_size.computed * std::cos( rotb ); + } + else if(fix90n==2){ //horizontal + dx= f2 * style->font_size.computed * std::sin( rotb ); + dy= 0.0; + } + else { + dx= f1 * style->font_size.computed * std::sin( rotb ); + dy= f1 * style->font_size.computed * std::cos( rotb ); + } + p2[Geom::X] += dx; + p2[Geom::Y] += dy; + } + + p2[Geom::X] = (p2[Geom::X] * PX2WORLD); + p2[Geom::Y] = (p2[Geom::Y] * PX2WORLD); + + int32_t const xpos = (int32_t) round(p2[Geom::X]); + int32_t const ypos = (int32_t) round(p2[Geom::Y]); + + // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is + // the number of VISIBLE characters, since some may combine from the UTF (8 originally, + // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of + // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former. + +// This is currently being smuggled in from caller as part of text, works +// MUCH better than the fallback hack below +// uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up + if(rtl>0){ + rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF); + } + else { // RTL text, U_TA_RTLREADING should be enough, but set this one too just in case + rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_RTLREADING, latin1_text, adx, U_RCL16_DEF); + } + free(latin1_text); + free(adx); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::text at U_WMREXTTEXTOUTW_set"); + } + + rec = wdeleteobject_set(&hfont, wht); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + g_error("Fatal programming error in PrintWmf::text at wdeleteobject_set"); + } + + return 0; +} + +void PrintWmf::init (void) +{ + read_system_fflist(); + + /* WMF print */ + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>Windows Metafile Print</name>\n" + "<id>org.inkscape.print.wmf</id>\n" + "<param name=\"destination\" type=\"string\"></param>\n" + "<param name=\"textToPath\" type=\"boolean\">true</param>\n" + "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n" + "<param name=\"FixPPTCharPos\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTDashLine\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTGrad2Polys\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTPatternAsHatch\" type=\"boolean\">false</param>\n" + "<print/>\n" + "</inkscape-extension>", new PrintWmf()); + + return; +} + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/wmf-print.h b/src/extension/internal/wmf-print.h new file mode 100644 index 000000000..5fe316417 --- /dev/null +++ b/src/extension/internal/wmf-print.h @@ -0,0 +1,147 @@ +/** @file + * @brief Windows Metafile printing - implementation + */ +/* Author: + * Ulf Erikson <ulferikson@users.sf.net> + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_WMF_H__ +#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_WMF_H__ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "uwmf.h" + +#include "extension/implementation/implementation.h" +//#include "extension/extension.h" + +#include <2geom/pathvector.h> +#include "sp-gradient.h" +#include "splivarot.h" // pieces for union on shapes +#include "display/canvas-bpath.h" // for SPWindRule + +#include <stack> + +namespace Inkscape { +namespace Extension { +namespace Internal { + +class PrintWmf : public Inkscape::Extension::Implementation::Implementation +{ + double _width; + double _height; + U_RECTL rc; + + uint32_t htextalignment; + uint32_t hbrush, hpen, hpenOld, hbrush_null, hpen_null; + uint32_t hmiterlimit; // used to minimize redundant records that set this + uint32_t hpolyfillmode; // used to minimize redundant records that set this + float htextcolor_rgb[3]; // used to minimize redundant records that set this + + std::stack<Geom::Affine> m_tr_stack; + Geom::PathVector fill_pathv; + Geom::Affine fill_transform; + bool use_stroke; + bool use_fill; + bool simple_shape; + bool usebk; + + unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); + bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); + +public: + PrintWmf (void); + virtual ~PrintWmf (void); + + /* Print functions */ + virtual unsigned int setup (Inkscape::Extension::Print * module); + + virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc); + virtual unsigned int finish (Inkscape::Extension::Print * module); + + /* Rendering methods */ + virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); + virtual unsigned int release(Inkscape::Extension::Print *module); + virtual unsigned int fill (Inkscape::Extension::Print *module, + Geom::PathVector const &pathv, + Geom::Affine const &ctm, SPStyle const *style, + Geom::OptRect const &pbox, Geom::OptRect const &dbox, + Geom::OptRect const &bbox); + virtual unsigned int stroke (Inkscape::Extension::Print * module, + Geom::PathVector const &pathv, + Geom::Affine const &ctm, SPStyle const *style, + Geom::OptRect const &pbox, Geom::OptRect const &dbox, + Geom::OptRect const &bbox); + virtual unsigned int image(Inkscape::Extension::Print *module, + unsigned char *px, + unsigned int w, + unsigned int h, + unsigned int rs, + Geom::Affine const &transform, + SPStyle const *style); + virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); + virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, + Geom::Point const &p, SPStyle const *style); + bool textToPath (Inkscape::Extension::Print * ext); + + static void init (void); +protected: + static void read_system_fflist(void); //this is not called by any other source files + static void search_long_fflist(const char *fontname, double *f1, double *f2, double *f3); + static void search_short_fflist(const char *fontname, double *f1, double *f2, double *f3); + static void smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *rtl, int *ndx, float scale); + U_COLORREF gethexcolor(uint32_t color); + uint32_t transweight(const unsigned int inkweight); + + int create_brush(SPStyle const *style, PU_COLORREF fcolor); + void destroy_brush(); + int create_pen(SPStyle const *style, const Geom::Affine &transform); + void destroy_pen(); + + void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor); + void swapRBinRGBA(char *px, int pixels); + + U_COLORREF avg_stop_color(SPGradient *gr); + + int hold_gradient(void *gr, int mode); + + inline U_COLORREF weight_opacity(U_COLORREF c1); + + U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t); + + Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); + + Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F); + + Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F); + + Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width); + + FillRule SPWR_to_LVFR(SPWindRule wr); + +}; + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + + +#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_WMF_H__ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : |
