diff options
| author | David Mathog <> | 2013-03-08 08:27:50 +0000 |
|---|---|---|
| committer | ~suv <suv-sf@users.sourceforge.net> | 2013-03-08 08:27:50 +0000 |
| commit | e298aeb969151e2a523d3aaef737ac04b6e5b0e8 (patch) | |
| tree | df7e286cc921f8c76684567d4253c7f312e3e2ad /src | |
| parent | merge from trunk (r12122) (diff) | |
| download | inkscape-e298aeb969151e2a523d3aaef737ac04b6e5b0e8.tar.gz inkscape-e298aeb969151e2a523d3aaef737ac04b6e5b0e8.zip | |
changes_2013_02_25a.patch
New: WMF import/export
implements WMF (Windows Metafile) read and write. Inkscape previously
supported that through uniconverter, which was not very good with WMF
files. The new version now has a complete wmf-print/wmf-inout
implementation, analogous to the previous emf-print/emf-inout. This
handles images, patterns, and various other goodies to the extent that
WMF does. WMF is a bit primitive, many fields are only 16 bits, so it
even more resolution sapping issues than does EMF. Given the choice,
always use the latter format.
(bzr r11668.1.52)
Diffstat (limited to 'src')
28 files changed, 19365 insertions, 672 deletions
diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index b5634f42f..273067e80 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -36,8 +36,10 @@ set(extension_SRC internal/cairo-render-context.cpp internal/cairo-renderer.cpp internal/cairo-renderer-pdf-out.cpp - internal/emf-win32-inout.cpp - internal/emf-win32-print.cpp + internal/emf-inout.cpp + internal/emf-print.cpp + internal/wmf-inout.cpp + internal/wmf-print.cpp internal/gdkpixbuf-input.cpp internal/gimpgrad.cpp internal/grid.cpp @@ -101,8 +103,10 @@ set(extension_SRC internal/cairo-renderer-pdf-out.h internal/cairo-renderer.h internal/clear-n_.h - internal/emf-win32-inout.h - internal/emf-win32-print.h + internal/emf-inout.h + internal/emf-print.h + internal/wmf-inout.h + internal/wmf-print.h internal/filter/bevels.h internal/filter/blurs.h internal/filter/bumps.h diff --git a/src/extension/init.cpp b/src/extension/init.cpp index 9b65ce1f8..3be7d1509 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -34,6 +34,8 @@ #include "internal/svgz.h" # 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" @@ -179,6 +181,8 @@ init() #endif Internal::PrintEmf::init(); Internal::Emf::init(); + Internal::PrintWmf::init(); + Internal::Wmf::init(); Internal::PovOutput::init(); Internal::JavaFXOutput::init(); Internal::OdfOutput::init(); diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index 7f5e975d4..341973870 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -164,10 +164,18 @@ ink_common_sources += \ 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 index eab47c5c8..d1587a5b6 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -26,7 +26,11 @@ # include "config.h" #endif -#define EMF_DRIVER +#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" @@ -43,15 +47,9 @@ #include "document.h" #include "libunicode-convert/unicode-convert.h" -#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> #include "emf-print.h" #include "emf-inout.h" -#include "uemf.h" -#include "text_reassemble.h" #define PRINT_EMF "org.inkscape.print.emf" @@ -87,33 +85,11 @@ Originally here, but moved up #include <stdint.h> */ -/* 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; /* Given "bitmap", this returns the pixel of bitmap at the point ("x", "y"). */ -static pixel_t * pixel_at (bitmap_t * bitmap, int x, int y) +pixel_t * Emf::pixel_at (bitmap_t * bitmap, int x, int y) { return bitmap->pixels + bitmap->width * y + x; } @@ -123,7 +99,7 @@ static pixel_t * pixel_at (bitmap_t * bitmap, int x, int y) success, non-zero on error. */ void -my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +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); @@ -143,7 +119,7 @@ my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) p->size += length; } -void toPNG(PMEMPNG accum, int width, int height, char *px){ +void Emf::toPNG(PMEMPNG accum, int width, int height, char *px){ bitmap_t bmstore; bitmap_t *bitmap=&bmstore; accum->buffer=NULL; // PNG constructed in memory will end up here, caller must free(). @@ -230,7 +206,7 @@ void toPNG(PMEMPNG accum, int width, int height, char *px){ /* convert an EMF RGB(A) color to 0RGB inverse of gethexcolor() in emf-print.cpp */ -uint32_t sethexcolor(U_COLORREF color){ +uint32_t Emf::sethexcolor(U_COLORREF color){ uint32_t out; out = (U_RGBAGetR(color) << 16) + @@ -261,8 +237,8 @@ Emf::check (Inkscape::Extension::Extension * /*module*/) } -static void -emf_print_document_to_file(SPDocument *doc, gchar const *filename) +void +Emf::print_document_to_file(SPDocument *doc, gchar const *filename) { Inkscape::Extension::Print *mod; SPPrintContext context; @@ -338,7 +314,7 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena ext->set_param_bool("FixImageRot",new_FixImageRot); ext->set_param_bool("textToPath", new_val); - emf_print_document_to_file(doc, filename); + print_document_to_file(doc, filename); return; } @@ -346,85 +322,11 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE}; // apply to either fill or stroke -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 - 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 - - U_SIZEL sizeWnd; - U_SIZEL sizeView; - U_POINTL winorg; - U_POINTL vieworg; - double ScaleInX, ScaleInY; - double ScaleOutX, ScaleOutY; - U_COLORREF textColor; - U_COLORREF bkColor; - uint32_t textAlign; - U_XFORM worldTransform; - U_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; - 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; /* 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 current_scale(PEMF_CALLBACK_DATA d){ +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 */ @@ -437,7 +339,7 @@ double current_scale(PEMF_CALLBACK_DATA d){ 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) */ -static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset){ +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("; @@ -461,20 +363,20 @@ static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int /* given the transformation matrix from worldTranform return the rotation angle in radians. counter clocwise from the x axis. */ -double current_rotation(PEMF_CALLBACK_DATA d){ +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 enlarge_hatches(PEMF_CALLBACK_DATA d){ +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 in_hatches(PEMF_CALLBACK_DATA d, char *test){ +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); @@ -485,7 +387,7 @@ int in_hatches(PEMF_CALLBACK_DATA d, char *test){ /* (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>. */ -uint32_t add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){ +uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){ char hatchname[64]; // big enough char hrotname[64]; // big enough char tmpcolor[8]; @@ -633,14 +535,14 @@ uint32_t add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchCol /* Add another 100 blank slots to the images array. */ -void enlarge_images(PEMF_CALLBACK_DATA d){ +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 in_images(PEMF_CALLBACK_DATA d, char *test){ +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); @@ -654,7 +556,8 @@ int in_images(PEMF_CALLBACK_DATA d, char *test){ 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 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 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 @@ -665,10 +568,11 @@ uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t MEMPNG mempng; // PNG in memory comes back in this mempng.buffer = NULL; - char *rgba_px=NULL; // RGBA pixels - char *px=NULL; // DIB pixels + 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; - PU_RGBQUAD ct = NULL; if(!cbBits || !cbBmi || (iUsage != U_DIB_RGB_COLORS) || @@ -677,7 +581,7 @@ uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t offBits, offBmi, &px, - &ct, + (const U_RGBQUAD **) &ct, &numCt, &width, &height, @@ -688,9 +592,10 @@ uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t // 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){ - ct[0] = U_RGB2BGR(d->dc[d->level].textColor); - ct[1] = U_RGB2BGR(d->dc[d->level].bkColor); + 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); @@ -812,8 +717,8 @@ uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t } -static void -output_style(PEMF_CALLBACK_DATA d, int iType) +void +Emf::output_style(PEMF_CALLBACK_DATA d, int iType) { // SVGOStringStream tmp_id; SVGOStringStream tmp_style; @@ -1000,8 +905,8 @@ output_style(PEMF_CALLBACK_DATA d, int iType) } -static double -_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) +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; @@ -1010,8 +915,8 @@ _pix_x_to_point(PEMF_CALLBACK_DATA d, double px) return(tmp); } -static double -_pix_y_to_point(PEMF_CALLBACK_DATA d, double py) +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; @@ -1021,8 +926,8 @@ _pix_y_to_point(PEMF_CALLBACK_DATA d, double py) } -static double -pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) +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); @@ -1030,8 +935,8 @@ pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) return x; } -static double -pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) +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; @@ -1041,8 +946,8 @@ pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) } -static double -pix_to_abs_size(PEMF_CALLBACK_DATA d, double px) +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; @@ -1050,7 +955,7 @@ pix_to_abs_size(PEMF_CALLBACK_DATA d, double px) /* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates */ -static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){ +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 << ","; @@ -1059,8 +964,8 @@ static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){ } -static void -select_pen(PEMF_CALLBACK_DATA d, int index) +void +Emf::select_pen(PEMF_CALLBACK_DATA d, int index) { PU_EMRCREATEPEN pEmr = NULL; @@ -1174,8 +1079,8 @@ select_pen(PEMF_CALLBACK_DATA d, int index) } -static void -select_extpen(PEMF_CALLBACK_DATA d, int index) +void +Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) { PU_EMREXTCREATEPEN pEmr = NULL; @@ -1350,8 +1255,8 @@ select_extpen(PEMF_CALLBACK_DATA d, int index) } -static void -select_brush(PEMF_CALLBACK_DATA d, int index) +void +Emf::select_brush(PEMF_CALLBACK_DATA d, int index) { uint32_t tidx; uint32_t iType; @@ -1396,8 +1301,8 @@ select_brush(PEMF_CALLBACK_DATA d, int index) } -static void -select_font(PEMF_CALLBACK_DATA d, int index) +void +Emf::select_font(PEMF_CALLBACK_DATA d, int index) { PU_EMREXTCREATEFONTINDIRECTW pEmr = NULL; @@ -1455,8 +1360,8 @@ select_font(PEMF_CALLBACK_DATA d, int index) 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) +void +Emf::delete_object(PEMF_CALLBACK_DATA d, int index) { if (index >= 0 && index < d->n_obj) { d->emf_obj[index].type = 0; @@ -1471,8 +1376,8 @@ delete_object(PEMF_CALLBACK_DATA d, int index) } -static void -insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj) +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); @@ -1485,7 +1390,7 @@ insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD 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 AI_hack(PU_EMRHEADER pEmr){ +int Emf::AI_hack(PU_EMRHEADER pEmr){ int ret=0; char *ptr; ptr = (char *)pEmr; @@ -1506,7 +1411,7 @@ int AI_hack(PU_EMRHEADER pEmr){ \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 *unknown_chars(size_t count){ +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; } @@ -1530,7 +1435,7 @@ uint32_t *unknown_chars(size_t count){ \param offBmi \param cbBmi */ -void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, +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){ @@ -1545,11 +1450,11 @@ void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, 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 - char *px=NULL; // DIB pixels + 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; - PU_RGBQUAD ct = NULL; if(!cbBits || !cbBmi || (iUsage != U_DIB_RGB_COLORS) || @@ -1558,7 +1463,7 @@ void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, offBits, offBmi, &px, - &ct, + (const U_RGBQUAD **) &ct, &numCt, &width, &height, @@ -1643,7 +1548,7 @@ void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, \param d Inkscape data structures returned by this call */ //THis was a callback, just build it into a normal function -int myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d) +int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d) { uint32_t off=0; uint32_t emr_mask; @@ -1661,7 +1566,10 @@ int myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d) tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ tsp.taln = ALILEFT + ALIBASE; tsp.ldir = LDIR_LR; - tsp.color = 0; /* RGBA Black */ + 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.condensed = 100; @@ -1859,8 +1767,7 @@ std::cout << "BEFORE DRAW" 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_str << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y) << " "; } } @@ -1976,13 +1883,11 @@ std::cout << "BEFORE DRAW" 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 ) << " "; + 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 ) << " "; + poly_path << "\n\tL " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " "; i++; } @@ -2184,8 +2089,7 @@ std::cout << "BEFORE DRAW" d->dc[d->level].cur = pEmr->ptl; tmp_path << - "\n\tM " << - pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + "\n\tM " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; break; } case U_EMR_SETMETARGN: dbg_str << "<!-- U_EMR_SETMETARGN -->\n"; break; @@ -2673,8 +2577,7 @@ std::cout << "BEFORE DRAW" d->mask |= emr_mask; tmp_path << - "\n\tL " << - pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + "\n\tL " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y) << " "; break; } case U_EMR_ARCTO: @@ -3009,8 +2912,8 @@ std::cout << "BEFORE DRAW" 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)){ - g_free(d->dc[d->level].font_name); - d->dc[d->level].font_name = g_strdup("Times New Roman"); + free(d->dc[d->level].font_name); + d->dc[d->level].font_name = strdup("Times New Roman"); } char *ansi_text; @@ -3028,9 +2931,12 @@ std::cout << "BEFORE DRAW" 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; - memcpy(&tsp.color, &d->dc[d->level].textColor, sizeof(uint32_t)); //It is already an RGBA binary value, but compiler is picky about types + 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; @@ -3179,7 +3085,7 @@ std::cout << "BEFORE DRAW" 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 ) << " "; + tmp_path << pix_to_xy( d, apts[i].x, apts[i].y) << " "; } } @@ -3196,7 +3102,7 @@ std::cout << "BEFORE DRAW" 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 ) << " "; + tmp_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; } break; @@ -3220,11 +3126,11 @@ std::cout << "BEFORE DRAW" 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 ) << " "; + 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 ) << " "; + poly_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; i++; } @@ -3344,7 +3250,7 @@ typedef struct } APMHEADER, *PAPMHEADER; #pragma pack( pop ) -void free_emf_strings(EMF_STRINGS name){ +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); @@ -3356,7 +3262,8 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) { EMF_CALLBACK_DATA d; - memset(&d, 0, sizeof(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)); diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index 62b5c6e1c..db253b375 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -11,12 +11,120 @@ #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 { +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 + 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 + + U_SIZEL sizeWnd; + U_SIZEL sizeView; + U_POINTL winorg; + U_POINTL vieworg; + double ScaleInX, ScaleInY; + double ScaleOutX, ScaleOutY; + U_COLORREF textColor; + U_COLORREF bkColor; + 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: @@ -36,6 +144,43 @@ public: 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, char *px); + static uint32_t sethexcolor(U_COLORREF color); + static void print_document_to_file(SPDocument *doc, gchar const *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 */ diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 1eec01f39..89ffbde44 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -45,7 +45,6 @@ #include "inkscape-version.h" #include "sp-root.h" -#include "emf-print.h" #include "unit-constants.h" @@ -63,6 +62,9 @@ #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" @@ -101,13 +103,13 @@ struct GRADVALUES{ static double PX2WORLD = 20.0f; static U_XFORM worldTransform; static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot; -static FFNEXUS *short_fflist = NULL; //only those fonts so far encountered -static FFNEXUS *long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf -static EMFTRACK *et = NULL; -static EMFHANDLES *eht = NULL; +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 read_system_fflist(void){ //this is not called by any other source files +void PrintEmf::read_system_fflist(void){ //this is not called by any other source files FFNEXUS *temp=NULL; FFNEXUS *ptr=NULL; std::fstream fffile; @@ -116,7 +118,7 @@ char fontname[128]; double f1,f2,f3; std::string path_to_ffconf; - if(long_fflist)return; + if(emf_long_fflist)return; path_to_ffconf=INKSCAPE_EXTENSIONDIR; #ifdef WIN32 path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax @@ -148,7 +150,7 @@ std::string path_to_ffconf; ptr=temp; } else { - long_fflist=ptr=temp; + emf_long_fflist=ptr=temp; } } fffile.close(); @@ -157,24 +159,24 @@ std::string path_to_ffconf; /* 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 search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files +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=long_fflist; - if(!long_fflist){ +FFNEXUS *tmp=emf_long_fflist; + if(!emf_long_fflist){ g_message("Programming error search_long_fflist called before read_system_fflist\n"); throw "boom"; } - ptr=long_fflist; + 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(!short_fflist){ - ptr=short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS)); + if(!emf_short_fflist){ + ptr=emf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS)); } else { - ptr=short_fflist; + ptr=emf_short_fflist; while(ptr->next){ ptr=ptr->next; } ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS)); ptr=ptr->next; @@ -189,16 +191,16 @@ FFNEXUS *tmp=long_fflist; /* 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 search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files +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(!long_fflist){ + if(!emf_long_fflist){ g_message("Programming error search_short_fflist called before read_system_fflist\n"); throw "boom"; } // 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=short_fflist; } // short_fflist may still be NULL + 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; @@ -207,7 +209,7 @@ static FFNEXUS *last=NULL; search_long_fflist(fontname, f1, f2, f3); } -void smuggle_adxky_out(const char *string, uint32_t **adx, double *ky, int *ndx, float scale){ +void PrintEmf::smuggle_adxky_out(const char *string, uint32_t **adx, double *ky, int *ndx, float scale){ float fdx; int i; uint32_t *ladx; @@ -233,7 +235,7 @@ void smuggle_adxky_out(const char *string, uint32_t **adx, double *ky, int *ndx, /* convert an 0RGB color to EMF U_COLORREF. inverse of sethexcolor() in emf-inout.cpp */ -U_COLORREF gethexcolor(uint32_t color){ +U_COLORREF PrintEmf::gethexcolor(uint32_t color){ U_COLORREF out; out = U_RGB( @@ -247,7 +249,7 @@ U_COLORREF gethexcolor(uint32_t color){ /* Translate inkscape weights to EMF weights. */ -uint32_t transweight(const unsigned int inkweight){ +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); @@ -261,16 +263,9 @@ uint32_t transweight(const unsigned int inkweight){ return(U_FW_NORMAL); } -PrintEmf::PrintEmf (void): - _width(0), - _height(0), - hbrush(0), - hbrushOld(0), - hpen(0), - use_stroke(false), - use_fill(false), - simple_shape(false) +PrintEmf::PrintEmf (void) { + // all of the class variables are initialized elsewhere, many in PrintWmf::Begin, } @@ -309,10 +304,15 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) 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; + use_stroke = use_fill = simple_shape = false; + Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview"); if(nv){ const char *p1 = nv->attribute("pagecolor"); @@ -455,10 +455,11 @@ unsigned int PrintEmf::comment (Inkscape::Extension::Print * /*module*/, // 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 hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor){ +void PrintEmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor){ int val; uint32_t hcolor=0; - if(0!=strncmp(name,"EMFhatch",8)){ return; } // not anything we can parse + // 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)){ @@ -480,11 +481,11 @@ void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor){ // // 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 EMFhatch3_3F7FFF return hatchType=3, hatchColor=3F7FFF (as a uint32_t), +// 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 brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor){ +void PrintEmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor){ if(depth==0){ *epixbuf = NULL; *hatchType = -1; @@ -500,7 +501,7 @@ void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatch } char temp[32]; // large enough temp[31]='\0'; - strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than EMFhatch#_###### + strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_###### hatch_classify(temp,hatchType,hatchColor); if(*hatchType != -1)return; @@ -526,7 +527,7 @@ void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatch } //swap R/B in 4 byte pixel -void swapRBinRGBA(char *px, int pixels){ +void PrintEmf::swapRBinRGBA(char *px, int pixels){ char tmp; for(int i=0;i<pixels*4;px+=4,i+=4){ tmp=px[2]; @@ -540,7 +541,7 @@ inline float opweight(float v1, float v2, float op){ return v1*op + v2*(1.0-op); } -U_COLORREF avg_stop_color(SPGradient *gr){ +U_COLORREF PrintEmf::avg_stop_color(SPGradient *gr){ U_COLORREF cr; int last = gr->vector.stops.size() -1; if(last>=1){ @@ -566,7 +567,7 @@ U_COLORREF avg_stop_color(SPGradient *gr){ return cr; } -int hold_gradient(void *gr, int mode){ +int PrintEmf::hold_gradient(void *gr, int mode){ gv.mode = mode; gv.grad = gr; if(mode==DRAW_RADIAL_GRADIENT){ @@ -705,13 +706,6 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ throw "Fatal programming error in PrintEmf::create_brush at createbrushindirect_set"; } - hbrush = brush; // need this later for destroy_brush - - rec = selectobject_set(brush, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - throw "Fatal programming error in PrintEmf::create_brush at selectobject_set"; - } - break; case DRAW_IMAGE: char *px; @@ -736,13 +730,14 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) } free(px); free(Bmi); // ct will be NULL because of colortype - - rec = selectobject_set(brush, eht); - if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ - throw "Fatal programming error in PrintEmf::create_brush at selectobject_set"; - } 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)){ + throw "Fatal programming error in PrintEmf::create_brush at selectobject_set"; + } + rec = U_EMRSETPOLYFILLMODE_set(fmode); if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ throw "Fatal programming error in PrintEmf::create_brush at U_EMRSETPOLYdrawmode_set"; @@ -1056,7 +1051,7 @@ unsigned int PrintEmf::release(Inkscape::Extension::Print * /*mod*/) } #define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) -inline U_COLORREF weight_opacity(U_COLORREF c1){ +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), @@ -1068,7 +1063,7 @@ inline U_COLORREF weight_opacity(U_COLORREF c1){ // return the color between c1 and c2, c1 for t=0, c2 for t=1.0 -U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t){ +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); @@ -1104,7 +1099,7 @@ U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t){ F is in RADIANS, but the SVGEllipticalArc needs degrees! */ -Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ +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; @@ -1125,7 +1120,7 @@ Geom::PathVector center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double /* rx2,ry2 must be larger than rx1,ry1! angle is in RADIANS */ -Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1, double ry1, double rx2, double ry2, double F){ +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; @@ -1152,7 +1147,7 @@ Geom::PathVector center_elliptical_ring_as_SVG_PathV(Geom::Point ctr, double rx1 } /* Elliptical hole in a large square extending from -50k to +50k */ -Geom::PathVector center_elliptical_hole_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){ +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; @@ -1176,7 +1171,7 @@ pos vector from center to leading edge neg vector from center to trailing edge width vector to side edge */ -Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){ +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); @@ -1191,7 +1186,7 @@ Geom::PathVector rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, /* Convert from SPWindRule to livarot's FillRule This is similar to what sp_selected_path_boolop() does */ -FillRule SPWR_to_LVFR(SPWindRule wr){ +FillRule PrintEmf::SPWR_to_LVFR(SPWindRule wr){ FillRule fr; if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h index eec013d1b..0832d6e30 100644 --- a/src/extension/internal/emf-print.h +++ b/src/extension/internal/emf-print.h @@ -22,6 +22,9 @@ //#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> @@ -84,13 +87,31 @@ public: static void init (void); protected: - 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(); + 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_adxky_out(const char *string, uint32_t **adx, double *ky, 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); + void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor); + 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); }; diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c index 4d52dfb33..b72bafa33 100644 --- a/src/extension/internal/text_reassemble.c +++ b/src/extension/internal/text_reassemble.c @@ -67,8 +67,8 @@ Optional compiler switches for development: File: text_reassemble.c -Version: 0.0.4 -Date: 24-JAN-2013 +Version: 0.0.5 +Date: 19-FEB-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2013 David Mathog and California Institute of Technology (Caltech) @@ -1640,7 +1640,7 @@ void TR_layout_2_svg(TR_INFO *tri){ if(k==0){ sprintf(obuf,"dx=\"%lf\" dy=\"%lf\" ",0.0, 0.0); } else { sprintf(obuf,"dx=\"%lf\" dy=\"%lf\" ",dx, dy); } TRPRINT(tri, obuf); - sprintf(obuf,"style=\"fill:#%6.6X;",tsp->color); + 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); @@ -1941,6 +1941,7 @@ int main(int argc, char *argv[]){ TR_INFO *tri=NULL; int flags=0; char *infile; + uint32_t utmp32; infile=malloc(strlen(argv[1])+1); strcpy(infile,argv[1]); @@ -1960,7 +1961,7 @@ int main(int argc, char *argv[]){ 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(" CND:(Condensed 50-200: 100=normal, 50=ultracondensed, 75=condensed, 200=expanded).\n"); - printf(" CLR:(RGBA color, HEX) \n"); + printf(" CLR:(RGB color, as 6 HEX digits, like: FF0000 (red) or 0000FF (blue)) \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"); @@ -1989,7 +1990,10 @@ int main(int argc, char *argv[]){ tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ tsp.taln = ALILEFT + ALIBASE; tsp.ldir = LDIR_LR; - tsp.color = 0; /* RGBA Black */ + tsp.color.Red = 0; /* RGBA Black */ + tsp.color.Green = 0; /* RGBA Black */ + tsp.color.Blue = 0; /* RGBA Black */ + tsp.color.Reserved = 0; /* unused */ tsp.italics = 0; tsp.weight = 80; tsp.condensed = 100; @@ -2090,7 +2094,11 @@ int main(int argc, char *argv[]){ if(1 != sscanf(data,"%d",&tsp.condensed) || tsp.condensed < 50 || tsp.condensed > 200)boom("Invalid CND:",lineno); break; case OPCLR: - if(1 != sscanf(data,"%x",&tsp.color) )boom("Invalid CLR:",lineno); + if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid CLR:",lineno); + tsp.color.Red = (utmp32 >> 4) & 0xFF; + tsp.color.Green = (utmp32 >> 2) & 0xFF; + tsp.color.Blue = (utmp32 >> 0) & 0xFF; + tsp.color.Reserved = 0; break; case OPFLAGS: if(1 != sscanf(data,"%d",&flags) )boom("Invalid FLAG:",lineno); diff --git a/src/extension/internal/text_reassemble.h b/src/extension/internal/text_reassemble.h index fb58d504e..cf8aa6729 100644 --- a/src/extension/internal/text_reassemble.h +++ b/src/extension/internal/text_reassemble.h @@ -4,13 +4,16 @@ See text_reassemble.c for notes File: text_reassemble.h -Version: 0.0.4 -Date: 24-JAN-2013 +Version: 0.0.6 +Date: 19-FEB-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 @@ -105,6 +108,13 @@ typedef struct { int 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 */ @@ -117,7 +127,7 @@ typedef struct { 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 */ - uint32_t color; /**< RGBA */ + TRCOLORREF color; /**< RGB */ int taln; /**< text alignment with respect to x,y */ int ldir; /**< language diretion LDIR_* */ int italics; /**< italics, as in FontConfig */ @@ -297,3 +307,4 @@ int trinfo_append_out(TR_INFO *tri, char *src); #ifdef __cplusplus } #endif +#endif /* _TEXT_REASSEMBLE_ */ diff --git a/src/extension/internal/uemf.c b/src/extension/internal/uemf.c index 47af366e7..b06990dbd 100644 --- a/src/extension/internal/uemf.c +++ b/src/extension/internal/uemf.c @@ -14,8 +14,8 @@ /* File: uemf.c -Version: 0.0.15 -Date: 01-FEB-2013 +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) @@ -34,6 +34,7 @@ extern "C" { #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 @@ -196,7 +197,7 @@ definitions are not needed in end user code, so they are here rather than in uem 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 * B->bmiHeader.biClrUsed; /* bmiheader + colortable*/ \ + E = sizeof(U_BITMAPINFOHEADER) + 4 * get_real_color_count((const char *) &(B->bmiHeader)); /* bmiheader + colortable*/ \ }\ else { C = 0; D = 0; E=0; } @@ -255,8 +256,8 @@ These functions are used for development and debugging and should be be includie \param size length in bytes of buf! */ int memprobe( - void *buf, - size_t size + const void *buf, + size_t size ){ int sum=0; char *ptr=(char *)buf; @@ -265,10 +266,10 @@ int memprobe( } /** - \brief Dump the eht structure. Not for use in production code. + \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 eht structure to dump + \param eht EMFHANDLES structure to dump */ void dumpeht( char *string, @@ -474,10 +475,12 @@ uint32_t emr_properties(uint32_t type){ } /** - \brief Derive from an EMF arc, chord, or pie the center, start, and end points, and the bounding rectangle. + \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 record U_EMRPIE, U_EMRCHORD, or _EMRARC record + \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 @@ -485,8 +488,10 @@ uint32_t emr_properties(uint32_t type){ \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 emr_arc_points_common( + PU_RECTL rclBox, + PU_POINTL ArcStart, + PU_POINTL ArcEnd, int *f1, int f2, PU_PAIRF center, @@ -501,15 +506,14 @@ int emr_arc_points( U_PAIRF radii; // x,y radii of ellipse U_PAIRF ratio; // intermediate value float scale, cross; - PU_EMRARC pEmr = (PU_EMRARC) (record); - center->x = ((float)(pEmr->rclBox.left + pEmr->rclBox.right ))/2.0; - center->y = ((float)(pEmr->rclBox.top + pEmr->rclBox.bottom))/2.0; - size->x = (float)(pEmr->rclBox.right - pEmr->rclBox.left ); - size->y = (float)(pEmr->rclBox.bottom - pEmr->rclBox.top ); - estart.x = (float)(pEmr->ptlStart.x); - estart.y = (float)(pEmr->ptlStart.y); - eend.x = (float)(pEmr->ptlEnd.x); - eend.y = (float)(pEmr->ptlEnd.y); + 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; @@ -555,21 +559,46 @@ int emr_arc_points( //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation //and the two unit vectors. - cross = start->x * end->y - start->y * end->x; + cross = vec_estart.x * vec_eend.y - vec_estart.y * vec_eend.x; if(!f2){ // counter clockwise rotation - if(cross >=0){ *f1 = 0; } - else { *f1 = 1; } - } - else { 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 @@ -594,7 +623,7 @@ int RGBA_to_DIB( uint32_t *cbPx, PU_RGBQUAD *ct, int *numCt, - char *rgba_px, + const char *rgba_px, int w, int h, int stride, @@ -608,7 +637,7 @@ int RGBA_to_DIB( int istart, iend, iinc; uint8_t r,g,b,a,tmp8; char *pxptr; - char *rptr; + const char *rptr; int found; int usedbytes; U_RGBQUAD color; @@ -763,6 +792,60 @@ int RGBA_to_DIB( } /** + \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. @@ -778,44 +861,39 @@ int RGBA_to_DIB( \param invert If DIB rows are in opposite order from RGBA rows */ int get_DIB_params( - void *pEmr, - uint32_t offBitsSrc, - uint32_t offBmiSrc, - char **px, - PU_RGBQUAD *ct, - uint32_t *numCt, - uint32_t *width, - uint32_t *height, - uint32_t *colortype, - uint32_t *invert + 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 = Bmi->bmiHeader.biCompression; - *width = Bmi->bmiHeader.biWidth; - *colortype = Bmi->bmiHeader.biBitCount; - if(Bmi->bmiHeader.biHeight < 0){ - *height = -Bmi->bmiHeader.biHeight; + bic = Bmih->biCompression; + *width = Bmih->biWidth; + *colortype = Bmih->biBitCount; + if(Bmih->biHeight < 0){ + *height = -Bmih->biHeight; *invert = 1; } else { - *height = Bmi->bmiHeader.biHeight; + *height = Bmih->biHeight; *invert = 0; } if(bic == U_BI_RGB){ - /* color table location, there may or may not actually be one there */ - *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); - *numCt = Bmi->bmiHeader.biClrUsed; - if(*numCt==0){ - if( *colortype == U_BCBM_MONOCHROME){ *numCt = 2; } - else if(*colortype == U_BCBM_COLOR4 ){ *numCt = 16; } - else if(*colortype == U_BCBM_COLOR8 ){ *numCt = 256; } - } - if( *colortype >= U_BCBM_COLOR16){ *ct = NULL; } + *numCt = get_real_color_count((const char *) Bmih); + if( numCt){ *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); } + else { *ct = NULL; } } else { - *numCt = Bmi->bmiHeader.biSizeImage; + *numCt = Bmih->biSizeImage; *ct = NULL; } *px = (char *)((char *)pEmr + offBitsSrc); @@ -837,15 +915,15 @@ int get_DIB_params( \param invert If DIB rows are in opposite order from RGBA rows */ int DIB_to_RGBA( - char *px, - PU_RGBQUAD ct, - int numCt, - char **rgba_px, - int w, - int h, - uint32_t colortype, - int use_ct, - int invert + 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; @@ -854,7 +932,7 @@ int DIB_to_RGBA( int i,j; int istart, iend, iinc; uint8_t r,g,b,a,tmp8; - char *pxptr; + const char *pxptr; char *rptr; int usedbytes; U_RGBQUAD color; @@ -1049,7 +1127,7 @@ writing the final data structure out to a file. \param emr record to duplicate */ char *emr_dup( - char *emr + const char *emr ){ char *dup; int irecsize; @@ -1274,7 +1352,7 @@ int emf_append( \param chunksize When needed increase space by this number of handles \param eht EMF handle table */ -int htable_create( +int emf_htable_create( uint32_t initsize, uint32_t chunksize, EMFHANDLES **eht @@ -1306,36 +1384,18 @@ int htable_create( ehtl->peak = 1; ehtl->sptr = 1; ehtl->top = 0; - ehtl->mftype = U_MFT_EMF; // default and for backwards compatibility, use htable_mftype to change for WMF. *eht = ehtl; return(0); } /** - \brief Set the metafile type on a handle table. - The type may be used to block accidental cross calls WMF->EMF and so forth. - \return 0 for success, -1 for failure. - \param type Metafile Enumeration - \param eht EMF handle table -*/ -int htable_mftype( - uint32_t type, - EMFHANDLES *eht - ){ - int ret=0; - if((type >= U_MFT_MIN) && (type <= U_MFT_MAX)){ eht->mftype = type; } - else { ret = -1; } - return(ret); -} - -/** \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 htable_delete( +int emf_htable_delete( uint32_t *ih, EMFHANDLES *eht ){ @@ -1361,7 +1421,7 @@ int htable_delete( \param ih handle \param eht EMF handle table */ -int htable_insert( +int emf_htable_insert( uint32_t *ih, EMFHANDLES *eht ){ @@ -1390,7 +1450,6 @@ int htable_insert( if(*ih > eht->top){ eht->top = *ih; } if(eht->sptr > eht->peak){ eht->peak = eht->sptr; } eht->sptr++; // next available handle - return(0); } @@ -1399,7 +1458,7 @@ int htable_insert( \return 0 for success, >=1 for failure. \param eht EMF handle table */ -int htable_free( +int emf_htable_free( EMFHANDLES **eht ){ EMFHANDLES *ehtl; @@ -1947,9 +2006,9 @@ PU_BITMAPINFO bitmapinfo_set( ){ char *record; int irecsize; - int cbColors, cbColors4,off; + int cbColors, cbColors4, off; - cbColors = 4*BmiHeader.biClrUsed; + cbColors = 4*get_real_color_count((char *) &BmiHeader); cbColors4 = UP4(cbColors); irecsize = sizeof(U_BITMAPINFOHEADER) + cbColors4; record = malloc(irecsize); @@ -2331,7 +2390,7 @@ Each should be called in preference to the underlying "base" EMR function. */ char *textcomment_set( - char *string + const char *string ){ if(!string)return(NULL); return(U_EMRCOMMENT_set(1 + strlen(string),string)); @@ -2355,9 +2414,8 @@ char *deleteobject_set( uint32_t *ihObject, EMFHANDLES *eht ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function uint32_t saveObject=*ihObject; - if(htable_delete(ihObject,eht))return(NULL); // invalid handle or other problem, cannot be deleted + if(emf_htable_delete(ihObject,eht))return(NULL); // invalid handle or other problem, cannot be deleted return(U_EMRDELETEOBJECT_set(saveObject)); } @@ -2372,9 +2430,8 @@ char *selectobject_set( uint32_t ihObject, EMFHANDLES *eht ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function if(!(U_STOCK_OBJECT & ihObject)){ // not a stock object, those go straight through - if(eht->top < ihObject)return(NULL); // handle this high is not in the table + 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)); @@ -2399,8 +2456,7 @@ char *extcreatepen_set( char *Px, PU_EXTLOGPEN elp ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihPen, eht))return(NULL); + if(emf_htable_insert(ihPen, eht))return(NULL); return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp )); } @@ -2417,8 +2473,7 @@ char *createpen_set( EMFHANDLES *eht, U_LOGPEN lopn ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihPen, eht))return(NULL); + if(emf_htable_insert(ihPen, eht))return(NULL); return(U_EMRCREATEPEN_set(*ihPen, lopn)); } @@ -2435,8 +2490,7 @@ char *createbrushindirect_set( EMFHANDLES *eht, U_LOGBRUSH lb ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihBrush, eht))return(NULL); + if(emf_htable_insert(ihBrush, eht))return(NULL); return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb)); } @@ -2460,8 +2514,7 @@ char *createdibpatternbrushpt_set( const char *Px ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihBrush, eht))return(NULL); + if(emf_htable_insert(ihBrush, eht))return(NULL); return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px)); } @@ -2485,8 +2538,7 @@ char *createmonobrush_set( const char *Px ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihBrush, eht))return(NULL); + if(emf_htable_insert(ihBrush, eht))return(NULL); return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px)); } @@ -2504,8 +2556,7 @@ char *createcolorspace_set( EMFHANDLES *eht, U_LOGCOLORSPACEA lcs ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihCS, eht))return(NULL); + if(emf_htable_insert(ihCS, eht))return(NULL); return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs)); } @@ -2528,8 +2579,7 @@ char *createcolorspacew_set( U_CBDATA cbData, uint8_t *Data ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihCS, eht))return(NULL); + if(emf_htable_insert(ihCS, eht))return(NULL); return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data)); } @@ -2548,8 +2598,7 @@ char *extcreatefontindirectw_set( const char *elf, const char *elfw ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihFont, eht))return(NULL); + if(emf_htable_insert(ihFont, eht))return(NULL); return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw)); } @@ -2566,8 +2615,7 @@ char *createpalette_set( EMFHANDLES *eht, U_LOGPALETTE lgpl ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihPal, eht))return(NULL); + if(emf_htable_insert(ihPal, eht))return(NULL); return(U_EMRCREATEPALETTE_set(*ihPal, lgpl)); } @@ -2588,8 +2636,7 @@ char *setpaletteentries_set( const U_NUM_LOGPLTNTRY cEntries, const PU_LOGPLTNTRY aPalEntries ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihPal, eht))return(NULL); + if(emf_htable_insert(ihPal, eht))return(NULL); return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries)); } @@ -2608,8 +2655,7 @@ char *fillrgn_set( const U_RECTL rclBounds, const PU_RGNDATA RgnData ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihBrush, eht))return(NULL); + if(emf_htable_insert(ihBrush, eht))return(NULL); return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData)); } @@ -2630,8 +2676,7 @@ char *framergn_set( const U_SIZEL szlStroke, const PU_RGNDATA RgnData ){ - if(U_MFT_MISMATCH(eht,U_MFT_EMF))return(NULL); // something not EMF calling EMF function - if(htable_insert(ihBrush, eht))return(NULL); + if(emf_htable_insert(ihBrush, eht))return(NULL); return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData)); } diff --git a/src/extension/internal/uemf.h b/src/extension/internal/uemf.h index a303498e2..4d620b424 100644 --- a/src/extension/internal/uemf.h +++ b/src/extension/internal/uemf.h @@ -13,8 +13,8 @@ /* File: uemf.h -Version: 0.0.12 -Date: 17-JAN-2013 +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) @@ -49,16 +49,6 @@ extern "C" { // *********************************************************************************** // Value enumerations and other predefined constants, alphabetical order by group -/** \defgroup U_MF_Qualifiers Metafile Enumeration - For EMFHANDLES mftype field - @{ -*/ -#define U_MFT_WMF 1 //!< 16 bit windows metafile -#define U_MFT_EMF 2 //!< 32 bit enhanced windows metafile -#define U_MFT_EMFP 3 //!< EMF plus (reserved, not implemented yet) -#define U_MFT_MAX 3 -#define U_MFT_MIN 1 -/** @} */ /** \defgroup Font_struct_widths Font name and style widths in characters For U_LOGFONT and U_LOGFONT_PANOSE, @@ -215,6 +205,7 @@ extern "C" { #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 @@ -1160,8 +1151,6 @@ extern "C" { // Utility macros #define UP4(A) (4 * ((A + 3 ) / 4)) //!< Round up to nearest multiple of 4 -#define U_MFT_MISMATCH(A,B) (A->mftype != B) //!< A is [EW]MFHANDLES and B is Metafile enumeration - /** @} */ typedef float U_FLOAT; @@ -2571,14 +2560,14 @@ typedef struct { } EMFTRACK; /** - The various create functions need a place to put their handles, which here are stored in the table below. + 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, but selecting another handle for the same type of graphic object, and thus - made deleteable. End user code must keep track of this for itself. + 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 @@ -2588,7 +2577,6 @@ typedef struct { 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) - uint32_t mftype; //!< Metafile type, see Metafile Enumeration (used to block erroneous calls, wmf=>emf, for instance) } EMFHANDLES; /** @@ -2604,7 +2592,7 @@ typedef struct { // ************************************************************************************************ // Prototypes -int memprobe(void *buf, size_t size); +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); @@ -2616,12 +2604,16 @@ 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 RGBA_to_DIB( char **px, uint32_t *cbPx, PU_RGBQUAD *ct, int *numCt, - char *rgba_px, int w, int h, int stride, uint32_t colortype, int use_ct, int invert); +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, - char **px, PU_RGBQUAD *ct, uint32_t *numCt, + 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(char *px, PU_RGBQUAD ct, int numCt, +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); @@ -2635,11 +2627,17 @@ 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); -int htable_create(uint32_t initsize, uint32_t chunksize, EMFHANDLES **eht); -int htable_delete(uint32_t *ih, EMFHANDLES *eht); -int htable_insert(uint32_t *ih, EMFHANDLES *eht); -int htable_free(EMFHANDLES **eht); -int htable_mftype(uint32_t type, EMFHANDLES *eht); + +/* 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); @@ -2699,9 +2697,9 @@ 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(char *emr); +char *emr_dup(const char *emr); -char *textcomment_set(char *string); +char *textcomment_set(const char *string); // These generate the handle and then call the underlying function char *deleteobject_set(uint32_t *ihObject, EMFHANDLES *eht); diff --git a/src/extension/internal/uemf_endian.c b/src/extension/internal/uemf_endian.c index 97bd209c0..cdae07a3d 100644 --- a/src/extension/internal/uemf_endian.c +++ b/src/extension/internal/uemf_endian.c @@ -17,8 +17,8 @@ /* File: uemf_endian.h -Version: 0.0.10 -Date: 11-JAN-2013 +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) @@ -129,8 +129,8 @@ void trivertex_swap( unsigned int count ){ for(;count; count--, tv++){ - U_swap4(tv,2); - U_swap2(&(tv->Red),4); + U_swap4(tv,2); /* x,y */ + U_swap2(&(tv->Red),4); /* Red, Green, Blue, Alpha */ } } @@ -155,7 +155,7 @@ void gradient4_swap( PU_GRADIENT4 g4, unsigned int count ){ - U_swap4(g4,4*count); + U_swap4(g4,2*count); //a gradient4 object has 2 int4's, NOT 4! } /** @@ -635,9 +635,10 @@ void U_EMRHEADER_swap(char *record, int torev){ PU_EMRHEADER pEmr = (PU_EMRHEADER)(record); if(torev){ nSize = pEmr->emr.nSize; + core5_swap(record, torev); } - core5_swap(record, torev); - if(!torev){ + else { + core5_swap(record, torev); nSize = pEmr->emr.nSize; } @@ -647,9 +648,10 @@ void U_EMRHEADER_swap(char *record, int torev){ if(torev){ nDesc = pEmr->nDescription; offDesc = pEmr->offDescription; + U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries } - U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries - if(!torev){ + else { + U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries nDesc = pEmr->nDescription; offDesc = pEmr->offDescription; } @@ -662,9 +664,10 @@ void U_EMRHEADER_swap(char *record, int torev){ cbPix = pEmr->cbPixelFormat; offPix = pEmr->offPixelFormat; if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); + U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat } - U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat - if(!torev){ + else { + U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat cbPix = pEmr->cbPixelFormat; offPix = pEmr->offPixelFormat; if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); diff --git a/src/extension/internal/uemf_print.c b/src/extension/internal/uemf_print.c index 6841e2982..1d6bebc40 100644 --- a/src/extension/internal/uemf_print.c +++ b/src/extension/internal/uemf_print.c @@ -4,8 +4,8 @@ /* File: uemf_print.c -Version: 0.0.11 -Date: 22-JAN-2013 +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) @@ -312,31 +312,42 @@ void logfont_panose_print( /** \brief Print a pointer to U_BITMAPINFOHEADER object. - \param Bmih pointer to a 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 */ -void bitmapinfoheader_print( - char *Bmih +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); } @@ -348,16 +359,16 @@ void bitmapinfoheader_print( be aligned in memory. */ void bitmapinfo_print( - char *Bmi + const char *Bmi ){ int i,k; - uint32_t biClrUsed; + int ClrUsed; U_RGBQUAD BmiColor; - printf("BmiHeader: "); bitmapinfoheader_print(Bmi + offsetof(U_BITMAPINFO,bmiHeader)); - memcpy(&biClrUsed, Bmi + offsetof(U_BITMAPINFO,bmiHeader) + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); - if(biClrUsed){ + printf("BmiHeader: "); + ClrUsed = bitmapinfoheader_print(Bmi + offsetof(U_BITMAPINFO,bmiHeader)); + if(ClrUsed){ k= offsetof(U_BITMAPINFO,bmiColors); - for(i=0; i<biClrUsed; i++, k+= sizeof(U_RGBQUAD)){ + for(i=0; i<ClrUsed; i++, k+= sizeof(U_RGBQUAD)){ memcpy(&BmiColor, Bmi+k, sizeof(U_RGBQUAD)); printf("%d:",i); rgbquad_print(BmiColor); } @@ -541,9 +552,9 @@ void pixelformatdescriptor_print( \param type 0 for 8 bit character, anything else for 16 */ void emrtext_print( - char *emt, - char *record, - int type + const char *emt, + const char *record, + int type ){ int i,off; char *string; @@ -588,16 +599,16 @@ by end user code and to further that end prototypes are NOT provided and they ar These are (mostly) ordered by U_EMR_* index number. The exceptions: - void core3_print(char *name, char *label, char *contents) - void core7_print(char *name, char *field1, char *field2, char *contents) - void core8_print(char *name, char *contents, int type) + 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(char *name, char *contents){ +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"); @@ -610,7 +621,7 @@ void core1_print(char *name, char *contents){ } // Functions with the same form starting with U_EMRPOLYPOLYLINE_print -void core2_print(char *name, char *contents){ +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"); @@ -631,7 +642,7 @@ void core2_print(char *name, char *contents){ // Functions with the same form starting with U_EMRSETMAPMODE_print -void core3_print(char *name, char *label, char *contents){ +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"); @@ -645,13 +656,13 @@ void core3_print(char *name, char *label, char *contents){ } // Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_print, also U_EMRFILLPATH_print, -void core4_print(char *name, char *contents){ +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(char *name, char *contents){ +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"); @@ -669,7 +680,7 @@ void core6_print(char *name, char *contents){ // 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(char *name, char *field1, char *field2, char *contents){ +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); @@ -681,7 +692,7 @@ void core7_print(char *name, char *field1, char *field2, char *contents){ } // For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one -void core8_print(char *name, char *contents, int type){ +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"); @@ -693,7 +704,7 @@ void core8_print(char *name, char *contents, int type){ } // Functions that take a rect and a pair of points, starting with U_EMRARC_print -void core9_print(char *name, char *contents){ +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"); @@ -701,7 +712,7 @@ void core9_print(char *name, char *contents){ } // Functions with the same form starting with U_EMRPOLYPOLYLINE16_print -void core10_print(char *name, char *contents){ +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"); @@ -722,7 +733,7 @@ void core10_print(char *name, char *contents){ } // Functions with the same form starting with U_EMRINVERTRGN_print and U_EMRPAINTRGN_print, -void core11_print(char *name, char *contents){ +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"); @@ -741,7 +752,7 @@ void core11_print(char *name, char *contents){ // common code for U_EMRCREATEMONOBRUSH_print and U_EMRCREATEDIBPATTERNBRUSHPT_print, -void core12_print(char *name, char *contents){ +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 ); @@ -757,7 +768,7 @@ void core12_print(char *name, char *contents){ } // common code for U_EMRALPHABLEND_print and U_EMRTRANSPARENTBLT_print, -void core13_print(char *name, char *contents){ +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"); @@ -790,7 +801,7 @@ They are listed in order by the corresponding U_EMR_* index number. \param name name of this type of record \param contents pointer to a buffer holding all EMR records */ -void U_EMRNOTIMPLEMENTED_print(char *name, char *contents){ +void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents){ printf(" Not Implemented!\n"); } @@ -799,7 +810,7 @@ void U_EMRNOTIMPLEMENTED_print(char *name, char *contents){ \brief Print a pointer to a U_EMR_HEADER record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRHEADER_print(char *contents){ +void U_EMRHEADER_print(const char *contents){ char *string; int p1len; @@ -851,7 +862,7 @@ void U_EMRHEADER_print(char *contents){ \brief Print a pointer to a U_EMR_POLYBEZIER record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYBEZIER_print(char *contents){ +void U_EMRPOLYBEZIER_print(const char *contents){ core1_print("U_EMRPOLYBEZIER", contents); } @@ -860,7 +871,7 @@ void U_EMRPOLYBEZIER_print(char *contents){ \brief Print a pointer to a U_EMR_POLYGON record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYGON_print(char *contents){ +void U_EMRPOLYGON_print(const char *contents){ core1_print("U_EMRPOLYGON", contents); } @@ -870,7 +881,7 @@ void U_EMRPOLYGON_print(char *contents){ \brief Print a pointer to a U_EMR_POLYLINE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYLINE_print(char *contents){ +void U_EMRPOLYLINE_print(const char *contents){ core1_print("U_EMRPOLYLINE", contents); } @@ -879,7 +890,7 @@ void U_EMRPOLYLINE_print(char *contents){ \brief Print a pointer to a U_EMR_POLYBEZIERTO record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYBEZIERTO_print(char *contents){ +void U_EMRPOLYBEZIERTO_print(const char *contents){ core1_print("U_EMRPOLYBEZIERTO", contents); } @@ -888,7 +899,7 @@ void U_EMRPOLYBEZIERTO_print(char *contents){ \brief Print a pointer to a U_EMR_POLYLINETO record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYLINETO_print(char *contents){ +void U_EMRPOLYLINETO_print(const char *contents){ core1_print("U_EMRPOLYLINETO", contents); } @@ -897,7 +908,7 @@ void U_EMRPOLYLINETO_print(char *contents){ \brief Print a pointer to a U_EMR_POLYPOLYLINE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYPOLYLINE_print(char *contents){ +void U_EMRPOLYPOLYLINE_print(const char *contents){ core2_print("U_EMRPOLYPOLYLINE", contents); } @@ -906,7 +917,7 @@ void U_EMRPOLYPOLYLINE_print(char *contents){ \brief Print a pointer to a U_EMR_POLYPOLYGON record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYPOLYGON_print(char *contents){ +void U_EMRPOLYPOLYGON_print(const char *contents){ core2_print("U_EMRPOLYPOLYGON", contents); } @@ -915,7 +926,7 @@ void U_EMRPOLYPOLYGON_print(char *contents){ \brief Print a pointer to a U_EMR_SETWINDOWEXTEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETWINDOWEXTEX_print(char *contents){ +void U_EMRSETWINDOWEXTEX_print(const char *contents){ core7_print("U_EMRSETWINDOWEXTEX", "szlExtent:","",contents); } @@ -924,7 +935,7 @@ void U_EMRSETWINDOWEXTEX_print(char *contents){ \brief Print a pointer to a U_EMR_SETWINDOWORGEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETWINDOWORGEX_print(char *contents){ +void U_EMRSETWINDOWORGEX_print(const char *contents){ core7_print("U_EMRSETWINDOWORGEX", "ptlOrigin:","",contents); } @@ -933,7 +944,7 @@ void U_EMRSETWINDOWORGEX_print(char *contents){ \brief Print a pointer to a U_EMR_SETVIEWPORTEXTEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETVIEWPORTEXTEX_print(char *contents){ +void U_EMRSETVIEWPORTEXTEX_print(const char *contents){ core7_print("U_EMRSETVIEWPORTEXTEX", "szlExtent:","",contents); } @@ -942,7 +953,7 @@ void U_EMRSETVIEWPORTEXTEX_print(char *contents){ \brief Print a pointer to a U_EMR_SETVIEWPORTORGEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETVIEWPORTORGEX_print(char *contents){ +void U_EMRSETVIEWPORTORGEX_print(const char *contents){ core7_print("U_EMRSETVIEWPORTORGEX", "ptlOrigin:","",contents); } @@ -951,7 +962,7 @@ void U_EMRSETVIEWPORTORGEX_print(char *contents){ \brief Print a pointer to a U_EMR_SETBRUSHORGEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETBRUSHORGEX_print(char *contents){ +void U_EMRSETBRUSHORGEX_print(const char *contents){ core7_print("U_EMRSETBRUSHORGEX", "ptlOrigin:","",contents); } @@ -960,7 +971,7 @@ void U_EMRSETBRUSHORGEX_print(char *contents){ \brief Print a pointer to a U_EMR_EOF record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREOF_print(char *contents){ +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); @@ -977,7 +988,7 @@ void U_EMREOF_print(char *contents){ \brief Print a pointer to a U_EMR_SETPIXELV record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETPIXELV_print(char *contents){ +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"); @@ -989,7 +1000,7 @@ void U_EMRSETPIXELV_print(char *contents){ \brief Print a pointer to a U_EMR_SETMAPPERFLAGS record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETMAPPERFLAGS_print(char *contents){ +void U_EMRSETMAPPERFLAGS_print(const char *contents){ PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(contents); printf(" dwFlags: %u\n",pEmr->dwFlags); } @@ -1000,7 +1011,7 @@ void U_EMRSETMAPPERFLAGS_print(char *contents){ \brief Print a pointer to a U_EMR_SETMAPMODE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETMAPMODE_print(char *contents){ +void U_EMRSETMAPMODE_print(const char *contents){ core3_print("U_EMRSETMAPMODE", "iMode:", contents); } @@ -1009,7 +1020,7 @@ void U_EMRSETMAPMODE_print(char *contents){ \brief Print a pointer to a U_EMR_SETBKMODE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETBKMODE_print(char *contents){ +void U_EMRSETBKMODE_print(const char *contents){ core3_print("U_EMRSETBKMODE", "iMode:", contents); } @@ -1018,7 +1029,7 @@ void U_EMRSETBKMODE_print(char *contents){ \brief Print a pointer to a U_EMR_SETPOLYFILLMODE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETPOLYFILLMODE_print(char *contents){ +void U_EMRSETPOLYFILLMODE_print(const char *contents){ core3_print("U_EMRSETPOLYFILLMODE", "iMode:", contents); } @@ -1027,7 +1038,7 @@ void U_EMRSETPOLYFILLMODE_print(char *contents){ \brief Print a pointer to a U_EMR_SETROP2 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETROP2_print(char *contents){ +void U_EMRSETROP2_print(const char *contents){ core3_print("U_EMRSETROP2", "dwRop:", contents); } @@ -1036,7 +1047,7 @@ void U_EMRSETROP2_print(char *contents){ \brief Print a pointer to a U_EMR_SETSTRETCHBLTMODE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETSTRETCHBLTMODE_print(char *contents){ +void U_EMRSETSTRETCHBLTMODE_print(const char *contents){ core3_print("U_EMRSETSTRETCHBLTMODE", "iMode:", contents); } @@ -1045,7 +1056,7 @@ void U_EMRSETSTRETCHBLTMODE_print(char *contents){ \brief Print a pointer to a U_EMR_SETTEXTALIGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETTEXTALIGN_print(char *contents){ +void U_EMRSETTEXTALIGN_print(const char *contents){ core3_print("U_EMRSETTEXTALIGN", "iMode:", contents); } @@ -1054,7 +1065,7 @@ void U_EMRSETTEXTALIGN_print(char *contents){ \brief Print a pointer to a U_EMR_SETCOLORADJUSTMENT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETCOLORADJUSTMENT_print(char *contents){ +void U_EMRSETCOLORADJUSTMENT_print(const char *contents){ PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(contents); printf(" ColorAdjustment:"); coloradjustment_print(pEmr->ColorAdjustment); @@ -1066,7 +1077,7 @@ void U_EMRSETCOLORADJUSTMENT_print(char *contents){ \brief Print a pointer to a U_EMR_SETTEXTCOLOR record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETTEXTCOLOR_print(char *contents){ +void U_EMRSETTEXTCOLOR_print(const char *contents){ core3_print("U_EMRSETTEXTCOLOR", "crColor:", contents); } @@ -1075,7 +1086,7 @@ void U_EMRSETTEXTCOLOR_print(char *contents){ \brief Print a pointer to a U_EMR_SETBKCOLOR record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETBKCOLOR_print(char *contents){ +void U_EMRSETBKCOLOR_print(const char *contents){ core3_print("U_EMRSETBKCOLOR", "crColor:", contents); } @@ -1084,7 +1095,7 @@ void U_EMRSETBKCOLOR_print(char *contents){ \brief Print a pointer to a U_EMR_OFFSETCLIPRGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMROFFSETCLIPRGN_print(char *contents){ +void U_EMROFFSETCLIPRGN_print(const char *contents){ core7_print("U_EMROFFSETCLIPRGN", "ptl:","",contents); } @@ -1093,7 +1104,7 @@ void U_EMROFFSETCLIPRGN_print(char *contents){ \brief Print a pointer to a U_EMR_MOVETOEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRMOVETOEX_print(char *contents){ +void U_EMRMOVETOEX_print(const char *contents){ core7_print("U_EMRMOVETOEX", "ptl:","",contents); } @@ -1102,7 +1113,7 @@ void U_EMRMOVETOEX_print(char *contents){ \brief Print a pointer to a U_EMR_SETMETARGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETMETARGN_print(char *contents){ +void U_EMRSETMETARGN_print(const char *contents){ } // U_EMREXCLUDECLIPRECT 29 @@ -1110,7 +1121,7 @@ void U_EMRSETMETARGN_print(char *contents){ \brief Print a pointer to a U_EMR_EXCLUDECLIPRECT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXCLUDECLIPRECT_print(char *contents){ +void U_EMREXCLUDECLIPRECT_print(const char *contents){ core4_print("U_EMREXCLUDECLIPRECT", contents); } @@ -1119,7 +1130,7 @@ void U_EMREXCLUDECLIPRECT_print(char *contents){ \brief Print a pointer to a U_EMR_INTERSECTCLIPRECT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRINTERSECTCLIPRECT_print(char *contents){ +void U_EMRINTERSECTCLIPRECT_print(const char *contents){ core4_print("U_EMRINTERSECTCLIPRECT", contents); } @@ -1128,7 +1139,7 @@ void U_EMRINTERSECTCLIPRECT_print(char *contents){ \brief Print a pointer to a U_EMR_SCALEVIEWPORTEXTEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSCALEVIEWPORTEXTEX_print(char *contents){ +void U_EMRSCALEVIEWPORTEXTEX_print(const char *contents){ core4_print("U_EMRSCALEVIEWPORTEXTEX", contents); } @@ -1138,7 +1149,7 @@ void U_EMRSCALEVIEWPORTEXTEX_print(char *contents){ \brief Print a pointer to a U_EMR_SCALEWINDOWEXTEX record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSCALEWINDOWEXTEX_print(char *contents){ +void U_EMRSCALEWINDOWEXTEX_print(const char *contents){ core4_print("U_EMRSCALEWINDOWEXTEX", contents); } @@ -1147,7 +1158,7 @@ void U_EMRSCALEWINDOWEXTEX_print(char *contents){ \brief Print a pointer to a U_EMR_SAVEDC record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSAVEDC_print(char *contents){ +void U_EMRSAVEDC_print(const char *contents){ } // U_EMRRESTOREDC 34 @@ -1155,7 +1166,7 @@ void U_EMRSAVEDC_print(char *contents){ \brief Print a pointer to a U_EMR_RESTOREDC record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRRESTOREDC_print(char *contents){ +void U_EMRRESTOREDC_print(const char *contents){ core3_print("U_EMRRESTOREDC", "iRelative:", contents); } @@ -1164,7 +1175,7 @@ void U_EMRRESTOREDC_print(char *contents){ \brief Print a pointer to a U_EMR_SETWORLDTRANSFORM record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETWORLDTRANSFORM_print(char *contents){ +void U_EMRSETWORLDTRANSFORM_print(const char *contents){ PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(contents); printf(" xform:"); xform_print(pEmr->xform); @@ -1176,7 +1187,7 @@ void U_EMRSETWORLDTRANSFORM_print(char *contents){ \brief Print a pointer to a U_EMR_MODIFYWORLDTRANSFORM record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRMODIFYWORLDTRANSFORM_print(char *contents){ +void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents){ PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(contents); printf(" xform:"); xform_print(pEmr->xform); @@ -1189,7 +1200,7 @@ void U_EMRMODIFYWORLDTRANSFORM_print(char *contents){ \brief Print a pointer to a U_EMR_SELECTOBJECT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSELECTOBJECT_print(char *contents){ +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 ); @@ -1204,7 +1215,7 @@ void U_EMRSELECTOBJECT_print(char *contents){ \brief Print a pointer to a U_EMR_CREATEPEN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATEPEN_print(char *contents){ +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"); @@ -1215,7 +1226,7 @@ void U_EMRCREATEPEN_print(char *contents){ \brief Print a pointer to a U_EMR_CREATEBRUSHINDIRECT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATEBRUSHINDIRECT_print(char *contents){ +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"); @@ -1226,7 +1237,7 @@ void U_EMRCREATEBRUSHINDIRECT_print(char *contents){ \brief Print a pointer to a U_EMR_DELETEOBJECT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRDELETEOBJECT_print(char *contents){ +void U_EMRDELETEOBJECT_print(const char *contents){ PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(contents); printf(" ihObject: %u\n", pEmr->ihObject ); } @@ -1236,7 +1247,7 @@ void U_EMRDELETEOBJECT_print(char *contents){ \brief Print a pointer to a U_EMR_ANGLEARC record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRANGLEARC_print(char *contents){ +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 ); @@ -1249,7 +1260,7 @@ void U_EMRANGLEARC_print(char *contents){ \brief Print a pointer to a U_EMR_ELLIPSE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRELLIPSE_print(char *contents){ +void U_EMRELLIPSE_print(const char *contents){ core4_print("U_EMRELLIPSE", contents); } @@ -1258,7 +1269,7 @@ void U_EMRELLIPSE_print(char *contents){ \brief Print a pointer to a U_EMR_RECTANGLE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRRECTANGLE_print(char *contents){ +void U_EMRRECTANGLE_print(const char *contents){ core4_print("U_EMRRECTANGLE", contents); } @@ -1267,7 +1278,7 @@ void U_EMRRECTANGLE_print(char *contents){ \brief Print a pointer to a U_EMR_ROUNDRECT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRROUNDRECT_print(char *contents){ +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"); @@ -1278,7 +1289,7 @@ void U_EMRROUNDRECT_print(char *contents){ \brief Print a pointer to a U_EMR_ARC record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRARC_print(char *contents){ +void U_EMRARC_print(const char *contents){ core9_print("U_EMRARC", contents); } @@ -1287,7 +1298,7 @@ void U_EMRARC_print(char *contents){ \brief Print a pointer to a U_EMR_CHORD record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCHORD_print(char *contents){ +void U_EMRCHORD_print(const char *contents){ core9_print("U_EMRCHORD", contents); } @@ -1296,7 +1307,7 @@ void U_EMRCHORD_print(char *contents){ \brief Print a pointer to a U_EMR_PIE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPIE_print(char *contents){ +void U_EMRPIE_print(const char *contents){ core9_print("U_EMRPIE", contents); } @@ -1305,7 +1316,7 @@ void U_EMRPIE_print(char *contents){ \brief Print a pointer to a U_EMR_SELECTPALETTE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSELECTPALETTE_print(char *contents){ +void U_EMRSELECTPALETTE_print(const char *contents){ core3_print("U_EMRSELECTPALETTE", "ihPal:", contents); } @@ -1314,7 +1325,7 @@ void U_EMRSELECTPALETTE_print(char *contents){ \brief Print a pointer to a U_EMR_CREATEPALETTE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATEPALETTE_print(char *contents){ +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"); @@ -1325,7 +1336,7 @@ void U_EMRCREATEPALETTE_print(char *contents){ \brief Print a pointer to a U_EMR_SETPALETTEENTRIES record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETPALETTEENTRIES_print(char *contents){ +void U_EMRSETPALETTEENTRIES_print(const char *contents){ int i; PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents); printf(" ihPal: %u\n",pEmr->ihPal); @@ -1346,7 +1357,7 @@ void U_EMRSETPALETTEENTRIES_print(char *contents){ \brief Print a pointer to a U_EMR_RESIZEPALETTE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRRESIZEPALETTE_print(char *contents){ +void U_EMRRESIZEPALETTE_print(const char *contents){ core7_print("U_EMRRESIZEPALETTE", "ihPal:","cEntries",contents); } @@ -1355,7 +1366,7 @@ void U_EMRRESIZEPALETTE_print(char *contents){ \brief Print a pointer to a U_EMR_REALIZEPALETTE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRREALIZEPALETTE_print(char *contents){ +void U_EMRREALIZEPALETTE_print(const char *contents){ } // U_EMREXTFLOODFILL 53 @@ -1363,7 +1374,7 @@ void U_EMRREALIZEPALETTE_print(char *contents){ \brief Print a pointer to a U_EMR_EXTFLOODFILL record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXTFLOODFILL_print(char *contents){ +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"); @@ -1375,7 +1386,7 @@ void U_EMREXTFLOODFILL_print(char *contents){ \brief Print a pointer to a U_EMR_LINETO record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRLINETO_print(char *contents){ +void U_EMRLINETO_print(const char *contents){ core7_print("U_EMRLINETO", "ptl:","",contents); } @@ -1384,7 +1395,7 @@ void U_EMRLINETO_print(char *contents){ \brief Print a pointer to a U_EMR_ARCTO record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRARCTO_print(char *contents){ +void U_EMRARCTO_print(const char *contents){ core9_print("U_EMRARCTO", contents); } @@ -1393,7 +1404,7 @@ void U_EMRARCTO_print(char *contents){ \brief Print a pointer to a U_EMR_POLYDRAW record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYDRAW_print(char *contents){ +void U_EMRPOLYDRAW_print(const char *contents){ int i; PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); @@ -1416,7 +1427,7 @@ void U_EMRPOLYDRAW_print(char *contents){ \brief Print a pointer to a U_EMR_SETARCDIRECTION record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETARCDIRECTION_print(char *contents){ +void U_EMRSETARCDIRECTION_print(const char *contents){ core3_print("U_EMRSETARCDIRECTION","arcDirection:", contents); } @@ -1425,7 +1436,7 @@ void U_EMRSETARCDIRECTION_print(char *contents){ \brief Print a pointer to a U_EMR_SETMITERLIMIT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETMITERLIMIT_print(char *contents){ +void U_EMRSETMITERLIMIT_print(const char *contents){ core3_print("U_EMRSETMITERLIMIT", "eMiterLimit:", contents); } @@ -1435,7 +1446,7 @@ void U_EMRSETMITERLIMIT_print(char *contents){ \brief Print a pointer to a U_EMR_BEGINPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRBEGINPATH_print(char *contents){ +void U_EMRBEGINPATH_print(const char *contents){ } // U_EMRENDPATH 60 @@ -1443,7 +1454,7 @@ void U_EMRBEGINPATH_print(char *contents){ \brief Print a pointer to a U_EMR_ENDPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRENDPATH_print(char *contents){ +void U_EMRENDPATH_print(const char *contents){ } // U_EMRCLOSEFIGURE 61 @@ -1451,7 +1462,7 @@ void U_EMRENDPATH_print(char *contents){ \brief Print a pointer to a U_EMR_CLOSEFIGURE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCLOSEFIGURE_print(char *contents){ +void U_EMRCLOSEFIGURE_print(const char *contents){ } // U_EMRFILLPATH 62 @@ -1459,7 +1470,7 @@ void U_EMRCLOSEFIGURE_print(char *contents){ \brief Print a pointer to a U_EMR_FILLPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRFILLPATH_print(char *contents){ +void U_EMRFILLPATH_print(const char *contents){ core4_print("U_EMRFILLPATH", contents); } @@ -1468,7 +1479,7 @@ void U_EMRFILLPATH_print(char *contents){ \brief Print a pointer to a U_EMR_STROKEANDFILLPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSTROKEANDFILLPATH_print(char *contents){ +void U_EMRSTROKEANDFILLPATH_print(const char *contents){ core4_print("U_EMRSTROKEANDFILLPATH", contents); } @@ -1477,7 +1488,7 @@ void U_EMRSTROKEANDFILLPATH_print(char *contents){ \brief Print a pointer to a U_EMR_STROKEPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSTROKEPATH_print(char *contents){ +void U_EMRSTROKEPATH_print(const char *contents){ core4_print("U_EMRSTROKEPATH", contents); } @@ -1486,7 +1497,7 @@ void U_EMRSTROKEPATH_print(char *contents){ \brief Print a pointer to a U_EMR_FLATTENPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRFLATTENPATH_print(char *contents){ +void U_EMRFLATTENPATH_print(const char *contents){ } // U_EMRWIDENPATH 66 @@ -1494,7 +1505,7 @@ void U_EMRFLATTENPATH_print(char *contents){ \brief Print a pointer to a U_EMR_WIDENPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRWIDENPATH_print(char *contents){ +void U_EMRWIDENPATH_print(const char *contents){ } // U_EMRSELECTCLIPPATH 67 @@ -1502,7 +1513,7 @@ void U_EMRWIDENPATH_print(char *contents){ \brief Print a pointer to a U_EMR_SELECTCLIPPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSELECTCLIPPATH_print(char *contents){ +void U_EMRSELECTCLIPPATH_print(const char *contents){ core3_print("U_EMRSELECTCLIPPATH", "iMode:", contents); } @@ -1511,7 +1522,7 @@ void U_EMRSELECTCLIPPATH_print(char *contents){ \brief Print a pointer to a U_EMR_ABORTPATH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRABORTPATH_print(char *contents){ +void U_EMRABORTPATH_print(const char *contents){ } // U_EMRUNDEF69 69 @@ -1522,7 +1533,7 @@ void U_EMRABORTPATH_print(char *contents){ \brief Print a pointer to a U_EMR_COMMENT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCOMMENT_print(char *contents){ +void U_EMRCOMMENT_print(const char *contents){ char *string; char *src; uint32_t cIdent,cbData; @@ -1574,7 +1585,7 @@ void U_EMRCOMMENT_print(char *contents){ \brief Print a pointer to a U_EMR_FILLRGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRFILLRGN_print(char *contents){ +void U_EMRFILLRGN_print(const char *contents){ int i,roff; PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); @@ -1595,7 +1606,7 @@ void U_EMRFILLRGN_print(char *contents){ \brief Print a pointer to a U_EMR_FRAMERGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRFRAMERGN_print(char *contents){ +void U_EMRFRAMERGN_print(const char *contents){ int i,roff; PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); @@ -1617,7 +1628,7 @@ void U_EMRFRAMERGN_print(char *contents){ \brief Print a pointer to a U_EMR_INVERTRGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRINVERTRGN_print(char *contents){ +void U_EMRINVERTRGN_print(const char *contents){ core11_print("U_EMRINVERTRGN", contents); } @@ -1626,7 +1637,7 @@ void U_EMRINVERTRGN_print(char *contents){ \brief Print a pointer to a U_EMR_PAINTRGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPAINTRGN_print(char *contents){ +void U_EMRPAINTRGN_print(const char *contents){ core11_print("U_EMRPAINTRGN", contents); } @@ -1635,7 +1646,7 @@ void U_EMRPAINTRGN_print(char *contents){ \brief Print a pointer to a U_EMR_EXTSELECTCLIPRGN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXTSELECTCLIPRGN_print(char *contents){ +void U_EMREXTSELECTCLIPRGN_print(const char *contents){ int i,roff; PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents); printf(" cbRgnData: %u\n",pEmr->cbRgnData); @@ -1654,7 +1665,7 @@ void U_EMREXTSELECTCLIPRGN_print(char *contents){ \brief Print a pointer to a U_EMR_BITBLT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRBITBLT_print(char *contents){ +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"); @@ -1680,7 +1691,7 @@ void U_EMRBITBLT_print(char *contents){ \brief Print a pointer to a U_EMR_STRETCHBLT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSTRETCHBLT_print(char *contents){ +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"); @@ -1707,7 +1718,7 @@ void U_EMRSTRETCHBLT_print(char *contents){ \brief Print a pointer to a U_EMR_MASKBLT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRMASKBLT_print(char *contents){ +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"); @@ -1744,7 +1755,7 @@ void U_EMRMASKBLT_print(char *contents){ \brief Print a pointer to a U_EMR_PLGBLT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPLGBLT_print(char *contents){ +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"); @@ -1782,7 +1793,7 @@ void U_EMRPLGBLT_print(char *contents){ \brief Print a pointer to a U_EMRSETDIBITSTODEVICE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETDIBITSTODEVICE_print(char *contents){ +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"); @@ -1807,7 +1818,7 @@ void U_EMRSETDIBITSTODEVICE_print(char *contents){ \brief Print a pointer to a U_EMR_STRETCHDIBITS record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSTRETCHDIBITS_print(char *contents){ +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"); @@ -1832,7 +1843,7 @@ void U_EMRSTRETCHDIBITS_print(char *contents){ \brief Print a pointer to a U_EMR_EXTCREATEFONTINDIRECTW record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXTCREATEFONTINDIRECTW_print(char *contents){ +void U_EMREXTCREATEFONTINDIRECTW_print(const char *contents){ PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (contents); printf(" ihFont: %u\n",pEmr->ihFont ); printf(" Font: "); @@ -1850,7 +1861,7 @@ void U_EMREXTCREATEFONTINDIRECTW_print(char *contents){ \brief Print a pointer to a U_EMR_EXTTEXTOUTA record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXTTEXTOUTA_print(char *contents){ +void U_EMREXTTEXTOUTA_print(const char *contents){ core8_print("U_EMREXTTEXTOUTA", contents, 0); } @@ -1859,7 +1870,7 @@ void U_EMREXTTEXTOUTA_print(char *contents){ \brief Print a pointer to a U_EMR_EXTTEXTOUTW record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXTTEXTOUTW_print(char *contents){ +void U_EMREXTTEXTOUTW_print(const char *contents){ core8_print("U_EMREXTTEXTOUTW", contents, 1); } @@ -1868,7 +1879,7 @@ void U_EMREXTTEXTOUTW_print(char *contents){ \brief Print a pointer to a U_EMR_POLYBEZIER16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYBEZIER16_print(char *contents){ +void U_EMRPOLYBEZIER16_print(const char *contents){ core6_print("U_EMRPOLYBEZIER16", contents); } @@ -1877,7 +1888,7 @@ void U_EMRPOLYBEZIER16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYGON16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYGON16_print(char *contents){ +void U_EMRPOLYGON16_print(const char *contents){ core6_print("U_EMRPOLYGON16", contents); } @@ -1886,7 +1897,7 @@ void U_EMRPOLYGON16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYLINE16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYLINE16_print(char *contents){ +void U_EMRPOLYLINE16_print(const char *contents){ core6_print("U_EMRPOLYLINE16", contents); } @@ -1895,7 +1906,7 @@ void U_EMRPOLYLINE16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYBEZIERTO16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYBEZIERTO16_print(char *contents){ +void U_EMRPOLYBEZIERTO16_print(const char *contents){ core6_print("U_EMRPOLYBEZIERTO16", contents); } @@ -1904,7 +1915,7 @@ void U_EMRPOLYBEZIERTO16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYLINETO16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYLINETO16_print(char *contents){ +void U_EMRPOLYLINETO16_print(const char *contents){ core6_print("U_EMRPOLYLINETO16", contents); } @@ -1913,7 +1924,7 @@ void U_EMRPOLYLINETO16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYPOLYLINE16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYPOLYLINE16_print(char *contents){ +void U_EMRPOLYPOLYLINE16_print(const char *contents){ core10_print("U_EMRPOLYPOLYLINE16", contents); } @@ -1922,7 +1933,7 @@ void U_EMRPOLYPOLYLINE16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYPOLYGON16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYPOLYGON16_print(char *contents){ +void U_EMRPOLYPOLYGON16_print(const char *contents){ core10_print("U_EMRPOLYPOLYGON16", contents); } @@ -1932,7 +1943,7 @@ void U_EMRPOLYPOLYGON16_print(char *contents){ \brief Print a pointer to a U_EMR_POLYDRAW16 record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPOLYDRAW16_print(char *contents){ +void U_EMRPOLYDRAW16_print(const char *contents){ int i; PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); @@ -1955,7 +1966,7 @@ void U_EMRPOLYDRAW16_print(char *contents){ \brief Print a pointer to a U_EMR_CREATEMONOBRUSH record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATEMONOBRUSH_print(char *contents){ +void U_EMRCREATEMONOBRUSH_print(const char *contents){ core12_print("U_EMRCREATEMONOBRUSH", contents); } @@ -1964,7 +1975,7 @@ void U_EMRCREATEMONOBRUSH_print(char *contents){ \brief Print a pointer to a U_EMR_CREATEDIBPATTERNBRUSHPT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATEDIBPATTERNBRUSHPT_print(char *contents){ +void U_EMRCREATEDIBPATTERNBRUSHPT_print(const char *contents){ core12_print("U_EMRCREATEDIBPATTERNBRUSHPT", contents); } @@ -1974,7 +1985,7 @@ void U_EMRCREATEDIBPATTERNBRUSHPT_print(char *contents){ \brief Print a pointer to a U_EMR_EXTCREATEPEN record. \param contents pointer to a buffer holding all EMR records */ -void U_EMREXTCREATEPEN_print(char *contents){ +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 ); @@ -1999,7 +2010,7 @@ void U_EMREXTCREATEPEN_print(char *contents){ \brief Print a pointer to a U_EMR_SETICMMODE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETICMMODE_print(char *contents){ +void U_EMRSETICMMODE_print(const char *contents){ core3_print("U_EMRSETICMMODE", "iMode:", contents); } @@ -2008,7 +2019,7 @@ void U_EMRSETICMMODE_print(char *contents){ \brief Print a pointer to a U_EMR_CREATECOLORSPACE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATECOLORSPACE_print(char *contents){ +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"); @@ -2019,7 +2030,7 @@ void U_EMRCREATECOLORSPACE_print(char *contents){ \brief Print a pointer to a U_EMR_SETCOLORSPACE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETCOLORSPACE_print(char *contents){ +void U_EMRSETCOLORSPACE_print(const char *contents){ core3_print("U_EMRSETCOLORSPACE", "ihCS:", contents); } @@ -2028,7 +2039,7 @@ void U_EMRSETCOLORSPACE_print(char *contents){ \brief Print a pointer to a U_EMR_DELETECOLORSPACE record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRDELETECOLORSPACE_print(char *contents){ +void U_EMRDELETECOLORSPACE_print(const char *contents){ core3_print("U_EMRDELETECOLORSPACE", "ihCS:", contents); } @@ -2042,7 +2053,7 @@ void U_EMRDELETECOLORSPACE_print(char *contents){ \brief Print a pointer to a U_EMR_PIXELFORMAT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRPIXELFORMAT_print(char *contents){ +void U_EMRPIXELFORMAT_print(const char *contents){ PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(contents); printf(" Pfd: "); pixelformatdescriptor_print(pEmr->pfd); printf("\n"); } @@ -2059,7 +2070,7 @@ void U_EMRPIXELFORMAT_print(char *contents){ \brief Print a pointer to a U_EMR_SMALLTEXTOUT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSMALLTEXTOUT_print(char *contents){ +void U_EMRSMALLTEXTOUT_print(const char *contents){ int roff; char *string; PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(contents); @@ -2100,7 +2111,7 @@ void U_EMRSMALLTEXTOUT_print(char *contents){ \brief Print a pointer to a U_EMR_ALPHABLEND record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRALPHABLEND_print(char *contents){ +void U_EMRALPHABLEND_print(const char *contents){ core13_print("U_EMRALPHABLEND", contents); } @@ -2109,7 +2120,7 @@ void U_EMRALPHABLEND_print(char *contents){ \brief Print a pointer to a U_EMR_SETLAYOUT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRSETLAYOUT_print(char *contents){ +void U_EMRSETLAYOUT_print(const char *contents){ core3_print("U_EMRSETLAYOUT", "iMode:", contents); } @@ -2118,7 +2129,7 @@ void U_EMRSETLAYOUT_print(char *contents){ \brief Print a pointer to a U_EMR_TRANSPARENTBLT record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRTRANSPARENTBLT_print(char *contents){ +void U_EMRTRANSPARENTBLT_print(const char *contents){ core13_print("U_EMRTRANSPARENTBLT", contents); } @@ -2129,7 +2140,7 @@ void U_EMRTRANSPARENTBLT_print(char *contents){ \brief Print a pointer to a U_EMR_GRADIENTFILL record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRGRADIENTFILL_print(char *contents){ +void U_EMRGRADIENTFILL_print(const char *contents){ int i; PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); @@ -2174,7 +2185,7 @@ void U_EMRGRADIENTFILL_print(char *contents){ \brief Print a pointer to a U_EMR_CREATECOLORSPACEW record. \param contents pointer to a buffer holding all EMR records */ -void U_EMRCREATECOLORSPACEW_print(char *contents){ +void U_EMRCREATECOLORSPACEW_print(const char *contents){ int i; PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents); printf(" ihCS: %u\n", pEmr->ihCS ); @@ -2198,7 +2209,7 @@ void U_EMRCREATECOLORSPACEW_print(char *contents){ \param recnum number of this record in contents \param off offset to this record in contents */ -int U_emf_onerec_print(char *contents, char *blimit, int recnum, size_t off){ +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; diff --git a/src/extension/internal/uemf_print.h b/src/extension/internal/uemf_print.h index 6354e49d9..238e0e659 100644 --- a/src/extension/internal/uemf_print.h +++ b/src/extension/internal/uemf_print.h @@ -4,8 +4,8 @@ /* File: uemf_print.h -Version: 0.0.4 -Date: 13-JAN-2013 +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) @@ -40,127 +40,127 @@ 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(char *Bmih); -void bitmapinfo_print(char *Bmi); +void bitmapinfoheader_print(const char *Bmih); +void bitmapinfo_print(const char *Bmi); void blend_print(U_BLEND blend); -void extlogpen_print(PU_EXTLOGPEN elp); +void extlogpen_print(const PU_EXTLOGPEN elp); void logpen_print(U_LOGPEN lp); void logpltntry_print(U_LOGPLTNTRY lpny); -void logpalette_print(PU_LOGPALETTE lp); +void logpalette_print(const PU_LOGPALETTE lp); void rgndataheader_print(U_RGNDATAHEADER rdh); -void rgndata_print(PU_RGNDATA rd); +void rgndata_print(const PU_RGNDATA rd); void coloradjustment_print(U_COLORADJUSTMENT ca); void pixelformatdescriptor_print(U_PIXELFORMATDESCRIPTOR pfd); -void emrtext_print(char *emt, char *record, int type); +void emrtext_print(const char *emt, const char *record, int type); /* prototypes for EMR records */ -void U_EMRNOTIMPLEMENTED_print(char *name, char *contents, int recnum, int off); -void U_EMRHEADER_print(char *contents, int recnum, int off); -void U_EMRPOLYBEZIER_print(char *contents, int recnum, int off); -void U_EMRPOLYGON_print(char *contents, int recnum, int off); -void U_EMRPOLYLINE_print(char *contents, int recnum, int off); -void U_EMRPOLYBEZIERTO_print(char *contents, int recnum, int off); -void U_EMRPOLYLINETO_print(char *contents, int recnum, int off); -void U_EMRPOLYPOLYLINE_print(char *contents, int recnum, int off); -void U_EMRPOLYPOLYGON_print(char *contents, int recnum, int off); -void U_EMRSETWINDOWEXTEX_print(char *contents, int recnum, int off); -void U_EMRSETWINDOWORGEX_print(char *contents, int recnum, int off); -void U_EMRSETVIEWPORTEXTEX_print(char *contents, int recnum, int off); -void U_EMRSETVIEWPORTORGEX_print(char *contents, int recnum, int off); -void U_EMRSETBRUSHORGEX_print(char *contents, int recnum, int off); -void U_EMREOF_print(char *contents, int recnum, int off); -void U_EMRSETPIXELV_print(char *contents, int recnum, int off); -void U_EMRSETMAPPERFLAGS_print(char *contents, int recnum, int off); -void U_EMRSETMAPMODE_print(char *contents, int recnum, int off); -void U_EMRSETBKMODE_print(char *contents, int recnum, int off); -void U_EMRSETPOLYFILLMODE_print(char *contents, int recnum, int off); -void U_EMRSETROP2_print(char *contents, int recnum, int off); -void U_EMRSETSTRETCHBLTMODE_print(char *contents, int recnum, int off); -void U_EMRSETTEXTALIGN_print(char *contents, int recnum, int off); -void U_EMRSETCOLORADJUSTMENT_print(char *contents, int recnum, int off); -void U_EMRSETTEXTCOLOR_print(char *contents, int recnum, int off); -void U_EMRSETBKCOLOR_print(char *contents, int recnum, int off); -void U_EMROFFSETCLIPRGN_print(char *contents, int recnum, int off); -void U_EMRMOVETOEX_print(char *contents, int recnum, int off); -void U_EMRSETMETARGN_print(char *contents, int recnum, int off); -void U_EMREXCLUDECLIPRECT_print(char *contents, int recnum, int off); -void U_EMRINTERSECTCLIPRECT_print(char *contents, int recnum, int off); -void U_EMRSCALEVIEWPORTEXTEX_print(char *contents, int recnum, int off); -void U_EMRSCALEWINDOWEXTEX_print(char *contents, int recnum, int off); -void U_EMRSAVEDC_print(char *contents, int recnum, int off); -void U_EMRRESTOREDC_print(char *contents, int recnum, int off); -void U_EMRSETWORLDTRANSFORM_print(char *contents, int recnum, int off); -void U_EMRMODIFYWORLDTRANSFORM_print(char *contents, int recnum, int off); -void U_EMRSELECTOBJECT_print(char *contents, int recnum, int off); -void U_EMRCREATEPEN_print(char *contents, int recnum, int off); -void U_EMRCREATEBRUSHINDIRECT_print(char *contents, int recnum, int off); -void U_EMRDELETEOBJECT_print(char *contents, int recnum, int off); -void U_EMRANGLEARC_print(char *contents, int recnum, int off); -void U_EMRELLIPSE_print(char *contents, int recnum, int off); -void U_EMRRECTANGLE_print(char *contents, int recnum, int off); -void U_EMRROUNDRECT_print(char *contents, int recnum, int off); -void U_EMRARC_print(char *contents, int recnum, int off); -void U_EMRCHORD_print(char *contents, int recnum, int off); -void U_EMRPIE_print(char *contents, int recnum, int off); -void U_EMRSELECTPALETTE_print(char *contents, int recnum, int off); -void U_EMRCREATEPALETTE_print(char *contents, int recnum, int off); -void U_EMRSETPALETTEENTRIES_print(char *contents, int recnum, int off); -void U_EMRRESIZEPALETTE_print(char *contents, int recnum, int off); -void U_EMRREALIZEPALETTE_print(char *contents, int recnum, int off); -void U_EMREXTFLOODFILL_print(char *contents, int recnum, int off); -void U_EMRLINETO_print(char *contents, int recnum, int off); -void U_EMRARCTO_print(char *contents, int recnum, int off); -void U_EMRPOLYDRAW_print(char *contents, int recnum, int off); -void U_EMRSETARCDIRECTION_print(char *contents, int recnum, int off); -void U_EMRSETMITERLIMIT_print(char *contents, int recnum, int off); -void U_EMRBEGINPATH_print(char *contents, int recnum, int off); -void U_EMRENDPATH_print(char *contents, int recnum, int off); -void U_EMRCLOSEFIGURE_print(char *contents, int recnum, int off); -void U_EMRFILLPATH_print(char *contents, int recnum, int off); -void U_EMRSTROKEANDFILLPATH_print(char *contents, int recnum, int off); -void U_EMRSTROKEPATH_print(char *contents, int recnum, int off); -void U_EMRFLATTENPATH_print(char *contents, int recnum, int off); -void U_EMRWIDENPATH_print(char *contents, int recnum, int off); -void U_EMRSELECTCLIPPATH_print(char *contents, int recnum, int off); -void U_EMRABORTPATH_print(char *contents, int recnum, int off); -void U_EMRCOMMENT_print(char *contents, int recnum, int off); -void U_EMRFILLRGN_print(char *contents, int recnum, int off); -void U_EMRFRAMERGN_print(char *contents, int recnum, int off); -void U_EMRINVERTRGN_print(char *contents, int recnum, int off); -void U_EMRPAINTRGN_print(char *contents, int recnum, int off); -void U_EMREXTSELECTCLIPRGN_print(char *contents, int recnum, int off); -void U_EMRBITBLT_print(char *contents, int recnum, int off); -void U_EMRSTRETCHBLT_print(char *contents, int recnum, int off); -void U_EMRMASKBLT_print(char *contents, int recnum, int off); -void U_EMRPLGBLT_print(char *contents, int recnum, int off); -void U_EMRSETDIBITSTODEVICE_print(char *contents, int recnum, int off); -void U_EMRSTRETCHDIBITS_print(char *contents, int recnum, int off); -void U_EMREXTCREATEFONTINDIRECTW_print(char *contents, int recnum, int off); -void U_EMREXTTEXTOUTA_print(char *contents, int recnum, int off); -void U_EMREXTTEXTOUTW_print(char *contents, int recnum, int off); -void U_EMRPOLYBEZIER16_print(char *contents, int recnum, int off); -void U_EMRPOLYGON16_print(char *contents, int recnum, int off); -void U_EMRPOLYLINE16_print(char *contents, int recnum, int off); -void U_EMRPOLYBEZIERTO16_print(char *contents, int recnum, int off); -void U_EMRPOLYLINETO16_print(char *contents, int recnum, int off); -void U_EMRPOLYPOLYLINE16_print(char *contents, int recnum, int off); -void U_EMRPOLYPOLYGON16_print(char *contents, int recnum, int off); -void U_EMRPOLYDRAW16_print(char *contents, int recnum, int off); -void U_EMRCREATEMONOBRUSH_print(char *contents, int recnum, int off); -void U_EMRCREATEDIBPATTERNBRUSHPT_print(char *contents, int recnum, int off); -void U_EMREXTCREATEPEN_print(char *contents, int recnum, int off); -void U_EMRSETICMMODE_print(char *contents, int recnum, int off); -void U_EMRCREATECOLORSPACE_print(char *contents, int recnum, int off); -void U_EMRSETCOLORSPACE_print(char *contents, int recnum, int off); -void U_EMRDELETECOLORSPACE_print(char *contents, int recnum, int off); -void U_EMRPIXELFORMAT_print(char *contents, int recnum, int off); -void U_EMRSMALLTEXTOUT_print(char *contents, int recnum, int off); -void U_EMRALPHABLEND_print(char *contents, int recnum, int off); -void U_EMRSETLAYOUT_print(char *contents, int recnum, int off); -void U_EMRTRANSPARENTBLT_print(char *contents, int recnum, int off); -void U_EMRGRADIENTFILL_print(char *contents, int recnum, int off); -void U_EMRCREATECOLORSPACEW_print(char *contents, int recnum, int off); -int U_emf_onerec_print(char *contents, char *blimit, int recnum, int off); +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 } diff --git a/src/extension/internal/uemf_utf.c b/src/extension/internal/uemf_utf.c index b9f677abe..294897124 100644 --- a/src/extension/internal/uemf_utf.c +++ b/src/extension/internal/uemf_utf.c @@ -392,6 +392,34 @@ char *U_Utf16leToUtf8( } /** + \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 @@ -438,7 +466,7 @@ char *U_Utf8ToLatin1( iconv_close(conv); if(status == (size_t) -1)return(NULL); if(len)*len=strlen(dst2); - return((uint32_t *) dst2); + return((char *) dst2); } /** @@ -469,7 +497,7 @@ char *U_Latin1ToUtf8( iconv_close(conv); if(status == (size_t) -1)return(NULL); if(len)*len=strlen(dst2); - return((uint32_t *) dst2); + return((char *) dst2); } /** diff --git a/src/extension/internal/uemf_utf.h b/src/extension/internal/uemf_utf.h index 20c7bf945..e42de23e6 100644 --- a/src/extension/internal/uemf_utf.h +++ b/src/extension/internal/uemf_utf.h @@ -39,6 +39,7 @@ 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); diff --git a/src/extension/internal/uwmf.c b/src/extension/internal/uwmf.c new file mode 100644 index 000000000..d2448cd09 --- /dev/null +++ b/src/extension/internal/uwmf.c @@ -0,0 +1,6869 @@ +/** + @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.9 +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 <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; + } + 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..30b781885 --- /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.7 +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 _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_BECOREHEADER 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..e2d2b0663 --- /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(Style == U_BS_PATTERN){ + 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..dce5d508e --- /dev/null +++ b/src/extension/internal/wmf-inout.cpp @@ -0,0 +1,3051 @@ +/** @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 "unit-constants.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>. +*/ +uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){ + char hatchname[64]; // big enough + char tmpcolor[8]; + uint32_t idx; + + if(hatchType==U_HS_DIAGCROSS){ // This is the only one with dependencies on others + (void) add_hatch(d,U_HS_FDIAGONAL,hatchColor); + (void) add_hatch(d,U_HS_BDIAGONAL,hatchColor); + } + + sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor)); + 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: + break; + } + + // WMF can take solid colors from background or the default text color but on conversion to inkscape + // these need to go to a defined color. Consequently the hatchType also has to go to a solid color, otherwise + // on export the background/text might not match at the time this is written, and the colors will shift. + if(hatchType > U_HS_SOLIDCLR)hatchType = U_HS_SOLIDCLR; + + sprintf(hatchname,"WMFhatch%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) += "\"\n"; + switch(hatchType){ + case U_HS_HORIZONTAL: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " <path d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_VERTICAL: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " <path d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" />\n"; + break; + case U_HS_FDIAGONAL: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n"; + *(d->defs) += " <line x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" id=\"sub"; + *(d->defs) += hatchname; + *(d->defs) += "\"/>\n"; + *(d->defs) += " <use xlink:href=\"#sub"; + *(d->defs) += hatchname; + *(d->defs) += "\" transform=\"translate(6,0)\"/>\n"; + *(d->defs) += " <use xlink:href=\"#sub"; + *(d->defs) += hatchname; + *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n"; + break; + case U_HS_BDIAGONAL: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n"; + *(d->defs) += " <line x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; + *(d->defs) += tmpcolor; + *(d->defs) += "\" id=\"sub"; + *(d->defs) += hatchname; + *(d->defs) += "\"/>\n"; + *(d->defs) += " <use xlink:href=\"#sub"; + *(d->defs) += hatchname; + *(d->defs) += "\" transform=\"translate(6,0)\"/>\n"; + *(d->defs) += " <use xlink:href=\"#sub"; + *(d->defs) += hatchname; + *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n"; + break; + case U_HS_CROSS: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " <path 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) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n"; + *(d->defs) += " <use xlink:href=\"#sub"; + sprintf(hatchname,"WMFhatch%d_%6.6X",U_HS_FDIAGONAL,sethexcolor(hatchColor)); + *(d->defs) += hatchname; + *(d->defs) += "\" transform=\"translate(0,0)\"/>\n"; + *(d->defs) += " <use xlink:href=\"#sub"; + sprintf(hatchname,"WMFhatch%d_%6.6X",U_HS_BDIAGONAL,sethexcolor(hatchColor)); + *(d->defs) += hatchname; + *(d->defs) += "\" transform=\"translate(0,0)\"/>\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) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " <path d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; + *(d->defs) += tmpcolor; + *(d->defs) += ";stroke:none"; + *(d->defs) += "\" />\n"; + break; + } + *(d->defs) += " "; + *(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 = 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 = 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"; + *(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); +} + +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 color as the fill, and the right size, 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 && + 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_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 { + std::cout << "Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled" << std::endl; + } + } +} + + +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.underline = font.Underline; + d->dc[d->level].style.text_decoration.line_through = font.StrikeOut; + + // 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 = ((font.Escapement + 3600) % 3600) / 10; // 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.underline = 0; + d->dc[d->level].style.text_decoration.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 + + /* 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.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 = PX_PER_IN/(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/ PX_PER_MM << "mm\"\n" << + " height=\"" << d->PixelsOutY/ PX_PER_MM << "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; + if ( (wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty){ // next record is valid type and forces pending text to be drawn immediately + 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); + } + +//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, &(d->dc[d->level].bkColor)); + break; + } + case U_WMR_SETBKMODE: dbg_str << "<!-- U_WMR_SETBKMODE -->\n"; 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)); + 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) << " "; + } + 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 ); + } + + 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 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)); + tsp.ldir = (d->dc[d->level].textAlign & U_TA_RTLREADING ? LDIR_RL : LDIR_LR); // language direction + 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 + (void) trinfo_load_fontname(d->tri, (uint8_t *)d->dc[d->level].font_name, &tsp); + // 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_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.underline = 0; + d.dc[0].style.text_decoration.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) + // 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; + + 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..613d43c8d --- /dev/null +++ b/src/extension/internal/wmf-inout.h @@ -0,0 +1,205 @@ +/** @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 { + +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 + 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 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 + + U_POINT16 sizeWnd; + U_POINT16 sizeView; + U_POINT16 winorg; + U_POINT16 vieworg; + double ScaleInX, ScaleInY; + double ScaleOutX, ScaleOutY; + U_COLORREF textColor; + U_COLORREF bkColor; + 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..c053f3222 --- /dev/null +++ b/src/extension/internal/wmf-print.cpp @@ -0,0 +1,1953 @@ +/** @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 "unit-constants.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; + 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_message("Unable to open file: %s\n", path_to_ffconf.c_str()); + throw "boom"; + } + 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 %[^\n]",&f1,&f2,&f3, &fontname[0]); + if(elements!=4){ + g_message("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str()); + throw "boom"; + } + 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(); +} + +/* 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_message("Programming error search_long_fflist called before read_system_fflist\n"); + throw "boom"; + } + 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_message("Programming error search_short_fflist called before read_system_fflist\n"); + throw "boom"; + } + // 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 *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)throw "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; +} + +/* convert an 0RGB color to EMF U_COLORREF. +inverse of sethexcolor() in emf-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) +{ +// std::cout << "begin " << std::endl; + 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; + use_stroke = use_fill = simple_shape = 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(IN_PER_PX); // 90 dpi inside inkscape, wmf file will be 1200 dpi + + float dwInchesX = d.width(); + float dwInchesY = d.height(); + int dwPxX = round(d.width() *1200.0); + int dwPxY = round(d.height()*1200.0); + + PU_PAIRF ps = U_PAIRF_set(dwInchesX, dwInchesY); + rec = U_WMRHEADER_set(ps,1200); // Example: drawing is A4 horizontal, 1200 dpi + if(!rec){ + throw "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)){ + throw "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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"; + } + + // bkmode never changes + rec = U_WMRSETBKMODE_set(U_TRANSPARENT); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE"; + } + + // Text alignment never changes + rec = U_WMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + throw "Fatal programming error in PrintWmf::text 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)){ + throw "Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set"; + } + + rec = U_WMRSETROP2_set(U_R2_COPYPEN); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + throw "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)){ + throw "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)){ + throw "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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set"; + } + destroy_brush(); // make this brush active + +// std::cout << "end begin" << std::endl; + + return 0; +} + + +unsigned int PrintWmf::finish (Inkscape::Extension::Print * /*mod*/) +{ +// std::cout << "finish " << std::endl; + 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)){ + throw "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)){ + throw "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)){ + throw "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)){ + throw "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 + +// std::cout << "end finish" << std::endl; + return 0; +} + + +unsigned int PrintWmf::comment (Inkscape::Extension::Print * /*module*/, + const char * /*comment*/) +{ +// std::cout << "comment " << std::endl; + if (!wt) return 0; + + // earlier versions had flush of fill here, but it never executed and was removed + +// std::cout << "end comment" << std::endl; + return 0; +} + +// Extract hatchType, hatchColor from a name like +// *MFhatch<hatchType>_<hatchColor> (WMF or EMF hatches are the same) +// 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 PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor){ + int val; + uint32_t hcolor=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(1 != sscanf(name,"%X",&hcolor)){ *hatchType = -1; } // again wrong syntax, cannot classify + *hatchColor = gethexcolor(hcolor); + } + 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){ + if(depth==0){ + *epixbuf = NULL; + *hatchType = -1; + *hatchColor = U_RGB(0,0,0); + } + 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); + 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); + 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); + 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 { + throw "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) +{ +// std::cout << "create_brush " << std::endl; + 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; + 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; + 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); + 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 = U_WLOGBRUSH_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: + rec = wcreatebrushindirect_set(&brush, wht, lb); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + throw "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)){ + throw "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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set"; + } + } +// std::cout << "end create_brush " << std::endl; + return 0; +} + + +void PrintWmf::destroy_brush() +{ +// std::cout << "destroy_brush " << std::endl; + 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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::destroy_brush"; + } + +// std::cout << "end destroy_brush" << std::endl; +} + + +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; +// std::cout << "create_pen " << std::endl; + + 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) (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)){ + throw "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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::create_pen at wselectobject_set"; + } + hpen = pen; // need this later for destroy_pen + + return 0; +// std::cout << "end create_pen" << std::endl; +} + +// delete the defined pen object +void PrintWmf::destroy_pen() +{ +// std::cout << "destroy_pen hpen: " << hpen<< std::endl; + 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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::destroy_pen"; + } +// std::cout << "end destroy_pen " << std::endl; +} + + + +unsigned int PrintWmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) +{ +// std::cout << "bind " << std::endl; + 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); + } + +// std::cout << "end bind" << std::endl; + return 1; +} + +unsigned int PrintWmf::release(Inkscape::Extension::Print * /*mod*/) +{ +// std::cout << "release " << std::endl; + m_tr_stack.pop(); +// std::cout << "end release" << std::endl; + 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*/) +{ +// std::cout << "fill " << std::endl; + 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 { + throw "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.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; + } + } + +// std::cout << "end fill" << std::endl; + 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*/) +{ +// std::cout << "stroke " << std::endl; + + 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; + + +// std::cout << "end stroke " << std::endl; + 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) +{ +// std::cout << "print_simple_shape " << std::endl <<std::flush; + + 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 (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) { + cubic = cubic; + 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)){ + throw "Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon"; + } + + done = true; + + } + + delete[] lpPoints; + +// std::cout << "end simple_shape " << std::endl; + 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 */ +{ +// std::cout << "image " << std::endl; + 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)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set"; + } + free(px); + free(Bmi); + if(numCt)free(ct); + +// std::cout << "end image" << std::endl; + 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) +{ +// std::cout << "print_pathv " << std::endl << std::flush; + 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 polypolygon, for all paths. Otherwise use + polygon or polyline separately on each path. 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 */ + 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){ // a single polypolygon + 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++ = 1 + 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_default(); ++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)){ + throw "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; + + /* 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. Note that size_default() ignores + the first point, for some reason. + */ + 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])); + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++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])); + } + + if (pit->end_default() == pit->end_closed()) { rec = U_WMRPOLYGON_set(nPoints, pt16hold); } + else { rec = U_WMRPOLYLINE_set(nPoints, pt16hold); } + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + throw "Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON/POLYLINE_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(); } +// std::cout << "end pathv" << std::endl; + + 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) +{ +// std::cout << "text " << std::endl; + 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; + int16_t *adx; + smuggle_adxky_out(text, &adx, &ky, &ndx, PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); // side effect: free() adx + + 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, + rot, + rot, + transweight(style->font_weight.computed), + (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC), + style->text_decoration.underline, + style->text_decoration.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)){ + throw "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)){ + throw "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)){ + throw "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 + rec = U_WMREXTTEXTOUT_set((U_POINT16) {xpos, ypos}, ndx, U_ETO_NONE, latin1_text, adx, U_RCL16_DEF); + free(latin1_text); + free(adx); + if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){ + throw "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)){ + throw "Fatal programming error in PrintWmf::text at wdeleteobject_set"; + } + +// std::cout << "end text" << std::endl; + return 0; +} + +void PrintWmf::init (void) +{ +// std::cout << "init " << std::endl; + 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..0262a2990 --- /dev/null +++ b/src/extension/internal/wmf-print.h @@ -0,0 +1,144 @@ +/** @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 hbrush, hpen, hpenOld, hbrush_null, hpen_null; + uint32_t hmiterlimit, hpolyfillmode; // used to minimize redundant records that set these + float htextcolor_rgb[3]; // used to minimize redundant records that set these + + std::stack<Geom::Affine> m_tr_stack; + Geom::PathVector fill_pathv; + Geom::Affine fill_transform; + bool use_stroke; + bool use_fill; + 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: + 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 *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); + void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor); + 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 : diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 3e63df1ac..a0a440308 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -21,6 +21,7 @@ #include <2geom/coord.h> #include <2geom/sbasis-to-bezier.h> #include <glibmm.h> +#include <math.h> // for M_PI using Geom::X; using Geom::Y; @@ -491,6 +492,315 @@ pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ) return output; } +/* + * Converts all segments in all paths to Geom::LineSegment. There is an intermediate + * stage where some may be converted to beziers. maxdisp is the maximum displacement from + * the line segment to the bezier curve. + * + * This is NOT a terribly fast method, but it should give a solution close to the one with the + * fewest points. + */ +Geom::PathVector +pathv_to_linear( Geom::PathVector const &pathv, double maxdisp) +{ + Geom::PathVector output; + Geom::PathVector tmppath = pathv_to_linear_and_cubic_beziers(pathv); + + // Now all path segments are either already lines, or they are beziers. + + for (Geom::PathVector::const_iterator pit = tmppath.begin(); pit != tmppath.end(); ++pit) { + output.push_back( Geom::Path() ); + output.back().start( pit->initialPoint() ); + output.back().close( pit->closed() ); + + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + if (is_straight_curve(*cit)) { + Geom::LineSegment ls(cit->initialPoint(), cit->finalPoint()); + output.back().append(ls); + } + else { /* all others must be Bezier curves */ + Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); + Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); + std::vector<Geom::Point> bzrpoints = b.points(); + Geom::Point A = bzrpoints[0]; + Geom::Point B = bzrpoints[1]; + Geom::Point C = bzrpoints[2]; + Geom::Point D = bzrpoints[3]; + std::vector<Geom::Point> pointlist; + pointlist.push_back(A); + recursive_bezier4( + A[X], A[Y], + B[X], B[Y], + C[X], C[Y], + D[X], D[Y], + pointlist, + 0); + pointlist.push_back(D); + Geom::Point r0; + Geom::Point r1 = pointlist[0]; + for (unsigned int i=1; i<pointlist.size();i++){ + r0 = r1; + r1 = pointlist[i]; + Geom::LineSegment ls(r0, r1); + output.back().append(ls); + } + pointlist.clear(); + } + } + } + + return output; +} + +// The next routine is modified from curv4_div::recursive_bezier from file agg_curves.cpp +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- +void +recursive_bezier4(const double x1, const double y1, + const double x2, const double y2, + const double x3, const double y3, + const double x4, const double y4, + std::vector<Geom::Point> &m_points, + int level) + { + // some of these should be parameters, but do it this way for now. + const double curve_collinearity_epsilon = 1e-30; + const double curve_angle_tolerance_epsilon = 0.01; + double m_cusp_limit = 0.0; + double m_angle_tolerance = 0.0; + double m_approximation_scale = 1.0; + double m_distance_tolerance_square = 0.5 / m_approximation_scale; + m_distance_tolerance_square *= m_distance_tolerance_square; + enum curve_recursion_limit_e { curve_recursion_limit = 32 }; +#define calc_sq_distance(A,B,C,D) ((A-C)*(A-C) + (B-D)*(B-D)) + + if(level > curve_recursion_limit) + { + return; + } + + + // Calculate all the mid-points of the line segments + //---------------------- + double x12 = (x1 + x2) / 2; + double y12 = (y1 + y2) / 2; + double x23 = (x2 + x3) / 2; + double y23 = (y2 + y3) / 2; + double x34 = (x3 + x4) / 2; + double y34 = (y3 + y4) / 2; + double x123 = (x12 + x23) / 2; + double y123 = (y12 + y23) / 2; + double x234 = (x23 + x34) / 2; + double y234 = (y23 + y34) / 2; + double x1234 = (x123 + x234) / 2; + double y1234 = (y123 + y234) / 2; + + + // Try to approximate the full cubic curve by a single straight line + //------------------ + double dx = x4-x1; + double dy = y4-y1; + + double d2 = fabs(((x2 - x4) * dy - (y2 - y4) * dx)); + double d3 = fabs(((x3 - x4) * dy - (y3 - y4) * dx)); + double da1, da2, k; + + switch((int(d2 > curve_collinearity_epsilon) << 1) + + int(d3 > curve_collinearity_epsilon)) + { + case 0: + // All collinear OR p1==p4 + //---------------------- + k = dx*dx + dy*dy; + if(k == 0) + { + d2 = calc_sq_distance(x1, y1, x2, y2); + d3 = calc_sq_distance(x4, y4, x3, y3); + } + else + { + k = 1 / k; + da1 = x2 - x1; + da2 = y2 - y1; + d2 = k * (da1*dx + da2*dy); + da1 = x3 - x1; + da2 = y3 - y1; + d3 = k * (da1*dx + da2*dy); + if(d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1) + { + // Simple collinear case, 1---2---3---4 + // We can leave just two endpoints + return; + } + if(d2 <= 0) d2 = calc_sq_distance(x2, y2, x1, y1); + else if(d2 >= 1) d2 = calc_sq_distance(x2, y2, x4, y4); + else d2 = calc_sq_distance(x2, y2, x1 + d2*dx, y1 + d2*dy); + + if(d3 <= 0) d3 = calc_sq_distance(x3, y3, x1, y1); + else if(d3 >= 1) d3 = calc_sq_distance(x3, y3, x4, y4); + else d3 = calc_sq_distance(x3, y3, x1 + d3*dx, y1 + d3*dy); + } + if(d2 > d3) + { + if(d2 < m_distance_tolerance_square) + { + m_points.push_back(Geom::Point(x2, y2)); + return; + } + } + else + { + if(d3 < m_distance_tolerance_square) + { + m_points.push_back(Geom::Point(x3, y3)); + return; + } + } + break; + + case 1: + // p1,p2,p4 are collinear, p3 is significant + //---------------------- + if(d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.push_back(Geom::Point(x23, y23)); + return; + } + + // Angle Condition + //---------------------- + da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2)); + if(da1 >= M_PI) da1 = 2*M_PI - da1; + + if(da1 < m_angle_tolerance) + { + m_points.push_back(Geom::Point(x2, y2)); + m_points.push_back(Geom::Point(x3, y3)); + return; + } + + if(m_cusp_limit != 0.0) + { + if(da1 > m_cusp_limit) + { + m_points.push_back(Geom::Point(x3, y3)); + return; + } + } + } + break; + + case 2: + // p1,p3,p4 are collinear, p2 is significant + //---------------------- + if(d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.push_back(Geom::Point(x23, y23)); + return; + } + + // Angle Condition + //---------------------- + da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); + if(da1 >= M_PI) da1 = 2*M_PI - da1; + + if(da1 < m_angle_tolerance) + { + m_points.push_back(Geom::Point(x2, y2)); + m_points.push_back(Geom::Point(x3, y3)); + return; + } + + if(m_cusp_limit != 0.0) + { + if(da1 > m_cusp_limit) + { + m_points.push_back(Geom::Point(x2, y2)); + return; + } + } + } + break; + + case 3: + // Regular case + //----------------- + if((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + // If the curvature doesn't exceed the distance_tolerance value + // we tend to finish subdivisions. + //---------------------- + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.push_back(Geom::Point(x23, y23)); + return; + } + + // Angle & Cusp Condition + //---------------------- + k = atan2(y3 - y2, x3 - x2); + da1 = fabs(k - atan2(y2 - y1, x2 - x1)); + da2 = fabs(atan2(y4 - y3, x4 - x3) - k); + if(da1 >= M_PI) da1 = 2*M_PI - da1; + if(da2 >= M_PI) da2 = 2*M_PI - da2; + + if(da1 + da2 < m_angle_tolerance) + { + // Finally we can stop the recursion + //---------------------- + m_points.push_back(Geom::Point(x23, y23)); + return; + } + + if(m_cusp_limit != 0.0) + { + if(da1 > m_cusp_limit) + { + m_points.push_back(Geom::Point(x2, y2)); + return; + } + + if(da2 > m_cusp_limit) + { + m_points.push_back(Geom::Point(x3, y3)); + return; + } + } + } + break; + } + + // Continue subdivision + //---------------------- + recursive_bezier4(x1, y1, x12, y12, x123, y123, x1234, y1234, m_points, level + 1); + recursive_bezier4(x1234, y1234, x234, y234, x34, y34, x4, y4, m_points, level + 1); +} + /** * rounds all corners of the rectangle 'outwards', i.e. x0 and y0 are floored, x1 and y1 are ceiled. diff --git a/src/helper/geom.h b/src/helper/geom.h index ecee58ec2..caff95733 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -26,6 +26,11 @@ void pathv_matrix_point_bbox_wind_distance ( Geom::PathVector const & pathv, Geo Geom::Coord tolerance, Geom::Rect const *viewbox); Geom::PathVector pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ); +Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double maxdisp ); +void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, + const double x3, const double y3, const double x4, const double y4, + std::vector<Geom::Point> &pointlist, + int level); void round_rectangle_outwards(Geom::Rect & rect); |
