From e60e608692759de9bbbf28788362b879568d1d9c Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 18:54:08 +0200 Subject: Fixes bug #986271: memory leak with bitmap images (bzr r11668.1.1) --- src/sp-image.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 07885ff4d..39e37ebc8 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -1119,6 +1119,7 @@ static void sp_image_print( SPItem *item, SPPrintContext *ctx ) t = ti * t; sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, t, item->style); } + free(px); // else big memory leak on each image print! } } -- cgit v1.2.3 From a249cbd90ab37fdc02a463b45e0bba0dcf3cf483 Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 18:55:14 +0200 Subject: Fixes bug #1029584: support custom dasharrays in 'Fill and Stroke > Stroke style' (bzr r11668.1.2) --- src/widgets/dash-selector.cpp | 86 +++++++++++++++++++++++++++++++++++++------ src/widgets/dash-selector.h | 5 +++ 2 files changed, 80 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp index 901d3b68c..51483a9c4 100644 --- a/src/widgets/dash-selector.cpp +++ b/src/widgets/dash-selector.cpp @@ -39,6 +39,7 @@ static double dash_4_1[] = {4.0, 1.0, -1.0}; static double dash_1_2[] = {1.0, 2.0, -1.0}; static double dash_1_4[] = {1.0, 4.0, -1.0}; +#define bd_len 7 // must correspond to the number of entries in the next line static double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, NULL}; static double **dashes = NULL; @@ -79,12 +80,18 @@ SPDashSelector::SPDashSelector() this->pack_start(*sb, false, false, 0); - for (int i = 0; dashes[i]; i++) { + int np=0; + while (dashes[np]){ np++;} + for (int i = 0; iappend()); row[dash_columns.dash] = dashes[i]; row[dash_columns.pixbuf] = Glib::wrap(sp_dash_to_pixbuf(dashes[i])); } + // add the custom one + Gtk::TreeModel::Row row = *(dash_store->append()); + row[dash_columns.dash] = dashes[np-1]; + row[dash_columns.pixbuf] = Glib::wrap(sp_text_to_pixbuf((char *)"Custom")); this->set_data("pattern", dashes[0]); } @@ -109,10 +116,10 @@ void SPDashSelector::init_dashes() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); std::vector dash_prefs = prefs->getAllDirs(_prefs_path); + int pos = 0; if (!dash_prefs.empty()) { - int pos = 0; SPStyle *style = sp_style_new (NULL); - dashes = g_new (double *, dash_prefs.size() + 1); + dashes = g_new (double *, dash_prefs.size() + 2); // +1 for custom slot, +1 for terminator slot for (std::vector::iterator i = dash_prefs.begin(); i != dash_prefs.end(); ++i) { sp_style_read_from_prefs(style, *i); @@ -130,23 +137,36 @@ void SPDashSelector::init_dashes() { } pos += 1; } - dashes[pos] = NULL; - } else { - dashes = builtin_dashes; + } else { // This code may never execute - a new preferences.xml is created for a new user. Maybe if the user deletes dashes from preferences.xml? + dashes = g_new (double *, bd_len + 2); // +1 for custom slot, +1 for terminator slot + int i; + for(i=0;i 0) { double delta = 0.0; for (int i = 0; i < ndash; i++) delta += dash[i]; delta /= 1000.0; - for (int i = 0; dashes[i]; i++) { + for (int i = 0; dashes[i]; i++,count++) { double *pattern = dashes[i]; int np = 0; while (pattern[np] >= 0.0) @@ -154,6 +174,7 @@ void SPDashSelector::set_dash (int ndash, double *dash, double o) if (np == ndash) { int j; for (j = 0; j < ndash; j++) { + if (!Geom::are_near(dash[j], pattern[j], delta)) break; } @@ -164,10 +185,27 @@ void SPDashSelector::set_dash (int ndash, double *dash, double o) } } } + else if(ndash==0) { + pos = 0; + } - this->set_data("pattern", dashes[pos]); - this->dash_combo.set_active(pos); - this->offset->set_value(o); + if(pos>=0){ + this->set_data("pattern", dashes[pos]); + this->dash_combo.set_active(pos); + this->offset->set_value(o); + } + else { // Hit a custom pattern in the SVG, write it into the combobox. + count--; // the one slot for custom patterns + double *d = dashes[count]; + int i=0; + for(i=0;i< (ndash > 15 ? 15 : ndash) ;i++) { + d[i]=dash[i]; + } // store the custom pattern + d[ndash]=-1.0; //terminate it + this->set_data("pattern", dashes[count]); + this->dash_combo.set_active(count); + this->offset->set_value(o); // what does this do???? + } } void SPDashSelector::get_dash(int *ndash, double **dash, double *off) @@ -227,6 +265,32 @@ GdkPixbuf* SPDashSelector::sp_dash_to_pixbuf(double *pattern) { return pixbuf; } +/** + * Fill a pixbuf with a text label using standard cairo drawing + */ +GdkPixbuf* SPDashSelector::sp_text_to_pixbuf(char *text) { + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); + + cairo_select_font_face (ct, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (ct, 12.0); + cairo_set_source_rgb (ct, 0.0, 0.0, 0.0); + cairo_move_to (ct, 16.0, 13.0); + cairo_show_text (ct, text); + + cairo_stroke (ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), + GDK_COLORSPACE_RGB, TRUE, 8, + preview_width, preview_height, cairo_image_surface_get_stride(s), + ink_cairo_pixbuf_cleanup, s); + convert_pixbuf_argb32_to_normal(pixbuf); + return pixbuf; +} void SPDashSelector::on_selection () { diff --git a/src/widgets/dash-selector.h b/src/widgets/dash-selector.h index 0a572f4de..ef828783e 100644 --- a/src/widgets/dash-selector.h +++ b/src/widgets/dash-selector.h @@ -45,6 +45,11 @@ private: */ GdkPixbuf* sp_dash_to_pixbuf(double *pattern); + /** + * Fill a pixbuf with text standard cairo drawing + */ + GdkPixbuf* sp_text_to_pixbuf(char *text); + /** * Callback for combobox image renderer */ -- cgit v1.2.3 From 1aee6d9e28c0e144560bbef9e6f861d98b5d29d8 Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 19:00:33 +0200 Subject: From bug #1048845: proposed addition to livarot for boolean operations (bzr r11668.1.3) --- src/splivarot.cpp | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/splivarot.h | 2 + 2 files changed, 219 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 4c1421684..ec82306af 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -53,6 +53,7 @@ #include "splivarot.h" #include "verbs.h" +#include "2geom/svg-path-parser.h" // to get from SVG on boolean to Geom::Path using Inkscape::DocumentUndo; @@ -109,7 +110,205 @@ sp_selected_path_slice(SPDesktop *desktop) } -// boolean operations +// boolean operations PathVectors A,B -> PathVector result. +// This is derived from sp_selected_path_boolop +// take the source paths from the file, do the operation, delete the originals and add the results +// fra,fra are fill_rules for PathVectors a,b +Geom::PathVector +sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, bool_op bop, fill_typ fra, fill_typ frb) +{ + + // extract the livarot Paths from the source objects + // also get the winding rule specified in the style + int nbOriginaux = 2; + std::vector originaux(nbOriginaux); + std::vector origWind(nbOriginaux); + origWind[0]=fra; + origWind[1]=frb; + Geom::PathVector patht; + // Livarot's outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly. + originaux[0] = Path_for_pathvector(pathv_to_linear_and_cubic_beziers( pathva)); + originaux[1] = Path_for_pathvector(pathv_to_linear_and_cubic_beziers( pathvb)); + + // some temporary instances, first + Shape *theShapeA = new Shape; + Shape *theShapeB = new Shape; + Shape *theShape = new Shape; + Path *res = new Path; + res->SetBackData(false); + Path::cut_position *toCut=NULL; + int nbToCut=0; + + if ( bop == bool_op_inters || bop == bool_op_union || bop == bool_op_diff || bop == bool_op_symdiff ) { + // true boolean op + // get the polygons of each path, with the winding rule specified, and apply the operation iteratively + originaux[0]->ConvertWithBackData(0.1); + + originaux[0]->Fill(theShape, 0); + + theShapeA->ConvertToShape(theShape, origWind[0]); + + originaux[1]->ConvertWithBackData(0.1); + + originaux[1]->Fill(theShape, 1); + + theShapeB->ConvertToShape(theShape, origWind[1]); + + theShape->Booleen(theShapeB, theShapeA, bop); + + } else if ( bop == bool_op_cut ) { + // cuts= sort of a bastard boolean operation, thus not the axact same modus operandi + // technically, the cut path is not necessarily a polygon (thus has no winding rule) + // it is just uncrossed, and cleaned from duplicate edges and points + // then it's fed to Booleen() which will uncross it against the other path + // then comes the trick: each edge of the cut path is duplicated (one in each direction), + // thus making a polygon. the weight of the edges of the cut are all 0, but + // the Booleen need to invert the ones inside the source polygon (for the subsequent + // ConvertToForme) + + // the cut path needs to have the highest pathID in the back data + // that's how the Booleen() function knows it's an edge of the cut + + // FIXME: this gives poor results, the final paths are full of extraneous nodes. Decreasing + // ConvertWithBackData parameter below simply increases the number of nodes, so for now I + // left it at 1.0. Investigate replacing this by a combination of difference and + // intersection of the same two paths. -- bb + { + Path* swap=originaux[0];originaux[0]=originaux[1];originaux[1]=swap; + int swai=origWind[0];origWind[0]=origWind[1];origWind[1]=(fill_typ)swai; + } + originaux[0]->ConvertWithBackData(1.0); + + originaux[0]->Fill(theShape, 0); + + theShapeA->ConvertToShape(theShape, origWind[0]); + + originaux[1]->ConvertWithBackData(1.0); + + originaux[1]->Fill(theShape, 1,false,false,false); //do not closeIfNeeded + + theShapeB->ConvertToShape(theShape, fill_justDont); // fill_justDont doesn't computes winding numbers + + // les elements arrivent en ordre inverse dans la liste + theShape->Booleen(theShapeB, theShapeA, bool_op_cut, 1); + + } else if ( bop == bool_op_slice ) { + // slice is not really a boolean operation + // you just put the 2 shapes in a single polygon, uncross it + // the points where the degree is > 2 are intersections + // just check it's an intersection on the path you want to cut, and keep it + // the intersections you have found are then fed to ConvertPositionsToMoveTo() which will + // make new subpath at each one of these positions + // inversion pour l'opŽration + { + Path* swap=originaux[0];originaux[0]=originaux[1];originaux[1]=swap; + int swai=origWind[0];origWind[0]=origWind[1];origWind[1]=(fill_typ)swai; + } + originaux[0]->ConvertWithBackData(1.0); + + originaux[0]->Fill(theShapeA, 0,false,false,false); // don't closeIfNeeded + + originaux[1]->ConvertWithBackData(1.0); + + originaux[1]->Fill(theShapeA, 1,true,false,false);// don't closeIfNeeded and just dump in the shape, don't reset it + + theShape->ConvertToShape(theShapeA, fill_justDont); + + if ( theShape->hasBackData() ) { + // should always be the case, but ya never know + { + for (int i = 0; i < theShape->numberOfPoints(); i++) { + if ( theShape->getPoint(i).totalDegree() > 2 ) { + // possibly an intersection + // we need to check that at least one edge from the source path is incident to it + // before we declare it's an intersection + int cb = theShape->getPoint(i).incidentEdge[FIRST]; + int nbOrig=0; + int nbOther=0; + int piece=-1; + float t=0.0; + while ( cb >= 0 && cb < theShape->numberOfEdges() ) { + if ( theShape->ebData[cb].pathID == 0 ) { + // the source has an edge incident to the point, get its position on the path + piece=theShape->ebData[cb].pieceID; + if ( theShape->getEdge(cb).st == i ) { + t=theShape->ebData[cb].tSt; + } else { + t=theShape->ebData[cb].tEn; + } + nbOrig++; + } + if ( theShape->ebData[cb].pathID == 1 ) nbOther++; // the cut is incident to this point + cb=theShape->NextAt(i, cb); + } + if ( nbOrig > 0 && nbOther > 0 ) { + // point incident to both path and cut: an intersection + // note that you only keep one position on the source; you could have degenerate + // cases where the source crosses itself at this point, and you wouyld miss an intersection + toCut=(Path::cut_position*)realloc(toCut, (nbToCut+1)*sizeof(Path::cut_position)); + toCut[nbToCut].piece=piece; + toCut[nbToCut].t=t; + nbToCut++; + } + } + } + } + { + // i think it's useless now + int i = theShape->numberOfEdges() - 1; + for (;i>=0;i--) { + if ( theShape->ebData[i].pathID == 1 ) { + theShape->SubEdge(i); + } + } + } + + } + } + + int* nesting=NULL; + int* conts=NULL; + int nbNest=0; + // pour compenser le swap juste avant + if ( bop == bool_op_slice ) { +// theShape->ConvertToForme(res, nbOriginaux, originaux, true); +// res->ConvertForcedToMoveTo(); + res->Copy(originaux[0]); + res->ConvertPositionsToMoveTo(nbToCut, toCut); // cut where you found intersections + free(toCut); + } else if ( bop == bool_op_cut ) { + // il faut appeler pour desallouer PointData (pas vital, mais bon) + // the Booleen() function did not deallocated the point_data array in theShape, because this + // function needs it. + // this function uses the point_data to get the winding number of each path (ie: is a hole or not) + // for later reconstruction in objects, you also need to extract which path is parent of holes (nesting info) + theShape->ConvertToFormeNested(res, nbOriginaux, &originaux[0], 1, nbNest, nesting, conts); + } else { + theShape->ConvertToForme(res, nbOriginaux, &originaux[0]); + } + + delete theShape; + delete theShapeA; + delete theShapeB; + delete originaux[0]; + delete originaux[1]; + + std::vector outres = Geom::parse_svg_path(res->svg_dump_path()); + + + delete res; + return outres; +} + + +/* Convert from a livarot path to a 2geom PathVector */ +Geom::PathVector pathliv_to_pathvector(Path *pathliv){ + std::vector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); + return outres; +} + + +// boolean operations on the desktop // take the source paths from the file, do the operation, delete the originals and add the results void sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description) @@ -746,7 +945,7 @@ Geom::PathVector* item_outline(SPItem const *item, bool bbox_only) } } - // Livarots outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly. + // Livarot's outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly. Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() ); Path *orig = new Path; @@ -1012,7 +1211,7 @@ sp_selected_path_outline(SPDesktop *desktop) curve->unref(); continue; } - // Livarots outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly. + // Livarot's outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly. Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curvetemp->get_pathvector() ); curvetemp->unref(); @@ -2065,6 +2264,21 @@ Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who) return Ancetre(a->parent(), who); } +// derived from Path_for_item +// there must be some other way to load dest directly from epathv, without going through pathv... +Path * +Path_for_pathvector(Geom::PathVector const &epathv) +{ + Geom::PathVector *pathv = new Geom::PathVector; + std::copy(epathv.begin(), epathv.end(), std::back_inserter(*pathv)); + + Path *dest = new Path; + dest->LoadPathVector(*pathv); + delete pathv; + + return dest; +} + Path * Path_for_item(SPItem *item, bool doTransformation, bool transformFull) { diff --git a/src/splivarot.h b/src/splivarot.h index 3d2a1ee58..ded4e1851 100644 --- a/src/splivarot.h +++ b/src/splivarot.h @@ -48,6 +48,7 @@ Geom::PathVector* item_outline(SPItem const *item, bool bbox_only = false); // simplifies a path (removes small segments and the like) void sp_selected_path_simplify (SPDesktop *desktop); +Path *Path_for_pathvector(Geom::PathVector const &pathv); Path *Path_for_item(SPItem *item, bool doTransformation, bool transformFull = true); Path *Path_for_item_before_LPE(SPItem *item, bool doTransformation, bool transformFull = true); Geom::PathVector* pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Affine extraPreAffine, Geom::Affine extraPostAffine); @@ -55,6 +56,7 @@ SPCurve *curve_for_item(SPItem *item); SPCurve *curve_for_item_before_LPE(SPItem *item); boost::optional get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg = 0); Geom::Point get_point_on_Path(Path *path, int piece, double t); +Geom::PathVector sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, bool_op bop, FillRule fra, FillRule frb); #endif -- cgit v1.2.3 From 5b1d0723c100c28807761b5990f3c48bbe4255ca Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 19:03:04 +0200 Subject: Fixes bug #1050064: quiet console messages about supported values for 'color-interpolation-filters' (bzr r11668.1.4) --- src/style.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/style.cpp b/src/style.cpp index 2facc86d8..ba720d538 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1236,7 +1236,9 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) case SP_PROP_COLOR_INTERPOLATION_FILTERS: // We read it but issue warning SPS_READ_IENUM_IF_UNSET(&style->color_interpolation_filters, val, enum_color_interpolation, true); - if( style->color_interpolation_filters.value != SP_CSS_COLOR_INTERPOLATION_SRGB ) { + static bool blab=true; // eliminate annoying repeated messages to console + if( blab && style->color_interpolation_filters.value != SP_CSS_COLOR_INTERPOLATION_SRGB ) { + blab = false; g_warning("Inkscape currently only supports color-interpolation-filters = sRGB"); } break; -- cgit v1.2.3 From c2a0804d5730d0af382b13097379dc7c20bb34d5 Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 19:06:25 +0200 Subject: Fixes bug #989972: avoid link error against static libstdc++ on Windows (bzr r11668.1.5) --- src/ui/tool/path-manipulator.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 35eb23f42..8a5a79ec3 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -949,10 +949,12 @@ void PathManipulator::hideDragPoint() * at the given time value */ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, double t) { - if (!first) throw std::invalid_argument("Subdivide after invalid iterator"); + //throw originally used std::invalid_argument, that caused a link error against static libstdc++, + //this form was only used here. + if (!first) throw "Subdivide after invalid iterator"; NodeList &list = NodeList::get(first); NodeList::iterator second = first.next(); - if (!second) throw std::invalid_argument("Subdivide after last node in open path"); + if (!second) throw "Subdivide after last node in open path"; // We need to insert the segment after 'first'. We can't simply use 'second' // as the point of insertion, because when 'first' is the last node of closed path, -- cgit v1.2.3 From 232af17364d232f01139e834bb27be16555b42e9 Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 19:16:23 +0200 Subject: Add libunicode-convert: routines for converting between Unicode and nonunicode fonts (bzr r11668.1.7) --- src/libunicode-convert/Makefile_insert | 5 + src/libunicode-convert/README | 1 + src/libunicode-convert/makefile.in | 17 + src/libunicode-convert/unicode-convert.c | 1008 ++++++++++++++++++++++++++++++ src/libunicode-convert/unicode-convert.h | 51 ++ 5 files changed, 1082 insertions(+) create mode 100644 src/libunicode-convert/Makefile_insert create mode 100644 src/libunicode-convert/README create mode 100644 src/libunicode-convert/makefile.in create mode 100644 src/libunicode-convert/unicode-convert.c create mode 100644 src/libunicode-convert/unicode-convert.h (limited to 'src') diff --git a/src/libunicode-convert/Makefile_insert b/src/libunicode-convert/Makefile_insert new file mode 100644 index 000000000..e69049310 --- /dev/null +++ b/src/libunicode-convert/Makefile_insert @@ -0,0 +1,5 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +ink_common_sources += \ + libunicode-convert/unicode-convert.c \ + libunicode-convert/unicode-convert.h diff --git a/src/libunicode-convert/README b/src/libunicode-convert/README new file mode 100644 index 000000000..51d96970d --- /dev/null +++ b/src/libunicode-convert/README @@ -0,0 +1 @@ +Some simple routines for converting between Unicode and nonunicode fonts. diff --git a/src/libunicode-convert/makefile.in b/src/libunicode-convert/makefile.in new file mode 100644 index 000000000..ca0d7dc1e --- /dev/null +++ b/src/libunicode-convert/makefile.in @@ -0,0 +1,17 @@ +# Convenience stub makefile to call the real Makefile. + +@SET_MAKE@ + +OBJEXT = @OBJEXT@ + +# Explicit so that it's the default rule. +all: + cd .. && $(MAKE) libunicode-convert/all + +clean %.a %.$(OBJEXT): + cd .. && $(MAKE) libunicode-convert/$@ + +.PHONY: all clean + +.SUFFIXES: +.SUFFIXES: .a .$(OBJEXT) diff --git a/src/libunicode-convert/unicode-convert.c b/src/libunicode-convert/unicode-convert.c new file mode 100644 index 000000000..c8d2de064 --- /dev/null +++ b/src/libunicode-convert/unicode-convert.c @@ -0,0 +1,1008 @@ +/** @file + * @brief Windows-only Enhanced Metafile input and output. + */ +/* Authors: + * David mathog + * + * Copyright (C) 2012 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + * + * References: + * see unicode-convert.h + * + * v1.4 08/21/2012 Changed this so that the incoming routines use uint32_t and the outgoing use uint16_t. This gets rid + * of wchar_t, which was different sizes on windows/linux, and required lots of ifdef's elsewhere in the code. + * v1.3 04/03/2012 Bullets were a problem. Symbol bullet -> Times New Roman Bullet looks OK, but + * it looked bad going the other way. Changed mapping Symbol bullet to 2219 (Bullet operator, math + * symbol.) That way Symbol bullet can map in and out, while other font bullet an remain in that + * font's bullet glyph. + * v1.2 03/26/2012 Introduced bug into SingleUnicodeToNon repaired. + * v1.1 03/25/2012 Changed ampersand mapping on Wingdings (to avoid normal Ampersand mapping + * to Wingdings ampersand when not intended. Fixed access bugs for when no conversion is + * mapped in UnicodeToNon and SingleUnicodeToNon + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "unicode-convert.h" + + +static bool hold_symb=0; // if any of these change, (re)generate the map table +static bool hold_wing=0; +static bool hold_zdng=0; +static bool hold_pua=0; +static unsigned char *from_unicode=NULL; +static unsigned char *to_font=NULL; + +/* The following tables were created from the files + adobe-dingbats.enc.gz + adobe-symbol.enc.gz + adobe-standard.enc.gz + + which came as part of the X11-font-encodings rpm on Mandriva 2010. + The original source for the data must have been Adobe. + Some also from: + ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt + http://www.csn.ul.ie/~caolan/wingdings/proposal/ + www.renderx.com/Tests/zapf-dingbats.pdf + + The intent is as follows: + + on conversion from ASCII/extended -> Unicode use the appropriate table for + the font and change font + code (symbol, zapf dingbats, wingdings). + Going the other way, set up two transfer tables, + the first is unicode -> 0-FF values, and the seond is unicode -> cvt_to_font. + These tables are filled dingbats, wingdings, then symbols, so with the rightmost one getting + precedence if both contain the symbol. + + Whereever possible do NOT map two input characters to the same output character, use a slightly + off character if it is somewhat close and disambiguates. + +v 1.0.0 14-MAR-2012, David Mathog + +*/ + +static unsigned int wingdings_convert[256]={ + 0xFFFD, // 0x00 no replacement + 0xFFFD, // 0x01 no replacement + 0xFFFD, // 0x02 no replacement + 0xFFFD, // 0x03 no replacement + 0xFFFD, // 0x04 no replacement + 0xFFFD, // 0x05 no replacement + 0xFFFD, // 0x06 no replacement + 0xFFFD, // 0x07 no replacement + 0xFFFD, // 0x08 no replacement + 0xFFFD, // 0x09 no replacement + 0xFFFD, // 0x0A no replacement + 0xFFFD, // 0x0B no replacement + 0xFFFD, // 0x0C no replacement + 0xFFFD, // 0x0D no replacement + 0xFFFD, // 0x0E no replacement + 0xFFFD, // 0x0F no replacement + 0xFFFD, // 0x10 no replacement + 0xFFFD, // 0x11 no replacement + 0xFFFD, // 0x12 no replacement + 0xFFFD, // 0x13 no replacement + 0xFFFD, // 0x14 no replacement + 0xFFFD, // 0x15 no replacement + 0xFFFD, // 0x16 no replacement + 0xFFFD, // 0x17 no replacement + 0xFFFD, // 0x18 no replacement + 0xFFFD, // 0x19 no replacement + 0xFFFD, // 0x1A no replacement + 0xFFFD, // 0x1B no replacement + 0xFFFD, // 0x1C no replacement + 0xFFFD, // 0x1D no replacement + 0xFFFD, // 0x1E no replacement + 0xFFFD, // 0x1F no replacement + 0x0020, // 0x20 SPACE + 0x270E, // 0x21 LOWER RIGHT PENCIL (close, but not exact) + 0x2702, // 0x22 BLACK SCISSORS + 0x2701, // 0x23 UPPER BLADE SCISSORS + 0xFFFD, // 0x24 no replacement + 0xFFFD, // 0x25 no replacement + 0xFFFD, // 0x26 no replacement + 0xFFFD, // 0x27 no replacement + 0x260E, // 0x28 BLACK TELEPHONE + 0x2706, // 0x29 TELEPHONE LOCATION SIGN (close, but not exact) + 0x2709, // 0x2A ENVELOPE + 0x2709, // 0x2B ENVELOPE (close, but not exact) + 0xFFFD, // 0x2C no replacement + 0xFFFD, // 0x2D no replacement + 0xFFFD, // 0x2E no replacement + 0xFFFD, // 0x2F no replacement + 0xFFFD, // 0x30 no replacement + 0xFFFD, // 0x31 no replacement + 0xFFFD, // 0x32 no replacement + 0xFFFD, // 0x33 no replacement + 0xFFFD, // 0x34 no replacement + 0xFFFD, // 0x35 no replacement + 0x231B, // 0x36 HOURGLASS + 0x2328, // 0x37 KEYBOARD + 0xFFFD, // 0x38 no replacement + 0xFFFD, // 0x39 no replacement + 0xFFFD, // 0x3A no replacement + 0xFFFD, // 0x3B no replacement + 0xFFFD, // 0x3C no replacement + 0xFFFD, // 0x3D no replacement + 0x2707, // 0x3E TAPE DRIVE + 0x270D, // 0x3F WRITING HAND + 0x270D, // 0x40 WRITING HAND (close, but not exact) + 0x270C, // 0x41 VICTORY HAND + 0xFFFD, // 0x42 3 FINGER UP HAND (no replacement) + 0xFFFD, // 0x43 THUMBS UP HAND (no replacement) + 0xFFFD, // 0x44 THUMBS DOWN HAND (no replacement) + 0x261C, // 0x45 WHITE LEFT POINTING INDEX + 0x261E, // 0x46 WHITE RIGHT POINTING INDEX + 0x261D, // 0x47 WHITE UP POINTING INDEX + 0x261F, // 0x48 WHITE DOWN POINTING INDEX + 0xFFFD, // 0x49 OPEN HAND (no replacement) + 0x263A, // 0x4A WHITE SMILING FACE + 0x263A, // 0x4B WHITE SMILING FACE (close, but not exact) + 0x2639, // 0x4C WHITE FROWNING FACE + 0xFFFD, // 0x4D BOMB (no replacement. 1F4A3) + 0x2620, // 0x4E SKULL AND CROSSBONES + 0x2690, // 0x4F WHITE FLAG (not exact) + 0x2691, // 0x50 WHITE PENANT (use BLACK FLAG) + 0x2708, // 0x51 AIRPLANE + 0x263C, // 0x52 WHITE SUN WITH RAYS (close, but not exact) + 0x2602, // 0x53 RAINDROP (use UMBRELLA) + 0x2744, // 0x54 SNOWFLAKE + 0x271D, // 0x55 WHITE LATIN CROSS (use BLACK CROSS) + 0x271E, // 0x56 SHADOWED WHITE LATIN CROSS + 0x271F, // 0x57 CELTIC CROSS (use OUTLINED LATIN CROSS) + 0x2720, // 0x58 MALTESE CROSS + 0x2721, // 0x59 STAR OF DAVID + 0x262A, // 0x5A STAR AND CRESCENT + 0x262F, // 0x5B YIN YANG + 0x0950, // 0x5C DEVANGARI OM CORRECT|CLOSE: Perhaps PROPOSE SACRED OM ? + 0x2638, // 0x5D WHEEL OF DHARMA + 0x2648, // 0x5E ARIES + 0x2649, // 0x5F TAURUS + 0x264A, // 0x60 GEMINI + 0x264B, // 0x61 CANCER + 0x264C, // 0x62 LEO + 0x264D, // 0x63 VIRGO + 0x264E, // 0x64 LIBRA + 0x264F, // 0x65 SCORPIUS + 0x2650, // 0x66 SAGITTARIUS + 0x2651, // 0x67 CAPRICORN + 0x2652, // 0x68 AQUARIUS + 0x2653, // 0x69 PISCES + 0xFFFD, // 0x6A LOWER CASE AMPERSAND)?) (no replacement) + 0xFF06, // 0x6B AMPERSAND (use FULL WIDTH AMPERSAND, close, but not exact. Do NOT use 0026, or it maps normal Ampersands to Wingdings Ampersand) + 0x25CF, // 0x6C BLACK CIRCLE + 0x274D, // 0x6D SHADOWED WHITE CIRCLE (close, but not exact) + 0x25A0, // 0x6E BLACK SQUARE + 0x25A3, // 0x6F WHITE SQUARE IN BLACK RECTANGLE (use BLACK SQUSRE in WHITE SQUARE) + 0x25A1, // 0x70 WHITE SQUARE (close, but not exact) + 0x2751, // 0x71 LOWER RIGHT SHADOWED WHITE SQUARE + 0x2752, // 0x72 UPPER RIGHT SHADOWED WHITE SQUARE + 0x25CA, // 0x73 LOZENGE (close, but not exact) + 0x25CA, // 0x74 LOZENGE (close, but not exact) + 0x25C6, // 0x75 BLACK DIAMOND + 0x2756, // 0x76 BLACK DIAMOND MINUS WHITE X + 0x25C6, // 0x77 BLACK DIAMOND (close, but not exact) + 0x2327, // 0x78 X IN A RECTANGLE BOX + 0x2353, // 0x79 APL FUNCTIONAL SYMBOL QUAD UP CARET(close, but not exact) + 0x2318, // 0x7A PLACE OF INTEREST SIGN + 0x2740, // 0x7B WHITE FLORETTE (close, but not exact) + 0x273F, // 0x7C BLACK FLORETTE (close, but not exact) + 0x275D, // 0x7D HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x275E, // 0x7E HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + 0xFFFD, // 0x7F unused + 0x24EA, // 0x80 CIRCLED DIGIT ZERO + 0x2460, // 0x81 CIRCLED DIGIT ONE + 0x2461, // 0x82 CIRCLED DIGIT TWO + 0x2462, // 0x83 CIRCLED DIGIT THREE + 0x2463, // 0x84 CIRCLED DIGIT FOUR + 0x2464, // 0x85 CIRCLED DIGIT FIVE + 0x2465, // 0x86 CIRCLED DIGIT SIX + 0x2466, // 0x87 CIRCLED DIGIT SEVEN + 0x2467, // 0x88 CIRCLED DIGIT EIGHT + 0x2468, // 0x89 CIRCLED DIGIT NINE + 0x2469, // 0x8A CIRCLED NUMBER TEN + 0xFFFD, // 0x8B no replacement + 0x2776, // 0x8C DINGBAT NEGATIVE CIRCLED DIGIT ONE + 0x2777, // 0x8D DINGBAT NEGATIVE CIRCLED DIGIT TWO + 0x2778, // 0x8E DINGBAT NEGATIVE CIRCLED DIGIT THREE + 0x2779, // 0x8F DINGBAT NEGATIVE CIRCLED DIGIT FOUR + 0x277A, // 0x90 DINGBAT NEGATIVE CIRCLED DIGIT FIVE + 0x277B, // 0x91 DINGBAT NEGATIVE CIRCLED DIGIT SIX + 0x277C, // 0x92 DINGBAT NEGATIVE CIRCLED DIGIT SEVEN + 0x277D, // 0x93 DINGBAT NEGATIVE CIRCLED DIGIT EIGHT + 0x277E, // 0x94 DINGBAT NEGATIVE CIRCLED DIGIT NINE + 0x277F, // 0x95 DINGBAT NEGATIVE CIRCLED NUMBER TEN + 0xFFFD, // 0x96 ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x97 REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x98 REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x99 ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9A ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9B REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9C REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9D ROTATED FLORAL HEART BULLET (no good replacement) + 0x2219, // 0x9E BULLET (use BULLET operator, so normal font BULLET will not convert to Symbol BULLET) + 0x25CF, // 0x9F BLACK CIRCLE (close, but not exact) + 0x25AA, // 0xA0 BLACK VERY SMALL SQUARE + 0x26AA, // 0xA1 WHITE CIRCLE (use MEDIUM WHITE CIRCLE) + 0x25CB, // 0xA2 HEAVY WHITE CIRCLE (use WHITE CIRCLE) + 0x25CD, // 0xA3 HEAVIEST CIRCLE (use CIRCLE WITH VERTICAL FILL) + 0x25C9, // 0xA4 CIRCLE WITH A CENTRAL DOT (close, dot much bigger) + 0x25CE, // 0xA5 BULLSEYE + 0x274D, // 0xA6 SHADOWED WHITE CIRCLE (close, but not exact) + 0xFFED, // 0xA7 BLACK SMALL SQUARE + 0x2610, // 0xA8 WHITE SQUARE (close, but not exact, different fro 25A1) + 0xFFFD, // 0xA9 no replacement + 0x2726, // 0xAA BLACK FOUR POINTED STAR MAYBE + 0x2605, // 0xAB BLACK STAR + 0x2736, // 0xAC SIX POINTED BLACK STAR + 0x2737, // 0xAD EIGHT POINTED RECTILINEAR BLACK STAR + 0x2738, // 0xAE TWELVE POINTED BLACK STAR + 0x2735, // 0xAF EIGHT POINTED PINWHEEL STAR + 0xFFFD, // 0xB0 no replacement + 0xFFFD, // 0xB1 no replacement + 0x2727, // 0xB2 WHITE FOUR POINTED STAR + 0x2726, // 0xB3 ROTATED WHITE FOUR POINTED STAR (use BLACK FOUR POINTED STAR) + 0xFFFD, // 0xB4 REPLACEMENT CHARACTER (close, but not exact) + 0x272A, // 0xB5 CIRCLED WHITE STAR + 0x2730, // 0xB6 SHADOWED WHITE STAR + 0xFFFD, // 0xB7 ANALOG CLOCK 1 (no replacement) + 0xFFFD, // 0xB8 ANALOG CLOCK 2 (no replacement) + 0xFFFD, // 0xB9 ANALOG CLOCK 3 (no replacement) + 0xFFFD, // 0xBA ANALOG CLOCK 4 (no replacement) + 0xFFFD, // 0xBB ANALOG CLOCK 5 (no replacement) + 0xFFFD, // 0xBC ANALOG CLOCK 6 (no replacement) + 0xFFFD, // 0xBD ANALOG CLOCK 7 (no replacement) + 0xFFFD, // 0xBE ANALOG CLOCK 8 (no replacement) + 0xFFFD, // 0xBF ANALOG CLOCK 9 (no replacement) + 0xFFFD, // 0xC0 ANALOG CLOCK 10 (no replacement) + 0xFFFD, // 0xC1 ANALOG CLOCK 11 (no replacement) + 0xFFFD, // 0xC2 ANALOG CLOCK 12 (no replacement) + 0x21B2, // 0xC3 TURN ARROW DOWN AND LEFT (Meaning close, shape differs) + 0x21B3, // 0xC4 TURN ARROW DOWN AND RIGHT (Meaning close, shape differs) + 0x21B0, // 0xC5 TURN ARROW UP AND LEFT (Meaning close, shape differs) + 0x21B1, // 0xC6 TURN ARROW UP AND RIGHT (Meaning close, shape differs) + 0x2B11, // 0xC7 TURN ARROW LEFT AND UP (Meaning close, shape differs) + 0x2B0F, // 0xC8 TURN ARROW RIGHT AND UP (Meaning close, shape differs) + 0x2B10, // 0xC9 TURN ARROW LEFT AND DOWN (Meaning close, shape differs) + 0x2B0E, // 0xCA TURN ARROW RIGHT AND DOWN (Meaning close, shape differs) + 0xFFFD, // 0xCB no replacement + 0xFFFD, // 0xCC no replacement + 0xFFFD, // 0xCD no replacement + 0xFFFD, // 0xCE no replacement + 0xFFFD, // 0xCF no replacement + 0xFFFD, // 0xD0 no replacement + 0xFFFD, // 0xD1 no replacement + 0xFFFD, // 0xD2 no replacement + 0xFFFD, // 0xD3 no replacement + 0xFFFD, // 0xD4 no replacement + 0x232B, // 0xD5 ERASE TO THE LEFT + 0x2326, // 0xD6 ERASE TO THE RIGHT + 0x25C0, // 0xD7 THREE-D LIGHTED LEFT ARROWHEAD (Use BLACK LEFT TRIANGLE) + 0x25B6, // 0xD8 THREE-D LIGHTED RIGHT ARROWHEAD (Use BLACK RIGHT TRIANGLE, 27A2 is exact but has no other directions) + 0x25B2, // 0xD9 THREE-D LIGHTED UP ARROWHEAD (Use BLACK UP TRIANGLE) + 0x25BC, // 0xDA THREE-D LIGHTED DOWN ARROWHEAD (Use BLACK DOWN TRIANGLE) + 0xFFFD, // 0xDB no replacement + 0x27B2, // 0xDC CIRCLED HEAVY WHITE RIGHTWARDS ARROW + 0xFFFD, // 0xDD no replacement + 0xFFFD, // 0xDE no replacement + 0x2190, // 0xDF LEFT ARROW + 0x2192, // 0xE0 RIGHT ARROW + 0x2191, // 0xE1 UP ARROW + 0x2193, // 0xE2 DOWN ARROW + 0x2196, // 0xE3 UPPER LEFT ARROW + 0x2197, // 0xE4 UPPER RIGHT ARROW + 0x2199, // 0xE5 LOWER LEFT ARROW + 0x2198, // 0xE6 LOWER RIGHT ARROW + 0x2B05, // 0xE7 HEAVY LEFT BLACK ARROW (same as regular BLACK ARROW) + 0x2B08, // 0xE8 HEAVY RIGHT BLACK ARROW (same as regular BLACK ARROW) + 0x2B06, // 0xE9 HEAVY UP BLACK ARROW (no equiv BLACK ARROW) + 0x2B07, // 0xEA HEAVY DOWN BLACK ARROW (same as regular BLACK ARROW) + 0x2B09, // 0xEB HEAVY UPPER LEFT BLACK ARROW same as regular BLACK ARROW) + 0x2B08, // 0xEC HEAVY UPPER RIGHT BLACK ARROW same as regular BLACK ARROW) + 0x2B0B, // 0xED HEAVY LOWER LEFT BLACK ARROW (same as regular BLACK ARROW) + 0x2B0A, // 0xEE HEAVY LOWER RIGHT BLACK ARROW (same as regular BLACK ARROW) + 0x21E6, // 0xEF LEFTWARDS WHITE ARROW + 0x21E8, // 0xF0 RIGHTWARDS WHITE ARROW + 0x21E7, // 0xF1 UPWARDS WHITE ARROW + 0x21E9, // 0xF2 DOWNWARDS WHITE ARROW + 0x21D4, // 0xF3 LEFT RIGHT DOUBLE ARROW + 0x21D5, // 0xF4 UP DOWN DOUBLE ARROW + 0x21D6, // 0xF5 NORTH WEST DOUBLE ARROW (close, but not exact) + 0x21D7, // 0xF6 NORTH EAST DOUBLE ARROW (close, but not exact) + 0x21D9, // 0xF7 SOUTH WEST DOUBLE ARROW (close, but not exact) + 0x21D8, // 0xF8 SOUTH EAST DOUBLE ARROW (close, but not exact) + 0xFFFD, // 0xF9 no replacement + 0xFFFD, // 0xFA no replacement + 0x2717, // 0xFB BALLOT X + 0x2713, // 0xFC CHECK MARK + 0x2612, // 0xFD BALLOT BOX WITH X + 0x2611, // 0xFE BALLOT BOX WITH CHECK + 0xFFFD // 0xFF no replacement +}; + +/* characters from zapf dingbat font, conversion to a unicode font. Change both the + code and the font on conversion. These are untested as the development machine did + not have the font installed. */ +static unsigned int dingbats_convert[256]={ + 0xFFFD, // 0x00 no replacement + 0xFFFD, // 0x01 no replacement + 0xFFFD, // 0x02 no replacement + 0xFFFD, // 0x03 no replacement + 0xFFFD, // 0x04 no replacement + 0xFFFD, // 0x05 no replacement + 0xFFFD, // 0x06 no replacement + 0xFFFD, // 0x07 no replacement + 0xFFFD, // 0x08 no replacement + 0xFFFD, // 0x09 no replacement + 0xFFFD, // 0x0A no replacement + 0xFFFD, // 0x0B no replacement + 0xFFFD, // 0x0C no replacement + 0xFFFD, // 0x0D no replacement + 0xFFFD, // 0x0E no replacement + 0xFFFD, // 0x0F no replacement + 0xFFFD, // 0x10 no replacement + 0xFFFD, // 0x11 no replacement + 0xFFFD, // 0x12 no replacement + 0xFFFD, // 0x13 no replacement + 0xFFFD, // 0x14 no replacement + 0xFFFD, // 0x15 no replacement + 0xFFFD, // 0x16 no replacement + 0xFFFD, // 0x17 no replacement + 0xFFFD, // 0x18 no replacement + 0xFFFD, // 0x19 no replacement + 0xFFFD, // 0x1A no replacement + 0xFFFD, // 0x1B no replacement + 0xFFFD, // 0x1C no replacement + 0xFFFD, // 0x1D no replacement + 0xFFFD, // 0x1E no replacement + 0xFFFD, // 0x1F no replacement + 0x0020, // 0x20 SPACE + 0x2701, // 0x21 UPPER BLADE SCISSORS + 0x2702, // 0x22 BLACK SCISSORS + 0x2703, // 0x23 LOWER BLADE SCISSORS + 0x2704, // 0x24 WHITE SCISSORS + 0x260E, // 0x25 BLACK TELEPHONE + 0x2706, // 0x26 TELEPHONE LOCATION SIGN + 0x2707, // 0x27 TAPE DRIVE + 0x2708, // 0x28 AIRPLANE + 0x2709, // 0x29 ENVELOPE + 0x261B, // 0x2A BLACK RIGHT POINTING INDEX + 0x261E, // 0x2B WHITE RIGHT POINTING INDEX + 0x270C, // 0x2C VICTORY HAND + 0x270D, // 0x2D WRITING HAND + 0x270E, // 0x2E LOWER RIGHT PENCIL + 0x270F, // 0x2F PENCIL + 0x2710, // 0x30 UPPER RIGHT PENCIL + 0x2711, // 0x31 WHITE NIB + 0x2712, // 0x32 BLACK NIB + 0x2713, // 0x33 CHECK MARK + 0x2714, // 0x34 HEAVY CHECK MARK + 0x2715, // 0x35 MULTIPLICATION X + 0x2716, // 0x36 HEAVY MULTIPLICATION X + 0x2717, // 0x37 BALLOT X + 0x2718, // 0x38 HEAVY BALLOT X + 0x2719, // 0x39 OUTLINED GREEK CROSS + 0x271A, // 0x3A HEAVY GREEK CROSS + 0x271B, // 0x3B OPEN CENTRE CROSS + 0x271C, // 0x3C HEAVY OPEN CENTRE CROSS + 0x271D, // 0x3D LATIN CROSS + 0x271E, // 0x3E SHADOWED WHITE LATIN CROSS + 0x271F, // 0x3F OUTLINED LATIN CROSS + 0x2720, // 0x40 MALTESE CROSS + 0x2721, // 0x41 STAR OF DAVID + 0x2722, // 0x42 FOUR TEARDROP-SPOKED ASTERISK + 0x2723, // 0x43 FOUR BALLOON-SPOKED ASTERISK + 0x2724, // 0x44 HEAVY FOUR BALLOON-SPOKED ASTERISK + 0x2725, // 0x45 FOUR CLUB-SPOKED ASTERISK + 0x2726, // 0x46 BLACK FOUR POINTED STAR + 0x2727, // 0x47 WHITE FOUR POINTED STAR + 0x2605, // 0x48 BLACK STAR + 0x2729, // 0x49 STRESS OUTLINED WHITE STAR + 0x272A, // 0x4A CIRCLED WHITE STAR + 0x272B, // 0x4B OPEN CENTRE BLACK STAR + 0x272C, // 0x4C BLACK CENTRE WHITE STAR + 0x272D, // 0x4D OUTLINED BLACK STAR + 0x272E, // 0x4E HEAVY OUTLINED BLACK STAR + 0x272F, // 0x4F PINWHEEL STAR + 0x2730, // 0x50 SHADOWED WHITE STAR + 0x2731, // 0x51 HEAVY ASTERISK + 0x2732, // 0x52 OPEN CENTRE ASTERISK + 0x2733, // 0x53 EIGHT SPOKED ASTERISK + 0x2734, // 0x54 EIGHT POINTED BLACK STAR + 0x2735, // 0x55 EIGHT POINTED PINWHEEL STAR + 0x2736, // 0x56 SIX POINTED BLACK STAR + 0x2737, // 0x57 EIGHT POINTED RECTILINEAR BLACK STAR + 0x2738, // 0x58 HEAVY EIGHT POINTED RECTILINEAR BLACK STAR + 0x2739, // 0x59 TWELVE POINTED BLACK STAR + 0x273A, // 0x5A SIXTEEN POINTED ASTERISK + 0x273B, // 0x5B TEARDROP-SPOKED ASTERISK + 0x273C, // 0x5C OPEN CENTRE TEARDROP-SPOKED ASTERISK + 0x273D, // 0x5D HEAVY TEARDROP-SPOKED ASTERISK + 0x273E, // 0x5E SIX PETALLED BLACK AND WHITE FLORETTE + 0x273F, // 0x5F BLACK FLORETTE + 0x2740, // 0x60 WHITE FLORETTE + 0x2741, // 0x61 EIGHT PETALLED OUTLINED BLACK FLORETTE + 0x2742, // 0x62 CIRCLED OPEN CENTRE EIGHT POINTED STAR + 0x2743, // 0x63 HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK + 0x2744, // 0x64 SNOWFLAKE + 0x2745, // 0x65 TIGHT TRIFOLIATE SNOWFLAKE + 0x2746, // 0x66 HEAVY CHEVRON SNOWFLAKE + 0x2747, // 0x67 SPARKLE + 0x2748, // 0x68 HEAVY SPARKLE + 0x2749, // 0x69 BALLOON-SPOKED ASTERISK + 0x274A, // 0x6A EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + 0x274B, // 0x6B HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + 0x25CF, // 0x6C BLACK CIRCLE + 0x274D, // 0x6D SHADOWED WHITE CIRCLE + 0x25A0, // 0x6E BLACK SQUARE + 0x274F, // 0x6F LOWER RIGHT DROP-SHADOWED WHITE SQUARE + 0x2750, // 0x70 UPPER RIGHT DROP-SHADOWED WHITE SQUARE + 0x2751, // 0x71 LOWER RIGHT SHADOWED WHITE SQUARE + 0x2752, // 0x72 UPPER RIGHT SHADOWED WHITE SQUARE + 0x25B2, // 0x73 BLACK UP-POINTING TRIANGLE + 0x25BC, // 0x74 BLACK DOWN-POINTING TRIANGLE + 0x25C6, // 0x75 BLACK DIAMOND + 0x2756, // 0x76 BLACK DIAMOND MINUS WHITE X + 0x25D7, // 0x77 RIGHT HALF BLACK CIRCLE + 0x2758, // 0x78 LIGHT VERTICAL BAR + 0x2759, // 0x79 MEDIUM VERTICAL BAR + 0x275A, // 0x7A HEAVY VERTICAL BAR + 0x275B, // 0x7B HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x275C, // 0x7C HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT + 0x275D, // 0x7D HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x275E, // 0x7E HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + 0xFFFD, // 0x7F no replacement + 0xF8D7, // 0x80 MEDIUM LEFT PARENTHESIS ORNAMENT + 0xF8D8, // 0x81 MEDIUM RIGHT PARENTHESIS ORNAMENT + 0xF8D9, // 0x82 MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + 0xF8DA, // 0x83 MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + 0xF8DB, // 0x84 MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + 0xF8DC, // 0x85 MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + 0xF8DD, // 0x86 HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + 0xF8DE, // 0x87 HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + 0xF8DF, // 0x88 HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + 0xF8E0, // 0x89 HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + 0xF8E1, // 0x8A LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + 0xF8E2, // 0x8B LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + 0xF8E3, // 0x8C MEDIUM LEFT CURLY BRACKET ORNAMENT + 0xF8E4, // 0x8D MEDIUM RIGHT CURLY BRACKET ORNAMENT + 0xFFFD, // 0x8E no replacement + 0xFFFD, // 0x8F no replacement + 0xFFFD, // 0x90 no replacement + 0xFFFD, // 0x91 no replacement + 0xFFFD, // 0x92 no replacement + 0xFFFD, // 0x93 no replacement + 0xFFFD, // 0x94 no replacement + 0xFFFD, // 0x95 no replacement + 0xFFFD, // 0x96 no replacement + 0xFFFD, // 0x97 no replacement + 0xFFFD, // 0x98 no replacement + 0xFFFD, // 0x99 no replacement + 0xFFFD, // 0x9A no replacement + 0xFFFD, // 0x9B no replacement + 0xFFFD, // 0x9C no replacement + 0xFFFD, // 0x9D no replacement + 0xFFFD, // 0x9E no replacement + 0xFFFD, // 0x9F no replacement + 0xFFFD, // 0xA0 no replacement + 0x2761, // 0xA1 CURVED STEM PARAGRAPH SIGN ORNAMENT + 0x2762, // 0xA2 HEAVY EXCLAMATION MARK ORNAMENT + 0x2763, // 0xA3 HEAVY HEART EXCLAMATION MARK ORNAMENT + 0x2764, // 0xA4 HEAVY BLACK HEART + 0x2765, // 0xA5 ROTATED HEAVY BLACK HEART BULLET + 0x2766, // 0xA6 FLORAL HEART + 0x2767, // 0xA7 ROTATED FLORAL HEART BULLET + 0x2663, // 0xA8 BLACK CLUB SUIT + 0x2666, // 0xA9 BLACK DIAMOND SUIT + 0x2665, // 0xAA BLACK HEART SUIT + 0x2660, // 0xAB BLACK SPADE SUIT + 0x2460, // 0xAC CIRCLED DIGIT ONE + 0x2461, // 0xAD CIRCLED DIGIT TWO + 0x2462, // 0xAE CIRCLED DIGIT THREE + 0x2463, // 0xAF CIRCLED DIGIT FOUR + 0x2464, // 0xB0 CIRCLED DIGIT FIVE + 0x2465, // 0xB1 CIRCLED DIGIT SIX + 0x2466, // 0xB2 CIRCLED DIGIT SEVEN + 0x2467, // 0xB3 CIRCLED DIGIT EIGHT + 0x2468, // 0xB4 CIRCLED DIGIT NINE + 0x2469, // 0xB5 CIRCLED NUMBER TEN + 0x2776, // 0xB6 DINGBAT NEGATIVE CIRCLED DIGIT ONE + 0x2777, // 0xB7 DINGBAT NEGATIVE CIRCLED DIGIT TWO + 0x2778, // 0xB8 DINGBAT NEGATIVE CIRCLED DIGIT THREE + 0x2779, // 0xB9 DINGBAT NEGATIVE CIRCLED DIGIT FOUR + 0x277A, // 0xBA DINGBAT NEGATIVE CIRCLED DIGIT FIVE + 0x277B, // 0xBB DINGBAT NEGATIVE CIRCLED DIGIT SIX + 0x277C, // 0xBC DINGBAT NEGATIVE CIRCLED DIGIT SEVEN + 0x277D, // 0xBD DINGBAT NEGATIVE CIRCLED DIGIT EIGHT + 0x277E, // 0xBE DINGBAT NEGATIVE CIRCLED DIGIT NINE + 0x277F, // 0xBF DINGBAT NEGATIVE CIRCLED NUMBER TEN + 0x2780, // 0xC0 DINGBAT CIRCLED SANS-SERIF DIGIT ONE + 0x2781, // 0xC1 DINGBAT CIRCLED SANS-SERIF DIGIT TWO + 0x2782, // 0xC2 DINGBAT CIRCLED SANS-SERIF DIGIT THREE + 0x2783, // 0xC3 DINGBAT CIRCLED SANS-SERIF DIGIT FOUR + 0x2784, // 0xC4 DINGBAT CIRCLED SANS-SERIF DIGIT FIVE + 0x2785, // 0xC5 DINGBAT CIRCLED SANS-SERIF DIGIT SIX + 0x2786, // 0xC6 DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN + 0x2787, // 0xC7 DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT + 0x2788, // 0xC8 DINGBAT CIRCLED SANS-SERIF DIGIT NINE + 0x2789, // 0xC9 DINGBAT CIRCLED SANS-SERIF NUMBER TEN + 0x278A, // 0xCA DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE + 0x278B, // 0xCB DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO + 0x278C, // 0xCC DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE + 0x278D, // 0xCD DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR + 0x278E, // 0xCE DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE + 0x278F, // 0xCF DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX + 0x2790, // 0xD0 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN + 0x2791, // 0xD1 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT + 0x2792, // 0xD2 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE + 0x2793, // 0xD3 DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN + 0x2794, // 0xD4 HEAVY WIDE-HEADED RIGHTWARDS ARROW + 0x2192, // 0xD5 RIGHTWARDS ARROW + 0x2194, // 0xD6 LEFT RIGHT ARROW + 0x2195, // 0xD7 UP DOWN ARROW + 0x2798, // 0xD8 HEAVY SOUTH EAST ARROW + 0x2799, // 0xD9 HEAVY RIGHTWARDS ARROW + 0x279A, // 0xDA HEAVY NORTH EAST ARROW + 0x279B, // 0xDB DRAFTING POINT RIGHTWARDS ARROW + 0x279C, // 0xDC HEAVY ROUND-TIPPED RIGHTWARDS ARROW + 0x279D, // 0xDD TRIANGLE-HEADED RIGHTWARDS ARROW + 0x279E, // 0xDE HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW + 0x279F, // 0xDF DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + 0x27A0, // 0xE0 HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + 0x27A1, // 0xE1 BLACK RIGHTWARDS ARROW + 0x27A2, // 0xE2 THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD + 0x27A3, // 0xE3 THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD + 0x27A4, // 0xE4 BLACK RIGHTWARDS ARROWHEAD + 0x27A5, // 0xE5 HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW + 0x27A6, // 0xE6 HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW + 0x27A7, // 0xE7 SQUAT BLACK RIGHTWARDS ARROW + 0x27A8, // 0xE8 HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW + 0x27A9, // 0xE9 RIGHT-SHADED WHITE RIGHTWARDS ARROW + 0x27AA, // 0xEA LEFT-SHADED WHITE RIGHTWARDS ARROW + 0x27AB, // 0xEB BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW + 0x27AC, // 0xEC FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW + 0x27AD, // 0xED HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x27AE, // 0xEE HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x27AF, // 0xEF NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0xFFFD, // 0xF0 no replacement + 0x27B1, // 0xF1 NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x27B2, // 0xF2 CIRCLED HEAVY WHITE RIGHTWARDS ARROW + 0x27B3, // 0xF3 WHITE-FEATHERED RIGHTWARDS ARROW + 0x27B4, // 0xF4 BLACK-FEATHERED SOUTH EAST ARROW + 0x27B5, // 0xF5 BLACK-FEATHERED RIGHTWARDS ARROW + 0x27B6, // 0xF6 BLACK-FEATHERED NORTH EAST ARROW + 0x27B7, // 0xF7 HEAVY BLACK-FEATHERED SOUTH EAST ARROW + 0x27B8, // 0xF8 HEAVY BLACK-FEATHERED RIGHTWARDS ARROW + 0x27B9, // 0xF9 HEAVY BLACK-FEATHERED NORTH EAST ARROW + 0x27BA, // 0xFA TEARDROP-BARBED RIGHTWARDS ARROW + 0x27BB, // 0xFB HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW + 0x27BC, // 0xFC WEDGE-TAILED RIGHTWARDS ARROW + 0x27BD, // 0xFD HEAVY WEDGE-TAILED RIGHTWARDS ARROW + 0x27BE, // 0xFE OPEN-OUTLINED RIGHTWARDS ARROW + 0xFFFD // 0xFF no replacement +}; + +/* characters from symbol font, conversion to a unicode font. Change both the + code and the font on conversion. */ +static unsigned int symbol_convert[256]={ + 0xFFFD, // 0x00 no replacement + 0xFFFD, // 0x01 no replacement + 0xFFFD, // 0x02 no replacement + 0xFFFD, // 0x03 no replacement + 0xFFFD, // 0x04 no replacement + 0xFFFD, // 0x05 no replacement + 0xFFFD, // 0x06 no replacement + 0xFFFD, // 0x07 no replacement + 0xFFFD, // 0x08 no replacement + 0xFFFD, // 0x09 no replacement + 0xFFFD, // 0x0A no replacement + 0xFFFD, // 0x0B no replacement + 0xFFFD, // 0x0C no replacement + 0xFFFD, // 0x0D no replacement + 0xFFFD, // 0x0E no replacement + 0xFFFD, // 0x0F no replacement + 0xFFFD, // 0x10 no replacement + 0xFFFD, // 0x11 no replacement + 0xFFFD, // 0x12 no replacement + 0xFFFD, // 0x13 no replacement + 0xFFFD, // 0x14 no replacement + 0xFFFD, // 0x15 no replacement + 0xFFFD, // 0x16 no replacement + 0xFFFD, // 0x17 no replacement + 0xFFFD, // 0x18 no replacement + 0xFFFD, // 0x19 no replacement + 0xFFFD, // 0x1A no replacement + 0xFFFD, // 0x1B no replacement + 0xFFFD, // 0x1C no replacement + 0xFFFD, // 0x1D no replacement + 0xFFFD, // 0x1E no replacement + 0xFFFD, // 0x1F no replacement + 0x0020, // 0x20 SPACE + 0x0021, // 0x21 EXCLAMATION MARK + 0x2200, // 0x22 FOR ALL + 0x0023, // 0x23 NUMBER SIGN + 0x2203, // 0x24 THERE EXISTS + 0x0025, // 0x25 PERCENT SIGN + 0x0026, // 0x26 AMPERSAND + 0x220B, // 0x27 CONTAINS AS MEMBER + 0x0028, // 0x28 OPENING PARENTHESIS + 0x0029, // 0x29 CLOSING PARENTHESIS + 0x2217, // 0x2A ASTERISK OPERATOR + 0x002B, // 0x2B PLUS SIGN + 0x002C, // 0x2C COMMA + 0x2212, // 0x2D MINUS SIGN + 0x002E, // 0x2E PERIOD + 0x002F, // 0x2F SLASH + 0x0030, // 0x30 DIGIT ZERO + 0x0031, // 0x31 DIGIT ONE + 0x0032, // 0x32 DIGIT TWO + 0x0033, // 0x33 DIGIT THREE + 0x0034, // 0x34 DIGIT FOUR + 0x0035, // 0x35 DIGIT FIVE + 0x0036, // 0x36 DIGIT SIX + 0x0037, // 0x37 DIGIT SEVEN + 0x0038, // 0x38 DIGIT EIGHT + 0x0039, // 0x39 DIGIT NINE + 0x003A, // 0x3A COLON + 0x003B, // 0x3B SEMICOLON + 0x003C, // 0x3C LESS-THAN SIGN + 0x003D, // 0x3D EQUALS SIGN + 0x003E, // 0x3E GREATER-THAN SIGN + 0x003F, // 0x3F QUESTION MARK + 0x2245, // 0x40 APPROXIMATELY EQUAL TO + 0x0391, // 0x41 GREEK CAPITAL LETTER ALPHA + 0x0392, // 0x42 GREEK CAPITAL LETTER BETA + 0x03A7, // 0x43 GREEK CAPITAL LETTER CHI + 0x0394, // 0x44 GREEK CAPITAL LETTER DELTA + 0x0395, // 0x45 GREEK CAPITAL LETTER EPSILON + 0x03A6, // 0x46 GREEK CAPITAL LETTER PHI + 0x0393, // 0x47 GREEK CAPITAL LETTER GAMMA + 0x0397, // 0x48 GREEK CAPITAL LETTER ETA + 0x0399, // 0x49 GREEK CAPITAL LETTER IOTA + 0x03D1, // 0x4A GREEK SMALL LETTER SCRIPT THETA + 0x039A, // 0x4B GREEK CAPITAL LETTER KAPPA + 0x039B, // 0x4C GREEK CAPITAL LETTER LAMBDA + 0x039C, // 0x4D GREEK CAPITAL LETTER MU + 0x039D, // 0x4E GREEK CAPITAL LETTER NU + 0x039F, // 0x4F GREEK CAPITAL LETTER OMICRON + 0x03A0, // 0x50 GREEK CAPITAL LETTER PI + 0x0398, // 0x51 GREEK CAPITAL LETTER THETA + 0x03A1, // 0x52 GREEK CAPITAL LETTER RHO + 0x03A3, // 0x53 GREEK CAPITAL LETTER SIGMA + 0x03A4, // 0x54 GREEK CAPITAL LETTER TAU + 0x03A5, // 0x55 GREEK CAPITAL LETTER UPSILON + 0x03C2, // 0x56 GREEK SMALL LETTER FINAL SIGMA + 0x03A9, // 0x57 GREEK CAPITAL LETTER OMEGA + 0x039E, // 0x58 GREEK CAPITAL LETTER XI + 0x03A8, // 0x59 GREEK CAPITAL LETTER PSI + 0x0396, // 0x5A GREEK CAPITAL LETTER ZETA + 0x005B, // 0x5B OPENING SQUARE BRACKET + 0x2234, // 0x5C THEREFORE + 0x005D, // 0x5D CLOSING SQUARE BRACKET + 0x22A5, // 0x5E UP TACK + 0x005F, // 0x5F SPACING UNDERSCORE + 0x203E, // 0x60 SPACING OVERSCORE + 0x03B1, // 0x61 GREEK SMALL LETTER ALPHA + 0x03B2, // 0x62 GREEK SMALL LETTER BETA + 0x03C7, // 0x63 GREEK SMALL LETTER CHI + 0x03B4, // 0x64 GREEK SMALL LETTER DELTA + 0x03B5, // 0x65 GREEK SMALL LETTER EPSILON + 0x03C6, // 0x66 GREEK SMALL LETTER PHI + 0x03B3, // 0x67 GREEK SMALL LETTER GAMMA + 0x03B7, // 0x68 GREEK SMALL LETTER ETA + 0x03B9, // 0x69 GREEK SMALL LETTER IOTA + 0x03D5, // 0x6A GREEK SMALL LETTER SCRIPT PHI + 0x03BA, // 0x6B GREEK SMALL LETTER KAPPA + 0x03BB, // 0x6C GREEK SMALL LETTER LAMBDA + 0x03BC, // 0x6D GREEK SMALL LETTER MU + 0x03BD, // 0x6E GREEK SMALL LETTER NU + 0x03BF, // 0x6F GREEK SMALL LETTER OMICRON + 0x03C0, // 0x70 GREEK SMALL LETTER PI + 0x03B8, // 0x71 GREEK SMALL LETTER THETA + 0x03C1, // 0x72 GREEK SMALL LETTER RHO + 0x03C3, // 0x73 GREEK SMALL LETTER SIGMA + 0x03C4, // 0x74 GREEK SMALL LETTER TAU + 0x03C5, // 0x75 GREEK SMALL LETTER UPSILON + 0x03D6, // 0x76 GREEK SMALL LETTER OMEGA PI + 0x03C9, // 0x77 GREEK SMALL LETTER OMEGA + 0x03BE, // 0x78 GREEK SMALL LETTER XI + 0x03C8, // 0x79 GREEK SMALL LETTER PSI + 0x03B6, // 0x7A GREEK SMALL LETTER ZETA + 0x007B, // 0x7B OPENING CURLY BRACKET + 0x007C, // 0x7C VERTICAL BAR + 0x007D, // 0x7D CLOSING CURLY BRACKET + 0x223C, // 0x7E TILDE OPERATOR + 0xFFFD, // 0x7F no replacement + 0xFFFD, // 0x80 no replacement + 0xFFFD, // 0x81 no replacement + 0xFFFD, // 0x82 no replacement + 0xFFFD, // 0x83 no replacement + 0xFFFD, // 0x84 no replacement + 0xFFFD, // 0x85 no replacement + 0xFFFD, // 0x86 no replacement + 0xFFFD, // 0x87 no replacement + 0xFFFD, // 0x88 no replacement + 0xFFFD, // 0x89 no replacement + 0xFFFD, // 0x8A no replacement + 0xFFFD, // 0x8B no replacement + 0xFFFD, // 0x8C no replacement + 0xFFFD, // 0x8D no replacement + 0xFFFD, // 0x8E no replacement + 0xFFFD, // 0x8F no replacement + 0xFFFD, // 0x90 no replacement + 0xFFFD, // 0x91 no replacement + 0xFFFD, // 0x92 no replacement + 0xFFFD, // 0x93 no replacement + 0xFFFD, // 0x94 no replacement + 0xFFFD, // 0x95 no replacement + 0xFFFD, // 0x96 no replacement + 0xFFFD, // 0x97 no replacement + 0xFFFD, // 0x98 no replacement + 0xFFFD, // 0x99 no replacement + 0xFFFD, // 0x9A no replacement + 0xFFFD, // 0x9B no replacement + 0xFFFD, // 0x9C no replacement + 0xFFFD, // 0x9D no replacement + 0xFFFD, // 0x9E no replacement + 0xFFFD, // 0x9F no replacement + 0x20AC, // 0xA0 EURO SIGN + 0x03D2, // 0xA1 GREEK CAPITAL LETTER UPSILON HOOK + 0x2032, // 0xA2 PRIME + 0x2264, // 0xA3 LESS THAN OR EQUAL TO + 0x2044, // 0xA4 FRACTION SLASH + 0x221E, // 0xA5 INFINITY + 0x0192, // 0xA6 LATIN SMALL LETTER SCRIPT F + 0x2663, // 0xA7 BLACK CLUB SUIT + 0x2666, // 0xA8 BLACK DIAMOND SUIT + 0x2665, // 0xA9 BLACK HEART SUIT + 0x2660, // 0xAA BLACK SPADE SUIT + 0x2194, // 0xAB LEFT RIGHT ARROW + 0x2190, // 0xAC LEFT ARROW + 0x2191, // 0xAD UP ARROW + 0x2192, // 0xAE RIGHT ARROW + 0x2193, // 0xAF DOWN ARROW + 0x00B0, // 0xB0 DEGREE SIGN + 0x00B1, // 0xB1 PLUS-OR-MINUS SIGN + 0x2033, // 0xB2 DOUBLE PRIME + 0x2265, // 0xB3 GREATER THAN OR EQUAL TO + 0x00D7, // 0xB4 MULTIPLICATION SIGN + 0x221D, // 0xB5 PROPORTIONAL TO + 0x2202, // 0xB6 PARTIAL DIFFERENTIAL + 0x2219, // 0xB7 BULLET (use BULLET operator, so normal font BULLET will not convert to Symbol BULLET) + 0x00F7, // 0xB8 DIVISION SIGN + 0x2260, // 0xB9 NOT EQUAL TO + 0x2261, // 0xBA IDENTICAL TO + 0x2248, // 0xBB ALMOST EQUAL TO + 0x2026, // 0xBC HORIZONTAL ELLIPSIS + 0xF8E6, // 0xBD VERTICAL ARROW EXTENDER + 0xF8E7, // 0xBE HORIZONTAL ARROW EXTENDER + 0x21B5, // 0xBF DOWN ARROW WITH CORNER LEFT + 0x2135, // 0xC0 FIRST TRANSFINITE CARDINAL + 0x2111, // 0xC1 BLACK-LETTER I + 0x211C, // 0xC2 BLACK-LETTER R + 0x2118, // 0xC3 SCRIPT P + 0x2297, // 0xC4 CIRCLED TIMES + 0x2295, // 0xC5 CIRCLED PLUS + 0x2205, // 0xC6 EMPTY SET + 0x2229, // 0xC7 INTERSECTION + 0x222A, // 0xC8 UNION + 0x2283, // 0xC9 SUPERSET OF + 0x2287, // 0xCA SUPERSET OF OR EQUAL TO + 0x2284, // 0xCB NOT A SUBSET OF + 0x2282, // 0xCC SUBSET OF + 0x2286, // 0xCD SUBSET OF OR EQUAL TO + 0x2208, // 0xCE ELEMENT OF + 0x2209, // 0xCF NOT AN ELEMENT OF + 0x2220, // 0xD0 ANGLE + 0x2207, // 0xD1 NABLA + 0x00AE, // 0xD2 REGISTERED TRADE MARK SIGN + 0x00A9, // 0xD3 COPYRIGHT SIGN + 0x2122, // 0xD4 TRADEMARK + 0x220F, // 0xD5 N-ARY PRODUCT + 0x221A, // 0xD6 SQUARE ROOT + 0x22C5, // 0xD7 DOT OPERATOR + 0x00AC, // 0xD8 NOT SIGN + 0x2227, // 0xD9 LOGICAL AND + 0x2228, // 0xDA LOGICAL OR + 0x21D4, // 0xDB LEFT RIGHT DOUBLE ARROW + 0x21D0, // 0xDC LEFT DOUBLE ARROW + 0x21D1, // 0xDD UP DOUBLE ARROW + 0x21D2, // 0xDE RIGHT DOUBLE ARROW + 0x21D3, // 0xDF DOWN DOUBLE ARROW + 0x25CA, // 0xE0 LOZENGE + 0x2329, // 0xE1 BRA + 0x00AE, // 0xE2 REGISTERED TRADE MARK SIGN + 0x00A9, // 0xE3 COPYRIGHT SIGN + 0x2122, // 0xE4 TRADEMARK + 0x2211, // 0xE5 N-ARY SUMMATION + 0x239B, // 0xE6 LEFT PAREN TOP + 0x239C, // 0xE7 LEFT PAREN EXTENDER + 0x239D, // 0xE8 LEFT PAREN BOTTOM + 0x23A1, // 0xE9 LEFT SQUARE BRACKET TOP + 0x23A2, // 0xEA LEFT SQUARE BRACKET EXTENDER + 0x23A3, // 0xEB LEFT SQUARE BRACKET BOTTOM + 0x23A7, // 0xEC LEFT CURLY BRACKET TOP + 0x23A8, // 0xED LEFT CURLY BRACKET MID + 0x23A9, // 0xEE LEFT CURLY BRACKET BOTTOM + 0x23AA, // 0xEF CURLY BRACKET EXTENDER + 0xFFFD, // 0xF0 no replacement + 0x232A, // 0xF1 KET + 0x222B, // 0xF2 INTEGRAL + 0x2320, // 0xF3 TOP HALF INTEGRAL + 0x23AE, // 0xF4 INTEGRAL EXTENDER + 0x2321, // 0xF5 BOTTOM HALF INTEGRAL + 0x239E, // 0xF6 RIGHT PAREN TOP + 0x239F, // 0xF7 RIGHT PAREN EXTENDER + 0x23A0, // 0xF8 RIGHT PAREN BOTTOM + 0x23A4, // 0xF9 RIGHT SQUARE BRACKET TOP + 0x23A5, // 0xFA RIGHT SQUARE BRACKET EXTENDER + 0x23A6, // 0xFB RIGHT SQUARE BRACKET BOTTOM + 0x23AB, // 0xFC RIGHT CURLY BRACKET TOP + 0x23AC, // 0xFD RIGHT CURLY BRACKET MID + 0x23AD, // 0xFE RIGHT CURLY BRACKET BOTTOM + 0xFFFD // 0xFF no replacement +}; + +/* Use this for debugging */ +#include +void UC_log_message(char *text){ +FILE *fp; + fp=fopen("c:/temp/debug.txt","a"); + fprintf(fp,"%s",text); + fclose(fp); +} + + +//if any character is in the MS private use area (F020 through F0FF) subtract F000, for use with Symbol and Wingdings* from older software +void msdepua (uint32_t *text) +{ + while(*text){ + if(*text >= 0xF020 && *text <= 0xF0FF){ *text -= 0xF000; } + text++; + } +} + +//move characters up to MS private use area (F020 through F0FF) +void msrepua (uint16_t *text) +{ + while(*text){ + if(*text >= 0x20 && *text <= 0xFF){ *text += 0xF000; } + text++; + } +} + +// Returns the font classification code +int isNon(char *font){ +int retval; + if(!strcmp(font,"Symbol")){ + retval=CVTSYM; + } + else if(!strcmp(font,"Wingdings")){ + retval=CVTWDG; + } + else if(!strcmp(font,"ZapfDingbats")){ + retval=CVTZDG; + } + else { + retval=CVTNON; + } + return retval; +} + +// Returns the font name, given the classification code, or NULL +// The returned value must NOT be free'd +char *FontName(int code){ +char *cptr; +static char name_symbol[]="Symbol"; +static char name_wingdings[]="Wingdings"; +static char name_zapfdingbats[]="ZapfDingbats"; + switch(code){ + case CVTSYM: cptr=&name_symbol[0]; break; + case CVTWDG: cptr=&name_wingdings[0]; break; + case CVTZDG: cptr=&name_zapfdingbats[0]; break; + default: cptr=NULL; break; + } + return(cptr); +} + + +// Goes through the uint32_t string converting as needed. +int NonToUnicode(uint32_t *text, char *font){ +int retval; +unsigned int *convert_from=NULL; + retval=isNon(font); + switch(retval){ + case CVTSYM: convert_from=symbol_convert; break; + case CVTWDG: convert_from=wingdings_convert; break; + case CVTZDG: convert_from=dingbats_convert; break; + default: return(retval); //no conversion + } + while(*text){ + if(*text > 0xFF){ *text = 0xFFFD; } // out of range + else { *text = convert_from[*text]; } + text++; + } + return(retval); +} + +//returns 1 if tables are defines for UnicodeToNon translation +int CanUTN(void){ + if(from_unicode)return(1); + return(0); +} + +//translates from Unicode to some non unicode font until the target font changes. +//A target font change is like symbol -> wingdings, or symbol -> no translation +//returns the number of characters changed in ecount +//returns the enum value for the destination value in edest +void UnicodeToNon(uint16_t *text, int *ecount, int *edest){ +int count=0; +unsigned char target=0; + if(to_font){ + if(text && (target=to_font[*text])){ //There is actually something here to convert + while(*text && target==to_font[*text]){ + *text=from_unicode[*text] + (hold_pua ? 0xF000 : 0 ); + text++; + count++; + } + } + *ecount=count; + *edest=target; + } + else { // no translation tables, so change nothing and return + *ecount=0; + *edest=CVTNON; + } +} + +//Indicates the type of translation for a single character, Unicode to some non unicode +//returns the enum value for the destination value. +//If no translation tables are defined returns CVTNON (no conversions) +int SingleUnicodeToNon(uint16_t text){ + if(to_font){return(to_font[text]); } + else { return(CVTNON); } +} + +void table_filler(unsigned int *src, int code){ +unsigned int i; + for(i=0;i<0x100;i++){ + if(src[i] == 0xFFFD)continue; /* no mapping Unicode -> nonUnicode */ + if(src[i] == i)continue; /* no remapping of spaces back to spaces, for instance */ + from_unicode[src[i]] = i; + to_font[src[i]] = code; + } +} + +//possibly (re)generate the tables +void TableGen(bool new_symb,bool new_wing, bool new_zdng, bool new_pua){ +int i; + if(hold_symb != new_symb || hold_wing != new_wing + || hold_zdng != new_zdng || hold_pua != new_pua ){ // must (re)generate tables + if(!from_unicode){ // create arrays + from_unicode = (unsigned char *) calloc(0x10000,sizeof(char)); + to_font = (unsigned char *) calloc(0x10000,sizeof(char)); + // should check here for malloc error + } + hold_symb = new_symb; + hold_wing = new_wing; + hold_zdng = new_zdng; + hold_pua = new_pua; + for(i=0;i<0x10000;i++){ from_unicode[i] = to_font[i] = 0; } + if(hold_zdng)table_filler(&dingbats_convert[0],CVTZDG); + if(hold_wing)table_filler(&wingdings_convert[0],CVTWDG); + if(hold_symb)table_filler(&symbol_convert[0],CVTSYM); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/src/libunicode-convert/unicode-convert.h b/src/libunicode-convert/unicode-convert.h new file mode 100644 index 000000000..ac1795092 --- /dev/null +++ b/src/libunicode-convert/unicode-convert.h @@ -0,0 +1,51 @@ +/** @file + * @brief Enhanced Metafile Input/Output + */ +/* Authors: + * David Mathog + * + * Copyright (C) 2012 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SEEN_UNICODE_CONVERT_H +#define SEEN_UNICODE_CONVERT_H +#include +#include +#include + + enum cvt_to_font {CVTNON, CVTSYM, CVTZDG, CVTWDG}; + + void msdepua(uint32_t *text); //translate down from Microsoft Private Use Area + void msrepua(uint16_t *text); //translate up to Microsoft Private Use Area + int isNon(char *font); //returns one of the cvt_to_font enum values + char *FontName(int code); //returns the font name (or NULL) given the enum code + int NonToUnicode(uint32_t *text, char *font); //nonunicode to Unicode translation + int CanUTN(void); // 1 if tables exist for UnicodeToNon translation + int SingleUnicodeToNon(uint16_t text); //retuns the enum value for this translation + void UnicodeToNon(uint16_t *text, int *ecount, int *edest); //translate Unicode to NonUnicode + void TableGen(bool symb, bool wing, bool zdng, bool pua); + +#ifdef __cplusplus +} +#endif + +#endif /* SEEN_UNICODE_CONVERT_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 : + + -- cgit v1.2.3 From 89bb2602a15a830b7e2133307a8ec6a08ebd0f84 Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 23 Sep 2012 19:19:33 +0200 Subject: Fixes bug #988601: omnibus patch for EMF input/output support (cross-platform) (bzr r11668.1.8) --- src/Makefile.am | 9 +- src/extension/init.cpp | 14 +- src/extension/internal/Makefile_insert | 12 +- src/extension/internal/emf-inout.cpp | 3140 ++++++++++++++++ src/extension/internal/emf-inout.h | 55 + src/extension/internal/emf-print.cpp | 2146 +++++++++++ src/extension/internal/emf-print.h | 113 + src/extension/internal/emf-win32-inout.cpp | 2569 ------------- src/extension/internal/emf-win32-inout.h | 57 - src/extension/internal/emf-win32-print.cpp | 942 ----- src/extension/internal/emf-win32-print.h | 120 - src/extension/internal/uemf.c | 5612 ++++++++++++++++++++++++++++ src/extension/internal/uemf.h | 2933 +++++++++++++++ src/extension/internal/uemf_endian.c | 1745 +++++++++ src/extension/internal/uemf_endian.h | 37 + src/extension/internal/uemf_print.c | 2577 +++++++++++++ src/extension/internal/uemf_print.h | 134 + src/libnrtype/Layout-TNG-Output.cpp | 58 +- src/style.h | 11 +- 19 files changed, 18574 insertions(+), 3710 deletions(-) create mode 100644 src/extension/internal/emf-inout.cpp create mode 100644 src/extension/internal/emf-inout.h create mode 100644 src/extension/internal/emf-print.cpp create mode 100644 src/extension/internal/emf-print.h delete mode 100644 src/extension/internal/emf-win32-inout.cpp delete mode 100644 src/extension/internal/emf-win32-inout.h delete mode 100644 src/extension/internal/emf-win32-print.cpp delete mode 100644 src/extension/internal/emf-win32-print.h create mode 100644 src/extension/internal/uemf.c create mode 100644 src/extension/internal/uemf.h create mode 100644 src/extension/internal/uemf_endian.c create mode 100644 src/extension/internal/uemf_endian.h create mode 100644 src/extension/internal/uemf_print.c create mode 100644 src/extension/internal/uemf_print.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index c27af0800..6eefa381c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -135,6 +135,7 @@ include live_effects/Makefile_insert include live_effects/parameter/Makefile_insert include libvpsc/Makefile_insert include libcola/Makefile_insert +include libunicode-convert/Makefile_insert include svg/Makefile_insert include widgets/Makefile_insert include debug/Makefile_insert @@ -190,10 +191,10 @@ EXTRA_DIST += \ widgets/makefile.in \ xml/makefile.in \ 2geom/makefile.in \ - extension/internal/emf-win32-inout.cpp \ - extension/internal/emf-win32-inout.h \ - extension/internal/emf-win32-print.cpp \ - extension/internal/emf-win32-print.h \ + extension/internal/emf-inout.cpp \ + extension/internal/emf-inout.h \ + extension/internal/emf-print.cpp \ + extension/internal/emf-print.h \ helper/sp-marshal.list \ show-preview.bmp \ winconsole.cpp \ diff --git a/src/extension/init.cpp b/src/extension/init.cpp index b0732568f..cd7c52d5e 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -32,10 +32,8 @@ #include "system.h" #include "db.h" #include "internal/svgz.h" -#ifdef WIN32 -# include "internal/emf-win32-inout.h" -# include "internal/emf-win32-print.h" -#endif +# include "internal/emf-inout.h" +# include "internal/emf-print.h" #ifdef HAVE_CAIRO_PDF # include "internal/cairo-renderer-pdf-out.h" # include "internal/cairo-png-out.h" @@ -171,10 +169,8 @@ init() Internal::PdfInputCairo::init(); } #endif -#ifdef WIN32 - Internal::PrintEmfWin32::init(); - Internal::EmfWin32::init(); -#endif + Internal::PrintEmf::init(); + Internal::Emf::init(); Internal::PovOutput::init(); Internal::JavaFXOutput::init(); Internal::OdfOutput::init(); @@ -308,7 +304,7 @@ build_module_from_dir(gchar const *dirname) continue; } - gchar *pathname = g_build_filename(dirname, filename, NULL); + gchar *pathname = g_build_filename(dirname, filename, (char *) NULL); build_from_file(pathname); g_free(pathname); } diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index e9b11553b..d1b2da8cd 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -133,10 +133,14 @@ ink_common_sources += \ extension/internal/filter/filter.h \ extension/internal/filter/drop-shadow.h \ extension/internal/filter/snow.h \ - extension/internal/emf-win32-print.h \ - extension/internal/emf-win32-print.cpp \ - extension/internal/emf-win32-inout.h \ - extension/internal/emf-win32-inout.cpp \ + extension/internal/uemf.c \ + extension/internal/uemf.h \ + extension/internal/uemf_endian.c \ + extension/internal/uemf_endian.h \ + extension/internal/emf-print.h \ + extension/internal/emf-print.cpp \ + extension/internal/emf-inout.h \ + extension/internal/emf-inout.cpp \ extension/internal/image-resolution.h \ extension/internal/image-resolution.cpp diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp new file mode 100644 index 000000000..4b2767313 --- /dev/null +++ b/src/extension/internal/emf-inout.cpp @@ -0,0 +1,3140 @@ +/** @file + * @brief Windows-only Enhanced Metafile input and output. + */ +/* Authors: + * Ulf Erikson + * Jon A. Cruz + * 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 + +#define EMF_DRIVER +#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 "emf-print.h" +#include "emf-inout.h" +#include "uemf.h" + +#define PRINT_EMF "org.inkscape.print.emf" + +#ifndef U_PS_JOIN_MASK +#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND) +#endif + +namespace Inkscape { +namespace Extension { +namespace Internal { + + +static float device_scale = DEVICESCALE; +static U_RECTL rc_old; +static bool clipset = false; +static uint32_t ICMmode=0; +static uint32_t BLTmode=0; + +/** Construct a PNG in memory from an RGB from the EMF file + +from: +http://www.lemoda.net/c/write-png/ + +which was based on: +http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng + +gcc -Wall -o testpng testpng.c -lpng +*/ + +#include +#include +#include +#include + +/* 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) +{ + 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 +my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + /* with libpng15 next line causes pointer deference error; use libpng12 */ + PMEMPNG p=(PMEMPNG)png_ptr->io_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 toPNG(PMEMPNG accum, int width, int height, char *px, uint32_t cbPx){ + bitmap_t bmstore; + bitmap_t *bitmap=&bmstore; + accum->buffer=NULL; // PNG constructed in memory will end up here, caller must free(). + accum->size=0; + bitmap->pixels=(pixel_t *)px; + bitmap->width = width; + bitmap->height = height; + + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + size_t x, y; + png_byte ** row_pointers = NULL; + /* The following number is set by trial and error only. I cannot + see where it it is documented in the libpng manual. + */ + int pixel_size = 3; + int depth = 8; + + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL){ + accum->buffer=NULL; + return; + } + + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL){ + png_destroy_write_struct (&png_ptr, &info_ptr); + accum->buffer=NULL; + return; + } + + /* Set up error handling. */ + + if (setjmp (png_jmpbuf (png_ptr))) { + png_destroy_write_struct (&png_ptr, &info_ptr); + accum->buffer=NULL; + return; + } + + /* Set image attributes. */ + + png_set_IHDR (png_ptr, + info_ptr, + bitmap->width, + bitmap->height, + depth, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + /* Initialize rows of PNG. */ + + row_pointers = (png_byte **) png_malloc (png_ptr, bitmap->height * sizeof (png_byte *)); + for (y = 0; y < bitmap->height; ++y) { + png_byte *row = + (png_byte *) png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size); + row_pointers[bitmap->height - y - 1] = row; // Row order in EMF is reversed. + for (x = 0; x < bitmap->width; ++x) { + pixel_t * pixel = pixel_at (bitmap, x, y); + *row++ = pixel->red; // R & B channels were set correctly by DIB_to_RGB + *row++ = pixel->green; + *row++ = pixel->blue; + } + } + + /* Write the image data to memory */ + + png_set_rows (png_ptr, info_ptr, row_pointers); + + png_set_write_fn(png_ptr, accum, my_png_write_data, NULL); + + png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + for (y = 0; y < bitmap->height; y++) { + png_free (png_ptr, row_pointers[y]); + } + png_free (png_ptr, row_pointers); + png_destroy_write_struct(&png_ptr, &info_ptr); + +} + +/* Given "value" and "max", the maximum value which we expect "value" + to take, this returns an integer between 0 and 255 proportional to + "value" divided by "max". */ + +static int pix (int value, int max) +{ + if (value < 0) + return 0; + return (int) (256.0 *((double) (value)/(double) max)); +} + +/* convert an EMF RGB(A) color to 0RGB +inverse of gethexcolor() in emf-print.cpp +*/ +uint32_t sethexcolor(U_COLORREF color){ + + uint32_t out; + out = (U_RGBAGetR(color) << 16) + + (U_RGBAGetG(color) << 8 ) + + (U_RGBAGetB(color) ); + return(out); +} + + +Emf::Emf (void) // The null constructor +{ + return; +} + + +Emf::~Emf (void) //The destructor +{ + return; +} + + +bool +Emf::check (Inkscape::Extension::Extension * /*module*/) +{ + if (NULL == Inkscape::Extension::db.get(PRINT_EMF)) + return FALSE; + return TRUE; +} + + +static void +emf_print_document_to_file(SPDocument *doc, gchar const *filename) +{ + Inkscape::Extension::Print *mod; + SPPrintContext context; + gchar const *oldconst; + gchar *oldoutput; + unsigned int ret; + + doc->ensureUpToDate(); + + mod = Inkscape::Extension::get_print(PRINT_EMF); + oldconst = mod->get_param_string("destination"); + oldoutput = g_strdup(oldconst); + mod->set_param_string("destination", filename); + +/* Start */ + context.module = mod; + /* fixme: This has to go into module constructor somehow */ + /* Create new arena */ + mod->base = doc->getRoot(); + Inkscape::Drawing drawing; + mod->dkey = SPItem::display_key_new(1); + mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); + drawing.setRoot(mod->root); + /* Print document */ + ret = mod->begin(doc); + if (ret) { + g_free(oldoutput); + throw Inkscape::Extension::Output::save_failed(); + } + mod->base->invoke_print(&context); + ret = mod->finish(); + /* Release arena */ + mod->base->invoke_hide(mod->dkey); + mod->base = NULL; + mod->root = NULL; // deleted by invoke_hide +/* end */ + + mod->set_param_string("destination", oldoutput); + g_free(oldoutput); + + return; +} + + +void +Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) +{ + Inkscape::Extension::Extension * ext; + + ext = Inkscape::Extension::db.get(PRINT_EMF); + if (ext == NULL) + return; + + bool new_val = mod->get_param_bool("textToPath"); + bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug + // reserve FixPPT2 for opacity bug. Currently EMF does not export opacity values + bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug + bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug + bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard EMF hatch + + TableGen( //possibly regenerate the unicode-convert tables + mod->get_param_bool("TnrToSymbol"), + mod->get_param_bool("TnrToWingdings"), + mod->get_param_bool("TnrToZapfDingbats"), + mod->get_param_bool("UsePUA") + ); + + ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result! + ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine); + ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys); + ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch); + ext->set_param_bool("textToPath", new_val); + + emf_print_document_to_file(doc, filename); + + return; +} + + +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; + class SPTextStyle tstyle; + 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; + float PixelsInX, PixelsInY; + float PixelsOutX, PixelsOutY; + U_POINTL winorg; + U_POINTL vieworg; + double ScaleInX, ScaleInY; + double ScaleOutX, ScaleOutY; + U_COLORREF textColor; + bool textColorSet; + U_COLORREF bkColor; + bool bkColorSet; + 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 xDPI, yDPI; + 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; + float dwInchesX; + float dwInchesY; + + 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 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. + + + int n_obj; + PEMF_OBJECT emf_obj; +} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA; + +/* Add another 100 blank slots to the hatches array. +*/ +void 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 i; + for(i=0; ihatches.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 . +*/ +uint32_t add_hatch(PEMF_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: + if(d->dc[d->level].textColorSet){ + sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor)); + } + break; + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + if(d->dc[d->level].bkColorSet){ + sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor)); + } + break; + default: + break; + } + + // EMF 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,"EMFhatch%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) += " 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) += " defs) += tmpcolor; + *(d->defs) += "\" />\n"; + *(d->defs) += " \n"; + break; + case U_HS_VERTICAL: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " defs) += tmpcolor; + *(d->defs) += "\" />\n"; + *(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) += " defs) += tmpcolor; + *(d->defs) += "\" id=\"sub"; + *(d->defs) += hatchname; + *(d->defs) += "\"/>\n"; + *(d->defs) += " defs) += hatchname; + *(d->defs) += "\" transform=\"translate(6,0)\"/>\n"; + *(d->defs) += " defs) += hatchname; + *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n"; + *(d->defs) += " \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) += " defs) += tmpcolor; + *(d->defs) += "\" id=\"sub"; + *(d->defs) += hatchname; + *(d->defs) += "\"/>\n"; + *(d->defs) += " defs) += hatchname; + *(d->defs) += "\" transform=\"translate(6,0)\"/>\n"; + *(d->defs) += " defs) += hatchname; + *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n"; + *(d->defs) += " \n"; + break; + case U_HS_CROSS: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " defs) += tmpcolor; + *(d->defs) += "\" />\n"; + *(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) += " defs) += hatchname; + *(d->defs) += "\" transform=\"translate(0,0)\"/>\n"; + *(d->defs) += " defs) += hatchname; + *(d->defs) += "\" transform=\"translate(0,0)\"/>\n"; + *(d->defs) += " \n"; + break; + case U_HS_SOLIDCLR: + case U_HS_DITHEREDCLR: + case U_HS_SOLIDTEXTCLR: + case U_HS_DITHEREDTEXTCLR: + case U_HS_SOLIDBKCLR: + case U_HS_DITHEREDBKCLR: + default: + *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n"; + *(d->defs) += " defs) += tmpcolor; + *(d->defs) += ";stroke:none"; + *(d->defs) += "\" />\n"; + *(d->defs) += " \n"; + break; + } + idx = d->hatches.count; + } + return(idx-1); +} + +/* Add another 100 blank slots to the images array. +*/ +void 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 i; + for(i=0; iimages.count; i++){ + if(strcmp(test,d->images.strings[i])==0)return(i+1); + } + return(0); +} + +/* (Conditionally) add an image. If a matching image already exists nothing happens. If one + does not exist it is added to the images list and also entered into . + + 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 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 + char *px=NULL; // DIB pixels + uint32_t width, height, colortype, numCt, invert; + PU_RGBQUAD ct = NULL; + if(!cbBits || + !cbBmi || + (iUsage != U_DIB_RGB_COLORS) || + !get_DIB_params( // this returns pointers and values, but allocates no memory + pEmr, + offBits, + offBmi, + &px, + &ct, + &numCt, + &width, + &height, + &colortype, + &invert + )){ + + // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map. + if(((PU_EMR)pEmr)->iType == U_EMR_CREATEMONOBRUSH){ + if(numCt==2){ + ct[0] = U_RGB2BGR(d->dc[d->level].textColor); + ct[1] = U_RGB2BGR(d->dc[d->level].bkColor); + } + else { // createmonobrush renders on other platforms this way + return(0xFFFFFFFF); + } + } + + if(!DIB_to_RGBA( + px, // DIB pixel array + ct, // DIB color table + numCt, // DIB color table number of entries + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array + 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, + rgba_px, + 4 * width * height); + free(rgba_px); + } + } + gchar *base64String; + 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 + if(d->images.count == d->images.size){ enlarge_images(d); } + idx = d->images.count; + d->images.strings[d->images.count++]=strdup(base64String); + + sprintf(imagename,"EMFimage%d",idx++); + sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer + + *(d->defs) += "\n"; + *(d->defs) += " 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) += " defs) += imagename; + *(d->defs) += "_ref\"\n "; + *(d->defs) += xywh; + *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; + *(d->defs) += " >\n"; + *(d->defs) += " defs) += imagename; + *(d->defs) += "_ign\" "; + *(d->defs) += " xlink:href=\"#"; + *(d->defs) += imagename; + *(d->defs) += "\" />\n"; + *(d->defs) += " \n"; + } + g_free(base64String); + return(idx-1); +} + + +static void +output_style(PEMF_CALLBACK_DATA d, int iType) +{ +// SVGOStringStream tmp_id; + SVGOStringStream tmp_style; + char tmp[1024] = {0}; + + float fill_rgb[3]; + sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb ); + float stroke_rgb[3]; + sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb); + + // for U_EMR_BITBLT with no image, try to approximate some of these operations/ + // Assume src color is "white" + if(d->dwRop3){ + switch(d->dwRop3){ + case U_PATINVERT: // treat all of these as black + case U_SRCINVERT: + case U_DSTINVERT: + case U_BLACKNESS: + case U_SRCERASE: + case U_NOTSRCCOPY: + fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0; + break; + case U_SRCCOPY: // treat all of these as white + case U_NOTSRCERASE: + case U_PATCOPY: + case U_WHITENESS: + fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0; + break; + case U_SRCPAINT: // use the existing color + case U_SRCAND: + case U_MERGECOPY: + case U_MERGEPAINT: + case U_PATPAINT: + default: + break; + } + d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT + } + + // Implement some of these, the ones where the original screen color does not matter. + // The options that merge screen and pen colors cannot be done correctly because we + // have no way of knowing what color is already on the screen. For those just pass the + // pen color through. + switch(d->dwRop2){ + case U_R2_BLACK: + fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0; + stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0; + break; + case U_R2_NOTMERGEPEN: + case U_R2_MASKNOTPEN: + break; + case U_R2_NOTCOPYPEN: + fill_rgb[0] = 1.0 - fill_rgb[0]; + fill_rgb[1] = 1.0 - fill_rgb[1]; + fill_rgb[2] = 1.0 - fill_rgb[2]; + stroke_rgb[0] = 1.0 - stroke_rgb[0]; + stroke_rgb[1] = 1.0 - stroke_rgb[1]; + stroke_rgb[2] = 1.0 - stroke_rgb[2]; + break; + case U_R2_MASKPENNOT: + case U_R2_NOT: + case U_R2_XORPEN: + case U_R2_NOTMASKPEN: + case U_R2_NOTXORPEN: + case U_R2_NOP: + case U_R2_MERGENOTPEN: + case U_R2_COPYPEN: + case U_R2_MASKPEN: + case U_R2_MERGEPENNOT: + case U_R2_MERGEPEN: + break; + case U_R2_WHITE: + fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0; + stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0; + break; + default: + break; + } + + +// tmp_id << "\n\tid=\"" << (d->id++) << "\""; +// *(d->outsvg) += tmp_id.str().c_str(); + *(d->outsvg) += "\n\tstyle=\""; + if (iType == U_EMR_STROKEPATH || !d->dc[d->level].fill_set) { + tmp_style << "fill:none;"; + } else { + switch(d->dc[d->level].fill_mode){ + // both of these use the url(#) method + case DRAW_PATTERN: + snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]); + tmp_style << tmp; + break; + case DRAW_IMAGE: + snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx); + tmp_style << tmp; + break; + case DRAW_PAINT: + default: // <-- this should never happen, but just in case... + snprintf(tmp, 1023, + "fill:#%02x%02x%02x;", + SP_COLOR_F_TO_U(fill_rgb[0]), + SP_COLOR_F_TO_U(fill_rgb[1]), + SP_COLOR_F_TO_U(fill_rgb[2])); + tmp_style << tmp; + break; + } + snprintf(tmp, 1023, + "fill-rule:%s;", + d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero"); + tmp_style << tmp; + tmp_style << "fill-opacity:1;"; + + if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 && + fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2]) + { + d->dc[d->level].stroke_set = false; + } + } + + if (iType == U_EMR_FILLPATH || !d->dc[d->level].stroke_set) { + tmp_style << "stroke:none;"; + } else { + switch(d->dc[d->level].stroke_mode){ + // both of these use the url(#) method + case DRAW_PATTERN: + snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]); + tmp_style << tmp; + break; + case DRAW_IMAGE: + snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx); + tmp_style << tmp; + break; + case DRAW_PAINT: + default: // <-- this should never happen, but just in case... + snprintf(tmp, 1023, + "stroke:#%02x%02x%02x;", + SP_COLOR_F_TO_U(stroke_rgb[0]), + SP_COLOR_F_TO_U(stroke_rgb[1]), + SP_COLOR_F_TO_U(stroke_rgb[2])); + tmp_style << tmp; + break; + } + tmp_style << "stroke-width:" << + MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;"; + + tmp_style << "stroke-linecap:" << + (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" : + d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" : + d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" : + "unknown") << ";"; + + tmp_style << "stroke-linejoin:" << + (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" : + d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" : + d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" : + "unknown") << ";"; + + // Set miter limit if known, even if it is not needed immediately (not miter) + tmp_style << "stroke-miterlimit:" << + MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; + + if (d->dc[d->level].style.stroke_dasharray_set && + d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) + { + tmp_style << "stroke-dasharray:"; + for (int i=0; idc[d->level].style.stroke_dash.n_dash; i++) { + if (i) + tmp_style << ","; + tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; + } + tmp_style << ";"; + tmp_style << "stroke-dashoffset:0;"; + } else { + tmp_style << "stroke-dasharray:none;"; + } + tmp_style << "stroke-opacity:1;"; + } + tmp_style << "\" "; + if (clipset) + tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" "; + clipset = false; + + *(d->outsvg) += tmp_style.str().c_str(); +} + + +static double +_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) +{ + double tmp = px - d->dc[d->level].winorg.x; + tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0; + tmp += d->dc[d->level].vieworg.x; + return tmp; +} + +static double +_pix_y_to_point(PEMF_CALLBACK_DATA d, double px) +{ + double tmp = px - d->dc[d->level].winorg.y; + tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0; + tmp += d->dc[d->level].vieworg.y; + return tmp; +} + + +static double +pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) +{ + double ppx = _pix_x_to_point(d, px); + double ppy = _pix_y_to_point(d, py); + + double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; + x *= device_scale; + + return x; +} + +static double +pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) +{ + double ppx = _pix_x_to_point(d, px); + double ppy = _pix_y_to_point(d, py); + + double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; + y *= device_scale; + + return y; +} + +static double +pix_to_size_point(PEMF_CALLBACK_DATA d, double px) +{ + double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); + double ppy = 0; + + double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21; + dx *= device_scale; + double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22; + dy *= device_scale; + + double tmp = sqrt(dx * dx + dy * dy); + return tmp; +} + + +static void +select_pen(PEMF_CALLBACK_DATA d, int index) +{ + PU_EMRCREATEPEN pEmr = NULL; + + if (index >= 0 && index < d->n_obj) + pEmr = (PU_EMRCREATEPEN) d->emf_obj[index].lpEMFR; + + if (!pEmr) + return; + + switch (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK) { + case U_PS_DASH: + case U_PS_DOT: + case U_PS_DASHDOT: + case U_PS_DASHDOTDOT: + { + int i = 0; + int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK); + d->dc[d->level].style.stroke_dash.n_dash = + penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 3; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + if (penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + } + + d->dc[d->level].style.stroke_dasharray_set = 1; + break; + } + + case U_PS_SOLID: + default: + { + d->dc[d->level].style.stroke_dasharray_set = 0; + break; + } + } + + switch (pEmr->lopn.lopnStyle & U_PS_ENDCAP_MASK) { + case U_PS_ENDCAP_ROUND: + { + d->dc[d->level].style.stroke_linecap.computed = 1; + break; + } + case U_PS_ENDCAP_SQUARE: + { + d->dc[d->level].style.stroke_linecap.computed = 2; + break; + } + case U_PS_ENDCAP_FLAT: + default: + { + d->dc[d->level].style.stroke_linecap.computed = 0; + break; + } + } + + switch (pEmr->lopn.lopnStyle & U_PS_JOIN_MASK) { + case U_PS_JOIN_BEVEL: + { + d->dc[d->level].style.stroke_linejoin.computed = 2; + break; + } + case U_PS_JOIN_MITER: + { + d->dc[d->level].style.stroke_linejoin.computed = 0; + break; + } + case U_PS_JOIN_ROUND: + default: + { + d->dc[d->level].style.stroke_linejoin.computed = 1; + break; + } + } + + d->dc[d->level].stroke_set = true; + + if (pEmr->lopn.lopnStyle == U_PS_NULL) { + d->dc[d->level].style.stroke_width.value = 0; + d->dc[d->level].stroke_set = false; + } else if (pEmr->lopn.lopnWidth.x) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_size_point( d, pEmr->lopn.lopnWidth.x ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + //d->dc[d->level].style.stroke_width.value = 1.0; + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_size_point( d, 1 ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } + + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lopn.lopnColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lopn.lopnColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lopn.lopnColor) ); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); +} + + +static void +select_extpen(PEMF_CALLBACK_DATA d, int index) +{ + PU_EMREXTCREATEPEN pEmr = NULL; + + if (index >= 0 && index < d->n_obj) + pEmr = (PU_EMREXTCREATEPEN) d->emf_obj[index].lpEMFR; + + if (!pEmr) + return; + + switch (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK) { + case U_PS_USERSTYLE: + { + if (pEmr->elp.elpNumEntries) { + d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries]; + for (unsigned int i=0; ielp.elpNumEntries; i++) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; +// Doing it this way typically results in a pattern that is tiny, better to assume the array +// is the same scale as for dot/dash below, that is, no scaling should be applied +// double dash_length = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] ); + double dash_length = pEmr->elp.elpStyleEntry[i]; + d->level = cur_level; + d->dc[d->level].style.stroke_dash.dash[i] = dash_length; + } + d->dc[d->level].style.stroke_dasharray_set = 1; + } else { + d->dc[d->level].style.stroke_dasharray_set = 0; + } + break; + } + + case U_PS_DASH: + case U_PS_DOT: + case U_PS_DASHDOT: + case U_PS_DASHDOTDOT: + { + int i = 0; + int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK); + d->dc[d->level].style.stroke_dash.n_dash = + penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; + if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) + delete[] d->dc[d->level].style.stroke_dash.dash; + d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 3; + d->dc[d->level].style.stroke_dash.dash[i++] = 2; + } + if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 2; + } + if (penstyle==U_PS_DASHDOTDOT) { + d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dash.dash[i++] = 2; + } + + d->dc[d->level].style.stroke_dasharray_set = 1; + break; + } + + case U_PS_SOLID: + default: + { + d->dc[d->level].style.stroke_dasharray_set = 0; + break; + } + } + + switch (pEmr->elp.elpPenStyle & U_PS_ENDCAP_MASK) { + case U_PS_ENDCAP_ROUND: + { + d->dc[d->level].style.stroke_linecap.computed = 1; + break; + } + case U_PS_ENDCAP_SQUARE: + { + d->dc[d->level].style.stroke_linecap.computed = 2; + break; + } + case U_PS_ENDCAP_FLAT: + default: + { + d->dc[d->level].style.stroke_linecap.computed = 0; + break; + } + } + + switch (pEmr->elp.elpPenStyle & U_PS_JOIN_MASK) { + case U_PS_JOIN_BEVEL: + { + d->dc[d->level].style.stroke_linejoin.computed = 2; + break; + } + case U_PS_JOIN_MITER: + { + d->dc[d->level].style.stroke_linejoin.computed = 0; + break; + } + case U_PS_JOIN_ROUND: + default: + { + d->dc[d->level].style.stroke_linejoin.computed = 1; + break; + } + } + + d->dc[d->level].stroke_set = true; + + if (pEmr->elp.elpPenStyle == U_PS_NULL) { + d->dc[d->level].style.stroke_width.value = 0; + d->dc[d->level].stroke_set = false; + } else if (pEmr->elp.elpWidth) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + //d->dc[d->level].style.stroke_width.value = 1.0; + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_size_point( d, 1 ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } + + if( pEmr->elp.elpBrushStyle == U_BS_SOLID){ + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) ); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + } + else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){ + d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor); + d->dc[d->level].stroke_mode = DRAW_PATTERN; + d->dc[d->level].stroke_set = true; + } + else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){ + d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); + d->dc[d->level].stroke_mode = DRAW_IMAGE; + d->dc[d->level].stroke_set = true; + } + else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + } +} + + +static void +select_brush(PEMF_CALLBACK_DATA d, int index) +{ + uint32_t tidx; + uint32_t iType; + + if (index >= 0 && index < d->n_obj){ + iType = ((PU_EMR) (d->emf_obj[index].lpEMFR))->iType; + if(iType == U_EMR_CREATEBRUSHINDIRECT){ + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR; + if( pEmr->lb.lbStyle == U_BS_SOLID){ + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lb.lbColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lb.lbColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lb.lbColor) ); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = true; + } + else if(pEmr->lb.lbStyle == U_BS_HATCHED){ + d->dc[d->level].fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor); + d->dc[d->level].fill_mode = DRAW_PATTERN; + d->dc[d->level].fill_set = true; + } + } + else if(iType == U_EMR_CREATEDIBPATTERNBRUSHPT || iType == U_EMR_CREATEMONOBRUSH){ + PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) d->emf_obj[index].lpEMFR; + tidx = add_image(d, (void *) pEmr, pEmr->cbBits, pEmr->cbBmi, pEmr->iUsage, pEmr->offBits, pEmr->offBmi); + if(tidx == 0xFFFFFFFF){ // This happens if createmonobrush has a DIB that isn't monochrome + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + } + else { + d->dc[d->level].fill_idx = tidx; + d->dc[d->level].fill_mode = DRAW_IMAGE; + } + d->dc[d->level].fill_set = true; + } + } +} + + +static void +select_font(PEMF_CALLBACK_DATA d, int index) +{ + PU_EMREXTCREATEFONTINDIRECTW pEmr = NULL; + + if (index >= 0 && index < d->n_obj) + pEmr = (PU_EMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR; + + if (!pEmr)return; + + + /* The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW + is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont + is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored + */ + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight ); + /* snap the font_size to the nearest .01. + See the notes where device_scale is 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 1% off, which is unlikely to be a problem. */ + font_size = round(100.0 * font_size)/100.0; + d->level = cur_level; + d->dc[d->level].style.font_size.computed = font_size; + d->dc[d->level].style.font_weight.value = + pEmr->elfw.elfLogFont.lfWeight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : + pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : + pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : + pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : + U_FW_NORMAL; + d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); + d->dc[d->level].style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline; + d->dc[d->level].style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut; + if (d->dc[d->level].tstyle.font_family.value){ free(d->dc[d->level].tstyle.font_family.value); } + d->dc[d->level].tstyle.font_family.value = + U_Utf16leToUtf8((uint16_t *) (pEmr->elfw.elfLogFont.lfFaceName), U_LF_FACESIZE, NULL); + d->dc[d->level].style.baseline_shift.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow +} + +static void +delete_object(PEMF_CALLBACK_DATA d, int index) +{ + if (index >= 0 && index < d->n_obj) { + d->emf_obj[index].type = 0; +// We are keeping a copy of the EMR rather than just a structure. Currently that is not necessary as the entire +// EMF is read in at once and is stored in a big malloc. However, in past versions it was handled +// reord by record, and we might need to do that again at some point in the future if we start running into EMF +// files too big to fit into memory. + if (d->emf_obj[index].lpEMFR) + free(d->emf_obj[index].lpEMFR); + d->emf_obj[index].lpEMFR = NULL; + } +} + + +static void +insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj) +{ + if (index >= 0 && index < d->n_obj) { + delete_object(d, index); + d->emf_obj[index].type = type; + d->emf_obj[index].level = d->level; + d->emf_obj[index].lpEMFR = emr_dup((char *) pObj); + } +} + +/** + \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 *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=length)return(0); //normally should exit from while after EMREOF sets OK to false. + + lpEMFR = (PU_ENHMETARECORD)(contents + off); +// std::cout << "record type: " << lpEMFR->iType << " length: " << lpEMFR->nSize << "offset: " << off <nSize; + + SVGOStringStream tmp_outsvg; + SVGOStringStream tmp_path; + SVGOStringStream tmp_str; + SVGOStringStream dbg_str; + + emr_mask = emr_properties(lpEMFR->iType); + +// std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; +/* +std::cout << "BEFORE DRAW" + << " test0 " << ( d->mask & U_DRAW_VISIBLE) + << " test1 " << ( d->mask & U_DRAW_FORCE) + << " test2 " << (emr_mask & U_DRAW_ALTERS) + << " test3 " << (emr_mask & U_DRAW_VISIBLE) + << " test4 " << !(d->mask & U_DRAW_ONLYTO) + << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) ) + << std::endl; +*/ + if ( (emr_mask != 0xFFFFFFFF) && // next record is valid type + (d->mask & U_DRAW_VISIBLE) && // This record is drawable + ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH + (emr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way + ( (emr_mask & U_DRAW_VISIBLE) // Next record is visible... + && + ( + ( !(d->mask & U_DRAW_ONLYTO) ) // Non *TO records cannot be followed by any Visible + || + ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) ) // *TO records can only be followed by other *TO records + ) + ) + ) + ){ +// std::cout << "PATH DRAW at TOP" << std::endl; + *(d->outsvg) += " drawtype){ // explicit draw type EMR record + output_style(d, d->drawtype); + } + else if(d->mask & U_DRAW_CLOSED){ // implicit draw type + output_style(d, U_EMR_STROKEANDFILLPATH); + } + else { + output_style(d, U_EMR_STROKEPATH); + } + *(d->outsvg) += "\n\t"; + *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! + *(d->outsvg) += *(d->path); + *(d->outsvg) += " \" /> \n"; + *(d->path) = ""; + // reset the flags + d->mask = 0; + d->drawtype = 0; + } +// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; + + switch (lpEMFR->iType) + { + case U_EMR_HEADER: + { + dbg_str << "\n"; + + *(d->outdef) += "\n"; + + if (d->pDesc) { + *(d->outdef) += "\n"; + } + + PU_EMRHEADER pEmr = (PU_EMRHEADER) lpEMFR; + SVGOStringStream tmp_outdef; + tmp_outdef << "xDPI = 2540; + d->yDPI = 2540; + + d->dc[d->level].PixelsInX = pEmr->rclFrame.right; // - pEmr->rclFrame.left; + d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom; // - pEmr->rclFrame.top; + + d->MMX = d->dc[d->level].PixelsInX / 100.0; + d->MMY = d->dc[d->level].PixelsInY / 100.0; + + d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM; + d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM; + + /* + calculate ratio of Inkscape dpi/device dpi + This can cause problems later due to accuracy limits in the EMF. A super high resolution + EMF might have a final device_scale of 0.074998, and adjusting the (integer) device size + by 1 will still not get it exactly to 0.075. Later when the font size is calculated it + can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by + snapping font sizes to the nearest .01. + */ + if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx) + device_scale = PX_PER_MM*pEmr->szlMillimeters.cx/pEmr->szlDevice.cx; + + tmp_outdef << + " width=\"" << d->MMX << "mm\"\n" << + " height=\"" << d->MMY << "mm\">\n"; + *(d->outdef) += tmp_outdef.str().c_str(); + *(d->outdef) += ""; // temporary end of header + + // d->defs holds any defines which are read in. + + tmp_outsvg << "\n\n\n"; // start of main body + + if (pEmr->nHandles) { + d->n_obj = pEmr->nHandles; + d->emf_obj = new EMF_OBJECT[d->n_obj]; + + // Init the new emf_obj list elements to null, provided the + // dynamic allocation succeeded. + if ( d->emf_obj != NULL ) + { + for( int i=0; i < d->n_obj; ++i ) + d->emf_obj[i].lpEMFR = NULL; + } //if + + } else { + d->emf_obj = NULL; + } + + break; + } + case U_EMR_POLYBEZIER: + { + dbg_str << "\n"; + + PU_EMRPOLYBEZIER pEmr = (PU_EMRPOLYBEZIER) lpEMFR; + uint32_t i,j; + + if (pEmr->cptl<4) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << + pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; + + for (i=1; icptl; ) { + tmp_str << "\n\tC "; + for (j=0; j<3 && icptl; j++,i++) { + tmp_str << + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYGON: + { + dbg_str << "\n"; + + PU_EMRPOLYGON pEmr = (PU_EMRPOLYGON) lpEMFR; + uint32_t i; + + if (pEmr->cptl < 2) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << + pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; + + for (i=1; icptl; i++) { + tmp_str << + "\n\tL " << + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + + tmp_path << tmp_str.str().c_str(); + tmp_path << " z"; + + break; + } + case U_EMR_POLYLINE: + { + dbg_str << "\n"; + + PU_EMRPOLYLINE pEmr = (PU_EMRPOLYLINE) lpEMFR; + uint32_t i; + + if (pEmr->cptl<2) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << + pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; + + for (i=1; icptl; i++) { + tmp_str << + "\n\tL " << + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYBEZIERTO: + { + dbg_str << "\n"; + + PU_EMRPOLYBEZIERTO pEmr = (PU_EMRPOLYBEZIERTO) lpEMFR; + uint32_t i,j; + + d->mask |= emr_mask; + + for (i=0; icptl;) { + tmp_path << "\n\tC "; + for (j=0; j<3 && icptl; j++,i++) { + tmp_path << + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + } + + break; + } + case U_EMR_POLYLINETO: + { + dbg_str << "\n"; + + PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) lpEMFR; + uint32_t i; + + d->mask |= emr_mask; + + for (i=0; icptl;i++) { + tmp_path << + "\n\tL " << + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + } + + break; + } + case U_EMR_POLYPOLYLINE: + case U_EMR_POLYPOLYGON: + { + if (lpEMFR->iType == U_EMR_POLYPOLYLINE) + dbg_str << "\n"; + if (lpEMFR->iType == U_EMR_POLYPOLYGON) + dbg_str << "\n"; + + PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) lpEMFR; + unsigned int n, i, j; + + d->mask |= emr_mask; + + U_POINTL *aptl = (PU_POINTL) &pEmr->aPolyCounts[pEmr->nPolys]; + + i = 0; + for (n=0; nnPolys && icptl; n++) { + SVGOStringStream poly_path; + + poly_path << "\n\tM " << + pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << + pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; + i++; + + for (j=1; jaPolyCounts[n] && icptl; j++) { + poly_path << "\n\tL " << + pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << + pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; + i++; + } + + tmp_str << poly_path.str().c_str(); + if (lpEMFR->iType == U_EMR_POLYPOLYGON) + tmp_str << " z"; + tmp_str << " \n"; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_SETWINDOWEXTEX: + { + dbg_str << "\n"; + + PU_EMRSETWINDOWEXTEX pEmr = (PU_EMRSETWINDOWEXTEX) lpEMFR; + + d->dc[d->level].sizeWnd = pEmr->szlExtent; + + if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; + if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX; + d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY; + } + } + + if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { + d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; + } + + d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; + d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; + + if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; + } + else { + d->dc[d->level].ScaleInX = 1; + d->dc[d->level].ScaleInY = 1; + } + + break; + } + case U_EMR_SETWINDOWORGEX: + { + dbg_str << "\n"; + + PU_EMRSETWINDOWORGEX pEmr = (PU_EMRSETWINDOWORGEX) lpEMFR; + d->dc[d->level].winorg = pEmr->ptlOrigin; + break; + } + case U_EMR_SETVIEWPORTEXTEX: + { + dbg_str << "\n"; + + PU_EMRSETVIEWPORTEXTEX pEmr = (PU_EMRSETVIEWPORTEXTEX) lpEMFR; + + d->dc[d->level].sizeView = pEmr->szlExtent; + + if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { + d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; + if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { + d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX; + d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY; + } + } + + if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; + } + + d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; + d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; + + if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; + } + else { + d->dc[d->level].ScaleInX = 1; + d->dc[d->level].ScaleInY = 1; + } + + break; + } + case U_EMR_SETVIEWPORTORGEX: + { + dbg_str << "\n"; + + PU_EMRSETVIEWPORTORGEX pEmr = (PU_EMRSETVIEWPORTORGEX) lpEMFR; + d->dc[d->level].vieworg = pEmr->ptlOrigin; + break; + } + case U_EMR_SETBRUSHORGEX: dbg_str << "\n"; break; + case U_EMR_EOF: + { + dbg_str << "\n"; + + tmp_outsvg << "\n"; + tmp_outsvg << "\n"; + *(d->outsvg) = *(d->outdef) + *(d->defs) + *(d->outsvg); + OK=0; + break; + } + case U_EMR_SETPIXELV: dbg_str << "\n"; break; + case U_EMR_SETMAPPERFLAGS: dbg_str << "\n"; break; + case U_EMR_SETMAPMODE: dbg_str << "\n"; break; + case U_EMR_SETBKMODE: dbg_str << "\n"; break; + case U_EMR_SETPOLYFILLMODE: + { + dbg_str << "\n"; + + PU_EMRSETPOLYFILLMODE pEmr = (PU_EMRSETPOLYFILLMODE) lpEMFR; + d->dc[d->level].style.fill_rule.value = + (pEmr->iMode == U_ALTERNATE ? 0 : + pEmr->iMode == U_WINDING ? 1 : 0); + break; + } + case U_EMR_SETROP2: + { + dbg_str << "\n"; + PU_EMRSETROP2 pEmr = (PU_EMRSETROP2) lpEMFR; + d->dwRop2 = pEmr->iMode; + break; + } + case U_EMR_SETSTRETCHBLTMODE: + { + PU_EMRSETSTRETCHBLTMODE pEmr = (PU_EMRSETSTRETCHBLTMODE) lpEMFR; // from wingdi.h + BLTmode = pEmr->iMode; + dbg_str << "\n"; + break; + } + case U_EMR_SETTEXTALIGN: + { + dbg_str << "\n"; + + PU_EMRSETTEXTALIGN pEmr = (PU_EMRSETTEXTALIGN) lpEMFR; + d->dc[d->level].textAlign = pEmr->iMode; + break; + } + case U_EMR_SETCOLORADJUSTMENT: + dbg_str << "\n"; + break; + case U_EMR_SETTEXTCOLOR: + { + dbg_str << "\n"; + + PU_EMRSETTEXTCOLOR pEmr = (PU_EMRSETTEXTCOLOR) lpEMFR; + d->dc[d->level].textColor = pEmr->crColor; + d->dc[d->level].textColorSet = true; + break; + } + case U_EMR_SETBKCOLOR: + { + dbg_str << "\n"; + + PU_EMRSETBKCOLOR pEmr = (PU_EMRSETBKCOLOR) lpEMFR; + d->dc[d->level].bkColor = pEmr->crColor; + d->dc[d->level].bkColorSet = true; + break; + } + case U_EMR_OFFSETCLIPRGN: dbg_str << "\n"; break; + case U_EMR_MOVETOEX: + { + dbg_str << "\n"; + + PU_EMRMOVETOEX pEmr = (PU_EMRMOVETOEX) lpEMFR; + + d->mask |= emr_mask; + + d->dc[d->level].cur = pEmr->ptl; + + tmp_path << + "\n\tM " << + pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << + pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + break; + } + case U_EMR_SETMETARGN: dbg_str << "\n"; break; + case U_EMR_EXCLUDECLIPRECT: dbg_str << "\n"; break; + case U_EMR_INTERSECTCLIPRECT: + { + dbg_str << "\n"; + + PU_EMRINTERSECTCLIPRECT pEmr = (PU_EMRINTERSECTCLIPRECT) lpEMFR; + U_RECTL rc = pEmr->rclClip; + clipset = true; + if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) + break; + rc_old = rc; + + double l = pix_to_x_point( d, rc.left, rc.top ); + double t = pix_to_y_point( d, rc.left, rc.top ); + double r = pix_to_x_point( d, rc.right, rc.bottom ); + double b = pix_to_y_point( d, rc.right, rc.bottom ); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\nid) << "\" >"; + tmp_rectangle << "\n"; + tmp_rectangle << "\n"; + + *(d->outdef) += tmp_rectangle.str().c_str(); + *(d->path) = ""; + break; + } + case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "\n"; break; + case U_EMR_SCALEWINDOWEXTEX: dbg_str << "\n"; break; + case U_EMR_SAVEDC: + dbg_str << "\n"; + + if (d->level < EMF_MAX_DC) { + d->dc[d->level + 1] = d->dc[d->level]; + d->level = d->level + 1; + } + break; + case U_EMR_RESTOREDC: + { + dbg_str << "\n"; + + PU_EMRRESTOREDC pEmr = (PU_EMRRESTOREDC) lpEMFR; + int old_level = d->level; + if (pEmr->iRelative >= 0) { + if (pEmr->iRelative < d->level) + d->level = pEmr->iRelative; + } + else { + if (d->level + pEmr->iRelative >= 0) + d->level = d->level + pEmr->iRelative; + } + while (old_level > d->level) { + if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))) + delete[] d->dc[old_level].style.stroke_dash.dash; + old_level--; + } + break; + } + case U_EMR_SETWORLDTRANSFORM: + { + dbg_str << "\n"; + + PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM) lpEMFR; + d->dc[d->level].worldTransform = pEmr->xform; + break; + } + case U_EMR_MODIFYWORLDTRANSFORM: + { + dbg_str << "\n"; + + PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM) lpEMFR; + switch (pEmr->iMode) + { + case U_MWT_IDENTITY: + d->dc[d->level].worldTransform.eM11 = 1.0; + d->dc[d->level].worldTransform.eM12 = 0.0; + d->dc[d->level].worldTransform.eM21 = 0.0; + d->dc[d->level].worldTransform.eM22 = 1.0; + d->dc[d->level].worldTransform.eDx = 0.0; + d->dc[d->level].worldTransform.eDy = 0.0; + break; + case U_MWT_LEFTMULTIPLY: + { +// d->dc[d->level].worldTransform = pEmr->xform * worldTransform; + + float a11 = pEmr->xform.eM11; + float a12 = pEmr->xform.eM12; + float a13 = 0.0; + float a21 = pEmr->xform.eM21; + float a22 = pEmr->xform.eM22; + float a23 = 0.0; + float a31 = pEmr->xform.eDx; + float a32 = pEmr->xform.eDy; + float a33 = 1.0; + + float b11 = d->dc[d->level].worldTransform.eM11; + float b12 = d->dc[d->level].worldTransform.eM12; + //float b13 = 0.0; + float b21 = d->dc[d->level].worldTransform.eM21; + float b22 = d->dc[d->level].worldTransform.eM22; + //float b23 = 0.0; + float b31 = d->dc[d->level].worldTransform.eDx; + float b32 = d->dc[d->level].worldTransform.eDy; + //float b33 = 1.0; + + float c11 = a11*b11 + a12*b21 + a13*b31;; + float c12 = a11*b12 + a12*b22 + a13*b32;; + //float c13 = a11*b13 + a12*b23 + a13*b33;; + float c21 = a21*b11 + a22*b21 + a23*b31;; + float c22 = a21*b12 + a22*b22 + a23*b32;; + //float c23 = a21*b13 + a22*b23 + a23*b33;; + float c31 = a31*b11 + a32*b21 + a33*b31;; + float c32 = a31*b12 + a32*b22 + a33*b32;; + //float c33 = a31*b13 + a32*b23 + a33*b33;; + + d->dc[d->level].worldTransform.eM11 = c11;; + d->dc[d->level].worldTransform.eM12 = c12;; + d->dc[d->level].worldTransform.eM21 = c21;; + d->dc[d->level].worldTransform.eM22 = c22;; + d->dc[d->level].worldTransform.eDx = c31; + d->dc[d->level].worldTransform.eDy = c32; + + break; + } + case U_MWT_RIGHTMULTIPLY: + { +// d->dc[d->level].worldTransform = worldTransform * pEmr->xform; + + float a11 = d->dc[d->level].worldTransform.eM11; + float a12 = d->dc[d->level].worldTransform.eM12; + float a13 = 0.0; + float a21 = d->dc[d->level].worldTransform.eM21; + float a22 = d->dc[d->level].worldTransform.eM22; + float a23 = 0.0; + float a31 = d->dc[d->level].worldTransform.eDx; + float a32 = d->dc[d->level].worldTransform.eDy; + float a33 = 1.0; + + float b11 = pEmr->xform.eM11; + float b12 = pEmr->xform.eM12; + //float b13 = 0.0; + float b21 = pEmr->xform.eM21; + float b22 = pEmr->xform.eM22; + //float b23 = 0.0; + float b31 = pEmr->xform.eDx; + float b32 = pEmr->xform.eDy; + //float b33 = 1.0; + + float c11 = a11*b11 + a12*b21 + a13*b31;; + float c12 = a11*b12 + a12*b22 + a13*b32;; + //float c13 = a11*b13 + a12*b23 + a13*b33;; + float c21 = a21*b11 + a22*b21 + a23*b31;; + float c22 = a21*b12 + a22*b22 + a23*b32;; + //float c23 = a21*b13 + a22*b23 + a23*b33;; + float c31 = a31*b11 + a32*b21 + a33*b31;; + float c32 = a31*b12 + a32*b22 + a33*b32;; + //float c33 = a31*b13 + a32*b23 + a33*b33;; + + d->dc[d->level].worldTransform.eM11 = c11;; + d->dc[d->level].worldTransform.eM12 = c12;; + d->dc[d->level].worldTransform.eM21 = c21;; + d->dc[d->level].worldTransform.eM22 = c22;; + d->dc[d->level].worldTransform.eDx = c31; + d->dc[d->level].worldTransform.eDy = c32; + + break; + } +// case MWT_SET: + default: + d->dc[d->level].worldTransform = pEmr->xform; + break; + } + break; + } + case U_EMR_SELECTOBJECT: + { + dbg_str << "\n"; + + PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT) lpEMFR; + unsigned int index = pEmr->ihObject; + + if (index & U_STOCK_OBJECT) { + switch (index) { + case U_NULL_BRUSH: + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = false; + break; + case U_BLACK_BRUSH: + case U_DKGRAY_BRUSH: + case U_GRAY_BRUSH: + case U_LTGRAY_BRUSH: + case U_WHITE_BRUSH: + { + float val = 0; + switch (index) { + case U_BLACK_BRUSH: + val = 0.0 / 255.0; + break; + case U_DKGRAY_BRUSH: + val = 64.0 / 255.0; + break; + case U_GRAY_BRUSH: + val = 128.0 / 255.0; + break; + case U_LTGRAY_BRUSH: + val = 192.0 / 255.0; + break; + case U_WHITE_BRUSH: + val = 255.0 / 255.0; + break; + } + d->dc[d->level].style.fill.value.color.set( val, val, val ); + + d->dc[d->level].fill_mode = DRAW_PAINT; + d->dc[d->level].fill_set = true; + break; + } + case U_NULL_PEN: + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = false; + break; + case U_BLACK_PEN: + case U_WHITE_PEN: + { + float val = index == U_BLACK_PEN ? 0 : 1; + d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_width.value = 1.0; + d->dc[d->level].style.stroke.value.color.set( val, val, val ); + + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + + break; + } + } + } else { + if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) { + switch (d->emf_obj[index].type) + { + case U_EMR_CREATEPEN: + select_pen(d, index); + break; + case U_EMR_CREATEBRUSHINDIRECT: + case U_EMR_CREATEDIBPATTERNBRUSHPT: + case U_EMR_CREATEMONOBRUSH: + select_brush(d, index); + break; + case U_EMR_EXTCREATEPEN: + select_extpen(d, index); + break; + case U_EMR_EXTCREATEFONTINDIRECTW: + select_font(d, index); + break; + } + } + } + break; + } + case U_EMR_CREATEPEN: + { + dbg_str << "\n"; + + PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN) lpEMFR; + insert_object(d, pEmr->ihPen, U_EMR_CREATEPEN, lpEMFR); + break; + } + case U_EMR_CREATEBRUSHINDIRECT: + { + dbg_str << "\n"; + + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) lpEMFR; + insert_object(d, pEmr->ihBrush, U_EMR_CREATEBRUSHINDIRECT, lpEMFR); + break; + } + case U_EMR_DELETEOBJECT: + dbg_str << "\n"; + break; + case U_EMR_ANGLEARC: + dbg_str << "\n"; + break; + case U_EMR_ELLIPSE: + { + dbg_str << "\n"; + + PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE) lpEMFR; + U_RECTL rclBox = pEmr->rclBox; + + double l = pix_to_x_point( d, rclBox.left, rclBox.top ); + double t = pix_to_y_point( d, rclBox.left, rclBox.top ); + double r = pix_to_x_point( d, rclBox.right, rclBox.bottom ); + double b = pix_to_y_point( d, rclBox.right, rclBox.bottom ); + + double cx = (l + r) / 2.0; + double cy = (t + b) / 2.0; + double rx = fabs(l - r) / 2.0; + double ry = fabs(t - b) / 2.0; + + SVGOStringStream tmp_ellipse; + tmp_ellipse << "cx=\"" << cx << "\" "; + tmp_ellipse << "cy=\"" << cy << "\" "; + tmp_ellipse << "rx=\"" << rx << "\" "; + tmp_ellipse << "ry=\"" << ry << "\" "; + + d->mask |= emr_mask; + + *(d->outsvg) += " iType); // + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_ellipse.str().c_str(); + *(d->outsvg) += "/> \n"; + *(d->path) = ""; + break; + } + case U_EMR_RECTANGLE: + { + dbg_str << "\n"; + + PU_EMRRECTANGLE pEmr = (PU_EMRRECTANGLE) lpEMFR; + U_RECTL rc = pEmr->rclBox; + + double l = pix_to_x_point( d, rc.left, rc.top ); + double t = pix_to_y_point( d, rc.left, rc.top ); + double r = pix_to_x_point( d, rc.right, rc.bottom ); + double b = pix_to_y_point( d, rc.right, rc.bottom ); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << l << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << b << " "; + tmp_rectangle << "\n\tL " << l << " " << b << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= emr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_EMR_ROUNDRECT: + { + dbg_str << "\n"; + + PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT) lpEMFR; + U_RECTL rc = pEmr->rclBox; + U_SIZEL corner = pEmr->szlCorner; + double f = 4.*(sqrt(2) - 1)/3; + + double l = pix_to_x_point(d, rc.left, rc.top); + double t = pix_to_y_point(d, rc.left, rc.top); + double r = pix_to_x_point(d, rc.right, rc.bottom); + double b = pix_to_y_point(d, rc.right, rc.bottom); + double cnx = pix_to_size_point(d, corner.cx/2); + double cny = pix_to_size_point(d, corner.cy/2); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << l << ", " << t + cny << " "; + tmp_rectangle << "\n\tC " << l << ", " << t + (1-f)*cny << " " << l + (1-f)*cnx << ", " << t << " " << l + cnx << ", " << t << " "; + tmp_rectangle << "\n\tL " << r - cnx << ", " << t << " "; + tmp_rectangle << "\n\tC " << r - (1-f)*cnx << ", " << t << " " << r << ", " << t + (1-f)*cny << " " << r << ", " << t + cny << " "; + tmp_rectangle << "\n\tL " << r << ", " << b - cny << " "; + tmp_rectangle << "\n\tC " << r << ", " << b - (1-f)*cny << " " << r - (1-f)*cnx << ", " << b << " " << r - cnx << ", " << b << " "; + tmp_rectangle << "\n\tL " << l + cnx << ", " << b << " "; + tmp_rectangle << "\n\tC " << l + (1-f)*cnx << ", " << b << " " << l << ", " << b - (1-f)*cny << " " << l << ", " << b - cny << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= emr_mask; + + tmp_path << tmp_rectangle.str().c_str(); + break; + } + case U_EMR_ARC: + { + dbg_str << "\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); + tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0 ; + tmp_path << " 0 "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y)<< " "; + + d->mask |= emr_mask; + } + else { + dbg_str << "\n"; + } + break; + } + case U_EMR_CHORD: + { + dbg_str << "\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); + tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0 ; + tmp_path << " 0 "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y); + tmp_path << " z "; + d->mask |= emr_mask; + } + else { + dbg_str << "\n"; + } + break; + } + case U_EMR_PIE: + { + dbg_str << "\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + tmp_path << "\n\tM " << pix_to_x_point(d, center.x, center.y) << "," << pix_to_y_point(d, center.x, center.y); + tmp_path << "\n\tL " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); + tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0; + tmp_path << " 0 "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y); + tmp_path << " z "; + d->mask |= emr_mask; + } + else { + dbg_str << "\n"; + } + break; + } + case U_EMR_SELECTPALETTE: dbg_str << "\n"; break; + case U_EMR_CREATEPALETTE: dbg_str << "\n"; break; + case U_EMR_SETPALETTEENTRIES: dbg_str << "\n"; break; + case U_EMR_RESIZEPALETTE: dbg_str << "\n"; break; + case U_EMR_REALIZEPALETTE: dbg_str << "\n"; break; + case U_EMR_EXTFLOODFILL: dbg_str << "\n"; break; + case U_EMR_LINETO: + { + dbg_str << "\n"; + + PU_EMRLINETO pEmr = (PU_EMRLINETO) lpEMFR; + + d->mask |= emr_mask; + + tmp_path << + "\n\tL " << + pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << + pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + break; + } + case U_EMR_ARCTO: + { + dbg_str << "\n"; + U_PAIRF center,start,end,size; + int f1; + int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); + if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ + // draw a line from current position to start + tmp_path << "\n\tL " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); + tmp_path << "\n\tM " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); + tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0 ; + tmp_path << " 0 "; + tmp_path << " " << f1 << "," << f2 << " "; + tmp_path << pix_to_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y)<< " "; + + d->mask |= emr_mask; + } + else { + dbg_str << "\n"; + } + break; + } + case U_EMR_POLYDRAW: dbg_str << "\n"; break; + case U_EMR_SETARCDIRECTION: + { + dbg_str << "\n"; + PU_EMRSETARCDIRECTION pEmr = (PU_EMRSETARCDIRECTION) lpEMFR; + if(d->arcdir == U_AD_CLOCKWISE || d->arcdir == U_AD_COUNTERCLOCKWISE){ // EMF file could be corrupt + d->arcdir = pEmr->iArcDirection; + } + break; + } + case U_EMR_SETMITERLIMIT: + { + dbg_str << "\n"; + + PU_EMRSETMITERLIMIT pEmr = (PU_EMRSETMITERLIMIT) lpEMFR; + + //The function takes a float but saves a 32 bit int in the U_EMR_SETMITERLIMIT record. + float miterlimit = *((int32_t *) &(pEmr->eMiterLimit)); + d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size + if (d->dc[d->level].style.stroke_miterlimit.value < 2) + d->dc[d->level].style.stroke_miterlimit.value = 2.0; + break; + } + case U_EMR_BEGINPATH: + { + dbg_str << "\n"; + // The next line should never be needed, should have been handled before main switch + *(d->path) = ""; + d->mask |= emr_mask; + break; + } + case U_EMR_ENDPATH: + { + dbg_str << "\n"; + d->mask &= (0xFFFFFFFF - U_DRAW_ONLYTO); // clear the OnlyTo bit (it might not have been set), prevents any further path extension + break; + } + case U_EMR_CLOSEFIGURE: + { + dbg_str << "\n"; + // EMF may contain multiple closefigures on one path + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + break; + } + case U_EMR_FILLPATH: + { + dbg_str << "\n"; + if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths + if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + } + d->mask |= emr_mask; + d->drawtype = U_EMR_FILLPATH; + } + break; + } + case U_EMR_STROKEANDFILLPATH: + { + dbg_str << "\n"; + if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths + if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + } + d->mask |= emr_mask; + d->drawtype = U_EMR_STROKEANDFILLPATH; + } + break; + } + case U_EMR_STROKEPATH: + { + dbg_str << "\n"; + if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths + d->mask |= emr_mask; + d->drawtype = U_EMR_STROKEPATH; + } + break; + } + case U_EMR_FLATTENPATH: dbg_str << "\n"; break; + case U_EMR_WIDENPATH: dbg_str << "\n"; break; + case U_EMR_SELECTCLIPPATH: dbg_str << "\n"; break; + case U_EMR_ABORTPATH: + { + dbg_str << "\n"; + *(d->path) = ""; + d->drawtype = 0; + break; + } + case U_EMR_UNDEF69: dbg_str << "\n"; break; + case U_EMR_COMMENT: + { + dbg_str << "\n"; + + PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT) lpEMFR; + + char *szTxt = (char *) pEmr->Data; + + for (uint32_t i = 0; i < pEmr->cbData; i++) { + if ( *szTxt) { + if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) { + tmp_str << *szTxt; + } + szTxt++; + } + } + + if (0 && strlen(tmp_str.str().c_str())) { + tmp_outsvg << " \n"; + } + + break; + } + case U_EMR_FILLRGN: dbg_str << "\n"; break; + case U_EMR_FRAMERGN: dbg_str << "\n"; break; + case U_EMR_INVERTRGN: dbg_str << "\n"; break; + case U_EMR_PAINTRGN: dbg_str << "\n"; break; + case U_EMR_EXTSELECTCLIPRGN: + { + dbg_str << "\n"; + + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) lpEMFR; + if (pEmr->iMode == U_RGN_COPY) + clipset = false; + break; + } + case U_EMR_BITBLT: + { + dbg_str << "\n"; + + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR; + // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at + // least it leaves objects where the operations should have been. + if (!pEmr->cbBmiSrc) { + // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead + double l = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double t = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double r = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + double b = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "\n\tM " << l << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << b << " "; + tmp_rectangle << "\n\tL " << l << " " << b << " "; + tmp_rectangle << "\n\tz"; + + d->mask |= emr_mask; + d->dwRop3 = pEmr->dwRop; // we will try to approximate SOME of these + d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that + + tmp_path << tmp_rectangle.str().c_str(); + } + break; + } + case U_EMR_STRETCHBLT: dbg_str << "\n"; break; + case U_EMR_MASKBLT: dbg_str << "\n"; break; + case U_EMR_PLGBLT: dbg_str << "\n"; break; + case U_EMR_SETDIBITSTODEVICE: dbg_str << "\n"; break; + case U_EMR_STRETCHDIBITS: + { + // Some applications use multiple EMF operations, including multiple STRETCHDIBITS to create + // images with transparent regions. PowerPoint does this with rotated images, for instance. + // Parsing all of that to derive a single resultant image object is left for a later version + // of this code. In the meantime, every STRETCHDIBITS goes directly to an image. The Inkscape + // user can sort out transparency later using Gimp, if need be. + + PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) lpEMFR; + double l = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double t = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double r = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); + double b = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); + SVGOStringStream tmp_image; + tmp_image << " y=\"" << t << "\"\n x=\"" << l <<"\"\n "; + + // The image ID is filled in much later when tmp_image is converted + + tmp_image << " xlink:href=\"data:image/png;base64,"; + + MEMPNG mempng; // PNG in memory comes back in this + mempng.buffer = NULL; + + char *rgba_px=NULL; // RGBA pixels + char *px=NULL; // DIB pixels + uint32_t width, height, colortype, numCt, invert; + PU_RGBQUAD ct = NULL; + if(!pEmr->cbBitsSrc || + !pEmr->cbBmiSrc || + (pEmr->iUsageSrc != U_DIB_RGB_COLORS) || + !get_DIB_params( // this returns pointers and values, but allocates no memory + pEmr, + pEmr->offBitsSrc, + pEmr->offBmiSrc, + &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 + 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, + rgba_px, + 4 * width * height); + free(rgba_px); + } + } + if(mempng.buffer){ + gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + free(mempng.buffer); + tmp_image << base64String ; + g_free(base64String); + } + else { + // insert a random 3x4 blotch otherwise + tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; + } + + tmp_image << "\"\n height=\"" << b-t+1 << "\"\n width=\"" << r-l+1 << "\"\n"; + + *(d->outsvg) += "\n\t outsvg) += tmp_image.str().c_str(); + *(d->outsvg) += "/> \n"; + *(d->path) = ""; + + dbg_str << "\n"; + break; + } + case U_EMR_EXTCREATEFONTINDIRECTW: + { + dbg_str << "\n"; + + PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) lpEMFR; + insert_object(d, pEmr->ihFont, U_EMR_EXTCREATEFONTINDIRECTW, lpEMFR); + break; + } + case U_EMR_EXTTEXTOUTA: + case U_EMR_EXTTEXTOUTW: + case U_EMR_SMALLTEXTOUT: + { + dbg_str << "\n"; + + PU_EMREXTTEXTOUTW pEmr = (PU_EMREXTTEXTOUTW) lpEMFR; + PU_EMRSMALLTEXTOUT pEmrS = (PU_EMRSMALLTEXTOUT) lpEMFR; + + double x1,y1; + int roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields, only used with U_EMR_SMALLTEXTOUT + int cChars; + if(lpEMFR->iType==U_EMR_SMALLTEXTOUT){ + x1 = pEmrS->Dest.x; + y1 = pEmrS->Dest.y; + cChars = pEmrS->cChars; + if(!(pEmrS->fuOptions & U_ETO_NO_RECT)){ roff += sizeof(U_RECTL); } + } + else { + x1 = pEmr->emrtext.ptlReference.x; + y1 = pEmr->emrtext.ptlReference.y; + cChars = 0; + } + + 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); + + double dfact; + if (d->dc[d->level].textAlign & U_TA_BASEBIT){ dfact = 0.00; } // alignments 0x10 to U_TA_BASELINE 0x18 + else if(d->dc[d->level].textAlign & U_TA_BOTTOM){ dfact = -0.35; } // alignments U_TA_BOTTOM 0x08 to 0x0E, factor is approximate + else { dfact = 0.85; } // alignments U_TA_TOP 0x00 to 0x07, factor is approximate + if (d->dc[d->level].style.baseline_shift.value) { + x += dfact * std::sin(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); + y += dfact * std::cos(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); + } + else { + y += dfact * fabs(d->dc[d->level].style.font_size.computed); + } + + uint32_t *dup_wt = NULL; + + if( lpEMFR->iType==U_EMR_EXTTEXTOUTA){ + /* These should be JUST ASCII, but they might not be... + If it holds Utf-8 or plain ASCII the first call will succeed. + If not, assume that it holds Latin1. + If that fails then someting is really screwed up! + */ + dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL); + if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL); + if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars); + } + else if( lpEMFR->iType==U_EMR_EXTTEXTOUTW){ + dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL); + if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars); + } + else { // U_EMR_SMALLTEXTOUT + if(pEmrS->fuOptions & U_ETO_SMALL_CHARS){ + dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, NULL); + } + else { + dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmrS + roff), cChars, NULL); + } + if(!dup_wt)dup_wt = unknown_chars(cChars); + } + + msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats + + if(NonToUnicode(dup_wt, d->dc[d->level].tstyle.font_family.value)){ + g_free(d->dc[d->level].tstyle.font_family.value); + d->dc[d->level].tstyle.font_family.value = g_strdup("Times New Roman"); + } + + char *ansi_text; + ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, NULL); + free(dup_wt); + + if (ansi_text) { +// gchar *p = ansi_text; +// while (*p) { +// if (*p < 32 || *p >= 127) { +// g_free(ansi_text); +// ansi_text = g_strdup(""); +// break; +// } +// p++; +// } + + SVGOStringStream ts; + + gchar *escaped_text = g_markup_escape_text(ansi_text, -1); + +// float text_rgb[3]; +// sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb ); + +// if (!d->dc[d->level].textColorSet) { +// d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]), +// SP_COLOR_F_TO_U(text_rgb[1]), +// SP_COLOR_F_TO_U(text_rgb[2])); +// } + + char tmp[128]; + snprintf(tmp, 127, + "fill:#%02x%02x%02x;", + U_RGBAGetR(d->dc[d->level].textColor), + U_RGBAGetG(d->dc[d->level].textColor), + U_RGBAGetB(d->dc[d->level].textColor)); + + bool i = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_ITALIC); + //bool o = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE); + bool b = (d->dc[d->level].style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) || + (d->dc[d->level].style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->dc[d->level].style.font_weight.value <= SP_CSS_FONT_WEIGHT_900); + // EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left + int lcr = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? 2 : ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? 0 : 1; + + ts << " id++) << "\"\n"; + ts << " xml:space=\"preserve\"\n"; + ts << " x=\"" << x << "\"\n"; + ts << " y=\"" << y << "\"\n"; + if (d->dc[d->level].style.baseline_shift.value) { + ts << " transform=\"" + << "rotate(-" << d->dc[d->level].style.baseline_shift.value + << " " << x << " " << y << ")" + << "\"\n"; + } + ts << " style=\"" + << "font-size:" << fabs(d->dc[d->level].style.font_size.computed) << "px;" + << tmp + << "font-style:" << (i ? "italic" : "normal") << ";" + << "font-weight:" << (b ? "bold" : "normal") << ";" + << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";" + << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";" + << "font-family:" << d->dc[d->level].tstyle.font_family.value << ";" + << "\"\n"; + ts << " >"; + ts << escaped_text; + ts << "\n"; + + *(d->outsvg) += ts.str().c_str(); + + g_free(escaped_text); + free(ansi_text); + } + + break; + } + case U_EMR_POLYBEZIER16: + { + dbg_str << "\n"; + + PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i,j; + + if (pEmr->cpts<4) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << + pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; + + for (i=1; icpts; ) { + tmp_str << "\n\tC "; + for (j=0; j<3 && icpts; j++,i++) { + tmp_str << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + } + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYGON16: + { + dbg_str << "\n"; + + PU_EMRPOLYGON16 pEmr = (PU_EMRPOLYGON16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + SVGOStringStream tmp_poly; + unsigned int i; + unsigned int first = 0; + + d->mask |= emr_mask; + + // skip the first point? + tmp_poly << "\n\tM " << + pix_to_x_point( d, apts[first].x, apts[first].y ) << " " << + pix_to_y_point( d, apts[first].x, apts[first].y ) << " "; + + for (i=first+1; icpts; i++) { + tmp_poly << "\n\tL " << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + } + + tmp_path << tmp_poly.str().c_str(); + tmp_path << "\n\tz"; + d->mask |= U_DRAW_CLOSED; + + break; + } + case U_EMR_POLYLINE16: + { + dbg_str << "\n"; + + PU_EMRPOLYLINE16 pEmr = (PU_EMRPOLYLINE16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i; + + if (pEmr->cpts<2) + break; + + d->mask |= emr_mask; + + tmp_str << + "\n\tM " << + pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << + pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; + + for (i=1; icpts; i++) { + tmp_str << + "\n\tL " << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYBEZIERTO16: + { + dbg_str << "\n"; + + PU_EMRPOLYBEZIERTO16 pEmr = (PU_EMRPOLYBEZIERTO16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i,j; + + d->mask |= emr_mask; + + for (i=0; icpts;) { + tmp_path << "\n\tC "; + for (j=0; j<3 && icpts; j++,i++) { + tmp_path << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + } + } + + break; + } + case U_EMR_POLYLINETO16: + { + dbg_str << "\n"; + + PU_EMRPOLYLINETO16 pEmr = (PU_EMRPOLYLINETO16) lpEMFR; + PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ? + uint32_t i; + + d->mask |= emr_mask; + + for (i=0; icpts;i++) { + tmp_path << + "\n\tL " << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + } + + break; + } + case U_EMR_POLYPOLYLINE16: + case U_EMR_POLYPOLYGON16: + { + if (lpEMFR->iType == U_EMR_POLYPOLYLINE16) + dbg_str << "\n"; + if (lpEMFR->iType == U_EMR_POLYPOLYGON16) + dbg_str << "\n"; + + PU_EMRPOLYPOLYGON16 pEmr = (PU_EMRPOLYPOLYGON16) lpEMFR; + unsigned int n, i, j; + + d->mask |= emr_mask; + + PU_POINT16 apts = (PU_POINT16) &pEmr->aPolyCounts[pEmr->nPolys]; + + i = 0; + for (n=0; nnPolys && icpts; n++) { + SVGOStringStream poly_path; + + poly_path << "\n\tM " << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + i++; + + for (j=1; jaPolyCounts[n] && icpts; j++) { + poly_path << "\n\tL " << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + i++; + } + + tmp_str << poly_path.str().c_str(); + if (lpEMFR->iType == U_EMR_POLYPOLYGON16) + tmp_str << " z"; + tmp_str << " \n"; + } + + tmp_path << tmp_str.str().c_str(); + + break; + } + case U_EMR_POLYDRAW16: dbg_str << "\n"; break; + case U_EMR_CREATEMONOBRUSH: + { + dbg_str << "\n"; + + PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) lpEMFR; + insert_object(d, pEmr->ihBrush, U_EMR_CREATEMONOBRUSH, lpEMFR); + break; + } + case U_EMR_CREATEDIBPATTERNBRUSHPT: + { + dbg_str << "\n"; + + PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) lpEMFR; + insert_object(d, pEmr->ihBrush, U_EMR_CREATEDIBPATTERNBRUSHPT, lpEMFR); + break; + } + case U_EMR_EXTCREATEPEN: + { + dbg_str << "\n"; + + PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN) lpEMFR; + insert_object(d, pEmr->ihPen, U_EMR_EXTCREATEPEN, lpEMFR); + break; + } + case U_EMR_POLYTEXTOUTA: dbg_str << "\n"; break; + case U_EMR_POLYTEXTOUTW: dbg_str << "\n"; break; + case U_EMR_SETICMMODE: + { + dbg_str << "\n"; +#if 0 + PU_EMRENABLEICM pEmr = (PU_EMRENABLEICM) lpEMFR; + ICMmode= pEmr->iMode; +#endif //0 + break; + } + case U_EMR_CREATECOLORSPACE: dbg_str << "\n"; break; + case U_EMR_SETCOLORSPACE: dbg_str << "\n"; break; + case U_EMR_DELETECOLORSPACE: dbg_str << "\n"; break; + case U_EMR_GLSRECORD: dbg_str << "\n"; break; + case U_EMR_GLSBOUNDEDRECORD: dbg_str << "\n"; break; + case U_EMR_PIXELFORMAT: dbg_str << "\n"; break; + case U_EMR_DRAWESCAPE: dbg_str << "\n"; break; + case U_EMR_EXTESCAPE: dbg_str << "\n"; break; + case U_EMR_UNDEF107: dbg_str << "\n"; break; + // U_EMR_SMALLTEXTOUT is handled with U_EMR_EXTTEXTOUTA/W above + case U_EMR_FORCEUFIMAPPING: dbg_str << "\n"; break; + case U_EMR_NAMEDESCAPE: dbg_str << "\n"; break; + case U_EMR_COLORCORRECTPALETTE: dbg_str << "\n"; break; + case U_EMR_SETICMPROFILEA: dbg_str << "\n"; break; + case U_EMR_SETICMPROFILEW: dbg_str << "\n"; break; + case U_EMR_ALPHABLEND: dbg_str << "\n"; break; + case U_EMR_SETLAYOUT: dbg_str << "\n"; break; + case U_EMR_TRANSPARENTBLT: dbg_str << "\n"; break; + case U_EMR_UNDEF117: dbg_str << "\n"; break; + case U_EMR_GRADIENTFILL: dbg_str << "\n"; break; + /* Gradient fill is doable for rectangles because those correspond to linear gradients. However, + the general case for the triangle fill, with a different color in each corner of the triangle, + has no SVG equivalent and cannot be easily emulated with SVG gradients. Except that so far + I (DM) have not been able to make an EMF with a rectangular gradientfill record which is not + completely toxic to other EMF readers. So far now, do nothing. + */ + case U_EMR_SETLINKEDUFIS: dbg_str << "\n"; break; + case U_EMR_SETTEXTJUSTIFICATION: dbg_str << "\n"; break; + case U_EMR_COLORMATCHTOTARGETW: dbg_str << "\n"; break; + case U_EMR_CREATECOLORSPACEW: dbg_str << "\n"; break; + default: + dbg_str << "\n"; + break; + } //end of switch +// When testing, uncomment the following to place a comment for each processed EMR record in the SVG +// *(d->outsvg) += dbg_str.str().c_str(); + *(d->outsvg) += tmp_outsvg.str().c_str(); + *(d->path) += tmp_path.str().c_str(); + + } //end of while +// When testing, uncomment the following to show the final SVG derived from the EMF +// std::cout << *(d->outsvg) << std::endl; + + return 1; +} + + +// Aldus Placeable Header =================================================== +// Since we are a 32bit app, we have to be sure this structure compiles to +// be identical to a 16 bit app's version. To do this, we use the #pragma +// to adjust packing, we use a uint16_t for the hmf handle, and a SMALL_RECT +// for the bbox rectangle. +#pragma pack( push ) +#pragma pack( 2 ) +typedef struct _SMALL_RECT { + int16_t Left; + int16_t Top; + int16_t Right; + int16_t Bottom; +} SMALL_RECT, *PSMALL_RECT; +typedef struct +{ + uint32_t dwKey; + uint16_t hmf; + SMALL_RECT bbox; + uint16_t wInch; + uint32_t dwReserved; + uint16_t wCheckSum; +} APMHEADER, *PAPMHEADER; +#pragma pack( pop ) + + +SPDocument * +Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) +{ + EMF_CALLBACK_DATA d; + + memset(&d, 0, sizeof(d)); + + d.dc[0].worldTransform.eM11 = 1.0; + d.dc[0].worldTransform.eM12 = 0.0; + d.dc[0].worldTransform.eM21 = 0.0; + d.dc[0].worldTransform.eM22 = 1.0; + d.dc[0].worldTransform.eDx = 0.0; + d.dc[0].worldTransform.eDy = 0.0; + + 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.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(emf_readdata(uri, &contents, &length))return(NULL); + + d.pDesc = NULL; + + + (void) myEnhMetaFileProc(contents,length, &d); + free(contents); + + + if (d.pDesc) + free( d.pDesc ); + +// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; + + SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); + + delete d.outsvg; + delete d.path; + delete d.outdef; + delete d.defs; + if(d.hatches.count){ free(d.hatches.strings); } + if(d.images.count){ free(d.images.strings); } + + if (d.emf_obj) { + int i; + for (i=0; i\n" + "" N_("EMF Input") "\n" + "org.inkscape.input.emf\n" + "\n" + ".emf\n" + "image/x-emf\n" + "" N_("Enhanced Metafiles (*.emf)") "\n" + "" N_("Enhanced Metafiles") "\n" + "org.inkscape.output.emf\n" + "\n" + "", new Emf()); + + /* EMF out */ + Inkscape::Extension::build_from_mem( + "\n" + "" N_("EMF Output") "\n" + "org.inkscape.output.emf\n" + "true\n" + "true\n" + "true\n" + "true\n" + "false\n" + "false\n" + "false\n" + "false\n" + "false\n" + "\n" + ".emf\n" + "image/x-emf\n" + "" N_("Enhanced Metafile (*.emf)") "\n" + "" N_("Enhanced Metafile") "\n" + "\n" + "", new Emf()); + + return; +} + + +} } } /* namespace Inkscape, Extension, Implementation */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h new file mode 100644 index 000000000..62b5c6e1c --- /dev/null +++ b/src/extension/internal/emf-inout.h @@ -0,0 +1,55 @@ +/** @file + * @brief Enhanced Metafile Input/Output + */ +/* Authors: + * Ulf Erikson + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef SEEN_EXTENSION_INTERNAL_EMF_H +#define SEEN_EXTENSION_INTERNAL_EMF_H + +#include "extension/implementation/implementation.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { + +class Emf : Inkscape::Extension::Implementation::Implementation { //This is a derived class + +public: + Emf(); // Empty constructor + + virtual ~Emf();//Destructor + + bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) + + void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename + SPDocument *doc, + gchar const *filename); + + virtual SPDocument *open( Inkscape::Extension::Input *mod, + const gchar *uri ); + + static void init(void);//Initialize the class + +private: +}; + +} } } /* namespace Inkscape, Extension, Implementation */ + + +#endif /* EXTENSION_INTERNAL_EMF_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp new file mode 100644 index 000000000..c70e5bd84 --- /dev/null +++ b/src/extension/internal/emf-print.cpp @@ -0,0 +1,2146 @@ +/** @file + * @brief Enhanced Metafile printing + */ +/* Authors: + * Ulf Erikson + * Jon A. Cruz + * 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 "emf-print.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 +extern "C" { +#include "libunicode-convert/unicode-convert.h" +} + + +namespace Inkscape { +namespace Extension { +namespace Internal { + +#define PXPERMETER 2835 + + +enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT}; + +struct FFNEXUS { + char *fontname; //Font name + FFNEXUS *next; //link to next nexus, NULL if this is the last + double f1; //Vertical (rotating) offset factor (* font height) + double f2; //Vertical (nonrotating) offset factor (* font height) + double f3; //Horizontal (nonrotating) offset factor (* font height) + }; + +struct GRADVALUES{ + Geom::Point p1; // center or start + Geom::Point p2; // xhandle or end + Geom::Point p3; // yhandle or unused + double r; // radius or unused + void *grad; // to access the stops information + int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value + U_COLORREF bgc; // document background color, this is as good a place as any to keep it + float rgb[3]; // also background color, but as 0-1 float. + }; + +/* globals */ +static double PX2WORLD = 20.0f; +static U_XFORM worldTransform; +static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch; +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 GRADVALUES gv; + +void 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(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 { + 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 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){ + g_message("Programming error search_long_fflist called before read_system_fflist\n"); + throw "boom"; + } + ptr=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)); + } + else { + ptr=short_fflist; + while(ptr->next){ ptr=ptr->next; } + ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS)); + ptr=ptr->next; + } + ptr->fontname=strdup(tmp->fontname); + *f1 = ptr->f1 = tmp->f1; + *f2 = ptr->f2 = tmp->f2; + *f3 = ptr->f3 = tmp->f3; + ptr->next=NULL; +} + +/* Looks for the fontname in the short list. If it does not find it, it looks in the long_fflist. +Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default. +*/ +void 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){ + 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 + 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 smuggle_adx_out(const char *string, uint32_t **adx, int *ndx, float scale){ + float fdx; + int i; + uint32_t *ladx; + const char *cptr=&string[strlen(string)+1]; + + *adx=NULL; + sscanf(cptr,"%7d",ndx); + if(!*ndx)return; // this could happen with an empty string + cptr += 7; + ladx = (uint32_t *) malloc(*ndx * sizeof(uint32_t) ); + *adx=ladx; + for(i=0; i<*ndx; i++,cptr+=7, ladx++){ + sscanf(cptr,"%7f",&fdx); + *ladx=(uint32_t) round(fdx * scale); + } +} + +/* convert an 0RGB color to EMF U_COLORREF. +inverse of sethexcolor() in emf-inout.cpp +*/ +U_COLORREF gethexcolor(uint32_t color){ + + U_COLORREF out; + out = U_RGB( + (color >> 16) & 0xFF, + (color >> 8) & 0xFF, + (color >> 0) & 0xFF + ); + return(out); +} + + +/* Translate inkscape weights to EMF weights. +*/ +uint32_t transweight(const unsigned int inkweight){ + if(inkweight == SP_CSS_FONT_WEIGHT_400)return(U_FW_NORMAL); + if(inkweight == SP_CSS_FONT_WEIGHT_100)return(U_FW_THIN); + if(inkweight == SP_CSS_FONT_WEIGHT_200)return(U_FW_EXTRALIGHT); + if(inkweight == SP_CSS_FONT_WEIGHT_300)return(U_FW_LIGHT); + // 400 is tested first, as it is the most common case + if(inkweight == SP_CSS_FONT_WEIGHT_500)return(U_FW_MEDIUM); + if(inkweight == SP_CSS_FONT_WEIGHT_600)return(U_FW_SEMIBOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_700)return(U_FW_BOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_800)return(U_FW_EXTRABOLD); + if(inkweight == SP_CSS_FONT_WEIGHT_900)return(U_FW_HEAVY); + return(U_FW_NORMAL); +} + +PrintEmf::PrintEmf (void): + _width(0), + _height(0), + hbrush(0), + hbrushOld(0), + hpen(0), + use_stroke(false), + use_fill(false), + simple_shape(false) +{ +} + + +PrintEmf::~PrintEmf (void) +{ + + /* restore default signal handling for SIGPIPE */ +#if !defined(_WIN32) && !defined(__WIN32__) + (void) signal(SIGPIPE, SIG_DFL); +#endif + return; +} + + +unsigned int PrintEmf::setup (Inkscape::Extension::Print * /*mod*/) +{ + return TRUE; +} + + +unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) +{ + U_SIZEL szlDev, szlMm; + U_RECTL rclBounds, rclFrame; + char *rec; + + gchar const *utf8_fn = mod->get_param_string("destination"); + FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); + FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); + FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); + FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); + + (void) emf_start(utf8_fn, 1000000, 250000, &et); // Initialize the et structure + (void) htable_create(128, 128, &eht); // Initialize the eht structure + + char *ansi_uri = (char *) utf8_fn; + + // width and height in px + _width = doc->getWidth(); + _height = doc->getHeight(); + + 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); + + float dwInchesX = d.width(); + float dwInchesY = d.height(); + + // dwInchesX x dwInchesY in micrometer units, dpi=90 -> 3543.3 dpm + (void) drawing_size((int) ceil(dwInchesX*25.4), (int) ceil(dwInchesY*25.4), 3.543307, &rclBounds, &rclFrame); + + // set up the device as A4 horizontal, 47.244094 dpmm (1200 dpi) + int MMX = 216; + int MMY = 279; + (void) device_size(MMX, MMY, 47.244094, &szlDev, &szlMm); // Drawing: A4 horizontal, 42744 dpm (1200 dpi) + int PixelsX = szlDev.cx; + int PixelsY = szlDev.cy; + + // set up the description: (version string)0(file)00 + char buff[1024]; + memset(buff,0, sizeof(buff)); + char *p1 = strrchr(ansi_uri, '\\'); + char *p2 = strrchr(ansi_uri, '/'); + char *p = MAX(p1, p2); + if (p) + p++; + else + p = ansi_uri; + snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)\1%s\1", Inkscape::version_string, __DATE__,p); + uint16_t *Description = U_Utf8ToUtf16le(buff, 0, NULL); + int cbDesc = 2 + wchar16len(Description); // also count the final terminator + (void) U_Utf16leEdit(Description, '\1', '\0'); // swap the temporary \1 characters for nulls + + // construct the EMRHEADER record and append it to the EMF in memory + rec = U_EMRHEADER_set( rclBounds, rclFrame, NULL, cbDesc, Description, szlDev, szlMm, 0); + free(Description); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at EMRHEADER"; + } + + + // Simplest mapping mode, supply all coordinates in pixels + rec = U_EMRSETMAPMODE_set(U_MM_TEXT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at EMRSETMAPMODE"; + } + + + // Correct for dpi in EMF vs dpi in Inkscape (always 90?) + // Also correct for the scaling in PX2WORLD, which is set to 20. Doesn't hurt for high resolution, + // helps prevent rounding errors for low resolution EMF. Low resolution EMF is possible if there + // are no print devices and the screen resolution is low. + + worldTransform.eM11 = ((float)PixelsX * 25.4f)/((float)MMX*90.0f*PX2WORLD); + worldTransform.eM12 = 0.0f; + worldTransform.eM21 = 0.0f; + worldTransform.eM22 = ((float)PixelsY * 25.4f)/((float)MMY*90.0f*PX2WORLD); + worldTransform.eDx = 0; + worldTransform.eDy = 0; + + rec = U_EMRMODIFYWORLDTRANSFORM_set(worldTransform, U_MWT_LEFTMULTIPLY); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM"; + } + + + if (1) { + snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY); + rec = textcomment_set(buff); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at textcomment_set 1"; + } + + snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN); + rec = textcomment_set(buff); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at textcomment_set 1"; + } + } + + return 0; +} + + +unsigned int PrintEmf::finish (Inkscape::Extension::Print * /*mod*/) +{ +// std::cout << "finish " << std::endl; + char *rec; + if (!et) return 0; + + + // earlier versions had flush of fill here, but it never executed and was removed + + rec = U_EMREOF_set(0,NULL,et); // generate the EOF record + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::finish"; + } + (void) emf_finish(et, eht); // Finalize and write out the EMF + emf_free(&et); // clean up + htable_free(&eht); // clean up + +// std::cout << "end finish" << std::endl; + return 0; +} + + +unsigned int PrintEmf::comment (Inkscape::Extension::Print * /*module*/, + const char * /*comment*/) +{ +// std::cout << "comment " << std::endl; + if (!et) return 0; + + // earlier versions had flush of fill here, but it never executed and was removed + +// std::cout << "end comment" << std::endl; + return 0; +} + +// Extracth hatchType, hatchColor from a name like +// EMFhatch_ +// 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){ + int val; + uint32_t hcolor=0; + if(0!=strncmp(name,"EMFhatch",8)){ return; } // not anything we can parse + name+=8; // EMFhatch already detected + val = 0; + while(*name && isdigit(*name)){ + val = 10*val + *name - '0'; + name++; + } + *hatchType = val; + if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify + *hatchType = -1; + } + else { + name++; + if(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 EMFhatch3_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){ + 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 EMFhatch#_###### + 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 swapRBinRGBA(char *px, int pixels){ + char tmp; + for(int i=0;ivector.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 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 emf-print.cpp called with invalid draw mode"; + } + return 1; +} + +// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring. +int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) +{ +// std::cout << "create_brush " << std::endl; + float rgb[3]; + char *rec; + U_LOGBRUSH lb; + uint32_t brush, fmode; + enum drawmode fill_mode; + GdkPixbuf *pixbuf; + uint32_t brushStyle; + int hatchType; + U_COLORREF hatchColor; + uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required. + uint32_t height = 0; + + if (!et) return 0; + + // set a default fill in case we can't figure out a better way to do it + fmode = U_ALTERNATE; + fill_mode = DRAW_PAINT; + brushStyle = U_BS_SOLID; + hatchType = U_HS_SOLIDCLR; + 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) return 1; // opacity isn't used here beyond this + + 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 = logbrush_set(brushStyle, hatchColor, hatchType); + + switch(fill_mode){ + case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices + case DRAW_RADIAL_GRADIENT: // ditto + case DRAW_PAINT: + case DRAW_PATTERN: + rec = createbrushindirect_set(&brush, eht, lb); + 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; + char *rgba_px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width*height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set"; + } + 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; + } + 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"; + } +// std::cout << "end create_brush " << std::endl; + return 0; +} + + +void PrintEmf::destroy_brush() +{ +// std::cout << "destroy_brush " << std::endl; + char *rec; + // before an object may be safely deleted it must no longer be selected + // select in a stock object to deselect this one, the stock object should + // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work? + rec = selectobject_set(U_NULL_BRUSH, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::destroy_brush at selectobject_set"; + } + if (hbrush){ + rec = deleteobject_set(&hbrush, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::destroy_brush"; + } + hbrush = 0; + } +// std::cout << "end destroy_brush" << std::endl; +} + + +int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) +{ + U_EXTLOGPEN *elp; + U_NUM_STYLEENTRY n_dash = 0; + U_STYLEENTRY *dash = NULL; + char *rec = NULL; + int linestyle = U_PS_SOLID; + int linecap = 0; + int linejoin = 0; + uint32_t pen; + uint32_t penStyle; + GdkPixbuf *pixbuf; + int hatchType; + U_COLORREF hatchColor; + uint32_t width,height; + char *px=NULL; + char *rgba_px; + uint32_t cbPx=0; + uint32_t colortype; + PU_RGBQUAD ct=NULL; + int numCt=0; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi=NULL; +// std::cout << "create_pen " << std::endl; + + if (!et) return 0; + + // set a default stroke in case we can't figure out a better way to do it + penStyle = U_BS_SOLID; + hatchColor = U_RGB(0, 0, 0); + hatchType = U_HS_HORIZONTAL; + + if (style) { + float rgb[3]; + + if(SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))){ // must be paint-server + SPPaintServer *paintserver = style->stroke.value.href->getObject(); + SPPattern *pat = SP_PATTERN (paintserver); + double dwidth = pattern_width(pat); + double dheight = pattern_height(pat); + width = dwidth; + height = dheight; + brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor); + if(pixbuf){ + penStyle = U_BS_DIBPATTERN; + rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); + // Not sure why the next swap is needed because the preceding does it, and the code is identical + // to that in stretchdibits_set, which does not need this. + swapRBinRGBA(px, width*height); + Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + } + else { // pattern + penStyle = U_BS_HATCHED; + 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 + penStyle = U_BS_HATCHED; + hatchType = U_HS_DIAGCROSS; + hatchColor = U_RGB(0xFF,0xC3,0xC3); + } + } + } + else if(SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))){ // must be a gradient + // currently we do not do anything with gradients, the code below has no net effect. + + SPPaintServer *paintserver = style->stroke.value.href->getObject(); + if (SP_IS_LINEARGRADIENT (paintserver)) { + SPLinearGradient *lg=SP_LINEARGRADIENT(paintserver); + + SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built + + Geom::Point p1 (lg->x1.computed, lg->y1.computed); + Geom::Point p2 (lg->x2.computed, lg->y2.computed); + + if (lg->gradientTransform_set) { + p1 = p1 * lg->gradientTransform; + p2 = p2 * lg->gradientTransform; + } + hatchColor = avg_stop_color(lg); + } + else if (SP_IS_RADIALGRADIENT (paintserver)) { + SPRadialGradient *rg=SP_RADIALGRADIENT(paintserver); + + SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built + double r = rg->r.computed; + + Geom::Point c (rg->cx.computed, rg->cy.computed); + Geom::Point xhandle_point(r, 0); + Geom::Point yhandle_point(0, -r); + yhandle_point += c; + xhandle_point += c; + if (rg->gradientTransform_set) { + c = c * rg->gradientTransform; + yhandle_point = yhandle_point * rg->gradientTransform; + xhandle_point = xhandle_point * rg->gradientTransform; + } + hatchColor = avg_stop_color(rg); + } + else { + // default fill + } + } + else if(style->stroke.isColor()){ // test last, always seems to be set, even for other types above + sp_color_get_rgb_floatv( &style->stroke.value.color, rgb ); + penStyle = U_BS_SOLID; + hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); + hatchType = U_HS_SOLIDCLR; + } + else { + // default fill + } + + + + using Geom::X; + using Geom::Y; + + Geom::Point zero(0, 0); + Geom::Point one(1, 1); + Geom::Point p0(zero * transform); + Geom::Point p1(one * transform); + Geom::Point p(p1 - p0); + + double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); + + if(!style->stroke_width.computed){return 0;} //if width is 0 do not (reset) the pen, it should already be NULL_PEN + uint32_t linewidth = MAX( 1, (uint32_t) (scale * style->stroke_width.computed * PX2WORLD) ); + + if (style->stroke_linecap.computed == 0) { + linecap = U_PS_ENDCAP_FLAT; + } + else if (style->stroke_linecap.computed == 1) { + linecap = U_PS_ENDCAP_ROUND; + } + else if (style->stroke_linecap.computed == 2) { + linecap = U_PS_ENDCAP_SQUARE; + } + + if (style->stroke_linejoin.computed == 0) { + linejoin = U_PS_JOIN_MITER; + } + else if (style->stroke_linejoin.computed == 1) { + linejoin = U_PS_JOIN_ROUND; + } + else if (style->stroke_linejoin.computed == 2) { + linejoin = U_PS_JOIN_BEVEL; + } + + if (style->stroke_dash.n_dash && + style->stroke_dash.dash ) + { + if(FixPPTDashLine){ // will break up line into many smaller lines. Override gradient if that was set, cannot do both. + penStyle = U_BS_SOLID; + hatchType = U_HS_HORIZONTAL; + } + else { + int i = 0; + while (linestyle != U_PS_USERSTYLE && + (i < style->stroke_dash.n_dash)) { + if (style->stroke_dash.dash[i] > 0.00000001) + linestyle = U_PS_USERSTYLE; + i++; + } + + if (linestyle == U_PS_USERSTYLE) { + n_dash = style->stroke_dash.n_dash; + dash = new uint32_t[n_dash]; + for (i = 0; i < style->stroke_dash.n_dash; i++) { + dash[i] = (uint32_t) (style->stroke_dash.dash[i]); + } + } + } + } + + elp = extlogpen_set( + U_PS_GEOMETRIC | linestyle | linecap | linejoin, + linewidth, + penStyle, + hatchColor, + hatchType, + n_dash, + dash); + + } + else { // if (!style) + linejoin=0; + elp = extlogpen_set( + linestyle, + 1, + U_BS_SOLID, + U_RGB(0,0,0), + U_HS_HORIZONTAL, + 0, + NULL); + } + + rec = extcreatepen_set(&pen, eht, Bmi, cbPx, px, elp ); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::create_pen at extcreatepen_set"; + } + free(elp); + if(Bmi)free(Bmi); + if(px)free(px); // ct will always be NULL + + rec = selectobject_set(pen, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::create_pen at selectobject_set"; + } + hpen = pen; // need this later for destroy_pen + + if (linejoin == U_PS_JOIN_MITER) { + float miterlimit = style->stroke_miterlimit.value; // This is a ratio. + + if (miterlimit < 1)miterlimit = 1; + + rec = U_EMRSETMITERLIMIT_set((uint32_t) miterlimit); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::create_pen at U_EMRSETMITERLIMIT_set"; + } + } + + if (n_dash) { + delete[] dash; + } + return 0; +// std::cout << "end create_pen" << std::endl; +} + +// set the current pen to the stock object NULL_PEN and then delete the defined pen object, if there is one. +void PrintEmf::destroy_pen() +{ +// std::cout << "destroy_pen hpen: " << hpen<< std::endl; + char *rec = NULL; + // before an object may be safely deleted it must no longer be selected + // select in a stock object to deselect this one, the stock object should + // never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work? + rec = selectobject_set(U_NULL_PEN, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::destroy_pen at selectobject_set"; + } + if (hpen){ + rec = deleteobject_set(&hpen, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::destroy_pen"; + } + hpen = 0; + } +// std::cout << "end destroy_pen " << std::endl; +} + + + +unsigned int PrintEmf::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 PrintEmf::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 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 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 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 outres = Geom::parse_svg_path(text); + return outres; +} + + +/* 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){ + 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 outres = Geom::parse_svg_path(text); + + return outres; +} + +/* 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){ + 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 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 rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width){ + std::vector outres; + Geom::Path cutter; + cutter.start( ctr + pos - width); + cutter.appendNew(ctr + pos + width); + cutter.appendNew(ctr + neg + width); + cutter.appendNew(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 SPWR_to_LVFR(SPWindRule wr){ + FillRule fr; + if(wr == SP_WIND_RULE_EVENODD){ + fr = fill_oddEven; + } + else { + fr = fill_nonZero; + } + return fr; +} + + +unsigned int PrintEmf::fill(Inkscape::Extension::Print * /*mod*/, + Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, + Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) +{ +// std::cout << "fill " << std::endl; + using Geom::X; + using Geom::Y; + + Geom::Affine tf = m_tr_stack.top(); + + use_fill = true; + use_stroke = false; + + // earlier versions had flush of fill here, but it never executed and was removed + + 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 EMF file because of the integer coordinate system. + Keep the overlap quite large so that loss of accuracy does not remove an overlap. + */ + destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below + Geom::Path cutter; + float rgb[3]; + U_COLORREF wc,c1,c2; + FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed); + double doff,doff_base,doff_range; + double divisions= 128.0; + int nstops; + int istop = 1; + float opa; // opacity at stop + + SPRadialGradient *tg = (SPRadialGradient *) (gv.grad); // linear/radial are the same here + nstops = tg->vector.stops.size(); + sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb); + opa = tg->vector.stops[0].opacity; + c1 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + sp_color_get_rgb_floatv(&tg->vector.stops[nstops-1].color, rgb); + opa = tg->vector.stops[nstops-1].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + doff = 0.0; + doff_base = 0.0; + doff_range = tg->vector.stops[1].offset; // next or last stop + + if(gv.mode==DRAW_RADIAL_GRADIENT){ + Geom::Point xv = gv.p2 - gv.p1; // X' vector + Geom::Point yv = gv.p3 - gv.p1; // Y' vector + Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector + double rx = hypot(xv[X],xv[Y]); + double ry = hypot(yv[X],yv[Y]); + double range = fmax(rx,ry); // length along the gradient + double step = range/divisions; // adequate approximation for gradient + double overlap = step/4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity". + Do this first so that outer colored ring will overlay it. + */ + pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y])); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb); + wc = weight_opacity(c2); + (void) create_brush(style, &wc); + print_pathv(pathvr, fill_transform); + + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + for(start = 0.0; start < range; start += step, doff += 1./divisions){ + stop = start + step + overlap; + if(stop > range)stop=range; + wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + (void) create_brush(style, &wc); + + pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y])); + + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if(doff >= doff_range - doff_base){ + istop++; + if(istop >= nstops)continue; // could happen on a rounding error + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1=c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + } + } + + } + else if(gv.mode == DRAW_LINEAR_GRADIENT){ + Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector + Geom::Point puv = uv.cw(); // perp. to unit vector + double range = Geom::distance(gv.p1,gv.p2); // length along the gradient + double step = range/divisions; // adequate approximation for gradient + double overlap = step/4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* before lower end of gradient, overlap first slice position */ + wc = weight_opacity(c1); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p1, uv*(overlap), uv*(-50000.0), puv*50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); + + /* after high end of gradient, overlap last slice poosition */ + wc = weight_opacity(c2); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p2, uv*(-overlap), uv*(50000.0), puv*50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); + + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + + for(start = 0.0; start < range; start += step, doff += 1./divisions){ + stop = start + step + overlap; + if(stop > range)stop=range; + pathvc = rect_cutter(gv.p1, uv*start, uv*stop, puv*50000.0); + + wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) ); + (void) create_brush(style, &wc); + Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if(doff >= doff_range - doff_base){ + istop++; + if(istop >= nstops)continue; // could happen on a rounding error + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1=c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa ); + } + } + } + else { + throw "Fatal programming error in PrintEmf::fill, invalid gradient type detected"; + } + use_fill = false; // gradients handled, be sure stroke does not use stroke and fill + } + else { + /* + Inkscape was not calling create_pen for objects with no border. + This was because it never called stroke() (next method). + PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can + become a visible border. + To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill. + */ + if (style->stroke.noneSet || style->stroke_width.computed == 0.0){ + destroy_pen(); //this sets the NULL_PEN + } + + /* postpone fill in case stroke also required AND all stroke paths closed + Dashes converted to line segments will "open" a closed path. + */ + bool all_closed = true; + for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){ + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){ + if (pit->end_default() != pit->end_closed()) { all_closed=false; } + } + } + if ( + (style->stroke.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 PrintEmf::stroke (Inkscape::Extension::Print * /*mod*/, + Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, + Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) +{ +// 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 (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 > tmp_pathpw; // pathv-> sbasis + Geom::Piecewise > tmp_pathpw2; // sbasis using arc length parameter + Geom::Piecewise > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes + Geom::Piecewise > 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 > 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 EMR_* primitives, like polygons, rectangles and ellipses. +// These use whatever the current pen/brush are and need not be followed by a FILLPATH or STROKEPATH. +// For other paths it sets a few flags and returns. +bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ +// std::cout << "print_simple_shape " << std::endl <begin(); cit != pit->end_open(); ++cit) + { + nodes++; + + if ( is_straight_curve(*cit) ) { + lines++; + } + else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { + cubic = cubic; + curves++; + } + } + } + + if (!nodes) + return false; + + U_POINT *lpPoints = new U_POINT[moves + lines + curves*3]; + int i = 0; + + /** + * For all Subpaths in the + */ + 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(&*cit)) + { + std::vector points = cubic->points(); + //Geom::Point p0 = points[0]; + Geom::Point p1 = points[1]; + Geom::Point p2 = points[2]; + Geom::Point p3 = points[3]; + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + p2[X] = (p2[X] * PX2WORLD); + p3[X] = (p3[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + p2[Y] = (p2[Y] * PX2WORLD); + p3[Y] = (p3[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + int32_t const x2 = (int32_t) round(p2[X]); + int32_t const y2 = (int32_t) round(p2[Y]); + int32_t const x3 = (int32_t) round(p3[X]); + int32_t const y3 = (int32_t) round(p3[Y]); + + lpPoints[i].x = x1; + lpPoints[i].y = y1; + lpPoints[i+1].x = x2; + lpPoints[i+1].y = y2; + lpPoints[i+2].x = x3; + lpPoints[i+2].y = y3; + i = i + 3; + } + } + } + + bool done = false; + bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); + bool polygon = false; + bool rectangle = false; + bool ellipse = false; + + if (moves == 1 && moves+lines == nodes && closed) { + polygon = true; +// if (nodes==5) { // disable due to LP Bug 407394 +// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && +// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) +// { +// rectangle = true; +// } +// } + } + else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { +// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && +// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && +// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && +// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && +// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && +// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) +// { // disable due to LP Bug 407394 +// ellipse = true; +// } + } + + if (polygon || ellipse) { + + if (use_fill && !use_stroke) { // only fill + rec = selectobject_set(U_NULL_PEN, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen"; + } + } + else if(!use_fill && use_stroke) { // only stroke + rec = selectobject_set(U_NULL_BRUSH, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush"; + } + } + + if (polygon) { + if (rectangle){ + U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[0].x, lpPoints[0].y}, (U_POINTL) {lpPoints[2].x, lpPoints[2].y}); + rec = U_EMRRECTANGLE_set(rcl); + } + else { + rec = U_EMRPOLYGON_set(U_RCL_DEF, nodes, lpPoints); + } + } + else if (ellipse) { + U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[6].x, lpPoints[3].y}, (U_POINTL) {lpPoints[0].x, lpPoints[9].y}); + rec = U_EMRELLIPSE_set(rcl); + } + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_simple_shape at retangle/ellipse/polygon"; + } + + done = true; + + // replace the handle we moved above, assuming there was something set already + if (use_fill && !use_stroke && hpen) { // only fill + rec = selectobject_set(hpen, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen"; + } + } + else if (!use_fill && use_stroke && hbrush){ // only stroke + rec = selectobject_set(hbrush, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush"; + } + } + + } + + delete[] lpPoints; + +// std::cout << "end simple_shape " << std::endl; + return done; +} + +/** Some parts based on win32.cpp by Lauris Kaplinski . 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. rotated images are mangled. They stay in their original orientation and are stretched + along X or Y. + 2. Transparency is lost on export. (Apparently a limitation of the EMF 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 PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not used */ + unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */ + unsigned int w, /** width of bitmap */ + unsigned int h, /** height of bitmap */ + unsigned int rs, /** row stride (normally w*4) */ + Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */ + SPStyle const *style) /** provides indirect link to image object */ +{ +// std::cout << "image " << std::endl; + double x1,x2,y1,y2; + char *rec = NULL; + Geom::Affine tf = m_tr_stack.top(); + + rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::image at EMRHEADER"; + } + + x1= atof(style->object->getAttribute("x")); + y1= atof(style->object->getAttribute("y")); + x2=x1 + atof(style->object->getAttribute("width")); + y2=y1 + atof(style->object->getAttribute("height")); + Geom::Point pLL(x1,y1); + Geom::Point pUR(x2,y2); + Geom::Point p2LL = pLL * tf; + Geom::Point p2UR = pUR * tf; + + char *px; + uint32_t cbPx; + uint32_t colortype; + PU_RGBQUAD ct; + int numCt; + U_BITMAPINFOHEADER Bmih; + PU_BITMAPINFO Bmi; + colortype = U_BCBM_COLOR32; + (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w*4, colortype, 0, 1); + Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); + Bmi = bitmapinfo_set(Bmih, ct); + + U_POINTL Dest = pointl_set(round(p2LL[Geom::X] * PX2WORLD), round(p2LL[Geom::Y] * PX2WORLD)); + U_POINTL cDest = pointl_set(round((p2UR[Geom::X]-p2LL[Geom::X]) * PX2WORLD), round((p2UR[Geom::Y]-p2LL[Geom::Y]) * PX2WORLD)); + U_POINTL Src = pointl_set(0,0); + U_POINTL cSrc = pointl_set(w,h); + rec = U_EMRSTRETCHDIBITS_set( + U_RCL_DEF, //! Bounding rectangle in device units + Dest, //! Destination UL corner in logical units + cDest, //! Destination W & H in logical units + Src, //! Source UL corner in logical units + cSrc, //! Source W & H in logical units + U_DIB_RGB_COLORS, //! DIBColors Enumeration + U_SRCCOPY, //! RasterOPeration Enumeration + Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section) + h*rs, //! size in bytes of px + px //! (Optional) bitmapbuffer (U_BITMAPINFO section) + ); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::image at U_EMRSTRETCHDIBITS_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 PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ +// std::cout << "print_pathv " << std::endl << std::flush; + char *rec = NULL; + + simple_shape = print_simple_shape(pathv, transform); + if (simple_shape || pathv.empty()){ + if (use_fill){ destroy_brush(); } // these must be cleared even if nothing is drawn or hbrush,hpen fill up + if (use_stroke){ destroy_pen(); } + return TRUE; + } + + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); + + rec = U_EMRBEGINPATH_set(); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_pathv at U_EMRBEGINPATH_set"; + } + + /** + * For all Subpaths in the + */ + for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) + { + using Geom::X; + using Geom::Y; + + + Geom::Point p0 = pit->initialPoint(); + + p0[X] = (p0[X] * PX2WORLD); + p0[Y] = (p0[Y] * PX2WORLD); + + U_POINTL ptl = pointl_set((int32_t) round(p0[X]), (int32_t) round(p0[Y])); + rec = U_EMRMOVETOEX_set(ptl); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_pathv at U_EMRMOVETOEX_set"; + } + + /** + * For all segments in the subpath + */ + for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) + { + if ( is_straight_curve(*cit) ) + { + //Geom::Point p0 = cit->initialPoint(); + Geom::Point p1 = cit->finalPoint(); + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + + ptl = pointl_set((int32_t) round(p1[X]), (int32_t) round(p1[Y])); + rec = U_EMRLINETO_set(ptl); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set"; + } + } + else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) + { + std::vector points = cubic->points(); + //Geom::Point p0 = points[0]; + Geom::Point p1 = points[1]; + Geom::Point p2 = points[2]; + Geom::Point p3 = points[3]; + + //p0[X] = (p0[X] * PX2WORLD); + p1[X] = (p1[X] * PX2WORLD); + p2[X] = (p2[X] * PX2WORLD); + p3[X] = (p3[X] * PX2WORLD); + //p0[Y] = (p0[Y] * PX2WORLD); + p1[Y] = (p1[Y] * PX2WORLD); + p2[Y] = (p2[Y] * PX2WORLD); + p3[Y] = (p3[Y] * PX2WORLD); + + //int32_t const x0 = (int32_t) round(p0[X]); + //int32_t const y0 = (int32_t) round(p0[Y]); + int32_t const x1 = (int32_t) round(p1[X]); + int32_t const y1 = (int32_t) round(p1[Y]); + int32_t const x2 = (int32_t) round(p2[X]); + int32_t const y2 = (int32_t) round(p2[Y]); + int32_t const x3 = (int32_t) round(p3[X]); + int32_t const y3 = (int32_t) round(p3[Y]); + + U_POINTL pt[3]; + pt[0].x = x1; + pt[0].y = y1; + pt[1].x = x2; + pt[1].y = y2; + pt[2].x = x3; + pt[2].y = y3; + + rec = U_EMRPOLYBEZIERTO_set(U_RCL_DEF, 3, pt); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_pathv at U_EMRPOLYBEZIERTO_set"; + } + } + else + { + g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used"); + } + } + + if (pit->end_default() == pit->end_closed()) { // there may be multiples of this on a single path + rec = U_EMRCLOSEFIGURE_set(); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_pathv at U_EMRCLOSEFIGURE_set"; + } + } + + } + + rec = U_EMRENDPATH_set(); // there may be only be one of these on a single path + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set"; + } + + // explicit FILL/STROKE commands are needed for each sub section of the path + if (use_fill && !use_stroke){ + rec = U_EMRFILLPATH_set(U_RCL_DEF); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set"; + } + } + else if (use_fill && use_stroke) { + rec = U_EMRSTROKEANDFILLPATH_set(U_RCL_DEF); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set"; + } + } + else if (!use_fill && use_stroke){ + rec = U_EMRSTROKEPATH_set(U_RCL_DEF); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set"; + } + } + + // clean out brush and pen, but only after all parts of the draw complete + if (use_fill){ + destroy_brush(); + } + if (use_stroke){ + destroy_pen(); + } +// std::cout << "end pathv" << std::endl; + + return TRUE; +} + + +bool PrintEmf::textToPath(Inkscape::Extension::Print * ext) +{ + return ext->get_param_bool("textToPath"); +} + +unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, + SPStyle const *const style) +{ +// std::cout << "text " << std::endl; + if (!et) return 0; + + char *rec = NULL; + int ccount,newfont; + int fix90n=0; + uint32_t hfont = 0; + Geom::Affine tf = m_tr_stack.top(); + double rot = -1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation, - sign for MM_TEXT + double rotb = -std::atan2(tf[1], tf[0]); // rotation for baseline offset for superscript/subscript, used below + double dx,dy; + double f1,f2,f3; + +#ifdef USE_PANGO_WIN32 +/* + font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style)); + if (tf) { + LOGFONT *lf = pango_win32_font_logfont(tf->pFont); + tf->Unref(); + hfont = CreateFontIndirect(lf); + g_free(lf); + } +*/ +#endif + + // the dx array is smuggled in like: textw1 w2 w3 ...wn, where the widths are floats 7 characters wide, including the space + int ndx; + uint32_t *adx; + smuggle_adx_out(text, &adx, &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 to NonUnicode, if possible. If any translate, all will, and all to + //the same font, because of code in Layout::print + UnicodeToNon(unicode_text, &ccount, &newfont); + + //PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value + //Some funky ones: Arial, Times New Roman + //Some not funky ones: Symbol and Verdana. + //Without a huge table we cannot catch them all, so just the most common problem ones. + if(FixPPTCharPos){ + switch(newfont){ + case CVTSYM: + search_short_fflist("Convert To Symbol", &f1, &f2, &f3); + break; + case CVTZDG: + search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3); + break; + case CVTWDG: + search_short_fflist("Convert To Wingdings", &f1, &f2, &f3); + break; + default: //also CVTNON + search_short_fflist(style->text->font_family.value, &f1, &f2, &f3); + break; + } + if(f2 || f3){ + int irem = ((int) round(rot)) % 900 ; + if(irem <=9 && irem >= -9){ + fix90n=1; //assume vertical + rot = (double) (((int) round(rot)) - irem); + rotb = rot*M_PI/1800.0; + if( abs(rot) == 900.0 ){ fix90n = 2; } + } + } + } + + /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision. + The EMF output files produced here have been designed so that the integer valued pt sizes + land right on an integer value in the EMF file, so those are exact. However, something like 18.1 pt will be + somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.) + */ + int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY())); + if (!hfont) { + + // Get font face name. Use changed font name if unicode mapped to one + // of the special fonts. + uint16_t *wfacename; + if(!newfont){ + wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL); + } + else { + wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL); + } + + // Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if + // it was streteched asymmetrically.) Few applications support text from EMF which is scaled + // differently by height/width, so leave lfWidth alone. + + U_LOGFONT lf = logfont_set( + textheight, + 0, + 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, + wfacename); + free(wfacename); + + rec = extcreatefontindirectw_set(&hfont, eht, (char *) &lf, NULL); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at extcreatefontindirectw_set"; + } + } + + rec = selectobject_set(hfont, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at selectobject_set"; + } + + float rgb[3]; + sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); + rec = U_EMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_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 EMF text alignment must always be TA_BASELINE|TA_LEFT. + rec = U_EMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at U_EMRSETTEXTALIGN_set"; + } + + // Transparent text background + rec = U_EMRSETBKMODE_set(U_TRANSPARENT); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at U_EMRSETBKMODE_set"; + } + + Geom::Point p2 = p * tf; + + //Handle super/subscripts. Negative sign because of geometry of MM_TEXT. + p2[Geom::X] -= style->baseline_shift.computed * std::sin( rotb ); + p2[Geom::Y] -= style->baseline_shift.computed * std::cos( rotb ); + + //Conditionally handle compensation for PPT EMF import bug (affects PPT 2003-2010, at least) + if(FixPPTCharPos){ + if(fix90n==1){ //vertical + dx= 0.0; + dy= f3 * style->font_size.computed * std::cos( rotb ); + } + else if(fix90n==2){ //horizontal + dx= f2 * style->font_size.computed * std::sin( rotb ); + dy= 0.0; + } + else { + dx= f1 * style->font_size.computed * std::sin( rotb ); + dy= f1 * style->font_size.computed * std::cos( rotb ); + } + p2[Geom::X] += dx; + p2[Geom::Y] += dy; + } + + p2[Geom::X] = (p2[Geom::X] * PX2WORLD); + p2[Geom::Y] = (p2[Geom::Y] * PX2WORLD); + + int32_t const xpos = (int32_t) round(p2[Geom::X]); + int32_t const ypos = (int32_t) round(p2[Geom::Y]); + + // The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is + // the number of VISIBLE characters, since some may combine from the UTF (8 originally, + // now 16) encoding. Conversely strlen() or wchar16len() would give the absolute number of + // encoding characters. Unclear if emrtext wants the former or the latter but for now assume the former. + +// This is currently being smuggled in from caller as part of text, works +// MUCH better than the fallback hack below +// uint32_t *adx = dx_set(textheight, U_FW_NORMAL, slen); // dx is needed, this makes one up + char *rec2 = emrtext_set( (U_POINTL) {xpos, ypos}, ndx, 2, unicode_text, U_ETO_NONE, U_RCL_DEF, adx); + free(unicode_text); + free(adx); + rec = U_EMREXTTEXTOUTW_set(U_RCL_DEF,U_GM_COMPATIBLE,1.0,1.0,(PU_EMRTEXT)rec2); + free(rec2); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at U_EMREXTTEXTOUTW_set"; + } + + // Must deselect an object before deleting it. Put the default font (back) in. + rec = selectobject_set(U_DEVICE_DEFAULT_FONT, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at selectobject_set"; + } + + if(hfont){ + rec = deleteobject_set(&hfont, eht); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::text at deleteobject_set"; + } + } + +// std::cout << "end text" << std::endl; + return 0; +} + +void PrintEmf::init (void) +{ +// std::cout << "init " << std::endl; + read_system_fflist(); + + /* EMF print */ + Inkscape::Extension::build_from_mem( + "\n" + "Enhanced Metafile Print\n" + "org.inkscape.print.emf\n" + "\n" + "true\n" + "true\n" + "false\n" + "false\n" + "false\n" + "false\n" + "\n" + "", new PrintEmf()); + + return; +} + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h new file mode 100644 index 000000000..eec013d1b --- /dev/null +++ b/src/extension/internal/emf-print.h @@ -0,0 +1,113 @@ +/** @file + * @brief Enhanced Metafile printing - implementation + */ +/* Author: + * Ulf Erikson + * + * Copyright (C) 2006-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ +#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "uemf.h" + +#include "extension/implementation/implementation.h" +//#include "extension/extension.h" + +#include <2geom/pathvector.h> + +#include + +namespace Inkscape { +namespace Extension { +namespace Internal { + +class PrintEmf : public Inkscape::Extension::Implementation::Implementation +{ + double _width; + double _height; + U_RECTL rc; + + uint32_t hbrush, hbrushOld, hpen, hpenOld; + + std::stack 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: + PrintEmf (void); + virtual ~PrintEmf (void); + + /* Print functions */ + virtual unsigned int setup (Inkscape::Extension::Print * module); + + virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc); + virtual unsigned int finish (Inkscape::Extension::Print * module); + + /* Rendering methods */ + virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); + virtual unsigned int release(Inkscape::Extension::Print *module); + virtual unsigned int fill (Inkscape::Extension::Print *module, + Geom::PathVector const &pathv, + Geom::Affine const &ctm, SPStyle const *style, + Geom::OptRect const &pbox, Geom::OptRect const &dbox, + Geom::OptRect const &bbox); + virtual unsigned int stroke (Inkscape::Extension::Print * module, + Geom::PathVector const &pathv, + Geom::Affine const &ctm, SPStyle const *style, + Geom::OptRect const &pbox, Geom::OptRect const &dbox, + Geom::OptRect const &bbox); + virtual unsigned int image(Inkscape::Extension::Print *module, + unsigned char *px, + unsigned int w, + unsigned int h, + unsigned int rs, + Geom::Affine const &transform, + SPStyle const *style); + virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); + virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, + Geom::Point const &p, SPStyle const *style); + bool textToPath (Inkscape::Extension::Print * ext); + + static void init (void); +protected: + 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(); + +}; + +} /* namespace Internal */ +} /* namespace Extension */ +} /* namespace Inkscape */ + + +#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_H__ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp deleted file mode 100644 index 7593a4806..000000000 --- a/src/extension/internal/emf-win32-inout.cpp +++ /dev/null @@ -1,2569 +0,0 @@ -/** @file - * @brief Windows-only Enhanced Metafile input and output. - */ -/* Authors: - * Ulf Erikson - * Jon A. Cruz - * Abhishek Sharma - * - * Copyright (C) 2006-2008 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - * - * References: - * - How to Create & Play Enhanced Metafiles in Win32 - * http://support.microsoft.com/kb/q145999/ - * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles - * http://support.microsoft.com/kb/q66949/ - * - Metafile Functions - * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp - * - Metafile Structures - * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp - */ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sp-root.h" -#include "sp-path.h" -#include "style.h" -#include "print.h" -#include "extension/system.h" -#include "extension/print.h" -#include "extension/db.h" -#include "extension/output.h" -#include "display/drawing.h" -#include "display/drawing-item.h" -#include "unit-constants.h" -#include "clear-n_.h" -#include "document.h" - -#define WIN32_LEAN_AND_MEAN -#include - -#include "emf-win32-print.h" -#include "emf-win32-inout.h" - - -#define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32" - -#ifndef PS_JOIN_MASK -#define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND) -#endif - -#define DPA 0x00A000C9 // TernaryRasterOperation - -namespace Inkscape { -namespace Extension { -namespace Internal { - -static float device_scale = DEVICESCALE; -static RECTL rc_old; -static bool clipset = false; - -EmfWin32::EmfWin32 (void) // The null constructor -{ - return; -} - - -EmfWin32::~EmfWin32 (void) //The destructor -{ - return; -} - - -bool -EmfWin32::check (Inkscape::Extension::Extension * /*module*/) -{ - if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32)) - return FALSE; - return TRUE; -} - - -static void -emf_print_document_to_file(SPDocument *doc, gchar const *filename) -{ - Inkscape::Extension::Print *mod; - SPPrintContext context; - gchar const *oldconst; - gchar *oldoutput; - unsigned int ret; - - doc->ensureUpToDate(); - - mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32); - oldconst = mod->get_param_string("destination"); - oldoutput = g_strdup(oldconst); - mod->set_param_string("destination", filename); - -/* Start */ - context.module = mod; - /* fixme: This has to go into module constructor somehow */ - /* Create new arena */ - mod->base = doc->getRoot(); - Inkscape::Drawing drawing; - mod->dkey = SPItem::display_key_new(1); - mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); - drawing.setRoot(mod->root); - /* Print document */ - ret = mod->begin(doc); - if (ret) { - g_free(oldoutput); - throw Inkscape::Extension::Output::save_failed(); - } - mod->base->invoke_print(&context); - ret = mod->finish(); - /* Release arena */ - mod->base->invoke_hide(mod->dkey); - mod->base = NULL; - mod->root = NULL; // deleted by invoke_hide -/* end */ - - mod->set_param_string("destination", oldoutput); - g_free(oldoutput); - - return; -} - - -void -EmfWin32::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) -{ - Inkscape::Extension::Extension * ext; - - ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32); - if (ext == NULL) - return; - - bool old_textToPath = ext->get_param_bool("textToPath"); - bool new_val = mod->get_param_bool("textToPath"); - ext->set_param_bool("textToPath", new_val); - - emf_print_document_to_file(doc, filename); - - ext->set_param_bool("textToPath", old_textToPath); - - return; -} - - - -typedef struct { - int type; - int level; - ENHMETARECORD *lpEMFR; -} EMF_OBJECT, *PEMF_OBJECT; - -typedef struct emf_device_context { - struct SPStyle style; - class SPTextStyle tstyle; - bool stroke_set; - bool fill_set; - - SIZEL sizeWnd; - SIZEL sizeView; - float PixelsInX, PixelsInY; - float PixelsOutX, PixelsOutY; - POINTL winorg; - POINTL vieworg; - double ScaleInX, ScaleInY; - double ScaleOutX, ScaleOutY; - COLORREF textColor; - bool textColorSet; - DWORD textAlign; - XFORM worldTransform; - POINTL cur; -} EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT; - -#define EMF_MAX_DC 128 - -typedef struct emf_callback_data { - Glib::ustring *outsvg; - Glib::ustring *path; - Glib::ustring *outdef; - - EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic.. - int level; - - double xDPI, yDPI; - bool pathless_stroke; - bool inpath; - - float MMX; - float MMY; - float dwInchesX; - float dwInchesY; - - unsigned int id; - CHAR *pDesc; - - int n_obj; - PEMF_OBJECT emf_obj; -} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA; - - -static void -output_style(PEMF_CALLBACK_DATA d, int iType) -{ -// SVGOStringStream tmp_id; - SVGOStringStream tmp_style; - char tmp[1024] = {0}; - - float fill_rgb[3]; - sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb ); - - float stroke_rgb[3]; - sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb); - -// tmp_id << "\n\tid=\"" << (d->id++) << "\""; -// *(d->outsvg) += tmp_id.str().c_str(); - *(d->outsvg) += "\n\tstyle=\""; - if (iType == EMR_STROKEPATH || !d->dc[d->level].fill_set) { - tmp_style << "fill:none;"; - } else { - snprintf(tmp, 1023, - "fill:#%02x%02x%02x;", - SP_COLOR_F_TO_U(fill_rgb[0]), - SP_COLOR_F_TO_U(fill_rgb[1]), - SP_COLOR_F_TO_U(fill_rgb[2])); - tmp_style << tmp; - snprintf(tmp, 1023, - "fill-rule:%s;", - d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero"); - tmp_style << tmp; - tmp_style << "fill-opacity:1;"; - - if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 && - fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2]) - { - d->dc[d->level].stroke_set = false; - } - } - - if (iType == EMR_FILLPATH || !d->dc[d->level].stroke_set) { - tmp_style << "stroke:none;"; - } else { - snprintf(tmp, 1023, - "stroke:#%02x%02x%02x;", - SP_COLOR_F_TO_U(stroke_rgb[0]), - SP_COLOR_F_TO_U(stroke_rgb[1]), - SP_COLOR_F_TO_U(stroke_rgb[2])); - tmp_style << tmp; - - tmp_style << "stroke-width:" << - MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;"; - - tmp_style << "stroke-linecap:" << - (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" : - d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" : - d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" : - "unknown") << ";"; - - tmp_style << "stroke-linejoin:" << - (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" : - d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" : - d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" : - "unknown") << ";"; - - if (d->dc[d->level].style.stroke_linejoin.computed == 0) { - tmp_style << "stroke-miterlimit:" << - MAX( 0.01, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; - } - - if (d->dc[d->level].style.stroke_dasharray_set && - d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) - { - tmp_style << "stroke-dasharray:"; - for (int i=0; idc[d->level].style.stroke_dash.n_dash; i++) { - if (i) - tmp_style << ","; - tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; - } - tmp_style << ";"; - tmp_style << "stroke-dashoffset:0;"; - } else { - tmp_style << "stroke-dasharray:none;"; - } - tmp_style << "stroke-opacity:1;"; - } - tmp_style << "\" "; - if (clipset) - tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" "; - clipset = false; - - *(d->outsvg) += tmp_style.str().c_str(); -} - - -static double -_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) -{ - double tmp = px - d->dc[d->level].winorg.x; - tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0; - tmp += d->dc[d->level].vieworg.x; - return tmp; -} - -static double -_pix_y_to_point(PEMF_CALLBACK_DATA d, double px) -{ - double tmp = px - d->dc[d->level].winorg.y; - tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0; - tmp += d->dc[d->level].vieworg.y; - return tmp; -} - - -static double -pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) -{ - double ppx = _pix_x_to_point(d, px); - double ppy = _pix_y_to_point(d, py); - - double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; - x *= device_scale; - - return x; -} - -static double -pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) -{ - double ppx = _pix_x_to_point(d, px); - double ppy = _pix_y_to_point(d, py); - - double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; - y *= device_scale; - - return y; -} - -static double -pix_to_size_point(PEMF_CALLBACK_DATA d, double px) -{ - double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); - double ppy = 0; - - double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21; - dx *= device_scale; - double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22; - dy *= device_scale; - - double tmp = sqrt(dx * dx + dy * dy); - return tmp; -} - - -static void -select_pen(PEMF_CALLBACK_DATA d, int index) -{ - PEMRCREATEPEN pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) { - case PS_DASH: - case PS_DOT: - case PS_DASHDOT: - case PS_DASHDOTDOT: - { - int i = 0; - int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; - if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - } - if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - } - if (penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - } - - d->dc[d->level].style.stroke_dasharray_set = 1; - break; - } - - case PS_SOLID: - default: - { - d->dc[d->level].style.stroke_dasharray_set = 0; - break; - } - } - - switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) { - case PS_ENDCAP_ROUND: - { - d->dc[d->level].style.stroke_linecap.computed = 1; - break; - } - case PS_ENDCAP_SQUARE: - { - d->dc[d->level].style.stroke_linecap.computed = 2; - break; - } - case PS_ENDCAP_FLAT: - default: - { - d->dc[d->level].style.stroke_linecap.computed = 0; - break; - } - } - - switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) { - case PS_JOIN_BEVEL: - { - d->dc[d->level].style.stroke_linejoin.computed = 2; - break; - } - case PS_JOIN_MITER: - { - d->dc[d->level].style.stroke_linejoin.computed = 0; - break; - } - case PS_JOIN_ROUND: - default: - { - d->dc[d->level].style.stroke_linejoin.computed = 1; - break; - } - } - - d->dc[d->level].stroke_set = true; - - if (pEmr->lopn.lopnStyle == PS_NULL) { - d->dc[d->level].style.stroke_width.value = 0; - d->dc[d->level].stroke_set = false; - } else if (pEmr->lopn.lopnWidth.x) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, pEmr->lopn.lopnWidth.x ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) - //d->dc[d->level].style.stroke_width.value = 1.0; - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, 1 ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } - - double r, g, b; - r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) ); - g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) ); - b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) ); - d->dc[d->level].style.stroke.value.color.set( r, g, b ); -} - - -static void -select_extpen(PEMF_CALLBACK_DATA d, int index) -{ - PEMREXTCREATEPEN pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) { - case PS_USERSTYLE: - { - if (pEmr->elp.elpNumEntries) { - d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries]; - for (unsigned int i=0; ielp.elpNumEntries; i++) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double dash_length = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] ); - d->level = cur_level; - d->dc[d->level].style.stroke_dash.dash[i] = dash_length; - } - d->dc[d->level].style.stroke_dasharray_set = 1; - } else { - d->dc[d->level].style.stroke_dasharray_set = 0; - } - break; - } - - case PS_DASH: - case PS_DOT: - case PS_DASHDOT: - case PS_DASHDOTDOT: - { - int i = 0; - int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; - if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; - } - if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; - } - if (penstyle==PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; - } - - d->dc[d->level].style.stroke_dasharray_set = 1; - break; - } - - case PS_SOLID: - default: - { - d->dc[d->level].style.stroke_dasharray_set = 0; - break; - } - } - - switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) { - case PS_ENDCAP_ROUND: - { - d->dc[d->level].style.stroke_linecap.computed = 1; - break; - } - case PS_ENDCAP_SQUARE: - { - d->dc[d->level].style.stroke_linecap.computed = 2; - break; - } - case PS_ENDCAP_FLAT: - default: - { - d->dc[d->level].style.stroke_linecap.computed = 0; - break; - } - } - - switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) { - case PS_JOIN_BEVEL: - { - d->dc[d->level].style.stroke_linejoin.computed = 2; - break; - } - case PS_JOIN_MITER: - { - d->dc[d->level].style.stroke_linejoin.computed = 0; - break; - } - case PS_JOIN_ROUND: - default: - { - d->dc[d->level].style.stroke_linejoin.computed = 1; - break; - } - } - - d->dc[d->level].stroke_set = true; - - if (pEmr->elp.elpPenStyle == PS_NULL) { - d->dc[d->level].style.stroke_width.value = 0; - d->dc[d->level].stroke_set = false; - } else if (pEmr->elp.elpWidth) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) - //d->dc[d->level].style.stroke_width.value = 1.0; - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, 1 ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } - - double r, g, b; - r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) ); - g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) ); - b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) ); - - d->dc[d->level].style.stroke.value.color.set( r, g, b ); -} - - -static void -select_brush(PEMF_CALLBACK_DATA d, int index) -{ - PEMRCREATEBRUSHINDIRECT pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - if (pEmr->lb.lbStyle == BS_SOLID) { - double r, g, b; - r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) ); - g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) ); - b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) ); - d->dc[d->level].style.fill.value.color.set( r, g, b ); - } - - d->dc[d->level].fill_set = true; -} - - -static void -select_font(PEMF_CALLBACK_DATA d, int index) -{ - PEMREXTCREATEFONTINDIRECTW pEmr = NULL; - - if (index >= 0 && index < d->n_obj) - pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR; - - if (!pEmr) - return; - - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight ); - d->level = cur_level; - d->dc[d->level].style.font_size.computed = font_size; - d->dc[d->level].style.font_weight.value = - pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : - pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : - pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : - pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : - pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : - pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : - pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : - pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : - pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : - pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : - FW_NORMAL; - d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); - d->dc[d->level].style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline; - d->dc[d->level].style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut; - if (d->dc[d->level].tstyle.font_family.value) - g_free(d->dc[d->level].tstyle.font_family.value); - d->dc[d->level].tstyle.font_family.value = - (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL ); - d->dc[d->level].style.baseline_shift.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow -} - -static void -delete_object(PEMF_CALLBACK_DATA d, int index) -{ - if (index >= 0 && index < d->n_obj) { - d->emf_obj[index].type = 0; - if (d->emf_obj[index].lpEMFR) - free(d->emf_obj[index].lpEMFR); - d->emf_obj[index].lpEMFR = NULL; - } -} - - -static void -insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj) -{ - if (index >= 0 && index < d->n_obj) { - delete_object(d, index); - d->emf_obj[index].type = type; - d->emf_obj[index].level = d->level; - d->emf_obj[index].lpEMFR = pObj; - } -} - -static void -assert_empty_path(PEMF_CALLBACK_DATA d, const char * /*fun*/) -{ - if (!d->path->empty()) { - // g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun); - - *(d->outsvg) += "\n"; - - *(d->path) = ""; - } -} - - -static int CALLBACK -myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const *lpEMFR, int /*nObj*/, LPARAM lpData) -{ - PEMF_CALLBACK_DATA d; - SVGOStringStream tmp_outsvg; - SVGOStringStream tmp_path; - SVGOStringStream tmp_str; - SVGOStringStream dbg_str; - - d = (PEMF_CALLBACK_DATA) lpData; - - if (d->pathless_stroke) { - if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 && - lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 && - lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO && - lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 && - lpEMFR->iType!=EMR_SETBKMODE && lpEMFR->iType!=EMR_SELECTOBJECT && - lpEMFR->iType!=EMR_BEGINPATH) - { - *(d->outsvg) += " outsvg) += "\n\t"; - *(d->outsvg) += *(d->path); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - d->pathless_stroke = false; - } - } - - switch (lpEMFR->iType) - { - case EMR_HEADER: - { - dbg_str << "\n"; - - *(d->outdef) += "\n"; - - if (d->pDesc) { - *(d->outdef) += "\n"; - } - - ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR; - SVGOStringStream tmp_outdef; - tmp_outdef << "xDPI = 2540; - d->yDPI = 2540; - - d->dc[d->level].PixelsInX = pEmr->rclFrame.right; // - pEmr->rclFrame.left; - d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom; // - pEmr->rclFrame.top; - - d->MMX = d->dc[d->level].PixelsInX / 100.0; - d->MMY = d->dc[d->level].PixelsInY / 100.0; - - d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM; - d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM; - - // calculate ratio of Inkscape dpi/device dpi - if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx) - device_scale = PX_PER_MM*pEmr->szlMillimeters.cx/pEmr->szlDevice.cx; - - tmp_outdef << - " width=\"" << d->MMX << "mm\"\n" << - " height=\"" << d->MMY << "mm\">\n"; - *(d->outdef) += tmp_outdef.str().c_str(); - *(d->outdef) += ""; // temporary end of header - - tmp_outsvg << "\n\n\n"; // start of main body - - if (pEmr->nHandles) { - d->n_obj = pEmr->nHandles; - d->emf_obj = new EMF_OBJECT[d->n_obj]; - - // Init the new emf_obj list elements to null, provided the - // dynamic allocation succeeded. - if ( d->emf_obj != NULL ) - { - for( int i=0; i < d->n_obj; ++i ) - d->emf_obj[i].lpEMFR = NULL; - } //if - - } else { - d->emf_obj = NULL; - } - - break; - } - case EMR_POLYBEZIER: - { - dbg_str << "\n"; - - PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR; - DWORD i,j; - - if (pEmr->cptl<4) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYBEZIER"); - - *(d->outsvg) += " outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; - - for (i=1; icptl; ) { - tmp_str << "\n\tC "; - for (j=0; j<3 && icptl; j++,i++) { - tmp_str << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYGON: - { - dbg_str << "\n"; - - EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR; - DWORD i; - - if (pEmr->cptl < 2) - break; - - assert_empty_path(d, "EMR_POLYGON"); - - *(d->outsvg) += " outsvg) += "\n\td=\""; - - tmp_str << - "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; - - for (i=1; icptl; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " z \" /> \n"; - - break; - } - case EMR_POLYLINE: - { - dbg_str << "\n"; - - EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR; - DWORD i; - - if (pEmr->cptl<2) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYLINE"); - - *(d->outsvg) += " outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; - - for (i=1; icptl; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYBEZIERTO: - { - dbg_str << "\n"; - - PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR; - DWORD i,j; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; icptl;) { - tmp_path << "\n\tC "; - for (j=0; j<3 && icptl; j++,i++) { - tmp_path << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - } - - break; - } - case EMR_POLYLINETO: - { - dbg_str << "\n"; - - PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR; - DWORD i; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; icptl;i++) { - tmp_path << - "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; - } - - break; - } - case EMR_POLYPOLYLINE: - case EMR_POLYPOLYGON: - { - if (lpEMFR->iType == EMR_POLYPOLYLINE) - dbg_str << "\n"; - if (lpEMFR->iType == EMR_POLYPOLYGON) - dbg_str << "\n"; - - PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR; - unsigned int n, i, j; - - if (!d->inpath) { - assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE"); - - *(d->outsvg) += " iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys]; - - i = 0; - for (n=0; nnPolys && icptl; n++) { - SVGOStringStream poly_path; - - poly_path << "\n\tM " << - pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << - pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; - i++; - - for (j=1; jaPolyCounts[n] && icptl; j++) { - poly_path << "\n\tL " << - pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << - pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; - i++; - } - - tmp_str << poly_path.str().c_str(); - if (lpEMFR->iType == EMR_POLYPOLYGON) - tmp_str << " z"; - tmp_str << " \n"; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_SETWINDOWEXTEX: - { - dbg_str << "\n"; - - PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR; - - d->dc[d->level].sizeWnd = pEmr->szlExtent; - - if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; - if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX; - d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY; - } - } - - if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; - } - - d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; - d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; - - if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { - d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; - d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; - } - else { - d->dc[d->level].ScaleInX = 1; - d->dc[d->level].ScaleInY = 1; - } - - break; - } - case EMR_SETWINDOWORGEX: - { - dbg_str << "\n"; - - PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR; - d->dc[d->level].winorg = pEmr->ptlOrigin; - break; - } - case EMR_SETVIEWPORTEXTEX: - { - dbg_str << "\n"; - - PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR; - - d->dc[d->level].sizeView = pEmr->szlExtent; - - if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; - if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX; - d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY; - } - } - - if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; - } - - d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; - d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; - - if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { - d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; - d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; - } - else { - d->dc[d->level].ScaleInX = 1; - d->dc[d->level].ScaleInY = 1; - } - - break; - } - case EMR_SETVIEWPORTORGEX: - { - dbg_str << "\n"; - - PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR; - d->dc[d->level].vieworg = pEmr->ptlOrigin; - break; - } - case EMR_SETBRUSHORGEX: - dbg_str << "\n"; - break; - case EMR_EOF: - { - dbg_str << "\n"; - - assert_empty_path(d, "EMR_EOF"); - tmp_outsvg << "\n"; - tmp_outsvg << "\n"; - *(d->outsvg) = *(d->outdef) + *(d->outsvg); - break; - } - case EMR_SETPIXELV: - dbg_str << "\n"; - break; - case EMR_SETMAPPERFLAGS: - dbg_str << "\n"; - break; - case EMR_SETMAPMODE: - dbg_str << "\n"; - break; - case EMR_SETBKMODE: - dbg_str << "\n"; - break; - case EMR_SETPOLYFILLMODE: - { - dbg_str << "\n"; - - PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR; - d->dc[d->level].style.fill_rule.value = - (pEmr->iMode == ALTERNATE ? 0 : - pEmr->iMode == WINDING ? 1 : 0); - break; - } - case EMR_SETROP2: - dbg_str << "\n"; - break; - case EMR_SETSTRETCHBLTMODE: - dbg_str << "\n"; - break; - case EMR_SETTEXTALIGN: - { - dbg_str << "\n"; - - PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR; - d->dc[d->level].textAlign = pEmr->iMode; - break; - } - case EMR_SETCOLORADJUSTMENT: - dbg_str << "\n"; - break; - case EMR_SETTEXTCOLOR: - { - dbg_str << "\n"; - - PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR; - d->dc[d->level].textColor = pEmr->crColor; - d->dc[d->level].textColorSet = true; - break; - } - case EMR_SETBKCOLOR: - dbg_str << "\n"; - break; - case EMR_OFFSETCLIPRGN: - dbg_str << "\n"; - break; - case EMR_MOVETOEX: - { - dbg_str << "\n"; - - PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - d->dc[d->level].cur = pEmr->ptl; - - tmp_path << - "\n\tM " << - pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << - pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; - break; - } - case EMR_SETMETARGN: - dbg_str << "\n"; - break; - case EMR_EXCLUDECLIPRECT: - dbg_str << "\n"; - break; - case EMR_INTERSECTCLIPRECT: - { - dbg_str << "\n"; - - PEMRINTERSECTCLIPRECT pEmr = (PEMRINTERSECTCLIPRECT) lpEMFR; - RECTL rc = pEmr->rclClip; - clipset = true; - if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) - break; - rc_old = rc; - - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "\nid) << "\" >"; - tmp_rectangle << "\n"; - tmp_rectangle << "\n"; - - assert_empty_path(d, "EMR_RECTANGLE"); - - *(d->outdef) += tmp_rectangle.str().c_str(); - *(d->path) = ""; - break; - } - case EMR_SCALEVIEWPORTEXTEX: - dbg_str << "\n"; - break; - case EMR_SCALEWINDOWEXTEX: - dbg_str << "\n"; - break; - case EMR_SAVEDC: - dbg_str << "\n"; - - if (d->level < EMF_MAX_DC) { - d->dc[d->level + 1] = d->dc[d->level]; - d->level = d->level + 1; - } - break; - case EMR_RESTOREDC: - { - dbg_str << "\n"; - - PEMRRESTOREDC pEmr = (PEMRRESTOREDC) lpEMFR; - int old_level = d->level; - if (pEmr->iRelative >= 0) { - if (pEmr->iRelative < d->level) - d->level = pEmr->iRelative; - } - else { - if (d->level + pEmr->iRelative >= 0) - d->level = d->level + pEmr->iRelative; - } - while (old_level > d->level) { - if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))) - delete[] d->dc[old_level].style.stroke_dash.dash; - old_level--; - } - break; - } - case EMR_SETWORLDTRANSFORM: - { - dbg_str << "\n"; - - PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR; - d->dc[d->level].worldTransform = pEmr->xform; - break; - } - case EMR_MODIFYWORLDTRANSFORM: - { - dbg_str << "\n"; - - PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR; - switch (pEmr->iMode) - { - case MWT_IDENTITY: - d->dc[d->level].worldTransform.eM11 = 1.0; - d->dc[d->level].worldTransform.eM12 = 0.0; - d->dc[d->level].worldTransform.eM21 = 0.0; - d->dc[d->level].worldTransform.eM22 = 1.0; - d->dc[d->level].worldTransform.eDx = 0.0; - d->dc[d->level].worldTransform.eDy = 0.0; - break; - case MWT_LEFTMULTIPLY: - { -// d->dc[d->level].worldTransform = pEmr->xform * worldTransform; - - float a11 = pEmr->xform.eM11; - float a12 = pEmr->xform.eM12; - float a13 = 0.0; - float a21 = pEmr->xform.eM21; - float a22 = pEmr->xform.eM22; - float a23 = 0.0; - float a31 = pEmr->xform.eDx; - float a32 = pEmr->xform.eDy; - float a33 = 1.0; - - float b11 = d->dc[d->level].worldTransform.eM11; - float b12 = d->dc[d->level].worldTransform.eM12; - //float b13 = 0.0; - float b21 = d->dc[d->level].worldTransform.eM21; - float b22 = d->dc[d->level].worldTransform.eM22; - //float b23 = 0.0; - float b31 = d->dc[d->level].worldTransform.eDx; - float b32 = d->dc[d->level].worldTransform.eDy; - //float b33 = 1.0; - - float c11 = a11*b11 + a12*b21 + a13*b31;; - float c12 = a11*b12 + a12*b22 + a13*b32;; - //float c13 = a11*b13 + a12*b23 + a13*b33;; - float c21 = a21*b11 + a22*b21 + a23*b31;; - float c22 = a21*b12 + a22*b22 + a23*b32;; - //float c23 = a21*b13 + a22*b23 + a23*b33;; - float c31 = a31*b11 + a32*b21 + a33*b31;; - float c32 = a31*b12 + a32*b22 + a33*b32;; - //float c33 = a31*b13 + a32*b23 + a33*b33;; - - d->dc[d->level].worldTransform.eM11 = c11;; - d->dc[d->level].worldTransform.eM12 = c12;; - d->dc[d->level].worldTransform.eM21 = c21;; - d->dc[d->level].worldTransform.eM22 = c22;; - d->dc[d->level].worldTransform.eDx = c31; - d->dc[d->level].worldTransform.eDy = c32; - - break; - } - case MWT_RIGHTMULTIPLY: - { -// d->dc[d->level].worldTransform = worldTransform * pEmr->xform; - - float a11 = d->dc[d->level].worldTransform.eM11; - float a12 = d->dc[d->level].worldTransform.eM12; - float a13 = 0.0; - float a21 = d->dc[d->level].worldTransform.eM21; - float a22 = d->dc[d->level].worldTransform.eM22; - float a23 = 0.0; - float a31 = d->dc[d->level].worldTransform.eDx; - float a32 = d->dc[d->level].worldTransform.eDy; - float a33 = 1.0; - - float b11 = pEmr->xform.eM11; - float b12 = pEmr->xform.eM12; - //float b13 = 0.0; - float b21 = pEmr->xform.eM21; - float b22 = pEmr->xform.eM22; - //float b23 = 0.0; - float b31 = pEmr->xform.eDx; - float b32 = pEmr->xform.eDy; - //float b33 = 1.0; - - float c11 = a11*b11 + a12*b21 + a13*b31;; - float c12 = a11*b12 + a12*b22 + a13*b32;; - //float c13 = a11*b13 + a12*b23 + a13*b33;; - float c21 = a21*b11 + a22*b21 + a23*b31;; - float c22 = a21*b12 + a22*b22 + a23*b32;; - //float c23 = a21*b13 + a22*b23 + a23*b33;; - float c31 = a31*b11 + a32*b21 + a33*b31;; - float c32 = a31*b12 + a32*b22 + a33*b32;; - //float c33 = a31*b13 + a32*b23 + a33*b33;; - - d->dc[d->level].worldTransform.eM11 = c11;; - d->dc[d->level].worldTransform.eM12 = c12;; - d->dc[d->level].worldTransform.eM21 = c21;; - d->dc[d->level].worldTransform.eM22 = c22;; - d->dc[d->level].worldTransform.eDx = c31; - d->dc[d->level].worldTransform.eDy = c32; - - break; - } -// case MWT_SET: - default: - d->dc[d->level].worldTransform = pEmr->xform; - break; - } - break; - } - case EMR_SELECTOBJECT: - { - dbg_str << "\n"; - - PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR; - unsigned int index = pEmr->ihObject; - - if (index >= ENHMETA_STOCK_OBJECT) { - index -= ENHMETA_STOCK_OBJECT; - switch (index) { - case NULL_BRUSH: - d->dc[d->level].fill_set = false; - break; - case BLACK_BRUSH: - case DKGRAY_BRUSH: - case GRAY_BRUSH: - case LTGRAY_BRUSH: - case WHITE_BRUSH: - { - float val = 0; - switch (index) { - case BLACK_BRUSH: - val = 0.0 / 255.0; - break; - case DKGRAY_BRUSH: - val = 64.0 / 255.0; - break; - case GRAY_BRUSH: - val = 128.0 / 255.0; - break; - case LTGRAY_BRUSH: - val = 192.0 / 255.0; - break; - case WHITE_BRUSH: - val = 255.0 / 255.0; - break; - } - d->dc[d->level].style.fill.value.color.set( val, val, val ); - - d->dc[d->level].fill_set = true; - break; - } - case NULL_PEN: - d->dc[d->level].stroke_set = false; - break; - case BLACK_PEN: - case WHITE_PEN: - { - float val = index == BLACK_PEN ? 0 : 1; - d->dc[d->level].style.stroke_dasharray_set = 0; - d->dc[d->level].style.stroke_width.value = 1.0; - d->dc[d->level].style.stroke.value.color.set( val, val, val ); - - d->dc[d->level].stroke_set = true; - - break; - } - } - } else { - if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) { - switch (d->emf_obj[index].type) - { - case EMR_CREATEPEN: - select_pen(d, index); - break; - case EMR_CREATEBRUSHINDIRECT: - select_brush(d, index); - break; - case EMR_EXTCREATEPEN: - select_extpen(d, index); - break; - case EMR_EXTCREATEFONTINDIRECTW: - select_font(d, index); - break; - } - } - } - break; - } - case EMR_CREATEPEN: - { - dbg_str << "\n"; - - PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR; - int index = pEmr->ihPen; - - EMRCREATEPEN *pPen = - (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) ); - pPen->lopn = pEmr->lopn; - insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen); - - break; - } - case EMR_CREATEBRUSHINDIRECT: - { - dbg_str << "\n"; - - PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR; - int index = pEmr->ihBrush; - - EMRCREATEBRUSHINDIRECT *pBrush = - (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) ); - pBrush->lb = pEmr->lb; - insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush); - - break; - } - case EMR_DELETEOBJECT: - dbg_str << "\n"; - break; - case EMR_ANGLEARC: - dbg_str << "\n"; - break; - case EMR_ELLIPSE: - { - dbg_str << "\n"; - - PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR; - RECTL rclBox = pEmr->rclBox; - - double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top ); - double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top ); - double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom ); - double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom ); - - double cx = (l + r) / 2.0; - double cy = (t + b) / 2.0; - double rx = fabs(l - r) / 2.0; - double ry = fabs(t - b) / 2.0; - - SVGOStringStream tmp_ellipse; - tmp_ellipse << "cx=\"" << cx << "\" "; - tmp_ellipse << "cy=\"" << cy << "\" "; - tmp_ellipse << "rx=\"" << rx << "\" "; - tmp_ellipse << "ry=\"" << ry << "\" "; - - assert_empty_path(d, "EMR_ELLIPSE"); - - *(d->outsvg) += " iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_ellipse.str().c_str(); - *(d->outsvg) += "/> \n"; - *(d->path) = ""; - break; - } - case EMR_RECTANGLE: - { - dbg_str << "\n"; - - PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR; - RECTL rc = pEmr->rclBox; - - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "d=\""; - tmp_rectangle << "\n\tM " << l << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << b << " "; - tmp_rectangle << "\n\tL " << l << " " << b << " "; - tmp_rectangle << "\n\tz"; - - assert_empty_path(d, "EMR_RECTANGLE"); - - *(d->outsvg) += " iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_rectangle.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - break; - } - case EMR_ROUNDRECT: - { - dbg_str << "\n"; - - PEMRROUNDRECT pEmr = (PEMRROUNDRECT) lpEMFR; - RECTL rc = pEmr->rclBox; - SIZEL corner = pEmr->szlCorner; - double f = 4.*(sqrt(2) - 1)/3; - - double l = pix_to_x_point(d, rc.left, rc.top); - double t = pix_to_y_point(d, rc.left, rc.top); - double r = pix_to_x_point(d, rc.right, rc.bottom); - double b = pix_to_y_point(d, rc.right, rc.bottom); - double cnx = pix_to_size_point(d, corner.cx/2); - double cny = pix_to_size_point(d, corner.cy/2); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "d=\""; - tmp_rectangle << "\n\tM " << l << ", " << t + cny << " "; - tmp_rectangle << "\n\tC " << l << ", " << t + (1-f)*cny << " " << l + (1-f)*cnx << ", " << t << " " << l + cnx << ", " << t << " "; - tmp_rectangle << "\n\tL " << r - cnx << ", " << t << " "; - tmp_rectangle << "\n\tC " << r - (1-f)*cnx << ", " << t << " " << r << ", " << t + (1-f)*cny << " " << r << ", " << t + cny << " "; - tmp_rectangle << "\n\tL " << r << ", " << b - cny << " "; - tmp_rectangle << "\n\tC " << r << ", " << b - (1-f)*cny << " " << r - (1-f)*cnx << ", " << b << " " << r - cnx << ", " << b << " "; - tmp_rectangle << "\n\tL " << l + cnx << ", " << b << " "; - tmp_rectangle << "\n\tC " << l + (1-f)*cnx << ", " << b << " " << l << ", " << b - (1-f)*cny << " " << l << ", " << b - cny << " "; - tmp_rectangle << "\n\tz"; - assert_empty_path(d, "EMR_ROUNDRECT"); - - *(d->outsvg) += " iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_rectangle.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - break; - } - case EMR_ARC: - dbg_str << "\n"; - break; - case EMR_CHORD: - dbg_str << "\n"; - break; - case EMR_PIE: - { - dbg_str << "\n"; - - PEMRPIE pEmr = (PEMRPIE) lpEMFR; - RECTL rc = pEmr->rclBox; - - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - double x1 = pix_to_x_point( d, pEmr->ptlStart.x, pEmr->ptlStart.y ); - double y1 = pix_to_y_point( d, pEmr->ptlStart.x, pEmr->ptlStart.y ); - double x2 = pix_to_x_point( d, pEmr->ptlEnd.x, pEmr->ptlEnd.y ); - double y2 = pix_to_y_point( d, pEmr->ptlEnd.x, pEmr->ptlEnd.y ); - - SVGOStringStream tmp_pie; - tmp_pie << "d=\"" << - "\n\tM " << x1 << " " << y1 << " "; - - double angle1 = -atan2(y1 - (t + b) / 2.0, x1 - (l + r) / 2.0); - double angle2 = -atan2(y2 - (t + b) / 2.0, x2 - (l + r) / 2.0); - double angle = angle2 - angle1; - if (angle < 0) angle += 2*M_PI; - - bool large_arc_flag = false; - if (angle > M_PI) large_arc_flag = true; - - tmp_pie << "\n\tA " << - fabs(l - r) / 2.0 << " " << - fabs(t - b) / 2.0 << " " << - "0 " << large_arc_flag << " 0 " << - x2 << " " << y2 << " " << - "\n\tL " << (l + r) / 2.0 << " " << (t + b) / 2.0 << " " << - "\n\tz"; - - assert_empty_path(d, "EMR_PIE"); - - *(d->outsvg) += " iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_pie.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - break; - } - case EMR_SELECTPALETTE: - dbg_str << "\n"; - break; - case EMR_CREATEPALETTE: - dbg_str << "\n"; - break; - case EMR_SETPALETTEENTRIES: - dbg_str << "\n"; - break; - case EMR_RESIZEPALETTE: - dbg_str << "\n"; - break; - case EMR_REALIZEPALETTE: - dbg_str << "\n"; - break; - case EMR_EXTFLOODFILL: - dbg_str << "\n"; - break; - case EMR_LINETO: - { - dbg_str << "\n"; - - PEMRLINETO pEmr = (PEMRLINETO) lpEMFR; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - tmp_path << - "\n\tL " << - pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << - pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; - break; - } - case EMR_ARCTO: - dbg_str << "\n"; - break; - case EMR_POLYDRAW: - dbg_str << "\n"; - break; - case EMR_SETARCDIRECTION: - dbg_str << "\n"; - break; - case EMR_SETMITERLIMIT: - { - dbg_str << "\n"; - - PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR; - - //BUG in SetMiterLimit() on mingw, possibly in underlying Windows(at least on XP?) - //The function takes a float but saves a 32 bit int in the EMR_SETMITERLIMIT record. - float miterlimit = *((int32_t *) &(pEmr->eMiterLimit)); - d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size - if (d->dc[d->level].style.stroke_miterlimit.value < 1.0) - d->dc[d->level].style.stroke_miterlimit.value = 1.0; - break; - } - case EMR_BEGINPATH: - { - dbg_str << "\n"; - - if (!d->pathless_stroke) { - tmp_path << "d=\""; - *(d->path) = ""; - } - d->pathless_stroke = false; - d->inpath = true; - break; - } - case EMR_ENDPATH: - { - dbg_str << "\n"; - - tmp_path << "\""; - d->inpath = false; - break; - } - case EMR_CLOSEFIGURE: - { - dbg_str << "\n"; - - tmp_path << "\n\tz"; - break; - } - case EMR_FILLPATH: - case EMR_STROKEANDFILLPATH: - case EMR_STROKEPATH: - { - if (lpEMFR->iType == EMR_FILLPATH) - dbg_str << "\n"; - if (lpEMFR->iType == EMR_STROKEANDFILLPATH) - dbg_str << "\n"; - if (lpEMFR->iType == EMR_STROKEPATH) - dbg_str << "\n"; - - *(d->outsvg) += " iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += *(d->path); - *(d->outsvg) += " /> \n"; - *(d->path) = ""; - break; - } - case EMR_FLATTENPATH: - dbg_str << "\n"; - break; - case EMR_WIDENPATH: - dbg_str << "\n"; - break; - case EMR_SELECTCLIPPATH: - dbg_str << "\n"; - break; - case EMR_ABORTPATH: - dbg_str << "\n"; - break; - case EMR_GDICOMMENT: - { - dbg_str << "\n"; - - PEMRGDICOMMENT pEmr = (PEMRGDICOMMENT) lpEMFR; - - CHAR *szTxt = (CHAR *) pEmr->Data; - - for (DWORD i = 0; i < pEmr->cbData; i++) { - if ( *szTxt) { - if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) { - tmp_str << *szTxt; - } - szTxt++; - } - } - - if (0 && strlen(tmp_str.str().c_str())) { - tmp_outsvg << " \n"; - } - - break; - } - case EMR_FILLRGN: - dbg_str << "\n"; - break; - case EMR_FRAMERGN: - dbg_str << "\n"; - break; - case EMR_INVERTRGN: - dbg_str << "\n"; - break; - case EMR_PAINTRGN: - dbg_str << "\n"; - break; - case EMR_EXTSELECTCLIPRGN: - { - dbg_str << "\n"; - - PEMREXTSELECTCLIPRGN pEmr = (PEMREXTSELECTCLIPRGN) lpEMFR; - if (pEmr->iMode == RGN_COPY) - clipset = false; - break; - } - case EMR_BITBLT: - { - dbg_str << "\n"; - - PEMRBITBLT pEmr = (PEMRBITBLT) lpEMFR; - if (pEmr->dwRop == DPA) { - // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead - double l = pix_to_x_point( d, pEmr->xDest, pEmr->yDest); - double t = pix_to_y_point( d, pEmr->xDest, pEmr->yDest); - double r = pix_to_x_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest); - double b = pix_to_y_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest); - - SVGOStringStream tmp_rectangle; - tmp_rectangle << "d=\""; - tmp_rectangle << "\n\tM " << l << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << b << " "; - tmp_rectangle << "\n\tL " << l << " " << b << " "; - tmp_rectangle << "\n\tz"; - - assert_empty_path(d, "EMR_BITBLT"); - - *(d->outsvg) += " iType); - *(d->outsvg) += "\n\t"; - *(d->outsvg) += tmp_rectangle.str().c_str(); - *(d->outsvg) += " \" /> \n"; - *(d->path) = ""; - } - break; - } - case EMR_STRETCHBLT: - dbg_str << "\n"; - break; - case EMR_MASKBLT: - dbg_str << "\n"; - break; - case EMR_PLGBLT: - dbg_str << "\n"; - break; - case EMR_SETDIBITSTODEVICE: - dbg_str << "\n"; - break; - case EMR_STRETCHDIBITS: - dbg_str << "\n"; - break; - case EMR_EXTCREATEFONTINDIRECTW: - { - dbg_str << "\n"; - - PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR; - int index = pEmr->ihFont; - - EMREXTCREATEFONTINDIRECTW *pFont = - (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) ); - pFont->elfw = pEmr->elfw; - insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont); - break; - } - case EMR_EXTTEXTOUTA: - { - dbg_str << "\n"; - break; - } - case EMR_EXTTEXTOUTW: - { - dbg_str << "\n"; - - PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR; - - double x1 = pEmr->emrtext.ptlReference.x; - double y1 = pEmr->emrtext.ptlReference.y; - - if (d->dc[d->level].textAlign & TA_UPDATECP) { - x1 = d->dc[d->level].cur.x; - y1 = d->dc[d->level].cur.y; - } - - double x = pix_to_x_point(d, x1, y1); - double y = pix_to_y_point(d, x1, y1); - - if (!(d->dc[d->level].textAlign & TA_BOTTOM)) - if (d->dc[d->level].style.baseline_shift.value) { - x += std::sin(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); - y += std::cos(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); - } - else - y += fabs(d->dc[d->level].style.font_size.computed); - - wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString); - - gchar *ansi_text = - (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL ); - - if (ansi_text) { -// gchar *p = ansi_text; -// while (*p) { -// if (*p < 32 || *p >= 127) { -// g_free(ansi_text); -// ansi_text = g_strdup(""); -// break; -// } -// p++; -// } - - SVGOStringStream ts; - - gchar *escaped_text = g_markup_escape_text(ansi_text, -1); - -// float text_rgb[3]; -// sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb ); - -// if (!d->dc[d->level].textColorSet) { -// d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]), -// SP_COLOR_F_TO_U(text_rgb[1]), -// SP_COLOR_F_TO_U(text_rgb[2])); -// } - - char tmp[128]; - snprintf(tmp, 127, - "fill:#%02x%02x%02x;", - GetRValue(d->dc[d->level].textColor), - GetGValue(d->dc[d->level].textColor), - GetBValue(d->dc[d->level].textColor)); - - bool i = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_ITALIC); - //bool o = (d->dc[d->level].style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE); - bool b = (d->dc[d->level].style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) || - (d->dc[d->level].style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->dc[d->level].style.font_weight.value <= SP_CSS_FONT_WEIGHT_900); - int lcr = ((d->dc[d->level].textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->dc[d->level].textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0; - - assert_empty_path(d, "EMR_EXTTEXTOUTW"); - - ts << " id++) << "\"\n"; - ts << " xml:space=\"preserve\"\n"; - ts << " x=\"" << x << "\"\n"; - ts << " y=\"" << y << "\"\n"; - if (d->dc[d->level].style.baseline_shift.value) { - ts << " transform=\"" - << "rotate(-" << d->dc[d->level].style.baseline_shift.value - << " " << x << " " << y << ")" - << "\"\n"; - } - ts << " style=\"" - << "font-size:" << fabs(d->dc[d->level].style.font_size.computed) << "px;" - << tmp - << "font-style:" << (i ? "italic" : "normal") << ";" - << "font-weight:" << (b ? "bold" : "normal") << ";" - << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";" - << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";" - << "font-family:" << d->dc[d->level].tstyle.font_family.value << ";" - << "\"\n"; - ts << " >"; - ts << escaped_text; - ts << "\n"; - - *(d->outsvg) += ts.str().c_str(); - - g_free(escaped_text); - g_free(ansi_text); - } - - break; - } - case EMR_POLYBEZIER16: - { - dbg_str << "\n"; - - PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i,j; - - if (pEmr->cpts<4) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYBEZIER16"); - - *(d->outsvg) += " outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << - pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; - - for (i=1; icpts; ) { - tmp_str << "\n\tC "; - for (j=0; j<3 && icpts; j++,i++) { - tmp_str << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYGON16: - { - dbg_str << "\n"; - - PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - SVGOStringStream tmp_poly; - unsigned int i; - unsigned int first = 0; - - assert_empty_path(d, "EMR_POLYGON16"); - - *(d->outsvg) += " outsvg) += "\n\td=\""; - - // skip the first point? - tmp_poly << "\n\tM " << - pix_to_x_point( d, apts[first].x, apts[first].y ) << " " << - pix_to_y_point( d, apts[first].x, apts[first].y ) << " "; - - for (i=first+1; icpts; i++) { - tmp_poly << "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - - *(d->outsvg) += tmp_poly.str().c_str(); - *(d->outsvg) += " z \" /> \n"; - - break; - } - case EMR_POLYLINE16: - { - dbg_str << "\n"; - - EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i; - - if (pEmr->cpts<2) - break; - - if (!d->inpath) { - assert_empty_path(d, "EMR_POLYLINE16"); - - *(d->outsvg) += " outsvg) += "\n\td=\""; - } - - tmp_str << - "\n\tM " << - pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << - pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; - - for (i=1; icpts; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYBEZIERTO16: - { - dbg_str << "\n"; - - PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i,j; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; icpts;) { - tmp_path << "\n\tC "; - for (j=0; j<3 && icpts; j++,i++) { - tmp_path << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - } - - break; - } - case EMR_POLYLINETO16: - { - dbg_str << "\n"; - - PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR; - POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? - DWORD i; - - if (d->path->empty()) { - d->pathless_stroke = true; - *(d->path) = "d=\""; - } - - for (i=0; icpts;i++) { - tmp_path << - "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - } - - break; - } - case EMR_POLYPOLYLINE16: - case EMR_POLYPOLYGON16: - { - if (lpEMFR->iType == EMR_POLYPOLYLINE16) - dbg_str << "\n"; - if (lpEMFR->iType == EMR_POLYPOLYGON16) - dbg_str << "\n"; - - PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR; - unsigned int n, i, j; - - if (!d->inpath) { - assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16"); - - *(d->outsvg) += " iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; - } - - POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys]; - - i = 0; - for (n=0; nnPolys && icpts; n++) { - SVGOStringStream poly_path; - - poly_path << "\n\tM " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - i++; - - for (j=1; jaPolyCounts[n] && icpts; j++) { - poly_path << "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; - i++; - } - - tmp_str << poly_path.str().c_str(); - if (lpEMFR->iType == EMR_POLYPOLYGON16) - tmp_str << " z"; - tmp_str << " \n"; - } - - if (d->inpath) { - tmp_path << tmp_str.str().c_str(); - } - else { - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; - } - - break; - } - case EMR_POLYDRAW16: - dbg_str << "\n"; - break; - case EMR_CREATEMONOBRUSH: - dbg_str << "\n"; - break; - case EMR_CREATEDIBPATTERNBRUSHPT: - { - dbg_str << "\n"; - - PEMRCREATEDIBPATTERNBRUSHPT pEmr = (PEMRCREATEDIBPATTERNBRUSHPT) lpEMFR; - int index = pEmr->ihBrush; - - EMRCREATEDIBPATTERNBRUSHPT *pBrush = - (EMRCREATEDIBPATTERNBRUSHPT *) malloc( sizeof(EMRCREATEDIBPATTERNBRUSHPT) ); - insert_object(d, index, EMR_CREATEDIBPATTERNBRUSHPT, (ENHMETARECORD *) pBrush); - break; - } - case EMR_EXTCREATEPEN: - { - dbg_str << "\n"; - - PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR; - int index = pEmr->ihPen; - - EMREXTCREATEPEN *pPen = - (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) + - sizeof(DWORD) * pEmr->elp.elpNumEntries ); - pPen->ihPen = pEmr->ihPen; - pPen->offBmi = pEmr->offBmi; - pPen->cbBmi = pEmr->cbBmi; - pPen->offBits = pEmr->offBits; - pPen->cbBits = pEmr->cbBits; - pPen->elp = pEmr->elp; - for (unsigned int i=0; ielp.elpNumEntries; i++) { - pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i]; - } - insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen); - - break; - } - case EMR_POLYTEXTOUTA: - dbg_str << "\n"; - break; - case EMR_POLYTEXTOUTW: - dbg_str << "\n"; - break; - case EMR_SETICMMODE: - dbg_str << "\n"; - break; - case EMR_CREATECOLORSPACE: - dbg_str << "\n"; - break; - case EMR_SETCOLORSPACE: - dbg_str << "\n"; - break; - case EMR_DELETECOLORSPACE: - dbg_str << "\n"; - break; - case EMR_GLSRECORD: - dbg_str << "\n"; - break; - case EMR_GLSBOUNDEDRECORD: - dbg_str << "\n"; - break; - case EMR_PIXELFORMAT: - dbg_str << "\n"; - break; - default: - dbg_str << "\n"; - break; - } - -// *(d->outsvg) += dbg_str.str().c_str(); - *(d->outsvg) += tmp_outsvg.str().c_str(); - *(d->path) += tmp_path.str().c_str(); - - return 1; -} - -static int CALLBACK -myMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, METARECORD * /*lpMFR*/, int /*nObj*/, LPARAM /*lpData*/) -{ - g_warning("Unable to import Windows Meta File.\n"); - return 0; -} - -// Aldus Placeable Header =================================================== -// Since we are a 32bit app, we have to be sure this structure compiles to -// be identical to a 16 bit app's version. To do this, we use the #pragma -// to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT -// for the bbox rectangle. -#pragma pack( push ) -#pragma pack( 2 ) -typedef struct -{ - DWORD dwKey; - WORD hmf; - SMALL_RECT bbox; - WORD wInch; - DWORD dwReserved; - WORD wCheckSum; -} APMHEADER, *PAPMHEADER; -#pragma pack( pop ) - - -SPDocument * -EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) -{ - EMF_CALLBACK_DATA d; - - memset(&d, 0, sizeof(d)); - - d.dc[0].worldTransform.eM11 = 1.0; - d.dc[0].worldTransform.eM12 = 0.0; - d.dc[0].worldTransform.eM21 = 0.0; - d.dc[0].worldTransform.eM22 = 1.0; - d.dc[0].worldTransform.eDx = 0.0; - d.dc[0].worldTransform.eDy = 0.0; - - gsize bytesRead = 0; - gsize bytesWritten = 0; - GError* error = NULL; - gchar *local_fn = - g_filename_from_utf8( uri, -1, &bytesRead, &bytesWritten, &error ); - - if (local_fn == NULL) { - return NULL; - } - - d.outsvg = new Glib::ustring(""); - d.path = new Glib::ustring(""); - d.outdef = new Glib::ustring(""); - - CHAR *ansi_uri = (CHAR *) local_fn; - gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL ); - WCHAR *unicode_uri = (WCHAR *) unicode_fn; - - DWORD filesize = 0; - HANDLE fp = NULL; - - HMETAFILE hmf; - HENHMETAFILE hemf; - - fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if ( fp != INVALID_HANDLE_VALUE ) { - filesize = GetFileSize(fp, NULL); - CloseHandle(fp); - } - - // Try open as Enhanced Metafile - hemf = GetEnhMetaFileW(unicode_uri); - - if (!hemf) { - // Try open as Windows Metafile - hmf = GetMetaFileW(unicode_uri); - - METAFILEPICT mp; - HDC hDC; - - if (!hmf) { - WCHAR szTemp[MAX_PATH]; - - DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH ); - if (dw) { - hmf = GetMetaFileW( szTemp ); - } - } - - if (hmf) { - DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL ); - - if (!nSize) - nSize = filesize; - - if (nSize) { - BYTE *lpvData = new BYTE[nSize]; - if (lpvData) { - DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData ); - if (dw) { - // Fill out a METAFILEPICT structure - mp.mm = MM_ANISOTROPIC; - mp.xExt = 1000; - mp.yExt = 1000; - mp.hMF = NULL; - // Get a reference DC - hDC = GetDC( NULL ); - // Make an enhanced metafile from the windows metafile - hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp ); - // Clean up - ReleaseDC( NULL, hDC ); - DeleteMetaFile( hmf ); - hmf = NULL; - } - else { - // EnumMetaFile - } - delete[] lpvData; - } - else { - DeleteMetaFile( hmf ); - hmf = NULL; - } - } - else { - DeleteMetaFile( hmf ); - hmf = NULL; - } - } - else { - // Try open as Aldus Placeable Metafile - HANDLE hFile; - hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - - if (hFile != INVALID_HANDLE_VALUE) { - DWORD nSize = GetFileSize( hFile, NULL ); - if (nSize) { - BYTE *lpvData = new BYTE[nSize]; - if (lpvData) { - DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL ); - if (dw) { - if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) { - // Fill out a METAFILEPICT structure - mp.mm = MM_ANISOTROPIC; - mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left; - mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch); - mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top; - mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch); - mp.hMF = NULL; - // Get a reference DC - hDC = GetDC( NULL ); - // Create an enhanced metafile from the bits - hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp ); - // Clean up - ReleaseDC( NULL, hDC ); - } - } - delete[] lpvData; - } - } - CloseHandle( hFile ); - } - } - } - - if ((!hemf && !hmf) || !d.outsvg || !d.path) { - if (d.outsvg) - delete d.outsvg; - if (d.path) - delete d.path; - if (d.outdef) - delete d.outdef; - if (local_fn) - g_free(local_fn); - if (unicode_fn) - g_free(unicode_fn); - if (hemf) - DeleteEnhMetaFile(hemf); - if (hmf) - DeleteMetaFile(hmf); - return NULL; - } - - d.pDesc = NULL; - - if (hemf) { - DWORD dwNeeded = GetEnhMetaFileDescriptionA( hemf, 0, NULL ); - if ( dwNeeded > 0 ) { - d.pDesc = (CHAR *) malloc( dwNeeded + 1 ); - if ( GetEnhMetaFileDescription( hemf, dwNeeded, d.pDesc ) == 0 ) - lstrcpy( d.pDesc, "" ); - if ( lstrlen( d.pDesc ) > 1 ) - d.pDesc[lstrlen(d.pDesc)] = '#'; - } - - // This ugly reinterpret_cast is to prevent old versions of gcc from whining about a mismatch in the const-ness of the arguments - EnumEnhMetaFile(NULL, hemf, reinterpret_cast(myEnhMetaFileProc), (LPVOID) &d, NULL); - DeleteEnhMetaFile(hemf); - } - else { - EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d); - DeleteMetaFile(hmf); - } - - if (d.pDesc) - free( d.pDesc ); - -// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; - - SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); - - delete d.outsvg; - delete d.path; - delete d.outdef; - - if (d.emf_obj) { - int i; - for (i=0; i\n" - "" N_("EMF Input") "\n" - "org.inkscape.input.emf.win32\n" - "\n" - ".emf\n" - "image/x-emf\n" - "" N_("Enhanced Metafiles (*.emf)") "\n" - "" N_("Enhanced Metafiles") "\n" - "org.inkscape.output.emf.win32\n" - "\n" - "", new EmfWin32()); - - /* WMF in */ - Inkscape::Extension::build_from_mem( - "\n" - "" N_("WMF Input") "\n" - "org.inkscape.input.wmf.win32\n" - "\n" - ".wmf\n" - "image/x-wmf\n" - "" N_("Windows Metafiles (*.wmf)") "\n" - "" N_("Windows Metafiles") "\n" - "org.inkscape.output.emf.win32\n" - "\n" - "", new EmfWin32()); - - /* EMF out */ - Inkscape::Extension::build_from_mem( - "\n" - "" N_("EMF Output") "\n" - "org.inkscape.output.emf.win32\n" - "true\n" - "\n" - ".emf\n" - "image/x-emf\n" - "" N_("Enhanced Metafile (*.emf)") "\n" - "" N_("Enhanced Metafile") "\n" - "\n" - "", new EmfWin32()); - - return; -} - - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* WIN32 */ -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-inout.h b/src/extension/internal/emf-win32-inout.h deleted file mode 100644 index 4b975c8de..000000000 --- a/src/extension/internal/emf-win32-inout.h +++ /dev/null @@ -1,57 +0,0 @@ -/** @file - * @brief Enhanced Metafile Input/Output - */ -/* Authors: - * Ulf Erikson - * - * Copyright (C) 2006-2008 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifndef SEEN_EXTENSION_INTERNAL_EMF_WIN32_H -#define SEEN_EXTENSION_INTERNAL_EMF_WIN32_H -#ifdef WIN32 - -#include "extension/implementation/implementation.h" - -namespace Inkscape { -namespace Extension { -namespace Internal { - -class EmfWin32 : Inkscape::Extension::Implementation::Implementation { //This is a derived class - -public: - EmfWin32(); // Empty constructor - - virtual ~EmfWin32();//Destructor - - bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) - - void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename - SPDocument *doc, - gchar const *filename); - - virtual SPDocument *open( Inkscape::Extension::Input *mod, - const gchar *uri ); - - static void init(void);//Initialize the class - -private: -}; - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* WIN32 */ - -#endif /* EXTENSION_INTERNAL_EMF_WIN32_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp deleted file mode 100644 index 2b79fd5a4..000000000 --- a/src/extension/internal/emf-win32-print.cpp +++ /dev/null @@ -1,942 +0,0 @@ -/** @file - * @brief Enhanced Metafile printing - */ -/* Authors: - * Ulf Erikson - * Jon A. Cruz - * Abhishek Sharma - * - * Copyright (C) 2006-2009 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -/* - * References: - * - How to Create & Play Enhanced Metafiles in Win32 - * http://support.microsoft.com/kb/q145999/ - * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles - * http://support.microsoft.com/kb/q66949/ - * - Metafile Functions - * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp - * - Metafile Structures - * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp - */ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - - -#include <2geom/pathvector.h> -#include <2geom/rect.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> -#include "helper/geom.h" -#include "helper/geom-curves.h" -#include "sp-item.h" - -#include "style.h" -#include "inkscape-version.h" -#include "sp-root.h" - -#include "emf-win32-print.h" - -#include "unit-constants.h" - -#include "extension/system.h" -#include "extension/print.h" -#include "document.h" - - -namespace Inkscape { -namespace Extension { -namespace Internal { - -static float dwDPI = 2540; - - -PrintEmfWin32::PrintEmfWin32 (void): - _width(0), - _height(0), - hdc(NULL), - hbrush(NULL), - hbrushOld(NULL), - hpen(NULL), - stroke_and_fill(false), - fill_only(false), - simple_shape(false) -{ -} - - -PrintEmfWin32::~PrintEmfWin32 (void) -{ - if (hdc) { - HENHMETAFILE metafile = CloseEnhMetaFile( hdc ); - if ( metafile ) { - DeleteEnhMetaFile( metafile ); - } - DeleteDC( hdc ); - } - - /* restore default signal handling for SIGPIPE */ -#if !defined(_WIN32) && !defined(__WIN32__) - (void) signal(SIGPIPE, SIG_DFL); -#endif - return; -} - - -unsigned int PrintEmfWin32::setup (Inkscape::Extension::Print * /*mod*/) -{ - return TRUE; -} - - -unsigned int PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) -{ - gchar const *utf8_fn = mod->get_param_string("destination"); - - gsize bytesRead = 0; - gsize bytesWritten = 0; - GError* error = NULL; - gchar *local_fn = - g_filename_from_utf8( utf8_fn, -1, &bytesRead, &bytesWritten, &error ); - - if (local_fn == NULL) { - return 1; - } - - CHAR *ansi_uri = (CHAR *) local_fn; - gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL ); - WCHAR *unicode_uri = (WCHAR *) unicode_fn; - - // width and height in px - _width = doc->getWidth(); - _height = doc->getHeight(); - - bool pageBoundingBox; - pageBoundingBox = mod->get_param_bool("pageBoundingBox"); - - Geom::Rect d; - if (pageBoundingBox) { - d = Geom::Rect::from_xywh(0, 0, _width, _height); - } else { - SPItem* doc_item = doc->getRoot(); - Geom::OptRect bbox = doc_item->desktopVisualBounds(); - if (bbox) d = *bbox; - } - - d *= Geom::Scale(IN_PER_PX); - - float dwInchesX = d.width(); - float dwInchesY = d.height(); - - // dwInchesX x dwInchesY in .01mm units - SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) ); - - // Get a Reference DC - HDC hScreenDC = GetDC( NULL ); - - // Get the physical characteristics of the reference DC - int PixelsX = GetDeviceCaps( hScreenDC, HORZRES ); - int PixelsY = GetDeviceCaps( hScreenDC, VERTRES ); - int MMX = GetDeviceCaps( hScreenDC, HORZSIZE ); - int MMY = GetDeviceCaps( hScreenDC, VERTSIZE ); - - CHAR buff[1024]; - ZeroMemory(buff, sizeof(buff)); - snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", Inkscape::version_string, __DATE__); - INT len = strlen(buff); - CHAR *p1 = strrchr(ansi_uri, '\\'); - CHAR *p2 = strrchr(ansi_uri, '/'); - CHAR *p = MAX(p1, p2); - if (p) - p++; - else - p = ansi_uri; - snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p); - - // Create the Metafile - { - WCHAR wbuff[1024]; - ZeroMemory(wbuff, sizeof(wbuff)); - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0])); - hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff ); - } - - // Release the reference DC - ReleaseDC( NULL, hScreenDC ); - - // Did we get a good metafile? - if (hdc == NULL) - { - g_free(local_fn); - g_free(unicode_fn); - return 1; - } - - // Anisotropic mapping mode - SetMapMode( hdc, MM_ANISOTROPIC ); - - // Set the Windows extent - int windowextX = (int) ceil(dwInchesX*dwDPI); - int windowextY = (int) ceil(dwInchesY*dwDPI); - SetWindowExtEx( hdc, windowextX, windowextY, NULL ); - - // Set the viewport extent to reflect - // dwInchesX" x dwInchesY" in device units - int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX); - int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY); - SetViewportExtEx( hdc, viewportextX, viewportextY, NULL ); - - if (1) { - snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY); - GdiComment(hdc, strlen(buff), (BYTE*) buff); - - snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN); - GdiComment(hdc, strlen(buff), (BYTE*) buff); - } - - SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) ); - - g_free(local_fn); - g_free(unicode_fn); - - m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight())); /// @fixme hardcoded doc2dt transform - - return 0; -} - - -unsigned int PrintEmfWin32::finish (Inkscape::Extension::Print * /*mod*/) -{ - if (!hdc) return 0; - - flush_fill(); // flush any pending fills - - HENHMETAFILE metafile = CloseEnhMetaFile( hdc ); - if ( metafile ) { - DeleteEnhMetaFile( metafile ); - } - DeleteDC( hdc ); - - hdc = NULL; - - return 0; -} - - -unsigned int PrintEmfWin32::comment (Inkscape::Extension::Print * /*module*/, - const char * /*comment*/) -{ - if (!hdc) return 0; - - flush_fill(); // flush any pending fills - - return 0; -} - - -int PrintEmfWin32::create_brush(SPStyle const *style) -{ - float rgb[3]; - - if (style) { - float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); - if (opacity <= 0.0) - return 1; - - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) ); - hbrushOld = (HBRUSH) SelectObject( hdc, hbrush ); - - SetPolyFillMode( hdc, - style->fill_rule.computed == 0 ? WINDING : - style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE ); - } else { // if (!style) - hbrush = CreateSolidBrush( RGB(255, 255, 255) ); - hbrushOld = (HBRUSH) SelectObject( hdc, hbrush ); - SetPolyFillMode( hdc, ALTERNATE ); - } - - return 0; -} - - -void PrintEmfWin32::destroy_brush() -{ - SelectObject( hdc, hbrushOld ); - if (hbrush) - DeleteObject( hbrush ); - hbrush = NULL; - hbrushOld = NULL; -} - - -void PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Affine &transform) -{ - if (style) { - float rgb[3]; - - sp_color_get_rgb_floatv(&style->stroke.value.color, rgb); - - LOGBRUSH lb; - ZeroMemory(&lb, sizeof(lb)); - lb.lbStyle = BS_SOLID; - lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] ); - - int linestyle = PS_SOLID; - int linecap = 0; - int linejoin = 0; - DWORD n_dash = 0; - DWORD *dash = NULL; - - using Geom::X; - using Geom::Y; - - Geom::Point zero(0, 0); - Geom::Point one(1, 1); - Geom::Point p0(zero * transform); - Geom::Point p1(one * transform); - Geom::Point p(p1 - p0); - - double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2); - - DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) ); - - if (style->stroke_linecap.computed == 0) { - linecap = PS_ENDCAP_FLAT; - } - else if (style->stroke_linecap.computed == 1) { - linecap = PS_ENDCAP_ROUND; - } - else if (style->stroke_linecap.computed == 2) { - linecap = PS_ENDCAP_SQUARE; - } - - if (style->stroke_linejoin.computed == 0) { - linejoin = PS_JOIN_MITER; - } - else if (style->stroke_linejoin.computed == 1) { - linejoin = PS_JOIN_ROUND; - } - else if (style->stroke_linejoin.computed == 2) { - linejoin = PS_JOIN_BEVEL; - } - - if (style->stroke_dash.n_dash && - style->stroke_dash.dash ) - { - int i = 0; - while (linestyle != PS_USERSTYLE && - (i < style->stroke_dash.n_dash)) { - if (style->stroke_dash.dash[i] > 0.00000001) - linestyle = PS_USERSTYLE; - i++; - } - - if (linestyle == PS_USERSTYLE) { - n_dash = style->stroke_dash.n_dash; - dash = new DWORD[n_dash]; - for (i = 0; i < style->stroke_dash.n_dash; i++) { - dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI); - } - } - } - - hpen = ExtCreatePen( - PS_GEOMETRIC | linestyle | linecap | linejoin, - linewidth, - &lb, - n_dash, - dash ); - - if ( !hpen && linestyle == PS_USERSTYLE ) { - hpen = ExtCreatePen( - PS_GEOMETRIC | PS_SOLID | linecap | linejoin, - linewidth, - &lb, - 0, - NULL ); - } - - if ( !hpen ) { - hpen = CreatePen( - PS_SOLID, - linewidth, - lb.lbColor ); - } - - hpenOld = (HPEN) SelectObject( hdc, hpen ); - - if (linejoin == PS_JOIN_MITER) { - float oldmiterlimit; - float miterlimit = style->stroke_miterlimit.value; //ratio, not a pt size - - SetMiterLimit( - hdc, - miterlimit, - &oldmiterlimit ); - } - - if (n_dash) { - delete[] dash; - } - } - else { // if (!style) - hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) ); - hpenOld = (HPEN) SelectObject( hdc, hpen ); - } -} - - -void PrintEmfWin32::destroy_pen() -{ - SelectObject( hdc, hpenOld ); - if (hpen) - DeleteObject( hpen ); - hpen = NULL; -} - - -void PrintEmfWin32::flush_fill() -{ - if (!fill_pathv.empty()) { - stroke_and_fill = false; - fill_only = true; - print_pathv(fill_pathv, fill_transform); - fill_only = false; - if (!simple_shape) - FillPath( hdc ); - destroy_brush(); - fill_pathv.clear(); - } -} - -unsigned int PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/) -{ - if (!m_tr_stack.empty()) { - Geom::Affine tr_top = m_tr_stack.top(); - m_tr_stack.push(transform * tr_top); - } else { - m_tr_stack.push(transform); - } - - return 1; -} - -unsigned int PrintEmfWin32::release(Inkscape::Extension::Print * /*mod*/) -{ - m_tr_stack.pop(); - return 1; -} - -unsigned int PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/, - Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, - Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) -{ - if (!hdc) return 0; - - Geom::Affine tf = m_tr_stack.top(); - - flush_fill(); // flush any pending fills - - if (style->fill.isColor()) { - if (create_brush(style)) - return 0; - } else { - // create_brush(NULL); - return 0; - } - - fill_pathv.clear(); - std::copy(pathv.begin(), pathv.end(), std::back_inserter(fill_pathv)); - fill_transform = tf; - - // postpone fill in case of stroke-and-fill - - return 0; -} - - -unsigned int PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/, - Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style, - Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) -{ - if (!hdc) return 0; - - Geom::Affine tf = m_tr_stack.top(); - - stroke_and_fill = ( pathv == fill_pathv ); - - if (!stroke_and_fill) { - flush_fill(); // flush any pending fills - } - - if (style->stroke.isColor()) { - create_pen(style, tf); - } else { - // create_pen(NULL, tf); - return 0; - } - - print_pathv(pathv, tf); - - if (stroke_and_fill) { - if (!simple_shape) - StrokeAndFillPath( hdc ); - destroy_brush(); - fill_pathv.clear(); - } else { - if (!simple_shape) - StrokePath( hdc ); - } - - destroy_pen(); - - return 0; -} - - -bool PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) -{ - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); - - int nodes = 0; - int moves = 0; - int lines = 0; - int curves = 0; - - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) - { - moves++; - nodes++; - - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - nodes++; - - if ( is_straight_curve(*cit) ) { - lines++; - } - else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - cubic = cubic; - curves++; - } - } - } - - if (!nodes) - return false; - - POINT *lpPoints = new POINT[moves + lines + curves*3]; - int i = 0; - - /** - * For all Subpaths in the - */ - 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] * IN_PER_PX * dwDPI); - p0[Y] = (p0[Y] * IN_PER_PX * dwDPI); - - LONG const x0 = (LONG) round(p0[X]); - LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - - lpPoints[i].x = x0; - lpPoints[i].y = y0; - i = i + 1; - - /** - * For all segments in the subpath - */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { - //Geom::Point p0 = cit->initialPoint(); - Geom::Point p1 = cit->finalPoint(); - - //p0[X] = (p0[X] * IN_PER_PX * dwDPI); - p1[X] = (p1[X] * IN_PER_PX * dwDPI); - //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI); - p1[Y] = (p1[Y] * IN_PER_PX * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - - lpPoints[i].x = x1; - lpPoints[i].y = y1; - i = i + 1; - } - else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) - { - std::vector 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] * IN_PER_PX * dwDPI); - p1[X] = (p1[X] * IN_PER_PX * dwDPI); - p2[X] = (p2[X] * IN_PER_PX * dwDPI); - p3[X] = (p3[X] * IN_PER_PX * dwDPI); - //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI); - p1[Y] = (p1[Y] * IN_PER_PX * dwDPI); - p2[Y] = (p2[Y] * IN_PER_PX * dwDPI); - p3[Y] = (p3[Y] * IN_PER_PX * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - LONG const x2 = (LONG) round(p2[X]); - LONG const y2 = (LONG) round(rc.bottom-p2[Y]); - LONG const x3 = (LONG) round(p3[X]); - LONG const y3 = (LONG) round(rc.bottom-p3[Y]); - - POINT pt[3]; - pt[0].x = x1; - pt[0].y = y1; - pt[1].x = x2; - pt[1].y = y2; - pt[2].x = x3; - pt[2].y = y3; - - lpPoints[i].x = x1; - lpPoints[i].y = y1; - lpPoints[i+1].x = x2; - lpPoints[i+1].y = y2; - lpPoints[i+2].x = x3; - lpPoints[i+2].y = y3; - i = i + 3; - } - } - } - - bool done = false; - bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); - bool polygon = false; - bool rectangle = false; - bool ellipse = false; - - if (moves == 1 && moves+lines == nodes && closed) { - polygon = true; -// if (nodes==5) { // disable due to LP Bug 407394 -// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && -// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) -// { -// rectangle = true; -// } -// } - } - else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { -// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && -// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && -// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && -// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && -// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && -// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) -// { // disable due to LP Bug 407394 -// ellipse = true; -// } - } - - if (polygon || ellipse) { - HPEN hpenTmp = NULL; - HPEN hpenOld = NULL; - HBRUSH hbrushTmp = NULL; - HBRUSH hbrushOld = NULL; - - if (!stroke_and_fill) { - if (fill_only) { - hpenTmp = (HPEN) GetStockObject(NULL_PEN); - hpenOld = (HPEN) SelectObject( hdc, hpenTmp ); - } - else { // if (stroke_only) - hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH); - hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp ); - } - } - - if (polygon) { - if (rectangle) - Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y ); - else - Polygon( hdc, lpPoints, nodes ); - } - else if (ellipse) { - Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y); - } - - done = true; - - if (hpenOld) - SelectObject( hdc, hpenOld ); - if (hpenTmp) - DeleteObject( hpenTmp ); - if (hbrushOld) - SelectObject( hdc, hbrushOld ); - if (hbrushTmp) - DeleteObject( hbrushTmp ); - } - - delete[] lpPoints; - - return done; -} - -unsigned int PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) -{ - simple_shape = print_simple_shape(pathv, transform); - - if (simple_shape) - return TRUE; - - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); - - BeginPath( hdc ); - - /** - * For all Subpaths in the - */ - 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] * IN_PER_PX * dwDPI); - p0[Y] = (p0[Y] * IN_PER_PX * dwDPI); - - LONG const x0 = (LONG) round(p0[X]); - LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - - MoveToEx( hdc, x0, y0, NULL ); - - /** - * For all segments in the subpath - */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) - { - if ( is_straight_curve(*cit) ) - { - //Geom::Point p0 = cit->initialPoint(); - Geom::Point p1 = cit->finalPoint(); - - //p0[X] = (p0[X] * IN_PER_PX * dwDPI); - p1[X] = (p1[X] * IN_PER_PX * dwDPI); - //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI); - p1[Y] = (p1[Y] * IN_PER_PX * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - - LineTo( hdc, x1, y1 ); - } - else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) - { - std::vector 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] * IN_PER_PX * dwDPI); - p1[X] = (p1[X] * IN_PER_PX * dwDPI); - p2[X] = (p2[X] * IN_PER_PX * dwDPI); - p3[X] = (p3[X] * IN_PER_PX * dwDPI); - //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI); - p1[Y] = (p1[Y] * IN_PER_PX * dwDPI); - p2[Y] = (p2[Y] * IN_PER_PX * dwDPI); - p3[Y] = (p3[Y] * IN_PER_PX * dwDPI); - - //LONG const x0 = (LONG) round(p0[X]); - //LONG const y0 = (LONG) round(rc.bottom-p0[Y]); - LONG const x1 = (LONG) round(p1[X]); - LONG const y1 = (LONG) round(rc.bottom-p1[Y]); - LONG const x2 = (LONG) round(p2[X]); - LONG const y2 = (LONG) round(rc.bottom-p2[Y]); - LONG const x3 = (LONG) round(p3[X]); - LONG const y3 = (LONG) round(rc.bottom-p3[Y]); - - POINT pt[3]; - pt[0].x = x1; - pt[0].y = y1; - pt[1].x = x2; - pt[1].y = y2; - pt[2].x = x3; - pt[2].y = y3; - - PolyBezierTo( hdc, pt, 3 ); - } - else - { - g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used"); - } - } - - if (pit->end_default() == pit->end_closed()) { - CloseFigure( hdc ); - } - } - - EndPath( hdc ); - - return TRUE; -} - - -bool PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext) -{ - return ext->get_param_bool("textToPath"); -} - -unsigned int PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p, - SPStyle const *const style) -{ - if (!hdc) return 0; - - HFONT hfont = NULL; - Geom::Affine tf = m_tr_stack.top(); - double rot = 1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation - -#ifdef USE_PANGO_WIN32 -/* - font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style)); - if (tf) { - LOGFONT *lf = pango_win32_font_logfont(tf->pFont); - tf->Unref(); - hfont = CreateFontIndirect(lf); - g_free(lf); - } -*/ -#endif - - if (!hfont) { - LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW)); - g_assert(lf != NULL); - - lf->lfHeight = -style->font_size.computed * IN_PER_PX * dwDPI; - lf->lfWidth = 0; - lf->lfEscapement = rot; - lf->lfOrientation = rot; - lf->lfWeight = - style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD : - style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY : - FW_NORMAL; - lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC); - lf->lfUnderline = style->text_decoration.underline; - lf->lfStrikeOut = style->text_decoration.line_through; - lf->lfCharSet = DEFAULT_CHARSET; - lf->lfOutPrecision = OUT_DEFAULT_PRECIS; - lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf->lfQuality = DEFAULT_QUALITY; - lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - - gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL ); - wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1); - g_free(unicode_name); - - hfont = CreateFontIndirectW(lf); - - g_free(lf); - } - - HFONT hfontOld = (HFONT) SelectObject(hdc, hfont); - - float rgb[3]; - sp_color_get_rgb_floatv( &style->fill.value.color, rgb ); - SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2])); - - // Text alignment: - // - (x,y) coordinates received by this filter are those of the point where the text - // actually starts, and already takes into account the text object's alignment; - // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT. - SetTextAlign(hdc, TA_BASELINE | TA_LEFT); - - // Transparent text background - SetBkMode(hdc, TRANSPARENT); - - Geom::Point p2 = p * tf; - p2[Geom::X] = (p2[Geom::X] * IN_PER_PX * dwDPI); - p2[Geom::Y] = (p2[Geom::Y] * IN_PER_PX * dwDPI); - - LONG const xpos = (LONG) round(p2[Geom::X]); - LONG const ypos = (LONG) round(rc.bottom - p2[Geom::Y]); - - { - gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL ); - TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text)); - } - - SelectObject(hdc, hfontOld); - DeleteObject(hfont); - - return 0; -} - -void PrintEmfWin32::init (void) -{ - /* EMF print */ - Inkscape::Extension::build_from_mem( - "\n" - "Enhanced Metafile Print\n" - "org.inkscape.print.emf.win32\n" - "\n" - "true\n" - "true\n" - "\n" - "", new PrintEmfWin32()); - - return; -} - -unsigned int PrintEmfWin32::image(Inkscape::Extension::Print * /* module */, /** not used */ - unsigned char *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 */ -{ - free(px); - return 0; -} - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif /* WIN32 */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/emf-win32-print.h deleted file mode 100644 index e7bd08477..000000000 --- a/src/extension/internal/emf-win32-print.h +++ /dev/null @@ -1,120 +0,0 @@ -/** @file - * @brief Enhanced Metafile printing - implementation - */ -/* Author: - * Ulf Erikson - * - * Copyright (C) 2006-2008 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ -#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ - -#ifdef WIN32 - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define WIN32_LEAN_AND_MEAN -#include - -#include "extension/implementation/implementation.h" -//#include "extension/extension.h" - -#include <2geom/pathvector.h> - -#include - -namespace Inkscape { -namespace Extension { -namespace Internal { - -class PrintEmfWin32 : public Inkscape::Extension::Implementation::Implementation -{ - double _width; - double _height; - HDC hdc; - RECT rc; - - HBRUSH hbrush, hbrushOld; - HPEN hpen, hpenOld; - - std::stack m_tr_stack; - Geom::PathVector fill_pathv; - Geom::Affine fill_transform; - bool stroke_and_fill; - bool fill_only; - bool simple_shape; - - unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); - bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); - unsigned int image(Inkscape::Extension::Print * /* module */, /** not used */ - unsigned char *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 */ - -public: - PrintEmfWin32 (void); - virtual ~PrintEmfWin32 (void); - - /* Print functions */ - virtual unsigned int setup (Inkscape::Extension::Print * module); - - virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc); - virtual unsigned int finish (Inkscape::Extension::Print * module); - - /* Rendering methods */ - virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const &transform, float opacity); - virtual unsigned int release(Inkscape::Extension::Print *module); - virtual unsigned int fill (Inkscape::Extension::Print *module, - Geom::PathVector const &pathv, - Geom::Affine const &ctm, SPStyle const *style, - Geom::OptRect const &pbox, Geom::OptRect const &dbox, - Geom::OptRect const &bbox); - virtual unsigned int stroke (Inkscape::Extension::Print * module, - Geom::PathVector const &pathv, - Geom::Affine const &ctm, SPStyle const *style, - Geom::OptRect const &pbox, Geom::OptRect const &dbox, - Geom::OptRect const &bbox); - virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); - virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, - Geom::Point const &p, SPStyle const *style); - bool textToPath (Inkscape::Extension::Print * ext); - - static void init (void); -protected: - int create_brush(SPStyle const *style); - - void destroy_brush(); - - void create_pen(SPStyle const *style, const Geom::Affine &transform); - - void destroy_pen(); - - void flush_fill(); - -}; - -} /* namespace Internal */ -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif /* WIN32 */ - -#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/uemf.c b/src/extension/internal/uemf.c new file mode 100644 index 000000000..9cbac159e --- /dev/null +++ b/src/extension/internal/uemf.c @@ -0,0 +1,5612 @@ +/** + @file uemf.c Functions for manipulating EMF files and structures. + + [U_EMR*]_set all take data and return a pointer to memory holding the constructed record. + The size of that record is also returned in recsize. + It is also in the second int32 in the record, but may have been byte swapped and so not usable. + If something goes wrong a NULL pointer is returned and recsize is set to 0. + + Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for + uninitialized data. + + Compile with "SOL8" defined for Solaris 8 or 9 (Sparc). +*/ + +/* +File: uemf.c +Version: 0.0.8 +Date: 14-SEP-2012 +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 +#include +#include +#include +#include +#include +#include +#include // for INT_MAX, INT_MIN +#include // for U_ROUND() +#if 0 +#include //Not actually used, looking for collisions +#include //Not actually used, looking for collisions +#include //Not actually used, looking for collisions +#endif +#include "uemf.h" +/* one prototype from uemf_endian. Put it here because end user should never need to see it, sno +not in uemf.h or uemf_endian.h */ +void U_swap2(void *ul, unsigned int count); + +/* ********************************************************************************************** +These definitions are for code pieces that are used many times in the following implementation. These +definitions are not needed in end user code, so they are here rather than in uemf.h. +*********************************************************************************************** */ + +//! @cond + +// this one may also be used A=Msk,B=MskBmi and F=cbMsk +#define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \ + if(A){\ + if(!B)return(NULL); /* size is derived from U_BIMAPINFO, but NOT from its size field, go figure*/ \ + C = F;\ + D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \ + E = sizeof(U_BITMAPINFOHEADER) + 4 * B->bmiHeader.biClrUsed; /* bmiheader + colortable*/ \ + }\ + else { D = 0; E=0; } + +// variable "off" must be declared in the function + +#define APPEND_PXBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR,C=cbBmi, D=Bmi, E=Px, F=cbImage, G=cbImage4 */ \ + if(C){\ + memcpy(A + off, D, C);\ + ((B *) A)->offBmiSrc = off;\ + ((B *) A)->cbBmiSrc = C;\ + off += C;\ + memcpy(A + off, E, F);\ + ((B *) A)->offBitsSrc = off;\ + ((B *) A)->cbBitsSrc = F;\ + if(G - F){ memset(A + off, 0, G - F); }\ + }\ + else {\ + ((B *) A)->offBmiSrc = 0;\ + ((B *) A)->cbBmiSrc = 0;\ + ((B *) A)->offBitsSrc = 0;\ + ((B *) A)->cbBitsSrc = 0;\ + } + +// variable "off" must be declared in the function + +#define APPEND_MSKBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR*,C=cbMskBmi, D=MskBmi, E=Msk, F=cbMskImage, G=cbMskImage4 */ \ + if(C){\ + memcpy(A + off, D, C);\ + ((B *) A)->offBmiMask = off;\ + ((B *) A)->cbBmiMask = C;\ + off += C;\ + memcpy(A + off, Msk, F);\ + ((B *) A)->offBitsMask = off;\ + ((B *) A)->cbBitsMask = F;\ + if(G - F){ memset(A + off, 0, G - F); }\ + }\ + else {\ + ((B *) A)->offBmiMask = 0;\ + ((B *) A)->cbBmiMask = 0;\ + ((B *) A)->offBitsMask = 0;\ + ((B *) A)->cbBitsMask = 0;\ + } + +/* iconv() has a funny cast on some older systems, on most recent ones + it is just char **. This tries to work around the issue. If you build this + on another funky system this code may need to be modified, or define ICONV_CAST + on the compile line(but it may be tricky). +*/ +#ifdef SOL8 +#define ICONV_CAST (const char **) +#endif //SOL8 +#if !defined(ICONV_CAST) +#define ICONV_CAST (char **) +#endif //ICONV_CAST +//! @endcond + +/* ********************************************************************************************** +These functions are used for development and debugging and should be be includied in production code. +*********************************************************************************************** */ + +/** + \brief Debugging utility, used with valgrind to find uninitialized values. Not for use in production code. + \param buf memory area to examine ! + \param size length in bytes of buf! +*/ +int memprobe( + void *buf, + size_t size + ){ + int sum=0; + char *ptr=(char *)buf; + for(;size;size--,ptr++){ sum += *ptr; } // read all bytes, trigger valgrind warning if any uninitialized + return(sum); +} + +/** + \brief Dump a UTF8 string. Not for use in production code. + \param src string to examine +*/ +void wchar8show( + const char *src + ){ + printf("char show\n"); + size_t srclen = 0; + while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; } +} + +/** + \brief Dump a UTF16 string. Not for use in production code. + \param src string to examine +*/ +void wchar16show( + const uint16_t *src + ){ + printf("uint16_t show\n"); + size_t srclen = 0; + while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; } +} + +/** + \brief Dump a UTF32 string. Not for use in production code. +*/ +void wchar32show( + const uint32_t *src + ){ + printf("uint32_t show\n"); + size_t srclen = 0; + while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; } +} + +/** + \brief Dump a wchar_t string. Not for use in production code. + \param src string to examine +*/ +void wchartshow( + const wchar_t *src + ){ + uint32_t val; + printf("wchar_t show\n"); + size_t srclen = 0; + while(*src){ + val = *src; // because *src is wchar_t is not strictly an integer type, can cause warnings on next line + printf("%d %d %x\n",(int) srclen,val,val); + srclen++; + src++; + } +} + +/** + \brief Dump the eht 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 +*/ +void dumpeht( + char *string, + unsigned int *handle, + EMFHANDLES *eht + ){ + uint32_t i; + printf("%s\n",string); + printf("sptr: %d peak: %d top: %d\n",eht->sptr,eht->peak,eht->top); + if(handle){ + printf("handle: %d \n",*handle); + } + for(i=0;i<=5;i++){ + printf("table[%d]: %d\n",i,eht->table[i]); + } + for(i=1;i<=5;i++){ + printf("stack[%d]: %d\n",i,eht->stack[i]); + } +} + +/* ********************************************************************************************** +These functions are used for character type conversions, Image conversions, and other +utility operations +*********************************************************************************************** */ + +/** + \brief Find the number of (storage) characters in a 16 bit character string, not including terminator. + \param src string to examine +*/ +size_t wchar16len( + const uint16_t *src + ){ + size_t srclen = 0; + while(*src){ srclen++; src++; } + return(srclen); +} + +/** + \brief Find the number of (storage) characters in a 32 bit character string, not including terminator. + \param src string to examine +*/ +size_t wchar32len( + const uint32_t *src + ){ + size_t srclen = 0; + while(*src){ srclen++; src++; } + return(srclen); +} + +/** + \brief Strncpy for wchar16 (UTF16). + \param dst destination (already allocated) + \param src source + \param nchars number of characters to copy +*/ +void wchar16strncpy( + uint16_t *dst, + const uint16_t *src, + size_t nchars + ){ + for(;nchars;nchars--,dst++,src++){ + *dst = *src; + if(!*src)break; + } +} + +/** + \brief Fill the output string with N characters, if the input string is shorter than N, pad with nulls. + \param dst destination (already allocated) + \param src source + \param nchars number of characters to copy + +*/ +void wchar16strncpypad( + uint16_t *dst, + const uint16_t *src, + size_t nchars + ){ + for(;*src && nchars;nchars--,dst++,src++){ *dst = *src; } + for(;nchars;nchars--,dst++){ *dst = 0; } // Pad the remainder +} + +/* For the following converstion functions, remember that iconv() modifies ALL of its parameters, + so save a pointer to the destination buffer!!!! + It isn't clear that terminators are being + copied properly, so be sure allocated space is a bit larger and cleared. +*/ + +/** + \brief Convert a UTF32LE string to a UTF16LE string. + \returns pointer to new string or NULL if it fails + \param src wchar_t string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint16_t *U_Utf32leToUtf16le( + const uint32_t *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + + if(max){ srclen = 4*max; } + else { srclen = 4 + 4*wchar32len(src); } //include terminator, length in BYTES + + dstlen = 2 + srclen; // this will always work, but may waste space + dst2 = dst = calloc(dstlen,1); // so there will be at least one terminator + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-16LE", "UTF-32LE"); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar16len((uint16_t *)dst2); + return((uint16_t *)dst2); +} + +/** + \brief Convert a UTF16LE string to a UTF32LE string. + \return pointer to new string or NULL if it fails + \param src UTF16LE string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint32_t *U_Utf16leToUtf32le( + const uint16_t *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = 2*max; } + else { srclen = 2*wchar16len(src)+2; } // include terminator, length in BYTES + dstlen = 2*(2 + srclen); // This should always work + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-32LE", "UTF-16LE"); + if ( conv == (iconv_t)-1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar32len((uint32_t *)dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a Latin1 string to a UTF32LE string. + \return pointer to new string or NULL if it fails + \param src Latin1 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator + + + U_EMR_EXTTEXTOUTA records are "8 bit ASCII". In theory that is ASCII in an 8 + bit character, but numerous applications store Latin1 in them, and some + _may_ store UTF-8 in them. Since very vew Latin1 strings are valid UTF-8 strings, + call U_Utf8ToUtf32le first, and if it fails, then call this function. +*/ +uint32_t *U_Latin1ToUtf32le( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = sizeof(uint32_t)*(1 + srclen); // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-32LE", "LATIN1"); + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar32len((uint32_t *)dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a UTF8 string to a UTF32LE string. + \return pointer to new string or NULL if it fails + \param src UTF8 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint32_t *U_Utf8ToUtf32le( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = sizeof(uint32_t)*(1 + srclen); // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-32LE", "UTF-8"); + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar32len((uint32_t *)dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a UTF32LE string to a UTF8 string. + \return pointer to new string or NULL if it fails + \param src wchar_t string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +char *U_Utf32leToUtf8( + const uint32_t *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + char *src2 = (char *) src; + size_t srclen,dstlen,status; + if(max){ srclen = 4*max; } + else { srclen = 4*(1 + wchar32len(src)); } //include terminator, length in BYTES + dstlen = 1 + srclen; // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-8", "UTF-32LE"); + if ( conv == (iconv_t)-1)return(NULL); + status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + return(dst2); +} + +/** + \brief Convert a UTF-8 string to a UTF16-LE string. + \return pointer to new string or NULL if it fails + \param src UTF8 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +uint16_t *U_Utf8ToUtf16le( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + iconv_t conv; + + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = 2 * (1 + srclen); // this will always work, but may waste space + dst2 = dst =calloc(dstlen,1); // so there will always be a terminator + if(!dst)return(NULL); + conv = iconv_open("UTF-16LE", "UTF-8"); + if (conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=wchar16len((uint16_t *)dst2); + return((uint16_t *)dst2); +} + +/** + \brief Convert a UTF16LE string to a UTF8 string. + \return pointer to new UTF8 string or NULL if it fails + \param src UTF16LE string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +char *U_Utf16leToUtf8( + const uint16_t *src, + size_t max, + size_t *len + ){ + char *dst, *dst2, *ret; + 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, but may waste space + dst2 = dst = (char *) calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-8", "UTF-16LE"); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + ret=U_strdup(dst2); // make a string of exactly the right size + free(dst2); // free the one which was probably too big + return(ret); +} + +/** + \brief Put a single 16 bit character into UTF-16LE form. + + Used in conjunction with U_Utf16leEdit(), because the character + representation would otherwise be dependent on machine Endianness. + + \return UTF16LE representation of the character. + \param src 16 bit character + +*/ +uint16_t U_Utf16le(const uint16_t src){ + uint16_t dst=src; +#if U_BYTE_SWAP + U_swap2(&dst,1); +#endif + return(dst); +} + +/** + \brief Single character replacement in a UTF-16LE string. + + Used solely for the Description field which contains + embedded nulls, which makes it difficult to manipulate. Use some other character and then swap it. + + \return number of substitutions, or -1 if src is not defined + \param src UTF16LE string to edit + \param find character to replace + \param replace replacestitute character + +*/ +int U_Utf16leEdit( + uint16_t *src, + uint16_t find, + uint16_t replace + ){ + int count=0; + if(!src)return(-1); + while(*src){ + if(*src == find){ *src = replace; count++; } + src++; + } + return(count); +} + +/** + \brief strdup for when strict C99 compliance is enforced + \returns duplicate string or NULL on error + \param s string to duplicate +*/ +char *U_strdup(const char *s){ + char *news=NULL; + size_t slen; + if(s){ + slen = strlen(s) + 1; //include the terminator! + news = malloc(slen); + if(news){ + memcpy(news,s,slen); + } + } + return(news); + +} + +/** + \brief Make up an approximate dx array to pass to emrtext_set(), based on character height and weight. + + Take abs. value of character height, get width by multiplying by 0.6, and correct weight + approximately, with formula (measured on screen for one text line of Arial). + Caller is responsible for free() on the returned pointer. + + \return pointer to dx array + \param height character height (absolute value will be used) + \param weight LF_Weight Enumeration (character weight) + \param members Number of entries to put into dx + +*/ +uint32_t *dx_set( + int32_t height, + uint32_t weight, + uint32_t members + ){ + uint32_t i, width, *dx; + dx = (uint32_t *) malloc(members * sizeof(uint32_t)); + if(dx){ + if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL; + width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904)); + for ( i = 0; i < members; i++ ){ dx[i] = width; } + } + return(dx); +} + +/** + \brief Look up the properties (a bit map) of a type of EMR record. + + \return bitmap of EMR record properties, or 0xFFFFFFFF on error + \param type EMR record type + +*/ +uint32_t emr_properties(uint32_t type){ + static uint32_t *table=NULL; + if(!table){ + table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_EMR_MAX)); + if(!table)return(0xFFFFFFFF); +// 0x40 0x20 0x10 0x08 0x04 0x02 0x01 +// Path properties (U_DRAW_*) ALTERS ONLYTO VISIBLE +// PATH FORCE CLOSED NOTEMPTY + table[ 0] = 0x00; //!< Does not map to any EMR record + table[ 1] = 0x00; //!< U_EMRHEADER 0 0 0 0 0 0 0 + table[ 2] = 0x03; //!< U_EMRPOLYBEZIER 0 0 0 0 0 1 1 + table[ 3] = 0x07; //!< U_EMRPOLYGON 0 0 0 0 1 1 1 + table[ 4] = 0x03; //!< U_EMRPOLYLINE 0 0 0 0 0 1 1 + table[ 5] = 0x0B; //!< U_EMRPOLYBEZIERTO 0 0 0 1 0 1 1 + table[ 6] = 0x0B; //!< U_EMRPOLYLINETO 0 0 0 1 0 1 1 + table[ 7] = 0x03; //!< U_EMRPOLYPOLYLINE 0 0 0 0 0 1 1 + table[ 8] = 0x07; //!< U_EMRPOLYPOLYGON 0 0 0 0 1 1 1 + table[ 9] = 0x20; //!< U_EMRSETWINDOWEXTEX 0 1 0 0 0 0 0 + table[ 10] = 0x20; //!< U_EMRSETWINDOWORGEX 0 1 0 0 0 0 0 + table[ 11] = 0x20; //!< U_EMRSETVIEWPORTEXTEX 0 1 0 0 0 0 0 + table[ 12] = 0x20; //!< U_EMRSETVIEWPORTORGEX 0 1 0 0 0 0 0 + table[ 13] = 0x20; //!< U_EMRSETBRUSHORGEX 0 1 0 0 0 0 0 + table[ 14] = 0x02; //!< U_EMREOF 0 1 0 0 0 0 0 Force out any pending draw + table[ 15] = 0x02; //!< U_EMRSETPIXELV 0 0 0 0 0 1 0 + table[ 16] = 0x20; //!< U_EMRSETMAPPERFLAGS 0 1 0 0 0 0 0 + table[ 17] = 0x20; //!< U_EMRSETMAPMODE 0 1 0 0 0 0 0 + table[ 18] = 0x20; //!< U_EMRSETBKMODE 0 1 0 0 0 0 0 + table[ 19] = 0x20; //!< U_EMRSETPOLYFILLMODE 0 1 0 0 0 0 0 + table[ 20] = 0x20; //!< U_EMRSETROP2 0 1 0 0 0 0 0 + table[ 21] = 0x20; //!< U_EMRSETSTRETCHBLTMODE 0 1 0 0 0 0 0 + table[ 22] = 0x20; //!< U_EMRSETTEXTALIGN 0 1 0 0 0 0 0 + table[ 23] = 0x20; //!< U_EMRSETCOLORADJUSTMENT 0 1 0 0 0 0 0 + table[ 24] = 0x20; //!< U_EMRSETTEXTCOLOR 0 1 0 0 0 0 0 + table[ 25] = 0x20; //!< U_EMRSETBKCOLOR 0 1 0 0 0 0 0 + table[ 26] = 0x20; //!< U_EMROFFSETCLIPRGN 0 1 0 0 0 0 0 + table[ 27] = 0x09; //!< U_EMRMOVETOEX 0 0 0 1 0 0 1 + table[ 28] = 0x20; //!< U_EMRSETMETARGN 0 1 0 0 0 0 0 + table[ 29] = 0x20; //!< U_EMREXCLUDECLIPRECT 0 1 0 0 0 0 0 + table[ 30] = 0x20; //!< U_EMRINTERSECTCLIPRECT 0 1 0 0 0 0 0 + table[ 31] = 0x20; //!< U_EMRSCALEVIEWPORTEXTEX 0 1 0 0 0 0 0 + table[ 32] = 0x20; //!< U_EMRSCALEWINDOWEXTEX 0 1 0 0 0 0 0 + table[ 33] = 0x20; //!< U_EMRSAVEDC 0 1 0 0 0 0 0 + table[ 34] = 0x20; //!< U_EMRRESTOREDC 0 1 0 0 0 0 0 + table[ 35] = 0x20; //!< U_EMRSETWORLDTRANSFORM 0 1 0 0 0 0 0 + table[ 36] = 0x20; //!< U_EMRMODIFYWORLDTRANSFORM 0 1 0 0 0 0 0 + table[ 37] = 0x20; //!< U_EMRSELECTOBJECT 0 1 0 0 0 0 0 + table[ 38] = 0x20; //!< U_EMRCREATEPEN 0 1 0 0 0 0 0 + table[ 39] = 0x20; //!< U_EMRCREATEBRUSHINDIRECT 0 1 0 0 0 0 0 + table[ 40] = 0x20; //!< U_EMRDELETEOBJECT 0 1 0 0 0 0 0 + table[ 41] = 0x03; //!< U_EMRANGLEARC 0 0 0 0 0 1 1 + table[ 42] = 0x07; //!< U_EMRELLIPSE 0 0 0 0 1 1 1 + table[ 43] = 0x07; //!< U_EMRRECTANGLE 0 0 0 0 1 1 1 + table[ 44] = 0x07; //!< U_EMRROUNDRECT 0 0 0 0 1 1 1 + table[ 45] = 0x03; //!< U_EMRARC 0 0 0 0 0 1 1 + table[ 46] = 0x07; //!< U_EMRCHORD 0 0 0 0 1 1 1 + table[ 47] = 0x07; //!< U_EMRPIE 0 0 0 0 1 1 1 + table[ 48] = 0x20; //!< U_EMRSELECTPALETTE 0 1 0 0 0 0 0 + table[ 49] = 0x20; //!< U_EMRCREATEPALETTE 0 1 0 0 0 0 0 + table[ 50] = 0x20; //!< U_EMRSETPALETTEENTRIES 0 1 0 0 0 0 0 + table[ 51] = 0x20; //!< U_EMRRESIZEPALETTE 0 1 0 0 0 0 0 + table[ 52] = 0x20; //!< U_EMRREALIZEPALETTE 0 1 0 0 0 0 0 + table[ 53] = 0x02; //!< U_EMREXTFLOODFILL 0 0 0 0 0 1 0 + table[ 54] = 0x0B; //!< U_EMRLINETO 0 0 0 1 0 1 1 + table[ 55] = 0x0B; //!< U_EMRARCTO 0 0 0 1 0 1 1 + table[ 56] = 0x03; //!< U_EMRPOLYDRAW 0 0 0 0 0 1 1 + table[ 57] = 0x20; //!< U_EMRSETARCDIRECTION 0 1 0 0 0 0 0 + table[ 58] = 0x20; //!< U_EMRSETMITERLIMIT 0 1 0 0 0 0 0 + table[ 59] = 0x60; //!< U_EMRBEGINPATH 1 1 0 0 0 0 0 + table[ 60] = 0x00; //!< U_EMRENDPATH 0 0 0 0 0 0 0 + table[ 61] = 0x04; //!< U_EMRCLOSEFIGURE 0 0 0 0 1 0 0 + table[ 62] = 0x14; //!< U_EMRFILLPATH 0 0 1 0 1 0 0 + table[ 63] = 0x14; //!< U_EMRSTROKEANDFILLPATH 0 0 1 0 1 0 0 + table[ 64] = 0x10; //!< U_EMRSTROKEPATH 0 0 1 0 0 0 0 + table[ 65] = 0x20; //!< U_EMRFLATTENPATH 0 1 0 0 0 0 0 + table[ 66] = 0x20; //!< U_EMRWIDENPATH 0 1 0 0 0 0 0 + table[ 67] = 0x20; //!< U_EMRSELECTCLIPPATH 0 1 0 0 0 0 0 + table[ 68] = 0x20; //!< U_EMRABORTPATH 0 1 0 0 0 0 0 + table[ 69] = 0x20; //!< U_EMRUNDEF69 0 1 0 0 0 0 0 + table[ 70] = 0x00; //!< U_EMRCOMMENT 0 0 0 0 0 0 0 + table[ 71] = 0x02; //!< U_EMRFILLRGN 0 0 0 0 0 1 0 + table[ 72] = 0x02; //!< U_EMRFRAMERGN 0 0 0 0 0 1 0 + table[ 73] = 0x02; //!< U_EMRINVERTRGN 0 0 0 0 0 1 0 + table[ 74] = 0x02; //!< U_EMRPAINTRGN 0 0 0 0 0 1 0 + table[ 75] = 0x20; //!< U_EMREXTSELECTCLIPRGN 0 1 0 0 0 0 0 + table[ 76] = 0x02; //!< U_EMRBITBLT 0 0 0 0 0 1 0 + table[ 77] = 0x02; //!< U_EMRSTRETCHBLT 0 0 0 0 0 1 0 + table[ 78] = 0x02; //!< U_EMRMASKBLT 0 0 0 0 0 1 0 + table[ 79] = 0x02; //!< U_EMRPLGBLT 0 0 0 0 0 1 0 + table[ 80] = 0x20; //!< U_EMRSETDIBITSTODEVICE 0 1 0 0 0 0 0 + table[ 81] = 0x20; //!< U_EMRSTRETCHDIBITS 0 1 0 0 0 0 0 + table[ 82] = 0x20; //!< U_EMREXTCREATEFONTINDIRECTW 0 1 0 0 0 0 0 + table[ 83] = 0x02; //!< U_EMREXTTEXTOUTA 0 0 0 0 0 1 0 + table[ 84] = 0x02; //!< U_EMREXTTEXTOUTW 0 0 0 0 0 1 0 + table[ 85] = 0x03; //!< U_EMRPOLYBEZIER16 0 0 0 0 0 1 1 + table[ 86] = 0x03; //!< U_EMRPOLYGON16 0 0 0 0 0 1 1 + table[ 87] = 0x03; //!< U_EMRPOLYLINE16 0 0 0 0 0 1 1 + table[ 88] = 0x0B; //!< U_EMRPOLYBEZIERTO16 0 0 0 1 0 1 1 + table[ 89] = 0x0B; //!< U_EMRPOLYLINETO16 0 0 0 1 0 1 1 + table[ 90] = 0x03; //!< U_EMRPOLYPOLYLINE16 0 0 0 0 0 1 1 + table[ 91] = 0x07; //!< U_EMRPOLYPOLYGON16 0 0 0 0 1 1 1 + table[ 92] = 0x03; //!< U_EMRPOLYDRAW16 0 0 0 0 0 1 1 + table[ 93] = 0x00; //!< U_EMRCREATEMONOBRUSH 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions + table[ 94] = 0x00; //!< U_EMRCREATEDIBPATTERNBRUSHPT 0 0 0 0 0 0 0 " + table[ 95] = 0x00; //!< U_EMREXTCREATEPEN 0 0 0 0 0 0 0 " + table[ 96] = 0x02; //!< U_EMRPOLYTEXTOUTA 0 0 0 0 0 1 0 + table[ 97] = 0x02; //!< U_EMRPOLYTEXTOUTW 0 0 0 0 0 1 0 + table[ 98] = 0x20; //!< U_EMRSETICMMODE 0 1 0 0 0 0 0 + table[ 99] = 0x20; //!< U_EMRCREATECOLORSPACE 0 1 0 0 0 0 0 + table[100] = 0x20; //!< U_EMRSETCOLORSPACE 0 1 0 0 0 0 0 + table[101] = 0x20; //!< U_EMRDELETECOLORSPACE 0 1 0 0 0 0 0 + table[102] = 0x20; //!< U_EMRGLSRECORD 0 1 0 0 0 0 0 + table[103] = 0x20; //!< U_EMRGLSBOUNDEDRECORD 0 1 0 0 0 0 0 + table[104] = 0x20; //!< U_EMRPIXELFORMAT 0 1 0 0 0 0 0 + table[105] = 0x20; //!< U_EMRDRAWESCAPE 0 1 0 0 0 0 0 + table[106] = 0x20; //!< U_EMREXTESCAPE 0 1 0 0 0 0 0 + table[107] = 0x20; //!< U_EMRUNDEF107 0 1 0 0 0 0 0 + table[108] = 0x02; //!< U_EMRSMALLTEXTOUT 0 0 0 0 0 1 0 + table[109] = 0x20; //!< U_EMRFORCEUFIMAPPING 0 1 0 0 0 0 0 + table[110] = 0x20; //!< U_EMRNAMEDESCAPE 0 1 0 0 0 0 0 + table[111] = 0x20; //!< U_EMRCOLORCORRECTPALETTE 0 1 0 0 0 0 0 + table[112] = 0x20; //!< U_EMRSETICMPROFILEA 0 1 0 0 0 0 0 + table[113] = 0x20; //!< U_EMRSETICMPROFILEW 0 1 0 0 0 0 0 + table[114] = 0x02; //!< U_EMRALPHABLEND 0 0 0 0 0 1 0 + table[115] = 0x20; //!< U_EMRSETLAYOUT 0 1 0 0 0 0 0 + table[116] = 0x02; //!< U_EMRTRANSPARENTBLT 0 0 0 0 0 1 0 + table[117] = 0x20; //!< U_EMRUNDEF117 0 1 0 0 0 0 0 + table[118] = 0x02; //!< U_EMRGRADIENTFILL 0 0 0 0 0 1 0 + table[119] = 0x20; //!< U_EMRSETLINKEDUFIS 0 1 0 0 0 0 0 + table[120] = 0x20; //!< U_EMRSETTEXTJUSTIFICATION 0 1 0 0 0 0 0 + table[121] = 0x20; //!< U_EMRCOLORMATCHTOTARGETW 0 1 0 0 0 0 0 + table[122] = 0x20; //!< U_EMRCREATECOLORSPACEW 0 1 0 0 0 0 0 + } + if(type<1 || type >U_EMR_MAX)return(0xFFFFFFFF); + return(table[type]); +} + +/** + \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 + ){ + U_PAIRF estart; // EMF start position, defines a radial + U_PAIRF eend; // EMF end position, defines a radial + U_PAIRF vec_estart; // define a unit vector from the center to estart + U_PAIRF vec_eend; // define a unit vector from the center to eend + U_PAIRF radii; // x,y radii of ellipse + U_PAIRF ratio; // intermediate value + float scale, cross; + 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); + radii.x = size->x/2.0; + radii.y = size->y/2.0; + + vec_estart.x = (estart.x - center->x); // initial vector, not unit length + vec_estart.y = (estart.y - center->y); + scale = sqrt(vec_estart.x*vec_estart.x + vec_estart.y*vec_estart.y); + if(!scale)return(1); // bogus record, has start at center + vec_estart.x /= scale; // now a unit vector + vec_estart.y /= scale; + + vec_eend.x = (eend.x - center->x); // initial vector, not unit length + vec_eend.y = (eend.y - center->y); + scale = sqrt(vec_eend.x*vec_eend.x + vec_eend.y*vec_eend.y); + if(!scale)return(2); // bogus record, has end at center + vec_eend.x /= scale; // now a unit vector + vec_eend.y /= scale; + + + // Find the intersection of the vectors with the ellipse. With no loss of generality + // we can translate the ellipse to the origin, then we just need to find tu (t a factor, u the unit vector) + // that also satisfies (x/Rx)^2 + (y/Ry)^2 = 1. x is t*(ux), y is t*(uy), where ux,uy are the x,y components + // of the unit vector. Substituting gives: + // (t*(ux)/Rx)^2 + (t*(uy)/Ry)^2 = 1 + // t^2 = 1/( (ux/Rx)^2 + (uy/Ry)^2 ) + // t = sqrt(1/( (ux/Rx)^2 + (uy/Ry)^2 )) + + ratio.x = vec_estart.x/radii.x; + ratio.y = vec_estart.y/radii.y; + ratio.x *= ratio.x; // we only use the square + ratio.y *= ratio.y; + scale = 1.0/sqrt(ratio.x + ratio.y); + start->x = center->x + scale * vec_estart.x; + start->y = center->y + scale * vec_estart.y; + + ratio.x = vec_eend.x/radii.x; + ratio.y = vec_eend.y/radii.y; + ratio.x *= ratio.x; // we only use the square + ratio.y *= ratio.y; + scale = 1.0/sqrt(ratio.x + ratio.y); + end->x = center->x + scale * vec_eend.x; + end->y = center->y + scale * vec_eend.y; + + //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation + //and the two unit vectors. + + cross = start->x * end->y - start->y * end->x; + if(!f2){ // counter clockwise rotation + if(cross >=0){ *f1 = 0; } + else { *f1 = 1; } + } + else { + if(cross >=0){ *f1 = 1; } + else { *f1 = 0; } + } + + + return(0); +} + +/** + \brief Convert a U_RGBA 32 bit pixmap to one of many different types of DIB pixmaps. + + Conversions to formats using color tables assume that the color table can hold every color + in the input image. If that assumption is false then the conversion will fail. Conversion + from 8 bit color to N bit colors (N<8) do so by shifting the appropriate number of bits. + + \return 0 on success, other values on errors. + \param px DIB pixel array + \param cbPx DIB pixel array size in bytes + \param ct DIB color table + \param numCt DIB color table number of entries + \param rgba_px U_RGBA pixel array (32 bits) + \param w Width of pixel array + \param h Height of pixel array + \param stride Row stride of input pixel array in bytes + \param colortype DIB BitCount Enumeration + \param use_ct If true use color table (only for 1-16 bit DIBs) + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int RGBA_to_DIB( + char **px, + uint32_t *cbPx, + PU_RGBQUAD *ct, + int *numCt, + char *rgba_px, + int w, + int h, + int stride, + uint32_t colortype, + int use_ct, + int invert + ){ + int bs; + int pad; + int i,j,k; + int istart, iend, iinc; + uint8_t r,g,b,a,tmp8; + char *pxptr; + char *rptr; + int found; + int usedbytes; + U_RGBQUAD color; + PU_RGBQUAD lct; + int32_t index; + + *px=NULL; + *ct=NULL; + *numCt=0; + *cbPx=0; + // sanity checking + if(!w || !h || !stride || !colortype || !rgba_px)return(1); + if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels + if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit + + bs = colortype/8; + if(bs<1){ + bs=1; + usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = w*bs; + } + pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.; + *cbPx = h * (usedbytes + pad); // Rows must start on a 4 byte boundary! + *px = (char *) malloc(*cbPx); + if(!px)return(4); + if(use_ct){ + *numCt = 1<< colortype; + if(*numCt >w*h)*numCt=w*h; + lct = (PU_RGBQUAD) malloc(*numCt * sizeof(U_RGBQUAD)); + if(!lct)return(5); + *ct = lct; + } + + if(invert){ + istart = h-1; + iend = -1; + iinc = -1; + } + else { + istart = 0; + iend = h; + iinc = 1; + } + + found = 0; + tmp8 = 0; + pxptr = *px; + for(i=istart; i!=iend; i+=iinc){ + rptr= rgba_px + i*stride; + for(j=0; j *numCt){ // More colors found than are supported by the color table + free(*ct); + free(*px); + *numCt=0; + *cbPx=0; + return(6); + } + index = found - 1; + *lct = color; + } + switch(colortype){ + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + tmp8 = tmp8 >> 1; // This seems wrong, as it fills from the top of each byte. But it works. + tmp8 |= index << 7; + if(!((j+1) % 8)){ + *pxptr++ = tmp8; + tmp8 = 0; + } + break; + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + tmp8 = tmp8 << 4; + tmp8 |= index; + if(!((j+1) % 2)){ + *pxptr++ = tmp8; + tmp8 = 0; + } + break; + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + tmp8 = index; + *pxptr++ = tmp8; + break; + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + } + else { + switch(colortype){ + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + b /= 8; g /= 8; r /= 8; + // Do it in this way so that the bytes are always stored Little Endian + tmp8 = b; + tmp8 |= g<<5; // least significant 3 bits of green + *pxptr++ = tmp8; + tmp8 = g>>3; // most significant 2 bits of green (there are only 5 bits of data) + tmp8 |= r<<2; + *pxptr++ = tmp8; + break; + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + *pxptr++ = b; + *pxptr++ = g; + *pxptr++ = r; + break; + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + *pxptr++ = b; + *pxptr++ = g; + *pxptr++ = r; + *pxptr++ = a; + break; + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + } + } + if( use_ct && colortype == U_BCBM_MONOCHROME && (j % 8) ){ + *pxptr++ = tmp8; // Write last few indices + tmp8 = 0; + } + if( use_ct && colortype == U_BCBM_COLOR4 && (j % 2) ){ + *pxptr++ = tmp8; // Write last few indices + tmp8 = 0; + } + if(pad){ + memset(pxptr,0,pad); // not strictly necessary, but set all bytes so that we can find important unset ones with valgrind + pxptr += pad; + } + } + return(0); +} + +/** + \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA() + + \return 0 on success, other values on errors. + \param pEmr pointer to EMR record that has a U_BITMAPINFO and bitmap + \param offBitsSrc Offset to the bitmap + \param offBmiSrc Offset to the U_BITMAPINFO + \param px pointer to DIB pixel array in pEmr + \param ct pointer to DIB color table in pEmr + \param numCt DIB color table number of entries + \param width Width of pixel array + \param height Height of pixel array (always returned as a positive number) + \param colortype DIB BitCount Enumeration + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int get_DIB_params( + void *pEmr, + uint32_t offBitsSrc, + uint32_t offBmiSrc, + char **px, + PU_RGBQUAD *ct, + uint32_t *numCt, + uint32_t *width, + uint32_t *height, + uint32_t *colortype, + uint32_t *invert + ){ + PU_BITMAPINFO Bmi = (PU_BITMAPINFO)((char *)pEmr + offBmiSrc); + if(Bmi->bmiHeader.biCompression != U_BI_RGB)return(1); + *width = Bmi->bmiHeader.biWidth; + *colortype = Bmi->bmiHeader.biBitCount; + *numCt = Bmi->bmiHeader.biClrUsed; + if(Bmi->bmiHeader.biHeight < 0){ + *height = -Bmi->bmiHeader.biHeight; + *invert = 1; + } + else { + *height = Bmi->bmiHeader.biHeight; + *invert = 0; + } + if(numCt){ + *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); + } + *px = (char *)((char *)pEmr + offBitsSrc); + return(0); +} + +/** + \brief Convert one of many different types of DIB pixmaps to an RGBA 32 bit pixmap. + + \return 0 on success, other values on errors. + \param px DIB pixel array + \param ct DIB color table + \param numCt DIB color table number of entries + \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free. + \param w Width of pixel array + \param h Height of pixel array + \param colortype DIB BitCount Enumeration + \param use_ct Kept for symmetry with RGBA_to_DIB, should be set to numCt + \param invert If DIB rows are in opposite order from RGBA rows +*/ +int DIB_to_RGBA( + char *px, + PU_RGBQUAD ct, + int numCt, + char **rgba_px, + int w, + int h, + uint32_t colortype, + int use_ct, + int invert + ){ + uint32_t cbRgba_px; + int stride; + int bs; + int pad; + int i,j; + int istart, iend, iinc; + uint8_t r,g,b,a,tmp8; + char *pxptr; + char *rptr; + int usedbytes; + U_RGBQUAD color; + int32_t index; + + // sanity checking + if(!w || !h || !colortype || !px)return(1); + if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels + if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit + if(use_ct && !numCt)return(4); //color table not adequately described + + stride = w * 4; + cbRgba_px = stride * h; + bs = colortype/8; + if(bs<1){ + bs=1; + usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = w*bs; + } + pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.; + *rgba_px = (char *) malloc(cbRgba_px); + if(!rgba_px)return(4); + + if(invert){ + istart = h-1; + iend = -1; + iinc = -1; + } + else { + istart = 0; + iend = h; + iinc = 1; + } + + pxptr = px; + tmp8 = 0; // silences a compiler warning, tmp8 always sets when j=0, so never used uninitialized + for(i=istart; i!=iend; i+=iinc){ + rptr= *rgba_px + i*stride; + for(j=0; j> 7; + tmp8 = tmp8 << 1; + break; + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + if(!(j % 2)){ tmp8 = *pxptr++; } + index = 0xF0 & tmp8; + index = index >> 4; + tmp8 = tmp8 << 4; + break; + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + index = (uint8_t) *pxptr++;; + break; + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + color = ct[index]; + b = U_BGRAGetB(color); + g = U_BGRAGetG(color); + r = U_BGRAGetR(color); + a = U_BGRAGetA(color); + } + else { + switch(colortype){ + case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods)) + // Do it in this way because the bytes are always stored Little Endian + tmp8 = *pxptr++; + b = (0x1F & tmp8) <<3; // 5 bits of b into the top 5 of 8 + g = tmp8 >> 5; // least significant 3 bits of green + tmp8 = *pxptr++; + r = (0x7C & tmp8) << 1; // 5 bits of r into the top 5 of 8 + g |= (0x3 & tmp8) << 3; // most significant 2 bits of green (there are only 5 bits of data) + g = g << 3; // restore intensity (have lost 3 bits of accuracy) + a = 0; + break; + case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE. + b = *pxptr++; + g = *pxptr++; + r = *pxptr++; + a = 0; + break; + case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. + b = *pxptr++; + g = *pxptr++; + r = *pxptr++; + a = *pxptr++; + break; + case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries + case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries + case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries + case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ? + default: + return(7); // This should not be possible, but might happen with memory corruption + } + } + *rptr++ = r; + *rptr++ = g; + *rptr++ = b; + *rptr++ = a; + } + for(j=0; jnSize; + dup=malloc(irecsize); + if(dup){ memcpy(dup,emr,irecsize); } + return(dup); +} + + +/** + \brief Start constructing an emf in memory. Supply the file name and initial size. + \return 0 for success, >=0 for failure. + \param name EMF filename (will be opened) + \param initsize Initialize EMF in memory to hold this many bytes + \param chunksize When needed increase EMF in memory by this number of bytes + \param et EMF in memory + + +*/ +int emf_start( + const char *name, + const uint32_t initsize, + const uint32_t chunksize, + EMFTRACK **et + ){ + FILE *fp; + EMFTRACK *etl=NULL; + + if(initsize < 1)return(1); + if(chunksize < 1)return(2); + if(!name)return(3); + etl = (EMFTRACK *) malloc(sizeof(EMFTRACK)); + if(!etl)return(4); + etl->buf = malloc(initsize); // no need to zero the memory + if(!etl->buf){ + free(etl); + return(5); + } + fp=emf_fopen(name,U_WRITE); + if(!fp){ + free(etl->buf); + free(etl); + return(6); + } + etl->fp = fp; + etl->allocated = initsize; + etl->used = 0; + etl->records = 0; + etl->PalEntries = 0; + etl->chunk = chunksize; + *et=etl; + return(0); +} + +/** + \brief Finalize the emf in memory and write it to the file. + \return 0 on success, >=1 on failure + \param et EMF in memory + \param eht EMF handle table (peak handle number needed) +*/ +int emf_finish( + EMFTRACK *et, + EMFHANDLES *eht + ){ + U_EMRHEADER *record; + + if(!et->fp)return(1); // This could happen if something stomps on memory, otherwise should be caught in emf_start + + // Set the header fields which were unknown up until this point + + record = (U_EMRHEADER *)et->buf; + record->nBytes = et->used; + record->nRecords = et->records; + record->nHandles = eht->peak + 1; + record->nPalEntries = et->PalEntries; + +#if U_BYTE_SWAP + //This is a Big Endian machine, EMF data must be Little Endian + U_emf_endian(et->buf,et->used,1); +#endif + + if(1 != fwrite(et->buf,et->used,1,et->fp))return(2); + (void) fclose(et->fp); + et->fp=NULL; + return(0); +} + +/** + \brief Release memory for an emf structure in memory. Call this after emf_finish(). + \return 0 on success, >=1 on failure + \param et EMF in memory +*/ +int emf_free( + EMFTRACK **et + ){ + EMFTRACK *etl; + if(!et)return(1); + etl=*et; + if(!etl)return(2); + free(etl->buf); + free(etl); + *et=NULL; + return(0); +} + +/** + \brief wrapper for fopen, works on any platform + \return 0 on success, >=1 on failure + \param filename file to open (either ASCII or UTF-8) + \param mode U_READ or U_WRITE (these map to "rb" and "wb") +*/ +FILE *emf_fopen( + const char *filename, + const int mode + ){ + FILE *fp = NULL; +#ifdef WIN32 + uint16_t *fn16; + uint16_t *md16; + if(mode == U_READ){ md16 = U_Utf8ToUtf16le("rb", 0, NULL); } + else { md16 = U_Utf8ToUtf16le("wb", 0, NULL); } + fn16 = U_Utf8ToUtf16le(filename, 0, NULL); + fp = _wfopen(fn16,md16); + free(fn16); + free(md16); +#else + if(mode == U_READ){ fp = fopen(filename,"rb"); } + else { fp = fopen(filename,"wb"); } +#endif + return(fp); +} +/** + \brief Retrieve contents of an EMF file by name. + \return 0 on success, >=1 on failure + \param filename Name of file to open, including the path + \param contents Contents of the file. Buffer must be free()'d by caller. + \param Number of bytes in Contents +*/ +int emf_readdata( + const char *filename, + char **contents, + size_t *length + ){ + FILE *fp; + int status=0; + + *contents=NULL; + fp=emf_fopen(filename,U_READ); + if(!fp){ status = 1; } + else { + // read the entire file into memory + fseek(fp, 0, SEEK_END); // move to end + *length = ftell(fp); + rewind(fp); + *contents = (char *) malloc(*length); + if(!*contents){ + status = 2; + } + else { + size_t inbytes = fread(*contents,*length,1,fp); + if(inbytes != 1){ + free(*contents); + status = 3; + } + else { +#if U_BYTE_SWAP + //This is a Big Endian machine, EMF data is Little Endian + U_emf_endian(*contents,*length,0); // LE to BE +#endif + } + } + fclose(fp); + } + return(status); +} + + +/** + \brief Append an EMF record to an emf in memory. This may reallocate buf memory. + \return 0 for success, >=1 for failure. + \param rec Record to append to EMF in memory + \param et EMF in memory + \param freerec If true, free rec after append +*/ +int emf_append( + U_ENHMETARECORD *rec, + EMFTRACK *et, + int freerec + ){ + size_t deficit; + +#ifdef U_VALGRIND + printf("\nbefore \n"); + printf(" probe %d\n",memprobe(rec, U_EMRSIZE(rec))); + printf("after \n"); +#endif + if(!rec)return(1); + if(!et)return(2); + if(rec->nSize + et->used > et->allocated){ + deficit = rec->nSize + et->used - et->allocated; + if(deficit < et->chunk)deficit = et->chunk; + et->allocated += deficit; + et->buf = realloc(et->buf,et->allocated); + if(!et->buf)return(3); + } + memcpy(et->buf + et->used, rec, rec->nSize); + et->used += rec->nSize; + et->records++; + if(rec->iType == U_EMR_EOF){ et->PalEntries = ((U_EMREOF *)rec)->cbPalEntries; } + if(freerec){ free(rec); } + return(0); +} + +/** + \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle. + \return 0 for success, >=1 for failure. + \param initsize Initialize with space for this number of handles + \param chunksize When needed increase space by this number of handles + \param eht EMF handle table +*/ +int htable_create( + uint32_t initsize, + uint32_t chunksize, + EMFHANDLES **eht + ){ + EMFHANDLES *ehtl; + unsigned int i; + + if(initsize<1)return(1); + if(chunksize<1)return(2); + ehtl = (EMFHANDLES *) malloc(sizeof(EMFHANDLES)); + if(!ehtl)return(3); + ehtl->table = malloc(initsize * sizeof(uint32_t)); + if(!ehtl->table){ + free(ehtl); + return(4); + } + ehtl->stack = malloc(initsize * sizeof(uint32_t)); + if(!ehtl->stack){ + free(ehtl); + free(ehtl->table); + return(5); + } + memset(ehtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table + for(i=1; istack[i]=i;} // preset the stack + ehtl->allocated = initsize; + ehtl->chunk = chunksize; + ehtl->table[0] = 0; // This slot isn't actually ever used + ehtl->stack[0] = 0; // This stack position isn't actually ever used + ehtl->peak = 1; + ehtl->sptr = 1; + ehtl->top = 0; + *eht = ehtl; + return(0); +} + + +/** + \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0. + \return 0 for success, >=1 for failure. + \param ih handle + \param eht EMF handle table + +*/ +int htable_delete( + uint32_t *ih, + EMFHANDLES *eht + ){ + if(!eht)return(1); + if(!eht->table)return(2); + if(!eht->stack)return(3); + if(*ih < 1)return(4); // invalid handle + if(!eht->table[*ih])return(5); // requested table position was not in use + eht->table[*ih]=0; // remove handle from table + while(eht->top>0 && !eht->table[eht->top]){ // adjust top + eht->top--; + } + eht->sptr--; // adjust stack + eht->stack[eht->sptr]=*ih; // place handle on stack + *ih=0; // invalidate handle variable, so a second delete will of it is not possible + return(0); +} + +/** + \brief Returns the index of the first free slot. + Call realloc() if needed. The slot is set to handle (indicates occupied) and the peak value is adjusted. + \return 0 for success, >=1 for failure. + \param ih handle + \param eht EMF handle table +*/ +int htable_insert( + uint32_t *ih, + EMFHANDLES *eht + ){ + unsigned int i; + size_t newsize; + + if(!eht)return(1); + if(!eht->table)return(2); + if(!eht->stack)return(3); + if(!ih)return(4); + if(eht->sptr >= eht->allocated - 1){ // need to reallocate + newsize=eht->allocated + eht->chunk; + eht->table = realloc(eht->table,newsize * sizeof(uint32_t)); + if(!eht->table)return(5); + memset(&eht->table[eht->allocated] , 0, eht->chunk * sizeof(uint32_t)); // zero all NEW slots in the table + + eht->stack = realloc(eht->stack,newsize * sizeof(uint32_t)); + if(!eht->stack)return(6); + for(i=eht->allocated; istack[i] = i; } // init all NEW slots in the stack + eht->allocated = newsize; + } + *ih = eht->stack[eht->sptr]; // handle that is inserted + if(eht->table[*ih])return(7); + eht->table[*ih] = *ih; // handle goes into preexisting (but zero) slot in table + eht->stack[eht->sptr] = 0; + if(*ih > eht->top){ eht->top = *ih; } + if(eht->sptr > eht->peak){ eht->peak = eht->sptr; } + eht->sptr++; // next available handle + + return(0); +} + +/** + \brief Free all memory in an htable. Sets the pointer to NULL. + \return 0 for success, >=1 for failure. + \param eht EMF handle table +*/ +int htable_free( + EMFHANDLES **eht + ){ + EMFHANDLES *ehtl; + if(!eht)return(1); + ehtl = *eht; + if(!ehtl)return(2); + if(!ehtl->table)return(3); + if(!ehtl->stack)return(4); + free(ehtl->table); + free(ehtl->stack); + free(ehtl); + *eht=NULL; + return(0); +} + +/* ********************************************************************************************** +These functions create standard structures used in the EMR records. +*********************************************************************************************** */ + + +/** + \brief Set up fields for an EMR_HEADER from the physical device's width and height in mm and dots per millimeter. + Typically this is something like 216,279,47.244 (Letter paper, 1200 DPI = 47.244 DPmm) + \return 0 for success, >=1 for failure. + \param xmm Device width in millimeters + \param ymm Device height in millimeters + \param dpmm Dots per millimeter + \param szlDev Device size structure in pixels + \param szlMm Device size structure in mm +*/ +int device_size( + const int xmm, + const int ymm, + const float dpmm, + U_SIZEL *szlDev, + U_SIZEL *szlMm + ){ + if(xmm < 0 || ymm < 0 || dpmm < 0)return(1); + szlDev->cx = U_ROUND((float) xmm * dpmm); + szlDev->cy = U_ROUND((float) ymm * dpmm);; + szlMm->cx = xmm; + szlMm->cy = ymm; + return(0); +} + +/** + \brief Set up fields for an EMR_HEADER for drawing by physical size in mm and dots per millimeter. + Technically rclBounds is supposed to be the extent of the drawing within the EMF, but libUEMF has no way + of knowing this since it never actually draws anything. Instead this is set to the full drawing size. + \return 0 for success, >=1 for failure. + \param xmm Drawing width in millimeters + \param ymm Drawing height in millimeters + \param dpmm Dots per millimeter + \param rclBounds Drawing size structure in pixels + \param rclFrame Drawing size structure in mm +*/ +int drawing_size( + const int xmm, + const int ymm, + const float dpmm, + U_RECTL *rclBounds, + U_RECTL *rclFrame + ){ + if(xmm < 0 || ymm < 0 || dpmm < 0)return(1); + rclBounds->left = 0; + rclBounds->top = 0; + rclBounds->right = U_ROUND((float) xmm * dpmm); // because coordinate system is 0,0 in upper left, N,M in lower right + rclBounds->bottom = U_ROUND((float) ymm * dpmm); + rclFrame->left = 0; + rclFrame->top = 0; + rclFrame->right = U_ROUND((float) xmm * 100.); + rclFrame->bottom = U_ROUND((float) ymm * 100.); + return(0); +} + +/** + \brief Set a U_COLORREF value from separeate R,G,B values. + Or use macro directly: cr = U_RGB(r,g,b). + \param red Red component + \param green Green component + \param blue Blue component + +*/ +U_COLORREF colorref_set( + uint8_t red, + uint8_t green, + uint8_t blue + ){ + U_COLORREF cr = (U_COLORREF){red , green, blue, 0}; + return(cr); +} + +/** + \brief Set rect and rectl objects from Upper Left and Lower Right corner points. + \param ul upper left corner of rectangle + \param lr lower right corner of rectangle +*/ +U_RECTL rectl_set( + U_POINTL ul, + U_POINTL lr + ){ + U_RECTL rct; + rct.left = ul.x; + rct.top = ul.y; + rct.right = lr.x; + rct.bottom = lr.y; + return(rct); +} + +/** + \brief Set sizel objects with X,Y values. + \param x X coordinate + \param y Y coordinate +*/ +U_SIZEL sizel_set( + int32_t x, + int32_t y + ){ + U_SIZEL sz; + sz.cx = x; + sz.cy = y; + return(sz); +} + +/** + \brief Set pointl objects with X,Y values. + \param x X coordinate + \param y Y coordinate +*/ +U_POINTL point32_set( + int32_t x, + int32_t y + ){ + U_POINTL pt; + pt.x = x; + pt.y = y; + return(pt); +} + +/** + \brief Set point16 objects with 16 bit X,Y values. + \param x X coordinate + \param y Y coordinate +*/ +U_POINT16 point16_set( + int16_t x, + int16_t y + ){ + U_POINT16 pt; + pt.x = x; + pt.y = y; + return(pt); +} + +/** + \brief Find the bounding rectangle from a polyline of a given width. + \param count number of points in the polyline + \param pts the polyline + \param width width of drawn line + +*/ +U_RECT findbounds( + uint32_t count, + PU_POINT pts, + uint32_t width + ){ + U_RECT rect={INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN }; + unsigned int i; + + for(i=0; ix < rect.left ) rect.left = pts->x; + if ( pts->x > rect.right ) rect.right = pts->x; + if ( pts->y < rect.top ) rect.top = pts->y; + if ( pts->y > rect.bottom ) rect.bottom = pts->y; + } + if(width > 0){ + rect.left -= width; + rect.right += width; + rect.top += width; + rect.bottom -= width; + } + return(rect); +} + +/** + \brief Find the bounding rectangle from a polyline of a given width. + \param count number of points in the polyline + \param pts the polyline + \param width width of drawn line + +*/ +U_RECT findbounds16( + uint32_t count, + PU_POINT16 pts, + uint32_t width + ){ + U_RECT rect={INT16_MAX, INT16_MAX, INT16_MIN, INT16_MIN }; + unsigned int i; + + for(i=0; ix < rect.left ) rect.left = pts->x; + if ( pts->x > rect.right ) rect.right = pts->x; + if ( pts->y < rect.top ) rect.top = pts->y; + if ( pts->y > rect.bottom ) rect.bottom = pts->y; + } + if(width > 0){ + rect.left -= width; + rect.right += width; + rect.top += width; + rect.bottom -= width; + } + return(rect); +} +/** + \brief Construct a U_LOGBRUSH structure. + \return U_LOGBRUSH structure + \param lbStyle LB_Style Enumeration + \param lbColor Brush color + \param lbHatch HatchStyle Enumertaion +*/ +U_LOGBRUSH logbrush_set( + uint32_t lbStyle, + U_COLORREF lbColor, + int32_t lbHatch + ){ + U_LOGBRUSH lb; + lb.lbStyle = lbStyle; + lb.lbColor = lbColor; + lb.lbHatch = lbHatch; + return(lb); +} + +/** + \brief Construct a U_XFORM structure. + \return U_XFORM structure + \param eM11 Rotation Matrix element + \param eM12 Rotation Matrix element + \param eM21 Rotation Matrix element + \param eM22 Rotation Matrix element + \param eDx Translation element + \param eDy Translation element +*/ +U_XFORM xform_set( + U_FLOAT eM11, + U_FLOAT eM12, + U_FLOAT eM21, + U_FLOAT eM22, + U_FLOAT eDx, + U_FLOAT eDy + ){ + U_XFORM xform; + xform.eM11 = eM11; + xform.eM12 = eM12; + xform.eM21 = eM21; + xform.eM22 = eM22; + xform.eDx = eDx; + xform.eDy = eDy; + return(xform); +} + +/** + \brief Construct a U_XFORM structure. + \return U_XFORM structure + \param scale Scale factor + \param axesRatio Ratio of minor axis/major axis + \param rot Rotation angle in degrees, positive is counter clockwise from the x axis. + \param axisRot Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis. + \param eDx Translation element + \param eDy Translation element + + Operation is: + 1 Conformal map of points based on scale, axis rotation, and axis ratio, + 2. Apply rotation + 3. Apply offset +*/ +U_XFORM xform_alt_set( + U_FLOAT scale, + U_FLOAT ratio, + U_FLOAT rot, + U_FLOAT axisrot, + U_FLOAT eDx, + U_FLOAT eDy + ){ + U_XFORM xform; + U_MAT2X2 mat1, mat2; + // angles are in degrees, must be in radians + rot *= (2.0 * U_PI)/360.0; + axisrot *= -(2.0 * U_PI)/360.0; + mat1.M11 = cos(rot); // set up the rotation matrix + mat1.M12 = -sin(rot); + mat1.M21 = sin(rot); + mat1.M22 = cos(rot); + if(ratio!=1.0){ // set scale/ellipticity matrix + mat2.M11 = scale*( cos(axisrot)*cos(axisrot) + ratio*sin(axisrot)*sin(axisrot) ); + mat2.M12 = mat2.M21 = scale*( sin(axisrot)*cos(axisrot) * (1.0 - ratio) ); + mat2.M22 = scale*( sin(axisrot)*sin(axisrot) + ratio*cos(axisrot)*cos(axisrot) ); + } + else { // when the ratio is 1.0 then the major axis angle is ignored and only scale matters + mat2.M11 = scale; + mat2.M12 = 0.0; + mat2.M21 = 0.0; + mat2.M22 = scale; + } + xform.eM11 = mat2.M11 * mat1.M11 + mat2.M12 * mat1.M21; + xform.eM12 = mat2.M11 * mat1.M12 + mat2.M12 * mat1.M22;; + xform.eM21 = mat2.M21 * mat1.M11 + mat2.M22 * mat1.M21; + xform.eM22 = mat2.M21 * mat1.M12 + mat2.M22 * mat1.M22; + xform.eDx = eDx; + xform.eDy = eDy; + return(xform); +} + + +/** + \brief Construct a U_LOGCOLORSPACEA structure. + \return U_LOGCOLORSPACEA structure + \param lcsCSType LCS_CSType Enumeration + \param lcsIntent LCS_Intent Enumeration + \param lcsEndpoints CIE XYZ color space endpoints + \param lcsGammaRGB Gamma For RGB + \param lcsFilename Could name an external color profile file, otherwise empty string +*/ +U_LOGCOLORSPACEA logcolorspacea_set( + int32_t lcsCSType, + int32_t lcsIntent, + U_CIEXYZTRIPLE lcsEndpoints, + U_LCS_GAMMARGB lcsGammaRGB, + char *lcsFilename + ){ + U_LOGCOLORSPACEA lcsa; + lcsa.lcsSignature = U_LCS_SIGNATURE; + lcsa.lcsVersion = U_LCS_SIGNATURE; + lcsa.lcsSize = sizeof(U_LOGCOLORSPACEA); + lcsa.lcsCSType = lcsCSType; + lcsa.lcsIntent = lcsIntent; + lcsa.lcsEndpoints = lcsEndpoints; + lcsa.lcsGammaRGB = lcsGammaRGB; + memset(lcsa.lcsFilename,0,U_MAX_PATH); // zero out the Filename field + strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + return(lcsa); +} + +/** + + \brief Construct a U_LOGCOLORSPACEW structure. + \return U_LOGCOLORSPACEW structure + \param lcsCSType LCS_CSType Enumeration + \param lcsIntent LCS_Intent Enumeration + \param lcsEndpoints CIE XYZ color space endpoints + \param lcsGammaRGB Gamma For RGB + \param lcsFilename Could name an external color profile file, otherwise empty string +*/ +U_LOGCOLORSPACEW logcolorspacew_set( + int32_t lcsCSType, + int32_t lcsIntent, + U_CIEXYZTRIPLE lcsEndpoints, + U_LCS_GAMMARGB lcsGammaRGB, + uint16_t *lcsFilename + ){ + U_LOGCOLORSPACEW lcsa; + lcsa.lcsSignature = U_LCS_SIGNATURE; + lcsa.lcsVersion = U_LCS_SIGNATURE; + lcsa.lcsSize = sizeof(U_LOGCOLORSPACEW); + lcsa.lcsCSType = lcsCSType; + lcsa.lcsIntent = lcsIntent; + lcsa.lcsEndpoints = lcsEndpoints; + lcsa.lcsGammaRGB = lcsGammaRGB; + wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + return(lcsa); +} + +/** + + \brief Construct a U_PANOSE structure. + \return U_PANOSE structure + \param bFamilyType FamilyType Enumeration + \param bSerifStyle SerifType Enumeration + \param bWeight Weight Enumeration + \param bProportion Proportion Enumeration + \param bContrast Contrast Enumeration + \param bStrokeVariation StrokeVariation Enumeration + \param bArmStyle ArmStyle Enumeration + \param bLetterform Letterform Enumeration + \param bMidline Midline Enumeration + \param bXHeight XHeight Enumeration +*/ +U_PANOSE panose_set( + uint8_t bFamilyType, + uint8_t bSerifStyle, + uint8_t bWeight, + uint8_t bProportion, + uint8_t bContrast, + uint8_t bStrokeVariation, + uint8_t bArmStyle, + uint8_t bLetterform, + uint8_t bMidline, + uint8_t bXHeight + ){ + U_PANOSE panose; + panose.bFamilyType = bFamilyType; + panose.bSerifStyle = bSerifStyle; + panose.bWeight = bWeight; + panose.bProportion = bProportion; + panose.bContrast = bContrast; + panose.bStrokeVariation = bStrokeVariation; + panose.bArmStyle = bArmStyle; + panose.bLetterform = bLetterform; + panose.bMidline = bMidline; + panose.bXHeight = bXHeight; + return(panose); +} + +/** + \brief Construct a U_LOGFONT structure. + \return U_LOGFONT structure + \param lfHeight Height in Logical units + \param lfWidth Average Width in Logical units + \param lfEscapement Angle in 0.1 degrees betweem escapement vector and X axis + \param lfOrientation Angle in 0.1 degrees between baseline and X axis + \param lfWeight LF_Weight Enumeration + \param lfItalic Italics: 0 or 1 + \param lfUnderline Underline: 0 or 1 + \param lfStrikeOut Strikeout: 0 or 1 + \param lfCharSet LF_CharSet Enumeration + \param lfOutPrecision LF_OutPrecision Enumeration + \param lfClipPrecision LF_ClipPrecision Enumeration + \param lfQuality LF_Quality Enumeration + \param lfPitchAndFamily LF_PitchAndFamily Enumeration + \param lfFaceName Name of font. truncates at U_LF_FACESIZE, smaller must be null terminated + +*/ +U_LOGFONT logfont_set( + int32_t lfHeight, + int32_t lfWidth, + int32_t lfEscapement, + int32_t lfOrientation, + int32_t lfWeight, + uint8_t lfItalic, + uint8_t lfUnderline, + uint8_t lfStrikeOut, + uint8_t lfCharSet, + uint8_t lfOutPrecision, + uint8_t lfClipPrecision, + uint8_t lfQuality, + uint8_t lfPitchAndFamily, + uint16_t *lfFaceName + ){ + U_LOGFONT lf; + lf.lfHeight = lfHeight; + lf.lfWidth = lfWidth; + lf.lfEscapement = lfEscapement; + lf.lfOrientation = lfOrientation; + lf.lfWeight = lfWeight; + lf.lfItalic = lfItalic; + lf.lfUnderline = lfUnderline; + lf.lfStrikeOut = lfStrikeOut; + lf.lfCharSet = lfCharSet; + lf.lfOutPrecision = lfOutPrecision; + lf.lfClipPrecision = lfClipPrecision; + lf.lfQuality = lfQuality; + lf.lfPitchAndFamily = lfPitchAndFamily; + wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero + return(lf); +} + + +/** + \brief Construct a U_LOGFONT_PANOSE structure. + \return U_LOGFONT_PANOSE structure + \param elfLogFont Basic font attributes + \param elfFullName Font full name, truncates at U_LF_FULLFACESIZE, smaller must be null terminated + \param elfStyle Font style, truncates at U_LF_FULLFACESIZE, smaller must be null terminated + \param elfStyleSize Font hinting starting at this point size, if 0, starts at Height + \param elfPanose Panose Object. If all zero, it is ignored. +*/ +U_LOGFONT_PANOSE logfont_panose_set( + U_LOGFONT elfLogFont, + uint16_t *elfFullName, + uint16_t *elfStyle, + uint32_t elfStyleSize, + U_PANOSE elfPanose + ){ + U_LOGFONT_PANOSE lfp; + memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed. Many should be ignored or must be 0. + wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE); + wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE); + lfp.elfLogFont = elfLogFont; + lfp.elfStyleSize = elfStyleSize; + lfp.elfPanose = elfPanose; + return(lfp); +} + +/** + \brief Construct a U_BITMAPINFOHEADER structure. + \return U_BITMAPINFOHEADER structure + \param biWidth Bitmap width in pixels + \param biHeight Bitmap height in pixels + \param biPlanes Planes (must be 1) + \param biBitCount BitCount Enumeration + \param biCompression BI_Compression Enumeration + \param biSizeImage Size in bytes of image + \param biXPelsPerMeter X Resolution in pixels/meter + \param biYPelsPerMeter Y Resolution in pixels/meter + \param biClrUsed Number of bmciColors in U_BITMAPCOREINFO + \param biClrImportant Number of bmciColors needed (0 means all). +*/ +U_BITMAPINFOHEADER bitmapinfoheader_set( + int32_t biWidth, + int32_t biHeight, + uint16_t biPlanes, + uint16_t biBitCount, + uint32_t biCompression, + uint32_t biSizeImage, + int32_t biXPelsPerMeter, + int32_t biYPelsPerMeter, + U_NUM_RGBQUAD biClrUsed, + uint32_t biClrImportant + ){ + U_BITMAPINFOHEADER Bmi; + Bmi.biSize = sizeof(U_BITMAPINFOHEADER); + Bmi.biWidth = biWidth; + Bmi.biHeight = biHeight; + Bmi.biPlanes = biPlanes; + Bmi.biBitCount = biBitCount; + Bmi.biCompression = biCompression; + Bmi.biSizeImage = biSizeImage; + Bmi.biXPelsPerMeter = biXPelsPerMeter; + Bmi.biYPelsPerMeter = biYPelsPerMeter; + Bmi.biClrUsed = biClrUsed; + Bmi.biClrImportant = biClrImportant; + return(Bmi); +} + + +/** + \brief Allocate and construct a U_BITMAPINFO structure. + \return Pointer to a U_BITMAPINFO structure + \param BmiHeader Geometry and pixel properties + \param BmiColors Color table (must be NULL for some values of BmiHeader->biBitCount) +*/ +PU_BITMAPINFO bitmapinfo_set( + U_BITMAPINFOHEADER BmiHeader, + PU_RGBQUAD BmiColors + ){ + char *record; + int irecsize; + int cbColors, cbColors4,off; + + cbColors = 4*BmiHeader.biClrUsed; + cbColors4 = UP4(cbColors); + irecsize = sizeof(U_BITMAPINFOHEADER) + cbColors4; + record = malloc(irecsize); + if(record){ + memcpy(record, &BmiHeader, sizeof(U_BITMAPINFOHEADER)); + if(cbColors){ + off = sizeof(U_BITMAPINFOHEADER); + memcpy(record + off, BmiColors, cbColors); + off += cbColors; + if(cbColors4 - cbColors){ memset(record + off, 0, cbColors4 - cbColors); } + } + } + return((PU_BITMAPINFO) record); +} + +/** + \brief Allocate and construct a U_EXTLOGPEN structure. + \return pointer to U_EXTLOGPEN structure, or NULL on error + \param elpPenStyle PenStyle Enumeration + \param elpWidth Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel) + \param elpBrushStyle LB_Style Enumeration + \param elpColor Pen color + \param elpHatch HatchStyle Enumeration + \param elpNumEntries Count of StyleEntry array + \param elpStyleEntry Array of StyleEntry (For user specified dot/dash patterns) +*/ +PU_EXTLOGPEN extlogpen_set( + uint32_t elpPenStyle, + uint32_t elpWidth, + uint32_t elpBrushStyle, + U_COLORREF elpColor, + int32_t elpHatch, + U_NUM_STYLEENTRY elpNumEntries, + U_STYLEENTRY *elpStyleEntry + ){ + int irecsize,szSyleArray; + char *record; + + if(elpNumEntries){ + if(!elpStyleEntry)return(NULL); + szSyleArray = elpNumEntries * sizeof(U_STYLEENTRY); + irecsize = sizeof(U_EXTLOGPEN) + szSyleArray - sizeof(U_STYLEENTRY); // first one is in the record + } + else { + szSyleArray = 0; + irecsize = sizeof(U_EXTLOGPEN); + } + record = malloc(irecsize); + if(record){ + ((PU_EXTLOGPEN) record)->elpPenStyle = elpPenStyle; + ((PU_EXTLOGPEN) record)->elpWidth = elpWidth; + ((PU_EXTLOGPEN) record)->elpBrushStyle = elpBrushStyle; + ((PU_EXTLOGPEN) record)->elpColor = elpColor; + ((PU_EXTLOGPEN) record)->elpHatch = elpHatch; + ((PU_EXTLOGPEN) record)->elpNumEntries = elpNumEntries; + if(elpNumEntries){ memcpy(((PU_EXTLOGPEN) record)->elpStyleEntry,elpStyleEntry,szSyleArray); } + else { memset(((PU_EXTLOGPEN) record)->elpStyleEntry,0,sizeof(U_STYLEENTRY)); } // not used, but this stops valgrind warnings + } + return((PU_EXTLOGPEN) record); +} + +/** + \brief Construct a U_LOGPEN structure. + \return U_LOGPEN structure + \param lopnStyle PenStyle Enumeration + \param lopnWidth Width of pen set by X, Y is ignored + \param lopnColor Pen color value + +*/ +U_LOGPEN logpen_set( + uint32_t lopnStyle, + U_POINT lopnWidth, + U_COLORREF lopnColor + ){ + U_LOGPEN lp; + lp.lopnStyle = lopnStyle; + lp.lopnWidth = lopnWidth; + lp.lopnColor = lopnColor; + return(lp); +} + +/** + \brief Construct a U_LOGPLTNTRY structure. + \return U_LOGPLTNTRY structure + \param peReserved Ignore + \param peRed Palette entry Red Intensity + \param peGreen Palette entry Green Intensity + \param peBlue Palette entry Blue Intensity +*/ +U_LOGPLTNTRY logpltntry_set( + uint8_t peReserved, + uint8_t peRed, + uint8_t peGreen, + uint8_t peBlue + ){ + U_LOGPLTNTRY lpny; + lpny.peReserved = peReserved; + lpny.peRed = peRed; + lpny.peGreen = peGreen; + lpny.peBlue = peBlue; + return(lpny); +} + +/** + \brief Allocate and construct a U_LOGPALETTE structure. + \return pointer to U_LOGPALETTE structure, or NULL on error. + \param palNumEntries Number of U_LOGPLTNTRY objects + \param palPalEntry array, PC_Entry Enumeration +*/ +PU_LOGPALETTE logpalette_set( + U_NUM_LOGPLTNTRY palNumEntries, + PU_LOGPLTNTRY *palPalEntry + ){ + PU_LOGPALETTE record; + int cbPalArray,irecsize; + + if(palNumEntries == 0 || !palPalEntry)return(NULL); + cbPalArray = palNumEntries * sizeof(U_LOGPLTNTRY); + irecsize = sizeof(U_LOGPALETTE) + cbPalArray - sizeof(U_LOGPLTNTRY); + record = (PU_LOGPALETTE) malloc(irecsize); + if(irecsize){ + record->palVersion = U_LP_VERSION; + record->palNumEntries = palNumEntries; + memcpy(record->palPalEntry,palPalEntry,cbPalArray); + } + return(record); +} + +/** + \brief Construct a U_RGNDATAHEADER structure. + \return U_RGNDATAHEADER structure + \param nCount Number of rectangles in region + \param rclBounds Region bounds +*/ +U_RGNDATAHEADER rgndataheader_set( + U_NUM_RECTL nCount, + U_RECTL rclBounds + ){ + U_RGNDATAHEADER rdh; + rdh.dwSize = U_RDH_OBJSIZE; + rdh.iType = U_RDH_RECTANGLES; + rdh.nCount = nCount; + rdh.nRgnSize = nCount * sizeof(U_RECTL); // Size in bytes of retangle array + rdh.rclBounds = rclBounds; + return(rdh); +} + +/** + \brief Allocate and construct a U_RGNDATA structure. + \return pointer to U_RGNDATA structure, or NULL on error. + \param rdh Data description + \param Buffer Array of U_RECTL elements +*/ +PU_RGNDATA rgndata_set( + U_RGNDATAHEADER rdh, + PU_RECTL Buffer + ){ + char *record; + int irecsize; + int szRgnArray,off; + + if(!Buffer || !rdh.nCount || !rdh.nRgnSize)return(NULL); + szRgnArray = rdh.nRgnSize; // size of the U_RECTL array + irecsize = sizeof(U_RGNDATA) + szRgnArray - sizeof(U_RECTL); // core + array - overlap + record = malloc(irecsize); + if(record){ + memcpy(record, &rdh, sizeof(U_RGNDATAHEADER)); + off = sizeof(U_RGNDATAHEADER); + memcpy(record + off, Buffer, szRgnArray); + } + return((PU_RGNDATA) record); +} + +/** + \brief Construct a U_COLORADJUSTMENT structure. + \return U_COLORADJUSTMENT structure + \param Size Size of this structure in bytes + \param Flags ColorAdjustment Enumeration + \param IlluminantIndex Illuminant Enumeration + \param RedGamma Red Gamma correction (range:2500:65000, 10000 is no correction) + \param GreenGamma Green Gamma correction (range:2500:65000, 10000 is no correction) + \param BlueGamma Blue Gamma correction (range:2500:65000, 10000 is no correction) + \param ReferenceBlack Values less than this are black (range:0:4000) + \param ReferenceWhite Values more than this are white (range:6000:10000) + \param Contrast Contrast adjustment (range:-100:100, 0 is no correction) + \param Brightness Brightness adjustment (range:-100:100, 0 is no correction) + \param Colorfulness Colorfulness adjustment (range:-100:100, 0 is no correction) + \param RedGreenTint Tine adjustment (range:-100:100, 0 is no correction) +*/ +U_COLORADJUSTMENT coloradjustment_set( + uint16_t Size, + uint16_t Flags, + uint16_t IlluminantIndex, + uint16_t RedGamma, + uint16_t GreenGamma, + uint16_t BlueGamma, + uint16_t ReferenceBlack, + uint16_t ReferenceWhite, + int16_t Contrast, + int16_t Brightness, + int16_t Colorfulness, + int16_t RedGreenTint + ){ + U_COLORADJUSTMENT ca; + ca.caSize = Size; + ca.caFlags = Flags; + ca.caIlluminantIndex = IlluminantIndex; + ca.caRedGamma = U_MNMX(RedGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX); + ca.caGreenGamma = U_MNMX(GreenGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX); + ca.caBlueGamma = U_MNMX(BlueGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX); + // Next one is different to eliminate compiler warning - U_R_B_MIN is 0 and unsigned + ca.caReferenceBlack = U_MAX( ReferenceBlack, U_REFERENCE_BLACK_MAX); + ca.caReferenceWhite = U_MNMX(ReferenceWhite, U_REFERENCE_WHITE_MIN, U_REFERENCE_WHITE_MAX); + ca.caContrast = U_MNMX(Contrast, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + ca.caBrightness = U_MNMX(Brightness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + ca.caColorfulness = U_MNMX(Colorfulness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + ca.caRedGreenTint = U_MNMX(RedGreenTint, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX); + return(ca); +} + +/** + \brief Construct a U_PIXELFORMATDESCRIPTOR structure. + \return U_PIXELFORMATDESCRIPTOR structure + \param dwFlags PFD_dwFlags Enumeration + \param iPixelType PFD_iPixelType Enumeration + \param cColorBits RGBA: total bits per pixel + \param cRedBits Red bits per pixel + \param cRedShift Red shift to data bits + \param cGreenBits Green bits per pixel + \param cGreenShift Green shift to data bits + \param cBlueBits Blue bits per pixel + \param cBlueShift Blue shift to data bits + \param cAlphaBits Alpha bits per pixel + \param cAlphaShift Alpha shift to data bits + \param cAccumBits Accumulator buffer, total bitplanes + \param cAccumRedBits Red accumulator buffer bitplanes + \param cAccumGreenBits Green accumulator buffer bitplanes + \param cAccumBlueBits Blue accumulator buffer bitplanes + \param cAccumAlphaBits Alpha accumulator buffer bitplanes + \param cDepthBits Depth of Z-buffer + \param cStencilBits Depth of stencil buffer + \param cAuxBuffers Depth of auxilliary buffers (not supported) + \param iLayerType PFD_iLayerType Enumeration, may be ignored + \param bReserved Bits 0:3/4:7 are number of Overlay/Underlay planes + \param dwLayerMask may be ignored + \param dwVisibleMask color or index of underlay plane + \param dwDamageMask may be ignored +*/ +U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set( + uint32_t dwFlags, + uint8_t iPixelType, + uint8_t cColorBits, + uint8_t cRedBits, + uint8_t cRedShift, + uint8_t cGreenBits, + uint8_t cGreenShift, + uint8_t cBlueBits, + uint8_t cBlueShift, + uint8_t cAlphaBits, + uint8_t cAlphaShift, + uint8_t cAccumBits, + uint8_t cAccumRedBits, + uint8_t cAccumGreenBits, + uint8_t cAccumBlueBits, + uint8_t cAccumAlphaBits, + uint8_t cDepthBits, + uint8_t cStencilBits, + uint8_t cAuxBuffers, + uint8_t iLayerType, + uint8_t bReserved, + uint32_t dwLayerMask, + uint32_t dwVisibleMask, + uint32_t dwDamageMask + ){ + U_PIXELFORMATDESCRIPTOR pfd; + pfd.nSize = sizeof(U_PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = dwFlags; + pfd.iPixelType = iPixelType; + pfd.cColorBits = cColorBits; + pfd.cRedBits = cRedBits; + pfd.cRedShift = cRedShift; + pfd.cGreenBits = cGreenBits; + pfd.cGreenShift = cGreenShift; + pfd.cBlueBits = cBlueBits; + pfd.cBlueShift = cBlueShift; + pfd.cAlphaBits = cAlphaBits; + pfd.cAlphaShift = cAlphaShift; + pfd.cAccumBits = cAccumBits; + pfd.cAccumRedBits = cAccumRedBits; + pfd.cAccumGreenBits = cAccumGreenBits; + pfd.cAccumBlueBits = cAccumBlueBits; + pfd.cAccumAlphaBits = cAccumAlphaBits; + pfd.cDepthBits = cDepthBits; + pfd.cStencilBits = cStencilBits; + pfd.cAuxBuffers = cAuxBuffers; + pfd.iLayerType = iLayerType; + pfd.bReserved = bReserved; + pfd.dwLayerMask = dwLayerMask; + pfd.dwVisibleMask = dwVisibleMask; + pfd.dwDamageMask = dwDamageMask; + return(pfd); +} + +/** + \brief Allocate and create a U_EMRTEXT structure followed by its variable pieces via a char* pointer. + Dx cannot be NULL, if the calling program has no appropriate values call dx_set() first. + \return char* pointer to U_EMRTEXT structure followed by its variable pieces, or NULL on error + \param ptlReference String start coordinates + \param NumString Number of characters in string, does NOT include a terminator + \param cbChar Number of bytes per character + \param String String to write + \param fOptions ExtTextOutOptions Enumeration + \param rcl (Optional, when fOptions & 7) grayed/clipping/opaque rectangle + \param Dx Character spacing array from the start of the RECORD +*/ +char *emrtext_set( + U_POINTL ptlReference, + U_NUM_STR NumString, + uint32_t cbChar, + void *String, + uint32_t fOptions, + U_RECTL rcl, + uint32_t *Dx + ){ + int irecsize,cbDxArray,cbString4,cbString,off; + char *record; + uint32_t *loffDx; + + if(!String)return(NULL); + if(!Dx)return(NULL); + cbString = cbChar * NumString; // size of the string in bytes + cbString4 = UP4(cbString); // size of the string buffer + cbDxArray = sizeof(uint32_t)*NumString; // size of Dx array storage + if(fOptions & U_ETO_PDY)cbDxArray += cbDxArray; // of the Dx buffer, here do both X and Y coordinates + irecsize = sizeof(U_EMRTEXT) + sizeof(uint32_t) + cbString4 + cbDxArray; // core structure + offDx + string buf + dx buf + if(!(fOptions & U_ETO_NO_RECT)){ irecsize += sizeof(U_RECTL); } // plus variable U_RECTL, when it is present + record = malloc(irecsize); + if(record){ + ((PU_EMRTEXT)record)->ptlReference = ptlReference; + ((PU_EMRTEXT)record)->nChars = NumString; + // pick up ((PU_EMRTEXT)record)->offString later + ((PU_EMRTEXT)record)->fOptions = fOptions; + off = sizeof(U_EMRTEXT); // location where variable pieces will start to be written + if(!(fOptions & U_ETO_NO_RECT)){ // variable field, may or may not be present + memcpy(record + off,&rcl, sizeof(U_RECTL)); + off += sizeof(U_RECTL); + } + loffDx = (uint32_t *)(record + off); // offDx will go here, but we do not know with what value yet + off += sizeof(uint32_t); + memcpy(record + off,String,cbString); // copy the string data to its buffer + ((PU_EMRTEXT)record)->offString = off; // now save offset in the structure + off += cbString; + if(cbString < cbString4){ + memset(record+off,0,cbString4-cbString); // keeps valgrind happy (initialize padding after string) + off += cbString4-cbString; + } + memcpy(record + off, Dx, cbDxArray); // copy the Dx data to its buffer + *loffDx = off; // now save offDx to the structure + } + return(record); +} + + + +/* ********************************************************************************************** +These functions are simpler or more convenient ways to generate the specified types of EMR records. +Each should be called in preference to the underlying "base" EMR function. +*********************************************************************************************** */ + + +/** + \brief Allocate and construct a U_EMRCOMMENT structure with a UTF8 string. + A U_EMRCOMMENT contains application specific data, and that may include contain null characters. This function may be used when the + comment only incluces UT8 text. + \return pointer to U_EMRCOMMENT structure, or NULL on error. + \param string UTF8 string to store in the comment + + +*/ +char *textcomment_set( + char *string + ){ + if(!string)return(NULL); + return(U_EMRCOMMENT_set(1 + strlen(string),string)); +} + +/** + \brief Allocate and construct a U_EMRDELETEOBJECT structure and also delete the requested object from the table. + Use this function instead of calling U_EMRDELETEOBJECT_set() directly. + \return pointer to U_EMRDELETEOBJECT structure, or NULL on error. + \param ihObject Pointer to handle to delete. This value is set to 0 if the function succeeds. + \param eht EMF handle table + + Note that calling this function should always be conditional on the specifed object being defined. It is easy to + write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined. + Then a later modification, possibly quite far away in the code, causes it to be undefined. That distant change will + result in a failure when this function reutrns. That problem cannot be handled here because the only values which + may be returned are a valid U_EMRDELETEOBJECT record or a NULL, and other errors could result in the NULL. + So the object must be checked before the call. +*/ +char *deleteobject_set( + uint32_t *ihObject, + EMFHANDLES *eht + ){ + uint32_t saveObject=*ihObject; + if(htable_delete(ihObject,eht))return(NULL); // invalid handle or other problem, cannot be deleted + return(U_EMRDELETEOBJECT_set(saveObject)); +} + +/** + \brief Allocate and construct a U_EMRSELECTOBJECT structure, checks that the handle specified is one that can actually be selected. + Use this function instead of calling U_EMRSELECTOBJECT_set() directly. + \return pointer to U_EMRSELECTOBJECT structure, or NULL on error. + \param ihObject handle to select + \param eht EMF handle table +*/ +char *selectobject_set( + uint32_t ihObject, + EMFHANDLES *eht + ){ + if(!(U_STOCK_OBJECT & ihObject)){ // not a stock object, those go straight through + if(eht->top < ihObject)return(NULL); // handle this high is not in the table + if(!eht->table[ihObject])return(NULL); // handle is not in the table, so not active, so cannot be selected + } + return(U_EMRSELECTOBJECT_set(ihObject)); +} + +/** + \brief Allocate and construct a U_EMREXTCREATEPEN structure, create a handle and return it. + Use this function instead of calling U_EMREXTCREATEPEN_set() directly. + \return pointer to U_EMREXTCREATEPEN structure, or NULL on error. + \param ihPen handle to be used by new object + \param eht EMF handle table + \param Bmi bitmapbuffer + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px pixel array (NULL if cbPx == 0) + \param elp Pen parameters (Size is Variable!!!!) +*/ +char *extcreatepen_set( + uint32_t *ihPen, + EMFHANDLES *eht, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + char *Px, + PU_EXTLOGPEN elp + ){ + if(htable_insert(ihPen, eht))return(NULL); + return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp )); +} + +/** + \brief Allocate and construct a U_EMRCREATEPEN structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEPEN_set() directly. + \return pointer to U_EMRCREATEPEN structure, or NULL on error. + \param ihPen handle to be used by new object + \param eht EMF handle table + \param lopn Pen parameters +*/ +char *createpen_set( + uint32_t *ihPen, + EMFHANDLES *eht, + U_LOGPEN lopn + ){ + if(htable_insert(ihPen, eht))return(NULL); + return(U_EMRCREATEPEN_set(*ihPen, lopn)); +} + +/** + \brief Allocate and construct a U_EMRCREATEBRUSHINDIRECT structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEBRUSHINDIRECT_set() directly. + \return pointer to U_EMRCREATEBRUSHINDIRECT structure, or NULL on error. + \param ihBrush handle to be used by new object + \param eht EMF handle table + \param lb Brush parameters +*/ +char *createbrushindirect_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + U_LOGBRUSH lb + ){ + if(htable_insert(ihBrush, eht))return(NULL); + return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb)); +} + +/** + \brief Allocate and construct a U_EMRCREATEDIBPATTERNBRUSHPT_set structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEDIBPATTERNBRUSHPT_set() directly. + \return pointer to U_EMRCREATEDIBPATTERNBRUSHPT_set structure, or NULL on error. + \param ihBrush handle to be used by new object + \param eht EMF handle table + \param iUsage DIBColors enumeration + \param Bmi Bitmap info + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *createdibpatternbrushpt_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const uint32_t iUsage, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + + ){ + if(htable_insert(ihBrush, eht))return(NULL); + return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px)); +} + +/** + \brief Allocate and construct a U_EMRCREATEMONOBRUSH_set structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEMONOBRUSH_set() directly. + \return pointer to U_EMRCREATEMONOBRUSH_set structure, or NULL on error. + \param ihBrush handle to be used by new object + \param eht EMF handle table + \param iUsage DIBColors enumeration + \param Bmi Bitmap info + \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row) + \param Px (Optional) bitmapbuffer (pixel array section ) +*/ +char *createmonobrush_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const uint32_t iUsage, + PU_BITMAPINFO Bmi, + const uint32_t cbPx, + const char *Px + + ){ + if(htable_insert(ihBrush, eht))return(NULL); + return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px)); +} + + +/** + \brief Allocate and construct a U_EMRCREATECOLORSPACE structure, create a handle and returns it + Use this function instead of calling U_EMRCREATECOLORSPACE_set() directly. + \return pointer to U_EMRCREATECOLORSPACE structure, or NULL on error. + \param ihCS ColorSpace handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param lcs ColorSpace parameters +*/ +char *createcolorspace_set( + uint32_t *ihCS, + EMFHANDLES *eht, + U_LOGCOLORSPACEA lcs + ){ + if(htable_insert(ihCS, eht))return(NULL); + return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs)); +} + +/** + \brief Allocate and construct a U_EMRCREATECOLORSPACEW structure, create a handle and returns it + Use this function instead of calling U_EMRCREATECOLORSPACEW_set() directly. + \return pointer to U_EMRCREATECOLORSPACEW structure, or NULL on error. + \param ihCS ColorSpace handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param lcs ColorSpace parameters + \param dwFlags If low bit set Data is present + \param cbData Number of bytes of theData field. + \param Data (Optional, dwFlags & 1) color profile data +*/ +char *createcolorspacew_set( + uint32_t *ihCS, + EMFHANDLES *eht, + U_LOGCOLORSPACEW lcs, + uint32_t dwFlags, + U_CBDATA cbData, + uint8_t *Data + ){ + if(htable_insert(ihCS, eht))return(NULL); + return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data)); +} + +/** + \brief Allocate and construct a U_EMREXTCREATEFONTINDIRECTW structure, create a handle and returns it + Use this function instead of calling U_EMREXTCREATEFONTINDIRECTW_set() directly. + \return pointer to U_EMREXTCREATEFONTINDIRECTW structure, or NULL on error. + \param ihFont Font handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param elf Pointer to Font parameters asPU_LOGFONT + \param elfw Pointer to Font parameters as U_LOGFONT_PANOSE +*/ +char *extcreatefontindirectw_set( + uint32_t *ihFont, + EMFHANDLES *eht, + const char *elf, + const char *elfw + ){ + if(htable_insert(ihFont, eht))return(NULL); + return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw)); +} + +/** + \brief Allocate and construct a U_EMRCREATEPALETTE structure, create a handle and returns it + Use this function instead of calling U_EMRCREATEPALETTE_set() directly. + \return pointer to U_EMRCREATEPALETTE structure, or NULL on error. + \param ihPal Palette handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param lgpl PaletteFont parameters +*/ +char *createpalette_set( + uint32_t *ihPal, + EMFHANDLES *eht, + U_LOGPALETTE lgpl + ){ + if(htable_insert(ihPal, eht))return(NULL); + return(U_EMRCREATEPALETTE_set(*ihPal, lgpl)); +} + +/** + \brief Allocate and construct a U_EMRSETPALETTEENTRIES structure, create a handle and returns it + Use this function instead of calling U_EMRSETPALETTEENTRIES_set() directly. + \return pointer to U_EMRSETPALETTEENTRIES structure, or NULL on error. + \param ihPal Palette handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param iStart First Palette entry in selected object to set + \param cEntries Number of Palette entries in selected object to set + \param aPalEntries Values to set with +*/ +char *setpaletteentries_set( + uint32_t *ihPal, + EMFHANDLES *eht, + const uint32_t iStart, + const U_NUM_LOGPLTNTRY cEntries, + const PU_LOGPLTNTRY aPalEntries + ){ + if(htable_insert(ihPal, eht))return(NULL); + return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries)); +} + +/** + \brief Allocate and construct a U_EMRFILLRGN structure, create a handle and returns it + Use this function instead of calling U_EMRFILLRGN_set() directly. + \return pointer to U_EMRFILLRGN structure, or NULL on error. + \param ihBrush Brush handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param rclBounds Bounding rectangle in device units + \param RgnData Pointer to a U_RGNDATA structure +*/ +char *fillrgn_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const U_RECTL rclBounds, + const PU_RGNDATA RgnData + ){ + if(htable_insert(ihBrush, eht))return(NULL); + return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData)); +} + +/** + \brief Allocate and construct a U_EMRFRAMERGN structure, create a handle and returns it + Use this function instead of calling U_EMRFRAMERGN_set() directly. + \return pointer to U_EMRFRAMERGN structure, or NULL on error. + \param ihBrush Brush handle, will be created and returned + \param eht Pointer to structure holding all EMF handles + \param rclBounds Bounding rectangle in device units + \param szlStroke W & H of Brush stroke + \param RgnData Pointer to a U_RGNDATA structure +*/ +char *framergn_set( + uint32_t *ihBrush, + EMFHANDLES *eht, + const U_RECTL rclBounds, + const U_SIZEL szlStroke, + const PU_RGNDATA RgnData + ){ + if(htable_insert(ihBrush, eht))return(NULL); + return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData)); +} + +/** + \brief Allocate and construct an array of U_POINT objects which has been subjected to a U_XFORM + \returns pointer to an array of U_POINT structures. + \param points pointer to the source U_POINT structures + \param count number of members in points + \param xform U_XFORM to apply + + May also be used to modify U_RECT by doubling the count and casting the pointer. +*/ +PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform){ + PU_POINT newpts; + int i; + float x,y; + newpts = (PU_POINT) malloc(count * sizeof(U_POINT)); + for(i=0; i\n\n"; // start of main body if (pEmr->nHandles) { d->n_obj = pEmr->nHandles; @@ -1724,15 +1854,13 @@ std::cout << "BEFORE DRAW" tmp_str << "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; + pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; for (i=1; icptl; ) { tmp_str << "\n\tC "; for (j=0; j<3 && icptl; j++,i++) { tmp_str << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } } @@ -1754,14 +1882,12 @@ std::cout << "BEFORE DRAW" tmp_str << "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; + pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; for (i=1; icptl; i++) { tmp_str << "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } tmp_path << tmp_str.str().c_str(); @@ -1783,14 +1909,12 @@ std::cout << "BEFORE DRAW" tmp_str << "\n\tM " << - pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << - pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; + pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; for (i=1; icptl; i++) { tmp_str << "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } tmp_path << tmp_str.str().c_str(); @@ -1810,8 +1934,7 @@ std::cout << "BEFORE DRAW" tmp_path << "\n\tC "; for (j=0; j<3 && icptl; j++,i++) { tmp_path << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } } @@ -1829,8 +1952,7 @@ std::cout << "BEFORE DRAW" for (i=0; icptl;i++) { tmp_path << "\n\tL " << - pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << - pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; + pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } break; @@ -1855,14 +1977,12 @@ std::cout << "BEFORE DRAW" SVGOStringStream poly_path; poly_path << "\n\tM " << - pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << - pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; + pix_to_xy( d, aptl[i].x, aptl[i].y ) << " "; i++; for (j=1; jaPolyCounts[n] && icptl; j++) { poly_path << "\n\tL " << - pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << - pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; + pix_to_xy( d, aptl[i].x, aptl[i].y ) << " "; i++; } @@ -1967,7 +2087,6 @@ std::cout << "BEFORE DRAW" { dbg_str << "\n"; - tmp_outsvg << "\n"; tmp_outsvg << "\n"; *(d->outsvg) = *(d->outdef) + *(d->defs) + *(d->outsvg); OK=0; @@ -2043,7 +2162,6 @@ std::cout << "BEFORE DRAW" PU_EMRSETTEXTCOLOR pEmr = (PU_EMRSETTEXTCOLOR) lpEMFR; d->dc[d->level].textColor = pEmr->crColor; - d->dc[d->level].textColorSet = true; break; } case U_EMR_SETBKCOLOR: @@ -2052,7 +2170,6 @@ std::cout << "BEFORE DRAW" PU_EMRSETBKCOLOR pEmr = (PU_EMRSETBKCOLOR) lpEMFR; d->dc[d->level].bkColor = pEmr->crColor; - d->dc[d->level].bkColorSet = true; break; } case U_EMR_OFFSETCLIPRGN: dbg_str << "\n"; break; @@ -2068,8 +2185,7 @@ std::cout << "BEFORE DRAW" tmp_path << "\n\tM " << - pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << - pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; break; } case U_EMR_SETMETARGN: dbg_str << "\n"; break; @@ -2085,19 +2201,20 @@ std::cout << "BEFORE DRAW" break; rc_old = rc; - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); + 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 << "\nid) << "\" >"; + tmp_rectangle << "\nid=\"clipEmfPath" << ++(d->id) << "\" >"; tmp_rectangle << "\n"; + tmp_rectangle << "\n x=\"" << dx << "\" "; + tmp_rectangle << "\n y=\"" << dy << "\" "; + tmp_rectangle << "\n width=\"" << dw << "\" "; + tmp_rectangle << "\n height=\"" << dh << "\" />"; + tmp_rectangle << "\n transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset tmp_rectangle << "\n"; *(d->outdef) += tmp_rectangle.str().c_str(); @@ -2372,15 +2489,10 @@ std::cout << "BEFORE DRAW" PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE) lpEMFR; U_RECTL rclBox = pEmr->rclBox; - double l = pix_to_x_point( d, rclBox.left, rclBox.top ); - double t = pix_to_y_point( d, rclBox.left, rclBox.top ); - double r = pix_to_x_point( d, rclBox.right, rclBox.bottom ); - double b = pix_to_y_point( d, rclBox.right, rclBox.bottom ); - - double cx = (l + r) / 2.0; - double cy = (t + b) / 2.0; - double rx = fabs(l - r) / 2.0; - double ry = fabs(t - b) / 2.0; + double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); + double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); + double rx = pix_to_abs_size( d, fabs(rclBox.right - rclBox.left )/2.0 ); + double ry = pix_to_abs_size( d, fabs(rclBox.top - rclBox.bottom)/2.0 ); SVGOStringStream tmp_ellipse; tmp_ellipse << "cx=\"" << cx << "\" "; @@ -2405,16 +2517,11 @@ std::cout << "BEFORE DRAW" PU_EMRRECTANGLE pEmr = (PU_EMRRECTANGLE) lpEMFR; U_RECTL rc = pEmr->rclBox; - double l = pix_to_x_point( d, rc.left, rc.top ); - double t = pix_to_y_point( d, rc.left, rc.top ); - double r = pix_to_x_point( d, rc.right, rc.bottom ); - double b = pix_to_y_point( d, rc.right, rc.bottom ); - SVGOStringStream tmp_rectangle; - tmp_rectangle << "\n\tM " << l << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << t << " "; - tmp_rectangle << "\n\tL " << r << " " << b << " "; - tmp_rectangle << "\n\tL " << l << " " << b << " "; + tmp_rectangle << "\n\tM " << pix_to_xy( d, rc.left , rc.top ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.top ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.bottom ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.left, rc.bottom ) << " "; tmp_rectangle << "\n\tz"; d->mask |= emr_mask; @@ -2430,24 +2537,54 @@ std::cout << "BEFORE DRAW" U_RECTL rc = pEmr->rclBox; U_SIZEL corner = pEmr->szlCorner; double f = 4.*(sqrt(2) - 1)/3; - - double l = pix_to_x_point(d, rc.left, rc.top); - double t = pix_to_y_point(d, rc.left, rc.top); - double r = pix_to_x_point(d, rc.right, rc.bottom); - double b = pix_to_y_point(d, rc.right, rc.bottom); - double cnx = pix_to_size_point(d, corner.cx/2); - double cny = pix_to_size_point(d, corner.cy/2); - + double f1 = 1.0 - f; + double cnx = corner.cx/2; + double cny = corner.cy/2; + SVGOStringStream tmp_rectangle; - tmp_rectangle << "\n\tM " << l << ", " << t + cny << " "; - tmp_rectangle << "\n\tC " << l << ", " << t + (1-f)*cny << " " << l + (1-f)*cnx << ", " << t << " " << l + cnx << ", " << t << " "; - tmp_rectangle << "\n\tL " << r - cnx << ", " << t << " "; - tmp_rectangle << "\n\tC " << r - (1-f)*cnx << ", " << t << " " << r << ", " << t + (1-f)*cny << " " << r << ", " << t + cny << " "; - tmp_rectangle << "\n\tL " << r << ", " << b - cny << " "; - tmp_rectangle << "\n\tC " << r << ", " << b - (1-f)*cny << " " << r - (1-f)*cnx << ", " << b << " " << r - cnx << ", " << b << " "; - tmp_rectangle << "\n\tL " << l + cnx << ", " << b << " "; - tmp_rectangle << "\n\tC " << l + (1-f)*cnx << ", " << b << " " << l << ", " << b - (1-f)*cny << " " << l << ", " << b - cny << " "; - tmp_rectangle << "\n\tz"; + tmp_rectangle << "\n" + << " M " + << pix_to_xy(d, rc.left , rc.top + cny ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.left , rc.top + cny*f1 ) + << " " + << pix_to_xy(d, rc.left + cnx*f1 , rc.top ) + << " " + << pix_to_xy(d, rc.left + cnx , rc.top ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, rc.right - cnx , rc.top ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.right - cnx*f1 , rc.top ) + << " " + << pix_to_xy(d, rc.right , rc.top + cny*f1 ) + << " " + << pix_to_xy(d, rc.right , rc.top + cny ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, rc.right , rc.bottom - cny ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.right , rc.bottom - cny*f1 ) + << " " + << pix_to_xy(d, rc.right - cnx*f1 , rc.bottom ) + << " " + << pix_to_xy(d, rc.right - cnx , rc.bottom ) + << "\n"; + tmp_rectangle << " L " + << pix_to_xy(d, rc.left + cnx , rc.bottom ) + << "\n"; + tmp_rectangle << " C " + << pix_to_xy(d, rc.left + cnx*f1 , rc.bottom ) + << " " + << pix_to_xy(d, rc.left , rc.bottom - cny*f1 ) + << " " + << pix_to_xy(d, rc.left , rc.bottom - cny ) + << "\n"; + tmp_rectangle << " z\n"; + d->mask |= emr_mask; @@ -2460,13 +2597,15 @@ std::cout << "BEFORE DRAW" U_PAIRF center,start,end,size; int f1; int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); - if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ - tmp_path << "\n\tM " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); - tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0 ; - tmp_path << " 0 "; + int stat = emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size); + if(!stat){ + tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " "; + tmp_path << 180.0 * current_rotation(d)/M_PI; + tmp_path << " "; tmp_path << " " << f1 << "," << f2 << " "; - tmp_path << pix_to_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y)<< " "; - + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; d->mask |= emr_mask; } else { @@ -2481,11 +2620,13 @@ std::cout << "BEFORE DRAW" int f1; int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ - tmp_path << "\n\tM " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); - tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0 ; - tmp_path << " 0 "; + 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_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y); + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; tmp_path << " z "; d->mask |= emr_mask; } @@ -2501,12 +2642,14 @@ std::cout << "BEFORE DRAW" int f1; int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ - tmp_path << "\n\tM " << pix_to_x_point(d, center.x, center.y) << "," << pix_to_y_point(d, center.x, center.y); - tmp_path << "\n\tL " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); - tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0; - tmp_path << " 0 "; + 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_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y); + tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; tmp_path << " z "; d->mask |= emr_mask; } @@ -2531,8 +2674,7 @@ std::cout << "BEFORE DRAW" tmp_path << "\n\tL " << - pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << - pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; + pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; break; } case U_EMR_ARCTO: @@ -2543,12 +2685,14 @@ std::cout << "BEFORE DRAW" int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ // draw a line from current position to start - tmp_path << "\n\tL " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); - tmp_path << "\n\tM " << pix_to_x_point(d, start.x, start.y) << "," << pix_to_y_point(d, start.x, start.y); - tmp_path << " A " << pix_to_x_point(d, size.x, size.y)/2.0 << "," << pix_to_y_point(d, size.x, size.y)/2.0 ; - tmp_path << " 0 "; + tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); + 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_x_point(d, end.x, end.y) << "," << pix_to_y_point(d, end.x, end.y)<< " "; + tmp_path << pix_to_xy(d, end.x, end.y)<< " "; d->mask |= emr_mask; } @@ -2691,27 +2835,20 @@ std::cout << "BEFORE DRAW" dbg_str << "\n"; PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR; - double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); - double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); - double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - //source position within the bitmap, in pixels - int sl = pEmr->Src.x + pEmr->xformSrc.eDx; - int st = pEmr->Src.y + pEmr->xformSrc.eDy; - int sw = 0; // extract all of the image - int sh = 0; - if(sl<0)sl=0; - if(st<0)st=0; - // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at + // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at // least it leaves objects where the operations should have been. if (!pEmr->cbBmiSrc) { // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead + int32_t dx = pEmr->Dest.x; + int32_t dy = pEmr->Dest.y; + int32_t dw = pEmr->cDest.x; + int32_t dh = pEmr->cDest.y; SVGOStringStream tmp_rectangle; - tmp_rectangle << "\n\tM " << dl << " " << dt << " "; - tmp_rectangle << "\n\tL " << dr << " " << dt << " "; - tmp_rectangle << "\n\tL " << dr << " " << db << " "; - tmp_rectangle << "\n\tL " << dl << " " << db << " "; + tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; + tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; tmp_rectangle << "\n\tz"; d->mask |= emr_mask; @@ -2721,7 +2858,18 @@ std::cout << "BEFORE DRAW" tmp_path << tmp_rectangle.str().c_str(); } else { - common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + //source position within the bitmap, in pixels + int sx = pEmr->Src.x + pEmr->xformSrc.eDx; + int sy = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = 0; // extract all of the image + int sh = 0; + if(sx<0)sx=0; + if(sy<0)sy=0; + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; @@ -2732,16 +2880,16 @@ std::cout << "BEFORE DRAW" PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) lpEMFR; // Always grab image, ignore modes. if (pEmr->cbBmiSrc) { - double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); - double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); - double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); //source position within the bitmap, in pixels - int sl = pEmr->Src.x + pEmr->xformSrc.eDx; - int st = pEmr->Src.y + pEmr->xformSrc.eDy; + int sx = pEmr->Src.x + pEmr->xformSrc.eDx; + int sy = pEmr->Src.y + pEmr->xformSrc.eDy; int sw = pEmr->cSrc.x; // extract the specified amount of the image int sh = pEmr->cSrc.y; - common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; @@ -2752,15 +2900,15 @@ std::cout << "BEFORE DRAW" PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) lpEMFR; // Always grab image, ignore masks and modes. if (pEmr->cbBmiSrc) { - double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); - double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); - double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - int sl = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels - int st = pEmr->Src.y + pEmr->xformSrc.eDy; + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels + int sy = pEmr->Src.y + pEmr->xformSrc.eDy; int sw = 0; // extract all of the image int sh = 0; - common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; @@ -2776,15 +2924,15 @@ std::cout << "BEFORE DRAW" // user can sort out transparency later using Gimp, if need be. PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) lpEMFR; - double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); - double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); - double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); - double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); - int sl = pEmr->Src.x; //source position within the bitmap, in pixels - int st = pEmr->Src.y; + double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double dw = pix_to_abs_size( d, pEmr->cDest.x); + double dh = pix_to_abs_size( d, pEmr->cDest.y); + int sx = pEmr->Src.x; //source position within the bitmap, in pixels + int sy = pEmr->Src.y; int sw = pEmr->cSrc.x; // extract the specified amount of the image int sh = pEmr->cSrc.y; - common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, + common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); dbg_str << "\n"; @@ -2919,6 +3067,7 @@ std::cout << "BEFORE DRAW" 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 + tsp.ori += 180.0 * current_rotation(d)/ M_PI; // radians to degrees tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear(). tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points (void) trinfo_load_fontname(d->tri, (uint8_t *)d->dc[d->level].font_name, &tsp); @@ -2956,17 +3105,12 @@ std::cout << "BEFORE DRAW" d->mask |= emr_mask; - tmp_str << - "\n\tM " << - pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << - pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; + tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " "; for (i=1; icpts; ) { tmp_str << "\n\tC "; for (j=0; j<3 && icpts; j++,i++) { - tmp_str << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + tmp_str << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; } } @@ -2987,14 +3131,10 @@ std::cout << "BEFORE DRAW" d->mask |= emr_mask; // skip the first point? - tmp_poly << "\n\tM " << - pix_to_x_point( d, apts[first].x, apts[first].y ) << " " << - pix_to_y_point( d, apts[first].x, apts[first].y ) << " "; + tmp_poly << "\n\tM " << pix_to_xy( d, apts[first].x, apts[first].y ) << " "; for (i=first+1; icpts; i++) { - tmp_poly << "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + tmp_poly << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; } tmp_path << tmp_poly.str().c_str(); @@ -3016,16 +3156,10 @@ std::cout << "BEFORE DRAW" d->mask |= emr_mask; - tmp_str << - "\n\tM " << - pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << - pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; + tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " "; for (i=1; icpts; i++) { - tmp_str << - "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + tmp_str << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; } tmp_path << tmp_str.str().c_str(); @@ -3045,9 +3179,7 @@ std::cout << "BEFORE DRAW" for (i=0; icpts;) { tmp_path << "\n\tC "; for (j=0; j<3 && icpts; j++,i++) { - tmp_path << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + tmp_path << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; } } @@ -3064,10 +3196,7 @@ std::cout << "BEFORE DRAW" d->mask |= emr_mask; for (i=0; icpts;i++) { - tmp_path << - "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + tmp_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; } break; @@ -3091,15 +3220,11 @@ std::cout << "BEFORE DRAW" for (n=0; nnPolys && icpts; n++) { SVGOStringStream poly_path; - poly_path << "\n\tM " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + poly_path << "\n\tM " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; i++; for (j=1; jaPolyCounts[n] && icpts; j++) { - poly_path << "\n\tL " << - pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << - pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; + poly_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; i++; } @@ -3244,6 +3369,8 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].worldTransform.eDx = 0.0; d.dc[0].worldTransform.eDy = 0.0; d.dc[0].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants + d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black) + d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white) if (uri == NULL) { return NULL; @@ -3349,6 +3476,7 @@ Emf::init (void) "false\n" "false\n" "false\n" + "false\n" "\n" ".emf\n" "image/x-emf\n" diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 97600a805..1eec01f39 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -100,7 +100,7 @@ struct GRADVALUES{ /* globals */ static double PX2WORLD = 20.0f; static U_XFORM worldTransform; -static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch; +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; @@ -302,6 +302,7 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc) FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); + FixImageRot = mod->get_param_bool("FixImageRot"); (void) emf_start(utf8_fn, 1000000, 250000, &et); // Initialize the et structure (void) htable_create(128, 128, &eht); // Initialize the eht structure @@ -627,7 +628,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) if(style->fill.isColor()){ fill_mode = DRAW_PAINT; float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); - if (opacity <= 0.0) return 1; // opacity isn't used here beyond this + 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]); @@ -1215,11 +1216,9 @@ unsigned int PrintEmf::fill(Inkscape::Extension::Print * /*mod*/, use_fill = true; use_stroke = false; - // earlier versions had flush of fill here, but it never executed and was removed - fill_transform = tf; - if (create_brush(style, NULL)){ + if (create_brush(style, NULL)){ // only happens if the style is a gradient /* Handle gradients. Uses modified livarot as 2geom boolops is currently broken. Can handle gradients with multiple stops. @@ -1389,8 +1388,6 @@ unsigned int PrintEmf::fill(Inkscape::Extension::Print * /*mod*/, } } - - // std::cout << "end fill" << std::endl; return 0; } @@ -1663,11 +1660,9 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff in the past (or will be in the future?) Not in current trunk. (4/19/2012) Limitations of this code: - 1. rotated images are mangled. They stay in their original orientation and are stretched - along X or Y. - 2. Transparency is lost on export. (Apparently a limitation of the EMF 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 + 1. Transparency is lost on export. (Apparently a limitation of the EMF format.) + 2. Probably messes up if row stride != w*4 + 3. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine that calls this one and passes px, but never removes the rest of the pixbuf. The first time this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more. If this routine is reduced to @@ -1685,7 +1680,7 @@ unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not SPStyle const *style) /** provides indirect link to image object */ { // std::cout << "image " << std::endl; - double x1,x2,y1,y2; + double x1,y1,dw,dh; char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); @@ -1694,14 +1689,12 @@ unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not throw "Fatal programming error in PrintEmf::image at EMRHEADER"; } - x1= atof(style->object->getAttribute("x")); - y1= atof(style->object->getAttribute("y")); - x2=x1 + atof(style->object->getAttribute("width")); - y2=y1 + atof(style->object->getAttribute("height")); + 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 pUR(x2,y2); - Geom::Point p2LL = pLL * tf; - Geom::Point p2UR = pUR * tf; + Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates char *px; uint32_t cbPx; @@ -1715,10 +1708,33 @@ unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); - U_POINTL Dest = pointl_set(round(p2LL[Geom::X] * PX2WORLD), round(p2LL[Geom::Y] * PX2WORLD)); - U_POINTL cDest = pointl_set(round((p2UR[Geom::X]-p2LL[Geom::X]) * PX2WORLD), round((p2UR[Geom::Y]-p2LL[Geom::Y]) * PX2WORLD)); + U_POINTL Dest = pointl_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD)); + U_POINTL cDest = pointl_set(round(dw * PX2WORLD), round(dh * PX2WORLD)); U_POINTL Src = pointl_set(0,0); U_POINTL cSrc = pointl_set(w,h); + if(!FixImageRot){ /* Rotate images - some programs cannot read them in correctly if they are rotated */ + tf[4] = tf[5] = 0.0; // get rid of the offset in the transform + Geom::Point pLL2prime = pLL2 * tf; + U_XFORM tmpTransform; + tmpTransform.eM11 = tf[0]; + tmpTransform.eM12 = tf[1]; + tmpTransform.eM21 = tf[2]; + tmpTransform.eM22 = tf[3]; + tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; //map pLL2 (now in EMF coordinates) back onto itself after the rotation + tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD; + + rec=U_EMRSAVEDC_set(); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at U_EMRSAVEDC_set"; + } + + + rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM"; + } + + } rec = U_EMRSTRETCHDIBITS_set( U_RCL_DEF, //! Bounding rectangle in device units Dest, //! Destination UL corner in logical units @@ -1737,7 +1753,14 @@ unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not free(px); free(Bmi); if(numCt)free(ct); - + + if(!FixImageRot){ + rec=U_EMRRESTOREDC_set(-1); + if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ + throw "Fatal programming error in PrintEmf::begin at U_EMRRESTOREDC_set"; + } + } + // std::cout << "end image" << std::endl; return 0; } @@ -1746,16 +1769,21 @@ unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) { // std::cout << "print_pathv " << std::endl << std::flush; - char *rec = NULL; + Geom::Affine tf = transform; + char *rec = NULL; - simple_shape = print_simple_shape(pathv, transform); + simple_shape = print_simple_shape(pathv, tf); if (simple_shape || pathv.empty()){ if (use_fill){ destroy_brush(); } // these must be cleared even if nothing is drawn or hbrush,hpen fill up if (use_stroke){ destroy_pen(); } return TRUE; } - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); + /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform, + that is handled by the EMF MODIFYWORLDTRANSFORM record + */ + + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * tf ); rec = U_EMRBEGINPATH_set(); if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ @@ -1892,6 +1920,7 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af if (use_stroke){ destroy_pen(); } + // std::cout << "end pathv" << std::endl; return TRUE; @@ -2119,6 +2148,7 @@ void PrintEmf::init (void) "false\n" "false\n" "false\n" + "false\n" "\n" "", new PrintEmf()); diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c index 623388373..4d52dfb33 100644 --- a/src/extension/internal/text_reassemble.c +++ b/src/extension/internal/text_reassemble.c @@ -1,61 +1,52 @@ -/* text_reassemble.c -version 0.0.3 2012-12-07 -Copyright 2012, Caltech and David Mathog - -Reassemble formatted text from a series of text/position/font records. +/** + @file text_reassemble.c +\verbatim Method: 1. For all ordered text objects which are sequential and share the same esc. 2. For the first only pull x,y,esc and save, these define origin and rotation. 3. Save the text object. 4. Phase I: For all saved text objects construct lines. - 5. Check for allowed overlaps on sequential saved text object bounding rectangles. + 5. Check for allowed overlaps on sequential saved text object bounding rectangles. 6 If found merge second with first, check next one. - 7. If not found, start a new complex (line). + 7. If not found, start a new complex (line). 8. Phase II; for all lines construct paragraphs. - 9. Check alignment and line spacing of preceding line with current line. - 10. if alignment is the same, and line spacing is compatible merge current line into - current paragraph. Reaverage line spacing over all lines in paragraph. Check next one. - 11. If alignment does not match start a new paragraph. + 9. Check alignment and line spacing of preceding line with current line. + 10. if alignment is the same, and line spacing is compatible merge current line into + current paragraph. Reaverage line spacing over all lines in paragraph. Check next one. + 11. If alignment does not match start a new paragraph. (Test program) 12. Over all phase II paragraphs 13. Over all phase I lines in each paragraph. 14. Over all text objects in each line. - Emit SVG correspnding to this construct to a file dump.svg. + Emit SVG corresponding to this construct to a file dump.svg. + (Conversion to other file types would be modeled on this example.) 15. Clean up. (General program) - Like for the Test program, but final represenation may not be SVG. - -During the accept stage (1) it uses fontconfig/freetype data to store up font faces and to -work out the extent of each substring. This code assumes all text goes L->R, if it goes the other way -the same groupings would occur, just mirror imaged. - -At step 5 it calculates overlapping bounding boxes == formatted strings. The bounding boxes are extended -out by 1 character laterally and .49 character vertically. If it was able to figure out justification -that is returned along with the number of formatted strings. - -The caller then retrieves the x,y,xe,ye,string,format,font data and uses it to construct a formatted -string in whatever format the caller happens to be using. For Inskcape this would be SVG. - -Finally the caller cleans up, releasing all of the stored memory. FreeType memory is always all released. -FontConfig memory is released except for, optionally, not calling FcFini(), which would likely cause -problems for any program that was using FontConfig elsewhere. + Like for the Test program, but final representation may not be SVG. + Text object and bounding rectangle memory would all be released. If another set of + text will be processed then hang onto both Freetype and Fontconfig structures. If no + other text will be processed here, then also release Freetype structures. If the caller uses + Fontconfig elsewhere then do not release it, otherwise, do so. NOTE ON COORDINATES: x is positive to the right, y is positive down. So (0,0) is the upper left corner, and the lower left corner of a rectangle has a LARGER Y coordinate than the upper left. Ie, LL=(10,10) UR=(30,5) is typical. +\endverbatim +*/ +/* -Compilation of test program: +Compilation of test program (with all debugging output, but not loop testing): On Windows use: - gcc -Wall -DWIN32 -DTEST \ + gcc -Wall -DWIN32 -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT \ -I. -I/c/progs/devlibs32/include -I/c/progs/devlibs32/include/freetype2\ -o text_reassemble text_reassemble.c uemf_utf.c \ - -lfreetype6 -lfontconfig-1 -lm -L/c/progs/devlibs32/bin + -lfreetype6 -lfontconfig-1 -liconv -lm -L/c/progs/devlibs32/bin On Linux use: - gcc -Wall -DTEST -I. -I/usr/include/freetype2 -o text_reassemble text_reassemble.c uemf_utf.c -lfreetype -lfontconfig -lm + gcc -Wall -DTEST -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT -I. -I/usr/include/freetype2 -o text_reassemble text_reassemble.c uemf_utf.c -lfreetype -lfontconfig -lm Compilation of object file only (Windows): @@ -75,6 +66,12 @@ Optional compiler switches for development: memory leaks. Ouput file is overwritten each time. +File: text_reassemble.c +Version: 0.0.4 +Date: 24-JAN-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -84,10 +81,11 @@ extern "C" { #include "text_reassemble.h" #include "uemf_utf.h" /* For a couple of text functions. Exact copy from libUEMF. */ -/* end of functions from libUEMF */ - -/* Utility function, find a (sub)string in a caseinvariant manner, used for locating "Narrow" in font name. - Returns -1 if no match, else returns the position (numbered from 0) of the first character of the match. +/** + \brief Find a (sub)string in a caseinvariant manner, used for locating "Narrow" in font name + \return Returns -1 if no match, else returns the position (numbered from 0) of the first character of the match. + \param string Text to search + \param sub Text to find */ int TR_findcasesub(char *string, char *sub){ int i,j; @@ -105,16 +103,19 @@ int TR_findcasesub(char *string, char *sub){ } /** -Get the advance for the 32 bit character, returned value has units of 1/64th of a Point. - When load_flags == FT_LOAD_NO_SCALE is used the internal advance is in 1/64th of a point. - This does NOT stop scaling on kerning values! - When load_flags == FT_LOAD_TARGET_NORMAL is used the internal advance also seem to be in 1/64th of a point. The scale + \brief Get the advance for the 32 bit character + + \return Returns -1 on error, or advance in units of 1/64th of a Point. + \param fsp Pointer to FNT_SPECS struct. + \param wc Current character (32 bit int) + \param pc Previous character + \param load_flags Controls internal advance: + FT_LOAD_NO_SCALE, internal advance is in 1/64th of a point. (kerning values are still scaled) + FT_LOAD_TARGET_NORMAL internal advance is in 1/64th of a point. The scale factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi). -kern_mode, One of FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, FT_KERNING_UNSCALED -wc is the current character -pc is the previous character, 0 if there was not one - If ymin,ymax are passed in, then if the character's limits decrease/increase that value, it is modified (for founding string bounding box) -On error return -1. + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. + \param ymin If the pointer is defined, the value is adjusted if ymin of wc character is less than the current value. + \param ymax If the pointer is defined, the value is adjusted if ymin of wc character is more than the current value. */ int TR_getadvance(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int load_flags, int kern_mode, int *ymin, int *ymax){ FT_Glyph glyph; @@ -137,15 +138,12 @@ int TR_getadvance(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int load_flags, int } /** -Get the kerning for a pair of 32 bit characters, returned value has units of 1/64th of a Point. - When load_flags == FT_LOAD_NO_SCALE is used the internal advance is in 1/64th of a point. - This does NOT stop scaling on kerning values! - When load_flags == FT_LOAD_TARGET_NORMAL is used the internal advance also seem to be in 1/64th of a point. The scale - factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi). -kern_mode, One of FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, FT_KERNING_UNSCALED -wc is the current character -pc is the previous character, 0 if there was not one -Returns 0 on error or if the kerning is 0. + \brief Get the kerning for a pair of 32 bit characters + \return Returns 0 on error, or kerning value (which may be 0) for the pair in units of 1/64th of a point. + \param fsp Pointer to FNT_SPECS struct. + \param wc Current character (32 bit int) + \param pc Previous character + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. */ int TR_getkern2(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int kern_mode){ int this_glyph_index; @@ -166,18 +164,12 @@ int TR_getkern2(FNT_SPECS *fsp, uint32_t wc, uint32_t pc, int kern_mode){ } /** -Get the kerning for a pair of 32 bit characters, where one is the last charcter in the previous text block, -and the other is the first in the current text block. - When load_flags == FT_LOAD_NO_SCALE is used the internal advance is in 1/64th of a point. - This does NOT stop scaling on kerning values! - When load_flags == FT_LOAD_TARGET_NORMAL is used the internal advance also seem to be in 1/64th of a point. The scale - factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi). -kern_mode, One of FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, FT_KERNING_UNSCALED -tsp is current text object -ptsp is the previous text object -wc is the current character -pc is the previous character -Returns 0 on error or if the kerning is 0. + \brief Get the kerning for a pair of 32 bit characters, where one is the last charcter in the previous text block, and the other is the first in the current text block. + \return Returns 0 on error, or kerning value (which may be 0) for the pair in units of 1/64th of a point. + \param fsp Pointer to FNT_SPECS struct. + \param tsp current text object + \param ptsp previous text object + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. */ int TR_kern_gap(FNT_SPECS *fsp, TCHUNK_SPECS *tsp, TCHUNK_SPECS *ptsp, int kern_mode){ int kern=0; @@ -206,14 +198,19 @@ int TR_kern_gap(FNT_SPECS *fsp, TCHUNK_SPECS *tsp, TCHUNK_SPECS *ptsp, int kern_ -/* If the complex is a TR_TXT or TR_LINE find its baseline. - If the complex is TR_PARA+* find the baseline of the last line. - If AscMax or DscMax exists find the maximum Ascender/Descender size in this complex. - If there are multiple text elements in a TR_LINE, the baseline is that of the - element that uses the largest font. This will definitely give the wrong - result if that line starts with a super or subscript that is full font size, but - they are usually smaller. - returns 0 if it screws up and cannot figure out the baseline. +/** + \brief Find baseline on Y axis of a complex. + If the complex is a TR_TEXT or TR_LINE find its baseline. + If the complex is TR_PARA_[UCLR]J find the baseline of the last line. + If there are multiple text elements in a TR_LINE, the baseline is that of the + element that uses the largest font. This will definitely give the wrong + result if that line starts with a super or subscript that is full font size, but + they are usually smaller. + \return Returns 0 if it cannot determine a baseline, else returns the baseline Y coordinate. + \param tri pointer to the TR_INFO structure holding all TR data + \param src index of the current complex + \param ymax If the pointer is defined, the value is adjusted if ymax of current complex is more than the current value. + \param ymin If the pointer is defined, the value is adjusted if ymin of current complex is less than the current value. */ double TR_baseline(TR_INFO *tri, int src, double *ymax, double *ymin){ double baseline=0; @@ -277,16 +274,28 @@ double TR_baseline(TR_INFO *tri, int src, double *ymax, double *ymin){ return(baseline); } -/* check or set vadvance on growing complex dst with positions of text in - potential TR_LINE/TR_TEXT src. Vadvance is a multiplicative factor like 1.25. - The distance between successive baselines is vadvance * max(font_size), where the maximum - is over all text elements in src. - lines is the index of the first text block that was added, so src - lines can be used - to determine the weight to give to each new vadvance value as it is merged into the - running weighted average. This improves the accuracy of the vertical advance, since - there can be some noise introduced when lines have different maximum font sizes. - Returns 0 on success. - Returns !0 on failure +/** + \brief Check or set vertical advance on the growing complex relative to the current complex. + Vadvance is a multiplicative factor like 1.25. + The distance between successive baselines is vadvance * max(font_size), where the maximum + is over all text elements in src. + The growing complex is always the last one in the CX_INFO section of the TR_INFO structure. + If an existing vadvance does not match the one which would be required to fit the next complex + to add to the growing one, it terminates a growing complex. (Ie, starts a new paragraph.) + Find baseline on Y axis of a complex. + If the complex is a TR_TEXT or TR_LINE find its baseline. + If the complex is TR_PARA+* find the baseline of the last line. + If there are multiple text elements in a TR_LINE, the baseline is that of the + element that uses the largest font. This will definitely give the wrong + result if that line starts with a super or subscript that is full font size, but + they are usually smaller. + \return Returns 0 on success, !0 on failure. + \param tri pointer to the TR_INFO structure holding all TR data + \param src index of the current complex, to be added to the growing complex. + This lets the value of "src - lines" determine the weight to give to each new vadvance value + as it is merged into the running weighted average. This improves the accuracy of the vertical advance, + since there can be some noise introduced when lines have different maximum font sizes. + \param lines index of the first text block that was added to the growing complex. */ int TR_check_set_vadvance(TR_INFO *tri, int src, int lines){ int status = 0; @@ -328,7 +337,10 @@ int TR_check_set_vadvance(TR_INFO *tri, int src, int lines){ } -/* Initialize the ftinfo system. Sets up a freetype library to use in this context. Returns NULL on failure. */ +/** + \brief Initialize an FT_INFO structure. Sets up a freetype library to use in this context. + \returns a pointer to the FT_INFO structure created, or NULL on error. +*/ FT_INFO *ftinfo_init(void){ FT_INFO *fti = NULL; if(FcInit()){ @@ -354,8 +366,11 @@ FT_INFO *ftinfo_init(void){ return(fti); } -/* verifies that there is space to add one more entry. - 0 on sucess, anything else is an error */ +/** + \brief Make an FT_INFO structure insertable. Adds storage as needed. + \param fti pointer to the FT_INFO structure + \returns 0 on success, !0 on error. +*/ int ftinfo_make_insertable(FT_INFO *fti){ int status=0; if(!fti)return(2); @@ -375,8 +390,12 @@ int ftinfo_make_insertable(FT_INFO *fti){ } -/* Insert an fsp into an fti - 0 on sucess, anything else is an error */ +/** + \brief Insert a copy of a FNT_SPECS structure into the FT_INFO structure. + \param fti pointer to the FT_INFO structure. + \param fsp pointer to the FNT_SPECS structure. + \returns 0 on success, !0 on error. +*/ int ftinfo_insert(FT_INFO *fti, FNT_SPECS *fsp){ int status=1; if(!fti)return(2); @@ -390,8 +409,11 @@ int ftinfo_insert(FT_INFO *fti, FNT_SPECS *fsp){ -/* Shut down the ftinfo system. Release all memory. - call like: fi_ptr = ftinfo_release(fi_ptr) +/** + \brief Release an FT_INFO structure. Release all associated memory. + Use like: fi_ptr = ftinfo_release(fi_ptr) + \param fti pointer to the FT_INFO structure. + \returns NULL. */ FT_INFO *ftinfo_release(FT_INFO *fti){ int i; @@ -410,9 +432,13 @@ FT_INFO *ftinfo_release(FT_INFO *fti){ return NULL; } -/* Clear the ftinfo system. Release all Freetype memory but do NOT shut down Fontconfig. This would - be called in preference to ftinfo_release if some other part of the program needed to continue using - Fontconfig.: fi_ptr = ftinfo_clear(fi_ptr) +/** + \brief Clear an FT_INFO structure. Release all Freetype memory but does not release Fontconfig. + This would be called in preference to ftinfo_release() if some other part of the program needed + to continue using Fontconfig. + Use like: fi_ptr = ftinfo_clear(fi_ptr) + \param fti pointer to the FT_INFO structure. + \returns NULL. */ FT_INFO *ftinfo_clear(FT_INFO *fti){ int i; @@ -431,8 +457,11 @@ FT_INFO *ftinfo_clear(FT_INFO *fti){ } -/* verifies that there is space to add one more entry. - 0 on sucess, anything else is an error */ +/** + \brief Make a CHILD_SPECS structure insertable. Adds storage as needed. + \param csp pointer to the CHILD_SPECS structure + \returns 0 on success, !0 on error. +*/ int csp_make_insertable(CHILD_SPECS *csp){ int status=0; if(!csp)return(2); @@ -451,7 +480,12 @@ int csp_make_insertable(CHILD_SPECS *csp){ return(status); } -/* Add a member (src) to a child spec. 0 on success, anything else is an error */ +/** + \brief Add a member to a CHILD_SPECS structure. (Member is an index for either a text object or a complex.) + \param dst pointer to the CHILD_SPECS structure. + \param src index of the member. + \returns 0 on success, !0 on error. +*/ int csp_insert(CHILD_SPECS *dst, int src){ int status=1; if(!dst)return(2); @@ -462,8 +496,14 @@ int csp_insert(CHILD_SPECS *dst, int src){ return(status); } -/* Add all the members of child spec src to child spec dst. -0 on success, anything else is an error */ +/** + \brief Append all the members of one CHILD_SPECS structure to another CHILD_SPECS structure. + Member is an index for either a text object or a complex. + The donor is not modified. + \param dst pointer to the recipient CHILD_SPECS structure. + \param src pointer to the donor CHILD_SPECS structure. + \returns 0 on success, !0 on error. +*/ int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src){ int i; int status=1; @@ -476,8 +516,10 @@ int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src){ return(status); } -/* Shut down the cxinfo system. Release all memory. - call like: (void) csp_release(csp_ptr). +/** + \brief Release a CHILD_SPECS structure. Release all associated memory. + \param csp pointer to the CHILD_SPECS structure. + \returns NULL. */ void csp_release(CHILD_SPECS *csp){ if(csp){ @@ -488,7 +530,10 @@ void csp_release(CHILD_SPECS *csp){ } -/* Initialize the cxinfo system. Returns NULL on failure. */ +/** + \brief Initialize an CX_INFO structure. Holds complexes (multiple text objects in known positions and order.) + \returns a pointer to the CX_INFO structure created, or NULL on error. +*/ CX_INFO *cxinfo_init(void){ CX_INFO *cxi = NULL; cxi = (CX_INFO *)calloc(1,sizeof(CX_INFO)); @@ -501,9 +546,11 @@ CX_INFO *cxinfo_init(void){ return(cxi); } -/* verifies that there is space to add one more entry. - Creates the structure if it is passed a null pointer. - 0 on sucess, anything else is an error */ +/** + \brief Make a CX_INFO structure insertable. Adds storage as needed. + \returns 0 on success, !0 on error. + \param cxi pointer to the CX_INFO structure +*/ int cxinfo_make_insertable(CX_INFO *cxi){ int status=0; if(cxi->used < cxi->space){ @@ -521,10 +568,14 @@ int cxinfo_make_insertable(CX_INFO *cxi){ return(status); } -/* Insert a complex of "type" with one member (src) and that src's associated rectangle (by index). - If type is TR_TEXT src is an index for tpi->chunks[] - If type is TR_LINE src is an index for cxi->kids[] - 0 on sucess, anything else is an error */ +/** + \brief Insert a complex into the CX_INFO structure. (Insert may be either TR_TEXT or TR_LINE.) + \returns 0 on success, !0 on error. + \param cxi pointer to the CX_INFO structure (complexes). + \param src index of the the complex to insert. + \param src_rt_tidx index of the bounding rectangle + \param type TR_TEXT (index is for tpi->chunks[]) or TR_LINE (index is for cxi->kids[]) +*/ int cxinfo_insert(CX_INFO *cxi, int src, int src_rt_tidx, enum tr_classes type){ int status=1; if(!cxi)return(2); @@ -537,10 +588,13 @@ int cxinfo_insert(CX_INFO *cxi, int src, int src_rt_tidx, enum tr_classes type){ return(status); } -/* Append a a complex "src" of the last complex and change the complex type to "type". - If type is TR_LINE src is an index for tpi->chunks[] - If type is TR_PARA_* src is an index for cxi->kids[], and the incoming complex is a line. - 0 on sucess, anything else is an error */ +/** + \brief Append a complex to the CX_INFO structure and give it a type. + \param cxi pointer to the CX_INFO structure (complexes). + \param src index of the complex to append. + \param type TR_LINE (src is an index for tpi->chunks[]) or TR_PARA (src is an index for cxi->kids[]). + \returns 0 on success, !0 on error. +*/ int cxinfo_append(CX_INFO *cxi, int src, enum tr_classes type){ int status=1; if(!cxi)return(2); @@ -552,8 +606,14 @@ int cxinfo_append(CX_INFO *cxi, int src, enum tr_classes type){ } -/* Merge a complex dst with N members (N>=1) by adding a second complex src . Change the type to "type" - 0 on sucess, anything else is an error */ +/** + \brief Merge a complex dst with N members (N>=1) by adding a second complex src, and change the type. + \param cxi pointer to the CX_INFO structure (complexes). + \param dst index of the complex to expand. + \param src index of the donor complex (which is not modified). + \param type TR_LINE (src is an index for tpi->chunks[]) or TR_PARA (src is an index for cxi->kids[]). + \returns 0 on success, !0 on error. +*/ int cxinfo_merge(CX_INFO *cxi, int dst, int src, enum tr_classes type){ int status =1; if(!cxi)return(2); @@ -564,7 +624,9 @@ int cxinfo_merge(CX_INFO *cxi, int dst, int src, enum tr_classes type){ return(status); } -/* For debugging purposes,not used in production code. +/** + \brief Dump the contents of the TR_INFO structure to stdout. For debugging purposes,not used in production code. + \param tri pointer to the TR_INFO structure. */ void cxinfo_dump(TR_INFO *tri){ int i,j,k; @@ -600,8 +662,11 @@ void cxinfo_dump(TR_INFO *tri){ return; } -/* Shut down the cxinfo system. Release all memory. - call like: cxi_ptr = cxinfo_release(cxi_ptr) +/** + \brief Release a CX_INFO structure. Release all associated memory. + use like: cxi = cxiinfo_release(cxi); + \param cxi pointer to the CX_INFO structure. + \returns NULL. */ CX_INFO *cxinfo_release(CX_INFO *cxi){ int i; @@ -614,7 +679,10 @@ CX_INFO *cxinfo_release(CX_INFO *cxi){ } -/* Initialize the tpinfo system. Returns NULL on failure. */ +/** + \brief Initialize an TP_INFO structure. Holds text objects from which complexes are built. + \returns a pointer to the TP_INFO structure created, or NULL on error. +*/ TP_INFO *tpinfo_init(void){ TP_INFO *tpi = NULL; tpi = (TP_INFO *)calloc(1,sizeof(TP_INFO)); @@ -628,8 +696,11 @@ TP_INFO *tpinfo_init(void){ } -/* verifies that there is space to add one more entry. - 0 on sucess, anything else is an error */ +/** + \brief Make a TP_INFO structure insertable. Adds storage as needed. + \returns 0 on success, !0 on error. + \param tpi pointer to the TP_INFO structure +*/ int tpinfo_make_insertable(TP_INFO *tpi){ int status=0; if(tpi->used >= tpi->space){ @@ -644,8 +715,12 @@ int tpinfo_make_insertable(TP_INFO *tpi){ return(status); } -/* Insert a TCHUNK_SPEC as a tpi chunk.. - 0 on sucess, anything else is an error */ +/** + \brief Insert a copy of a TCHUNK_SPECS structure into a TP_INFO structure. (Insert a text object.) + \returns 0 on success, !0 on error. + \param tpi pointer to the TP_INFO structure + \param tsp pointer to the TCHUNK_SPECS structure +*/ int tpinfo_insert(TP_INFO *tpi, TCHUNK_SPECS *tsp){ int status=1; if(!tpi)return(2); @@ -658,8 +733,11 @@ int tpinfo_insert(TP_INFO *tpi, TCHUNK_SPECS *tsp){ return(status); } -/* Shut down the tpinfo system. Release all memory. - call like: tpi_ptr = tpinfo_release(tpi_ptr) +/** + \brief Release a TP_INFO structure. Release all associated memory. + use like: tpi = tpinfo_release(tpi); + \returns NULL. + \param tpi pointer to the TP_INFO structure. */ TP_INFO *tpinfo_release(TP_INFO *tpi){ int i; @@ -672,7 +750,10 @@ TP_INFO *tpinfo_release(TP_INFO *tpi){ return NULL; } -/* Initialize the brinfo system. Returns NULL on failure. */ +/** + \brief Initialize an BR_INFO structure. Holds bounding rectangles, for both text objects and complexes. + \returns a pointer to the BR_INFO structure created, or NULL on error. +*/ BR_INFO *brinfo_init(void){ BR_INFO *bri = NULL; bri = (BR_INFO *)calloc(1,sizeof(BR_INFO)); @@ -685,9 +766,11 @@ BR_INFO *brinfo_init(void){ return(bri); } -/* verifies that there is space to add one more entry. - Creates rects if that pointer is NULL. - 0 on sucess, anything else is an error */ +/** + \brief Make a BR_INFO structure insertable. Adds storage as needed. + \returns 0 on success, !0 on error. + \param bri pointer to the BR_INFO structure +*/ int brinfo_make_insertable(BR_INFO *bri){ int status=0; if(!bri)return(2); @@ -698,9 +781,12 @@ int brinfo_make_insertable(BR_INFO *bri){ return(status); } -/** Append a BRECT_SPEC element to brinfo. - Side effect - may realloc bri->rects, so element MUST NOT be a pointer into that array! - 0 on sucess, anything else is an error */ +/** + \brief Insert a copy of a BRECT_SPEC structure into a BR_INFO structure. (Insert a bounding rectangle.) + \returns 0 on success, !0 on error. + \param bri pointer to the BR_INFO structure + \param element pointer to the BRECT_SPECS structure +*/ int brinfo_insert(BR_INFO *bri, BRECT_SPECS *element){ int status=1; if(!bri)return(2); @@ -711,8 +797,13 @@ int brinfo_insert(BR_INFO *bri, BRECT_SPECS *element){ return(status); } -/** Merge BRECT_SPEC element src with dst. dst becomes the merged result. - 0 on sucess, anything else is an error */ +/** + \brief Merge BRECT_SPEC element src into/with BRECT_SPEC element dst. src is unchanged. (Merge two bounding rectangles.) + \returns 0 on success, !0 on error. + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. +*/ int brinfo_merge(BR_INFO *bri, int dst, int src){ if(!bri)return(1); if(dst<0 || dst>= bri->used)return(2); @@ -735,18 +826,26 @@ printf("bri_Merge into rect:%d (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%l return(0); } -/** Check for an allowable overlap of two rectangles. The method works backwards, look for all reasons - they might not overlap, and none are found, then the rectangles do overlap. - An overlap here does not count just a line or a point - area must be involved. - dst one retangle to test - src the other rectangle to test - rp_src padding to apply to src, make it a little bigger, as in, allow leading or trailing spaces - 0 on sucess, 1 on no overlap, anything else is an error */ +/** + \brief Check for an allowable overlap of two bounding rectangles. + Allowable overlap is any area overlap of src and dst bounding rectangles, after + they have been expanded (padded) by allowed edge expansions. (For instance, if + missing spaces must be accounted for.) + The method works backwards: look for all reasons they might not overlap, + if none are found, then the rectangles do overlap. + An overlap here does not count just a line or a point - area must be involved. + \returns 0 on success (overlap detected), 1 on no overlap, anything else is an error. + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. + \param rp_dst Pointer to edge padding values for dst. + \param rp_src Pointer to edge padding values for src. +*/ int brinfo_overlap(BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD *rp_src){ int status; BRECT_SPECS *br_dst; BRECT_SPECS *br_src; - if(!bri)return(2); + if(!bri || !rp_dst || !rp_src)return(2); if(dst<0 || dst>= bri->used)return(3); if(src<0 || src>= bri->used)return(4); br_dst=&bri->rects[dst]; @@ -759,8 +858,21 @@ int brinfo_overlap(BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD *rp_sr ){ status = 1; } - else { /* overlap not excluded, so it must occur */ - status = 0; + else { + /* overlap not excluded, so it must occur. + Only accept overlaps that are mostly at one end or the other, not mostly top or bottom. + If the following condition is true then there is no more than a tiny bit of horizontal overlap of src + within dist, which suggests that the two pieces of text may be considered part of one line. + (For a vertical alphabet the same method could be used for up/down.) */ + if( + (br_src->xll >= br_dst->xur - rp_dst->right) || /* src overlaps just a little on the right (L->R language) */ + (br_src->xur <= br_dst->xll + rp_dst->left) /* src overlaps just a little on the left (R->L language) */ + ){ + status = 0; + } + else { /* Too much overlap, reject the overlap */ + status = 1; + } } /* printf("Overlap status:%d\nOverlap trects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n", @@ -795,9 +907,16 @@ printf("Overlap rprect (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n return(status); } -/* Attempt to deduce justification of a paragraph from the bounding rectangles for two lines. If type in not UJ -then the alignment must match or UJ is returned. "slop" is the numeric inaccuracy which is permitted - two values -within that range are the same as identical.*/ +/** + \brief Try to deduce justification of a paragraph from the bounding rectangles for two successive lines. + \returns one of TR_PARA_ UJ (unknown justified), LJ, CJ, or RJ (left, center, or right justified). + \param bri pointer to the BR_INFO structure + \param dst index of the destination bounding rectangle. + \param src index of the source bounding rectangle. + \param slop allowed error in edge alignment. + \param type Preexisting justification for dst, if any. Justification of dst and src must match this or + TR_PARA_UJ is returned even if dst and src have some (other) alignment. +*/ enum tr_classes brinfo_pp_alignment(BR_INFO *bri, int dst, int src, double slop, enum tr_classes type){ enum tr_classes newtype; BRECT_SPECS *br_dst = & bri->rects[dst]; @@ -841,8 +960,11 @@ newtype, return(newtype); } -/* Shut down the tpinfo system. Release all memory. - call like: bri_ptr = brinfo_release(bri_ptr) +/** + \brief Release a BR_INFO structure. Release all associated memory. + use like: bri = brinfo_release(bri); + \param bri pointer to the BR_INFO structure. + \returns NULL. */ BR_INFO *brinfo_release(BR_INFO *bri){ if(bri){ @@ -854,7 +976,10 @@ BR_INFO *brinfo_release(BR_INFO *bri){ -/* Initialize the trinfo system. Returns NULL on failure. */ +/** + \brief Initialize an TR_INFO structure. Holds all data for text reassembly. + \returns a pointer to the TR_INFO structure created, or NULL on error. +*/ TR_INFO *trinfo_init(TR_INFO *tri){ if(tri)return(tri); /* tri is already set, double initialization is not allowed */ if(!(tri = (TR_INFO *)calloc(1,sizeof(TR_INFO))) || @@ -872,7 +997,14 @@ TR_INFO *trinfo_init(TR_INFO *tri){ return(tri); } -/* release all memory from the trinfo system. */ +/** + \brief Release a TR_INFO structure completely. + Release all associated memory, including FontConfig. + See also trinfo_clear() and trinfo_release_except_FC(). + use like: tri = trinfo_release(tri); + \param tri pointer to the TR_INFO structure. + \returns NULL. +*/ TR_INFO *trinfo_release(TR_INFO *tri){ if(tri){ if(tri->bri)tri->bri=brinfo_release(tri->bri); @@ -885,8 +1017,15 @@ TR_INFO *trinfo_release(TR_INFO *tri){ return(NULL); } -/* release everything except Fontconfig, which may still be needed elsewhere in a program -and there is no way to figure that out here. */ +/** + \brief Release a TR_INFO structure mostly. + Release all associated memory EXCEPT Fontconfig. + Fontconfig may still be needed elsewhere in a program and there is no way to figure that out here. + See also trinfo_clear() and trinfo_release(). + use like: tri = trinfo_release_except_FC(tri); + \param tri pointer to the TR_INFO structure. + \returns NULL. +*/ TR_INFO *trinfo_release_except_FC(TR_INFO *tri){ if(tri){ if(tri->bri)tri->bri=brinfo_release(tri->bri); @@ -899,9 +1038,15 @@ TR_INFO *trinfo_release_except_FC(TR_INFO *tri){ return(NULL); } -/* clear the text and rectangle memory from the trinfo system. Leave the font -information alone unless there is an error, in which case clear that too. The odds -are that at least some of the fonts will be reused, so faster to leave them in place. */ +/** + \brief Clear a TR_INFO structure. + Releases text and rectangle information, but retains font information, both + Freetype information and Fontconfig information. + See also trinfo_release() and trinfo_release_except_FC(). + Use like: tri = trinfo_clear(tri); + \param tri pointer to the TR_INFO structure. + \returns NULL. +*/ TR_INFO *trinfo_clear(TR_INFO *tri){ if(tri){ tri->dirty = 0; /* set these back to their defaults */ @@ -927,8 +1072,12 @@ TR_INFO *trinfo_clear(TR_INFO *tri){ return(tri); } -/* Load the face by fontname and font size, return the idx. If this combination is already loaded then look it up - and return the idx. +/** + \brief Load a (new) font by name into a TR_INFO structure. + \returns index of font. If the font was already loaded return the existing index. + \param tri pointer to the TR_INFO structure. + \param fontname UTF-8 font name + \param tsp pointer to the TCHUNK_SPECS structure - used to construct a font query string. */ int trinfo_load_fontname(TR_INFO *tri, uint8_t *fontname, TCHUNK_SPECS *tsp){ @@ -1009,14 +1158,17 @@ int trinfo_load_fontname(TR_INFO *tri, uint8_t *fontname, TCHUNK_SPECS *tsp){ } -/* Set the quantization error value. If coordinates have passed through an integer form limits - in accuracy may have been imposed. For instance, if the X coordinate of a point in such a file - is 1000, and the conversion factor from those coordinates to points is .04, then eq is .04. This - just says that single coordinates are only good to within .04, and two coordinates may differ by as much - as .08, just due to quantization error. So if some calculation shows a difference of - .02 it may be interpreted as this sort of error and set to 0.0. - - Returns 0 on success, >0 on error. +/** + \brief Set the quantization error value for a TR_INFO structure. + If coordinates have passed through an integer form limits + in accuracy may have been imposed. For instance, if the X coordinate of a point in such a file + is 1000, and the conversion factor from those coordinates to points is .04, then eq is .04. This + just says that single coordinates are only good to within .04, and two coordinates may differ by as much + as .08, just due to quantization error. So if some calculation shows a difference of + .02 it may be interpreted as this sort of error and set to 0.0. + \returns 0 on success, !0 on error. + \param tri pointer to TR_INFO structure + \param qe quantization error. */ int trinfo_load_qe(TR_INFO *tri, double qe){ if(!tri)return(1); @@ -1025,9 +1177,16 @@ int trinfo_load_qe(TR_INFO *tri, double qe){ return(0); } -/* Set the FT parameters flags and kern mode and decide whether or not to to use kerning. - No error checking on those values. - Returns 0 on success, >0 on error. +/** + \brief Set Freetype parameters and kerning mode (if any) in a TRI_INFO structure. + \returns 0 on success, !0 on error. + \param tri pointer to a TR_INFO structure + \param use_kern 0 if kerning is to be employed, !0 otherwise. + \param load_flags Controls internal advance: + FT_LOAD_NO_SCALE, internal advance is in 1/64th of a point. (kerning values are still scaled) + FT_LOAD_TARGET_NORMAL internal advance is in 1/64th of a point. The scale + factor seems to be (Font Size in points)*(DPI)/(32.0 pnts)*(72 dpi). + \param kern_mode FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED. Set to match calling application. */ int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode){ if(!tri)return(1); @@ -1037,8 +1196,11 @@ int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mod return(0); } -/* Append text to the output buffer, expanding it if necessary. - returns 0 on success, -1 on failure +/** + \brief Append text to a TR_INFO struct's output buffer, expanding it if necessary. + \returns 0 on success, !0 on error. + \param tri pointer to a TR_INFO structure + \param src Pointer to a text string. */ int trinfo_append_out(TR_INFO *tri, char *src){ size_t slen; @@ -1057,20 +1219,22 @@ int trinfo_append_out(TR_INFO *tri, char *src){ } -/* load a text record into the system. On success returns 0. Any error returns !0. - Escapement must match that of first record. - Status of -1 indicates that an escapement change was detected. - idx etc in tsp must have been set. - load_flags - see TR_getadvance, must match graphics model of CURRENT program. - kern_mode - see TR_getadvance, must match graphics model of CURRENT program. - use_kern - true if kerning is used, must match graphics model of CURRENT program +/** + \brief Load a text object into a TR_INFO struct. + \returns 0 on success, !0 on error. -1 means that the escapement is different from the objects already loaded. + \param tri pointer to a TR_INFO structure + \param tsp pointer to a TCHUNK_SPECS structure (text object to load) + \param escapement angle in degrees of the text object. + \param flags special processing flags: + TR_EMFBOT calculate Y coordinates of ALIBOT object compatible with EMF files TA_BOTTOM alignment. */ int trinfo_load_textrec(TR_INFO *tri, TCHUNK_SPECS *tsp, double escapement, int flags){ int status; double x,y,xe; - double asc,dsc; + double asc,dsc; /* these are the ascender/descender for the actual text */ int ymin,ymax; + double fasc,fdsc; /* these are the ascender/descender for the font as a whole (text independent) */ TP_INFO *tpi; FT_INFO *fti; BR_INFO *bri; @@ -1104,8 +1268,8 @@ int trinfo_load_textrec(TR_INFO *tri, TCHUNK_SPECS *tsp, double escapement, int tpinfo_insert(tpi,tsp); current=tpi->used-1; - ymin = 64000; - ymax = -64000; + ymin = 64000; + ymax = -64000; /* The geometry model has origin Y at the top of screen, positive Y is down, maximum positive Y is at the bottom of the screen. That makes "top" (by positive Y) actually the bottom @@ -1140,6 +1304,13 @@ printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,% else { return(6); } prev=*tptr; } + asc = ((double) (ymax))/64.0; + dsc = ((double) (ymin))/64.0; /* This is negative */ +/* This did not work very well because the ascender/descender went well beyond the actual characters, causing + overlaps on lines that did not actually overlap (vertically). + asc = ((double) (fsp->face->ascender) )/64.0; + dsc = ((double) (fsp->face->descender))/64.0; +*/ free(text32); @@ -1149,6 +1320,10 @@ printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,% if(status>=0){ fsp->spcadv = ((double) status)/64.0; } else { return(7); } } + + /* find the font ascender descender (general one, not specific for current text) */ + fasc = ((double) (fsp->face->ascender) )/64.0; + fdsc = ((double) (fsp->face->descender))/64.0; if(tri->load_flags & FT_LOAD_NO_SCALE){ xe *= tsp->fs/32.0; @@ -1169,29 +1344,26 @@ printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,% bsp.xur = tpi->chunks[current].x; } - asc = ((double) (ymax))/64.0; - dsc = ((double) (ymin))/64.0; /* This is negative */ -/* This did not work very well because the ascender/descender went well beyond the actual characters, causing - overlaps on lines that did not actually overlap (vertically). - asc = ((double) (fsp->face->ascender) )/64.0; - dsc = ((double) (fsp->face->descender))/64.0; -*/ if(tri->load_flags & FT_LOAD_NO_SCALE){ - asc *= tsp->fs/32.0; - dsc *= tsp->fs/32.0; + asc *= tsp->fs/32.0; + dsc *= tsp->fs/32.0; + fasc *= tsp->fs/32.0; + fdsc *= tsp->fs/32.0; } - /* From this point forward y is on the baseline, so need to correct it in chunks */ - if( taln & ALIVERT & ALITOP ){ tpi->chunks[current].y += -dsc + asc; } - else if( taln & ALIVERT & ALIBASE){ } /* no correction required */ + /* From this point forward y is on the baseline, so need to correct it in chunks. The asc/dsc are the general + ones for the font, else the text content will muck around with the baseline in BAD ways. */ + if( taln & ALIVERT & ALITOP ){ tpi->chunks[current].y += fasc; } + else if( taln & ALIVERT & ALIBASE){ } /* no correction required */ else{ /* taln & ALIVERT & ALIBOT */ - if(flags & TR_EMFBOT){ tpi->chunks[current].y -= 0.35 * tsp->fs; } /* compatible with EMF implementations */ - else { tpi->chunks[current].y += dsc; } + if(flags & TR_EMFBOT){ tpi->chunks[current].y -= 0.35 * tsp->fs; } /* compatible with EMF implementations */ + else { tpi->chunks[current].y += fdsc; } } tpi->chunks[current].boff = -dsc; - /* since y is always on the baseline, the lower left and upper right are easy */ + /* since y is always on the baseline, the lower left and upper right are easy. These use asc/dsc for the particular text, + so that the bounding box will fit it tightly. */ bsp.yll = tpi->chunks[current].y - dsc; bsp.yur = tpi->chunks[current].y - asc; brinfo_insert(bri,&bsp); @@ -1200,10 +1372,14 @@ printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,% return(0); } -/* Font weight conversion, from fontconfig weights to SVG weights. -Anything not recognized becomes "normal" == 400. There is no interpolation because a value -that mapped to 775, for instance, most likely would not display at a weight intermediate -between 700 and 800. +/** + \brief Fontweight conversion. Fontconfig units to SVG units. + Anything not recognized becomes "normal" == 400. + There is no interpolation because a value that mapped to 775, for instance, most + likely would not display properly because it is intermediate between 700 and 800, and + only those need be supported in SVG viewers. + \returns SVG font weight + \param weight Fontconfig font weight. */ int TR_weight_FC_to_SVG(int weight){ int ret=400; @@ -1220,9 +1396,15 @@ int TR_weight_FC_to_SVG(int weight){ return(ret); } -/* Set the padding that will be added to rectangles before checking for overlaps. - Method is set for L->R, or R->L text, not correct for vertical text. -*/ +/** + \brief Set the padding that will be added to bounding rectangles before checking for overlaps in brinfo_overlap(). + \returns void + \param rt_pad pointer to an RT_PAD structure. + \param up padding for the top of a bounding rectangle. + \param down padding for the bottom of a bounding rectangle. + \param left padding for the left of a bounding rectangle. + \param right padding for the right of a bounding rectangle. +*/ void TR_rt_pad_set(RT_PAD *rt_pad, double up, double down, double left, double right){ rt_pad->up = up; rt_pad->down = down; @@ -1230,7 +1412,10 @@ void TR_rt_pad_set(RT_PAD *rt_pad, double up, double down, double left, double r rt_pad->right = right; } -/* Convert from analyzed complexes to SVG format, stored in the "out" buffer of the tri. +/** + \brief Convert from analyzed complexes to SVG format. + \returns void + \param tri pointer to a TR_INFO struct which will be analyzed. Result is stored in its "out" buffer. */ void TR_layout_2_svg(TR_INFO *tri){ double x = tri->x; @@ -1481,15 +1666,19 @@ void TR_layout_2_svg(TR_INFO *tri){ } /* end of i loop */ } -/** Attempt to figure out what the text was originally. - 1. Group text strings by overlaps (optionally allowing up to two spaces to be added) to produce larger rectangles. - Larger rectangles that are more or less sequential are LINES, otherwise they are EQN. - 2. Group sequential LINES into paragraphs (by smooth progression in position down page). +/** + \brief Attempt to figure out the original organization, in lines and paragraphs, of the text objects. + The method is: + 1. Generate complexes from the text objects (strings) by overlaps (optionally allowing up to two spaces to be + added) to produce larger rectangles. Complexes that are more or less sequential and have 2 or more text objects + are TR_LINEs, therwise they are TR_TEXT. + 2. Group sequential complexes (TR_LINE or TR_TEXT) into TR_PARA_UJ (paragraphs,by smooth progression in vertical + position down page). 3. Analyze the paragraphs to classify them as Left/Center/Right justified (possibly with indentation.) If - they do not fall into any of these categories break that one back down into LINES. - 4. Return the number of complex text objects. Value will be >=1 and <= number of text strings. - - Values <0 are errors + they do not fall into any of these categories break that one back down into TR_LINE/TR_TEXT. + 4. Return the number of complex text objects. + \returns Number of complexes. (>=1, <= number of text objects.) <0 is an error. + \param tri pointer to the TR_INFO structure holding the data, which will also hold the results. */ int TR_layout_analyze(TR_INFO *tri){ int i,j; @@ -1533,13 +1722,13 @@ int TR_layout_analyze(TR_INFO *tri){ TR_rt_pad_set(&rt_pad_i,tri->qe, tri->qe, 0.0, tri->qe + 2.0 * fti->fonts[tpi->chunks[i].fi_idx].spcadv); for(j=i+1; jused; j++){ - /* Reject font size changes of greater than 50%, these almost certainly not continuous text. These happen + /* Reject font size changes of greater than 50%, these are almost certainly not continuous text. These happen in math formulas, for instance, where a sum or integral is much larger than the other symbols. */ ratio = (double)(tpi->chunks[j].fs)/(double)(tpi->chunks[i].fs); if(ratio >2.0 || ratio <0.5)break; - /* for the trailing text: pad with one leading and no trailing spaces */ - TR_rt_pad_set(&rt_pad_j,tri->qe, tri->qe, 1.0 * fti->fonts[tpi->chunks[j].fi_idx].spcadv, 0.0); + /* for the trailing text: pad with one leading and trailing spaces (so it should work L->R and R->L */ + TR_rt_pad_set(&rt_pad_j,tri->qe, tri->qe, fti->fonts[tpi->chunks[j].fi_idx].spcadv, fti->fonts[tpi->chunks[j].fi_idx].spcadv); src_rt = tpi->chunks[j].rt_tidx; if(!brinfo_overlap(bri, dst_rt, /* index into bri for dst */ @@ -1547,7 +1736,9 @@ int TR_layout_analyze(TR_INFO *tri){ &rt_pad_i,&rt_pad_j)){ (void) cxinfo_append(cxi,j,TR_LINE); (void) brinfo_merge(bri,dst_rt,src_rt); - TR_rt_pad_set(&rt_pad_i, tri->qe, tri->qe, 0.0, tri->qe + 2.0 * fti->fonts[tpi->chunks[j].fi_idx].spcadv); + /* for the leading text: pad with two leading and trailing spaces (so it should work L->R and R->L */ + TR_rt_pad_set(&rt_pad_i, tri->qe, tri->qe, + tri->qe + 2.0 * fti->fonts[tpi->chunks[j].fi_idx].spcadv, tri->qe + 2.0 * fti->fonts[tpi->chunks[j].fi_idx].spcadv); } else { /* either alignment ge*/ break; @@ -1618,6 +1809,7 @@ int TR_layout_analyze(TR_INFO *tri){ } +/* no doxygen documentation below this point, these pieces are for the text program, not the library. */ #if TEST #define MAXLINE 2048 /* big enough for testing */ diff --git a/src/extension/internal/text_reassemble.h b/src/extension/internal/text_reassemble.h index 04c63940f..fb58d504e 100644 --- a/src/extension/internal/text_reassemble.h +++ b/src/extension/internal/text_reassemble.h @@ -1,9 +1,14 @@ -/* text_reassemble.h -version 0.0.2 2012-12-07 -Copyright 2012, Caltech and David Mathog +/** + @file text_reassemble.h libTERE headers. See text_reassemble.c for notes +File: text_reassemble.h +Version: 0.0.4 +Date: 24-JAN-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -22,6 +27,7 @@ extern "C" { #include FT_FREETYPE_H #include FT_GLYPH_H +/** \cond */ #define TEREMIN(A,B) (A < B ? A : B) #define TEREMAX(A,B) (A > B ? A : B) @@ -31,151 +37,196 @@ extern "C" { #define ALLOCINFO_CHUNK 32 #define ALLOCOUT_CHUNK 8192 #define TRPRINT trinfo_append_out +/** \endcond */ -/* text alignment types */ -#define ALILEFT 0x01 -#define ALICENTER 0x02 -#define ALIRIGHT 0x04 -#define ALIHORI 0x07 -#define ALITOP 0x08 -#define ALIBASE 0x10 -#define ALIBOT 0x20 -#define ALIVERT 0x38 - -/* language direction types */ -#define LDIR_LR 0x00 -#define LDIR_RL 0x01 -#define LDIR_TB 0x02 - -/* Flags */ -#define TR_EMFBOT 0x01 /* use an approximation compatible with EMF file's "BOTTOM" text orientation, which is not the "bottom" for Freetype fonts */ - -/* complex classification types - TR_TEXT simple text object - TR_LINE linear assembly of TR_TEXTS - TR_PARA_UJ sequential assembly of TR_LINE into a paragraph, with unknown justification properties - TR_PARA_LJ ..., left justified - TR_PARA_CJ ..., center justified - TR_PARA_RJ ..., right justified -*/ -enum tr_classes {TR_TEXT,TR_LINE,TR_PARA_UJ,TR_PARA_LJ,TR_PARA_CJ,TR_PARA_RJ}; - -/* Fontinfo structure, values related to fonts */ +/** \defgroup text alignment types + Location of text's {X,Y} coordinate on bounding rectangle. + Values are compatible with Fontconfig. + @{ +*/ +#define ALILEFT 0x01 /**< text object horizontal alignment = left */ +#define ALICENTER 0x02 /**< text object horizontal alignment = center */ +#define ALIRIGHT 0x04 /**< text object horizontal alignment = right */ +#define ALIHORI 0x07 /**< text object horizontal alignment mask */ +#define ALITOP 0x08 /**< text object vertical alignment = top */ +#define ALIBASE 0x10 /**< text object vertical alignment = baseline */ +#define ALIBOT 0x20 /**< text object vertical alignment = bottom */ +#define ALIVERT 0x38 /**< text object vertical alignment mask */ +/** @} */ + +/** \defgroup language direction types + @{ +*/ +#define LDIR_LR 0x00 /**< left to right */ +#define LDIR_RL 0x01 /**< right to left */ +#define LDIR_TB 0x02 /**< top to bottom */ +/** @} */ + +/** \defgroup special processing flags + @{ +*/ +#define TR_EMFBOT 0x01 /**< use an approximation compatible with EMF file's "BOTTOM" text orientation, which is not the "bottom" for Freetype fonts */ +/** @} */ + +/** \enum tr_classes +classification of complexes + @{ +*/ +enum tr_classes { + TR_TEXT, /**< simple text object */ + TR_LINE, /**< linear assembly of TR_TEXTs */ + TR_PARA_UJ, /**< sequential assembly of TR_LINEs and TR_TEXTs into a paragraph - + unknown justification properties */ + TR_PARA_LJ, /**< ditto, left justified */ + TR_PARA_CJ, /**< ditto, center justified */ + TR_PARA_RJ /**< ditto, right justified */ + }; +/** @} */ + +/** + \brief Information for a font instance. +*/ typedef struct { - FT_Face face; /* font face structures (FT_FACE is a pointer!) */ - uint8_t *file; /* pointers to font paths to files */ - uint8_t *fname; /* pointers to font names */ - FcPattern *fpat; /* must hang onto this or faces operations break */ - double spcadv; /* advance equal to a space, in points */ - double fsize; /* face size in points */ + FT_Face face; /**< font face structures (FT_FACE is a pointer!) */ + uint8_t *file; /**< pointers to font paths to files */ + uint8_t *fname; /**< pointers to font names */ + FcPattern *fpat; /**< must hang onto this or faces operations break */ + double spcadv; /**< advance equal to a space, in points */ + double fsize; /**< face size in points */ } FNT_SPECS; +/** + \brief Information for all font instances. +*/ typedef struct { - FT_Library library; /* Fontconfig handle */ - FNT_SPECS *fonts; /* Array of fontinfo structures */ - int space; /* storage slots allocated */ - int used; /* storage slots in use */ + FT_Library library; /**< Fontconfig handle */ + FNT_SPECS *fonts; /**< Array of fontinfo structures */ + int space; /**< storage slots allocated */ + int used; /**< storage slots in use */ } FT_INFO; +/** + \brief Information for a single text object +*/ typedef struct { - uint8_t *string; /* UTF-8 text */ - double ori; /* Orientation, angle of characters with respect to baseline in degrees */ - double fs; /* font size of text */ - double x; /* x coord relative to tri x,y, in points */ - double y; /* y coord */ - 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 */ - int taln; /* text alignment with respect to x,y */ - int ldir; /* language diretion LDIR_* */ - int italics; /* italics, as in FontConfig */ - int weight; /* weight, as in FontConfig */ - int condensed; /* condensed, as in FontConfig */ - int co; /* condensed override, if set Font name included narrow */ - int rt_tidx; /* index of rectangle that contains it */ - int fi_idx; /* index of the font it uses */ + uint8_t *string; /**< UTF-8 text */ + double ori; /**< Orientation, angle of characters with respect to baseline in degrees */ + double fs; /**< font size of text */ + double x; /**< x coordinate, relative to TR_INFO x,y, in points */ + double y; /**< y coordinate, relative to TR_INFO x,y, in points */ + double 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 */ + int taln; /**< text alignment with respect to x,y */ + int ldir; /**< language diretion LDIR_* */ + int italics; /**< italics, as in FontConfig */ + int weight; /**< weight, as in FontConfig */ + int condensed; /**< condensed, as in FontConfig */ + int co; /**< condensed override, if set Font name included narrow */ + int rt_tidx; /**< index of rectangle that contains it */ + int fi_idx; /**< index of the font it uses */ } TCHUNK_SPECS; -/* Text Info/Position Info structure, values related to text properties and string geometry +/** + \brief Information for all text objects. Coordinates here are INTERNAL, after offset/rotate using values in TR_INFO. */ typedef struct { - TCHUNK_SPECS *chunks; /* text chunks */ - int space; /* storage slots allocated */ - int used; /* storage slots in use */ + TCHUNK_SPECS *chunks; /**< text chunks */ + int space; /**< storage slots allocated */ + int used; /**< storage slots in use */ } TP_INFO; -/* Bounding Rectangle(s) structure +/** + \brief Information for a single bounding rectangle. Coordinates here are INTERNAL, after offset/rotate using values in TR_INFO. */ typedef struct { - double xll; /* x rectangle lower left corner */ - double yll; /* y " */ - double xur; /* x upper right corner */ - double yur; /* y " */ - double xbearing; /* x bearing of the leftmost character */ + double xll; /**< x rectangle lower left corner */ + double yll; /**< y " */ + double xur; /**< x upper right corner */ + double yur; /**< y " */ + double xbearing; /**< x bearing of the leftmost character */ } BRECT_SPECS; +/** + \brief Information for all bounding rectangles. +*/ typedef struct { - BRECT_SPECS *rects; /* bounding rectangles */ - int space; /* storage slots allocated */ - int used; /* storage slots in use */ + BRECT_SPECS *rects; /**< bounding rectangles */ + int space; /**< storage slots allocated */ + int used; /**< storage slots in use */ } BR_INFO; +/** + \brief List of all members of a single complex. +*/ typedef struct { - int *members; /* array of immediate children (for TR_PARA_* these are indicies - for TR_TEXT or TR_LINE complexes also in cxi. For TR_TEXT - and TR_LINE these are indices to the actual text in tpi.) */ - int space; /* storage slots allocated */ - int used; /* storage slots in use */ + int *members; /**< array of immediate children (for TR_PARA_* these are indicies + for TR_TEXT or TR_LINE complexes also in cxi. For TR_TEXT + and TR_LINE these are indices to the actual text in tpi.) */ + int space; /**< storage slots allocated */ + int used; /**< storage slots in use */ } CHILD_SPECS; -/* Complex info structure, values related to the assembly of complex text from smaller pieces */ +/** + \brief Information for a single complex. +*/ typedef struct { - int rt_cidx; /* index of rectangle that contains all members */ - enum tr_classes type; /* classification of the complex */ - CHILD_SPECS kids; /* immediate child nodes of this complex, for type TR_TEXT the - idx refers to the tpi data. otherwise, cxi data */ + int rt_cidx; /**< index of rectangle that contains all members */ + enum tr_classes type; /**< classification of the complex */ + CHILD_SPECS kids; /**< immediate child nodes of this complex, for type TR_TEXT the + idx refers to the tpi data. otherwise, cxi data */ } CX_SPECS; +/** + \brief Information for all complexes. +*/ typedef struct { - CX_SPECS *cx; /* complexes */ - int space; /* storage slots allocated */ - int used; /* storage slots in use */ - int phase1; /* Number of complexes (lines + text fragments) entered in phase 1 */ - int lines; /* Number of lines in phase 1 */ - int paras; /* Number of complexes (paras) entered in phase 2 */ + CX_SPECS *cx; /**< complexes */ + int space; /**< storage slots allocated */ + int used; /**< storage slots in use */ + int phase1; /**< Number of complexes (lines + text fragments) entered in phase 1 */ + int lines; /**< Number of lines in phase 1 */ + int paras; /**< Number of complexes (paras) entered in phase 2 */ } CX_INFO; -/* Text reassemble, overall structure */ +/** + \brief Information for the entire text reassembly system. +*/ typedef struct { - FT_INFO *fti; /* Font info storage */ - TP_INFO *tpi; /* Text Info/Position Info storage */ - BR_INFO *bri; /* Bounding Rectangle Info storage */ - CX_INFO *cxi; /* Complex Info storage */ - uint8_t *out; /* buffer to hold formatted output */ - double qe; /* quantization error in points. */ - double esc; /* escapement angle in DEGREES */ - double x; /* coordinates of first text, in points */ - double y; - int dirty; /* 1 if text records are loaded */ - int use_kern; /* 1 if kerning is used, 0 if not */ - int load_flags; /* FT_LOAD_NO_SCALE or FT_LOAD_TARGET_NORMAL */ - int kern_mode; /* FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED */ - int outspace; /* storage in output buffer allocated */ - int outused; /* storage in output buffer in use */ + FT_INFO *fti; /**< Font info storage */ + TP_INFO *tpi; /**< Text Info/Position Info storage */ + BR_INFO *bri; /**< Bounding Rectangle Info storage */ + CX_INFO *cxi; /**< Complex Info storage */ + uint8_t *out; /**< buffer to hold formatted output */ + double qe; /**< quantization error in points. */ + double esc; /**< escapement angle in DEGREES */ + double x; /**< x coordinate of first text object, in points */ + double y; /**< y coordinate of first text object, in points */ + int dirty; /**< 1 if text records are loaded */ + int use_kern; /**< 1 if kerning is used, 0 if not */ + int load_flags; /**< FT_LOAD_NO_SCALE or FT_LOAD_TARGET_NORMAL */ + int kern_mode; /**< FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED */ + int outspace; /**< storage in output buffer allocated */ + int outused; /**< storage in output buffer in use */ } TR_INFO; /* padding added to rectangles before overlap test */ +/** + \brief Information for one padding record. (Padding is added to bounding rectangles before overlap tests.) +*/ typedef struct { - double up; /* to top */ - double down; /* to bottom */ - double left; /* to left */ - double right; /* to right */ + double up; /**< to top */ + double down; /**< to bottom */ + double left; /**< to left */ + double right; /**< to right */ } RT_PAD; -/* iconv() has a funny cast on some older systems, on most recent ones +/** \cond */ +/* + iconv() has a funny cast on some older systems, on most recent ones it is just char **. This tries to work around the issue. If you build this on another funky system this code may need to be modified, or define ICONV_CAST on the compile line(but it may be tricky). @@ -186,6 +237,7 @@ typedef struct { #if !defined(ICONV_CAST) #define ICONV_CAST (char **) #endif //ICONV_CAST +/** \endcond */ /* Prototypes */ int TR_findcasesub(char *string, char *sub); @@ -209,7 +261,6 @@ int csp_make_insertable(CHILD_SPECS *csp); int csp_insert(CHILD_SPECS *csp, int src); int csp_merge(CHILD_SPECS *dst, CHILD_SPECS *src); void csp_release(CHILD_SPECS *csp); -#define csp_clear csp_release /* since the CHILD_SPECS area itself is not deleted, clear == reset */ CX_INFO *cxinfo_init(void); int cxinfo_make_insertable(CX_INFO *cxi); diff --git a/src/extension/internal/uemf.c b/src/extension/internal/uemf.c index 39d44555c..47af366e7 100644 --- a/src/extension/internal/uemf.c +++ b/src/extension/internal/uemf.c @@ -14,11 +14,11 @@ /* File: uemf.c -Version: 0.0.11 -Date: 07-DEC-2012 +Version: 0.0.15 +Date: 01-FEB-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -44,6 +44,145 @@ extern "C" { not in uemf.h or uemf_endian.h */ void U_swap2(void *ul, unsigned int count); +/** + \brief Look up the name of the EMR record by type. Returns U_EMR_INVALID if out of range. + + \return name of the EMR record, "U_EMR_INVALID" if out of range. + \param idx EMR record type. + +*/ +char *U_emr_names(unsigned int idx){ + if(idx U_EMR_MAX){ idx = 0; } + static char *U_WMR_NAMES[U_EMR_MAX+1]={ + "U_EMR_INVALID", + "U_EMR_HEADER", + "U_EMR_POLYBEZIER", + "U_EMR_POLYGON", + "U_EMR_POLYLINE", + "U_EMR_POLYBEZIERTO", + "U_EMR_POLYLINETO", + "U_EMR_POLYPOLYLINE", + "U_EMR_POLYPOLYGON", + "U_EMR_SETWINDOWEXTEX", + "U_EMR_SETWINDOWORGEX", + "U_EMR_SETVIEWPORTEXTEX", + "U_EMR_SETVIEWPORTORGEX", + "U_EMR_SETBRUSHORGEX", + "U_EMR_EOF", + "U_EMR_SETPIXELV", + "U_EMR_SETMAPPERFLAGS", + "U_EMR_SETMAPMODE", + "U_EMR_SETBKMODE", + "U_EMR_SETPOLYFILLMODE", + "U_EMR_SETROP2", + "U_EMR_SETSTRETCHBLTMODE", + "U_EMR_SETTEXTALIGN", + "U_EMR_SETCOLORADJUSTMENT", + "U_EMR_SETTEXTCOLOR", + "U_EMR_SETBKCOLOR", + "U_EMR_OFFSETCLIPRGN", + "U_EMR_MOVETOEX", + "U_EMR_SETMETARGN", + "U_EMR_EXCLUDECLIPRECT", + "U_EMR_INTERSECTCLIPRECT", + "U_EMR_SCALEVIEWPORTEXTEX", + "U_EMR_SCALEWINDOWEXTEX", + "U_EMR_SAVEDC", + "U_EMR_RESTOREDC", + "U_EMR_SETWORLDTRANSFORM", + "U_EMR_MODIFYWORLDTRANSFORM", + "U_EMR_SELECTOBJECT", + "U_EMR_CREATEPEN", + "U_EMR_CREATEBRUSHINDIRECT", + "U_EMR_DELETEOBJECT", + "U_EMR_ANGLEARC", + "U_EMR_ELLIPSE", + "U_EMR_RECTANGLE", + "U_EMR_ROUNDRECT", + "U_EMR_ARC", + "U_EMR_CHORD", + "U_EMR_PIE", + "U_EMR_SELECTPALETTE", + "U_EMR_CREATEPALETTE", + "U_EMR_SETPALETTEENTRIES", + "U_EMR_RESIZEPALETTE", + "U_EMR_REALIZEPALETTE", + "U_EMR_EXTFLOODFILL", + "U_EMR_LINETO", + "U_EMR_ARCTO", + "U_EMR_POLYDRAW", + "U_EMR_SETARCDIRECTION", + "U_EMR_SETMITERLIMIT", + "U_EMR_BEGINPATH", + "U_EMR_ENDPATH", + "U_EMR_CLOSEFIGURE", + "U_EMR_FILLPATH", + "U_EMR_STROKEANDFILLPATH", + "U_EMR_STROKEPATH", + "U_EMR_FLATTENPATH", + "U_EMR_WIDENPATH", + "U_EMR_SELECTCLIPPATH", + "U_EMR_ABORTPATH", + "U_EMR_UNDEF69", + "U_EMR_COMMENT", + "U_EMR_FILLRGN", + "U_EMR_FRAMERGN", + "U_EMR_INVERTRGN", + "U_EMR_PAINTRGN", + "U_EMR_EXTSELECTCLIPRGN", + "U_EMR_BITBLT", + "U_EMR_STRETCHBLT", + "U_EMR_MASKBLT", + "U_EMR_PLGBLT", + "U_EMR_SETDIBITSTODEVICE", + "U_EMR_STRETCHDIBITS", + "U_EMR_EXTCREATEFONTINDIRECTW", + "U_EMR_EXTTEXTOUTA", + "U_EMR_EXTTEXTOUTW", + "U_EMR_POLYBEZIER16", + "U_EMR_POLYGON16", + "U_EMR_POLYLINE16", + "U_EMR_POLYBEZIERTO16", + "U_EMR_POLYLINETO16", + "U_EMR_POLYPOLYLINE16", + "U_EMR_POLYPOLYGON16", + "U_EMR_POLYDRAW16", + "U_EMR_CREATEMONOBRUSH", + "U_EMR_CREATEDIBPATTERNBRUSHPT", + "U_EMR_EXTCREATEPEN", + "U_EMR_POLYTEXTOUTA", + "U_EMR_POLYTEXTOUTW", + "U_EMR_SETICMMODE", + "U_EMR_CREATECOLORSPACE", + "U_EMR_SETCOLORSPACE", + "U_EMR_DELETECOLORSPACE", + "U_EMR_GLSRECORD", + "U_EMR_GLSBOUNDEDRECORD", + "U_EMR_PIXELFORMAT", + "U_EMR_DRAWESCAPE", + "U_EMR_EXTESCAPE", + "U_EMR_UNDEF107", + "U_EMR_SMALLTEXTOUT", + "U_EMR_FORCEUFIMAPPING", + "U_EMR_NAMEDESCAPE", + "U_EMR_COLORCORRECTPALETTE", + "U_EMR_SETICMPROFILEA", + "U_EMR_SETICMPROFILEW", + "U_EMR_ALPHABLEND", + "U_EMR_SETLAYOUT", + "U_EMR_TRANSPARENTBLT", + "U_EMR_UNDEF117", + "U_EMR_GRADIENTFILL", + "U_EMR_SETLINKEDUFIS", + "U_EMR_SETTEXTJUSTIFICATION", + "U_EMR_COLORMATCHTOTARGETW", + "U_EMR_CREATECOLORSPACEW" + }; + return(U_WMR_NAMES[idx]); +} + + + /* ********************************************************************************************** These definitions are for code pieces that are used many times in the following implementation. These definitions are not needed in end user code, so they are here rather than in uemf.h. @@ -72,7 +211,10 @@ definitions are not needed in end user code, so they are here rather than in uem memcpy(A + off, E, F);\ ((B *) A)->offBitsSrc = off;\ ((B *) A)->cbBitsSrc = F;\ - if(G - F){ memset(A + off, 0, G - F); }\ + if(G - F){ \ + off += F;\ + memset(A + off, 0, G - F); \ + }\ }\ else {\ ((B *) A)->offBmiSrc = 0;\ @@ -182,6 +324,7 @@ uint32_t *dx_set( /** \brief Look up the properties (a bit map) of a type of EMR record. + Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc.. \return bitmap of EMR record properties, or U_EMR_INVALID on error or release of all memory \param type EMR record type. If U_EMR_INVALID release memory. (There is no U_EMR_INVALID EMR record type) @@ -201,129 +344,129 @@ uint32_t emr_properties(uint32_t type){ // 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01 // Path properties (U_DRAW_*) TEXT ALTERS ONLYTO VISIBLE // PATH FORCE CLOSED NOTEMPTY - table[ 0] = 0x00; //!< Does not map to any EMR record - table[ 1] = 0x80; //!< U_EMRHEADER 1 0 0 0 0 0 0 0 - table[ 2] = 0x83; //!< U_EMRPOLYBEZIER 1 0 0 0 0 0 1 1 - table[ 3] = 0x87; //!< U_EMRPOLYGON 1 0 0 0 0 1 1 1 - table[ 4] = 0x83; //!< U_EMRPOLYLINE 1 0 0 0 0 0 1 1 - table[ 5] = 0x8B; //!< U_EMRPOLYBEZIERTO 1 0 0 0 1 0 1 1 - table[ 6] = 0x8B; //!< U_EMRPOLYLINETO 1 0 0 0 1 0 1 1 - table[ 7] = 0x83; //!< U_EMRPOLYPOLYLINE 1 0 0 0 0 0 1 1 - table[ 8] = 0x87; //!< U_EMRPOLYPOLYGON 1 0 0 0 0 1 1 1 - table[ 9] = 0xA0; //!< U_EMRSETWINDOWEXTEX 1 0 1 0 0 0 0 0 - table[ 10] = 0xA0; //!< U_EMRSETWINDOWORGEX 1 0 1 0 0 0 0 0 - table[ 11] = 0xA0; //!< U_EMRSETVIEWPORTEXTEX 1 0 1 0 0 0 0 0 - table[ 12] = 0xA0; //!< U_EMRSETVIEWPORTORGEX 1 0 1 0 0 0 0 0 - table[ 13] = 0xA0; //!< U_EMRSETBRUSHORGEX 1 0 1 0 0 0 0 0 - table[ 14] = 0x82; //!< U_EMREOF 1 0 1 0 0 0 0 0 Force out any pending draw - table[ 15] = 0x82; //!< U_EMRSETPIXELV 1 0 0 0 0 0 1 0 - table[ 16] = 0xA0; //!< U_EMRSETMAPPERFLAGS 1 0 1 0 0 0 0 0 - table[ 17] = 0xA0; //!< U_EMRSETMAPMODE 1 0 1 0 0 0 0 0 - table[ 18] = 0x20; //!< U_EMRSETBKMODE 0 0 1 0 0 0 0 0 - table[ 19] = 0xA0; //!< U_EMRSETPOLYFILLMODE 1 0 1 0 0 0 0 0 - table[ 20] = 0xA0; //!< U_EMRSETROP2 1 0 1 0 0 0 0 0 - table[ 21] = 0xA0; //!< U_EMRSETSTRETCHBLTMODE 1 0 1 0 0 0 0 0 - table[ 22] = 0x20; //!< U_EMRSETTEXTALIGN 0 0 1 0 0 0 0 0 - table[ 23] = 0xA0; //!< U_EMRSETCOLORADJUSTMENT 1 0 1 0 0 0 0 0 - table[ 24] = 0x20; //!< U_EMRSETTEXTCOLOR 0 0 1 0 0 0 0 0 - table[ 25] = 0x20; //!< U_EMRSETBKCOLOR 0 0 1 0 0 0 0 0 - table[ 26] = 0xA0; //!< U_EMROFFSETCLIPRGN 1 0 1 0 0 0 0 0 - table[ 27] = 0x89; //!< U_EMRMOVETOEX 1 0 0 0 1 0 0 1 - table[ 28] = 0xA0; //!< U_EMRSETMETARGN 1 0 1 0 0 0 0 0 - table[ 29] = 0xA0; //!< U_EMREXCLUDECLIPRECT 1 0 1 0 0 0 0 0 - table[ 30] = 0xA0; //!< U_EMRINTERSECTCLIPRECT 1 0 1 0 0 0 0 0 - table[ 31] = 0xA0; //!< U_EMRSCALEVIEWPORTEXTEX 1 0 1 0 0 0 0 0 - table[ 32] = 0xA0; //!< U_EMRSCALEWINDOWEXTEX 1 0 1 0 0 0 0 0 - table[ 33] = 0xA0; //!< U_EMRSAVEDC 1 0 1 0 0 0 0 0 - table[ 34] = 0xA0; //!< U_EMRRESTOREDC 1 0 1 0 0 0 0 0 - table[ 35] = 0xA0; //!< U_EMRSETWORLDTRANSFORM 1 0 1 0 0 0 0 0 - table[ 36] = 0xA0; //!< U_EMRMODIFYWORLDTRANSFORM 1 0 1 0 0 0 0 0 - table[ 37] = 0x20; //!< U_EMRSELECTOBJECT 0 0 1 0 0 0 0 0 - table[ 38] = 0x20; //!< U_EMRCREATEPEN 0 0 1 0 0 0 0 0 - table[ 39] = 0x20; //!< U_EMRCREATEBRUSHINDIRECT 0 0 1 0 0 0 0 0 - table[ 40] = 0x20; //!< U_EMRDELETEOBJECT 0 0 1 0 0 0 0 0 - table[ 41] = 0x83; //!< U_EMRANGLEARC 1 0 0 0 0 0 1 1 - table[ 42] = 0x87; //!< U_EMRELLIPSE 1 0 0 0 0 1 1 1 - table[ 43] = 0x87; //!< U_EMRRECTANGLE 1 0 0 0 0 1 1 1 - table[ 44] = 0x87; //!< U_EMRROUNDRECT 1 0 0 0 0 1 1 1 - table[ 45] = 0x83; //!< U_EMRARC 1 0 0 0 0 0 1 1 - table[ 46] = 0x87; //!< U_EMRCHORD 1 0 0 0 0 1 1 1 - table[ 47] = 0x87; //!< U_EMRPIE 1 0 0 0 0 1 1 1 - table[ 48] = 0xA0; //!< U_EMRSELECTPALETTE 1 0 1 0 0 0 0 0 - table[ 49] = 0xA0; //!< U_EMRCREATEPALETTE 1 0 1 0 0 0 0 0 - table[ 50] = 0xA0; //!< U_EMRSETPALETTEENTRIES 1 0 1 0 0 0 0 0 - table[ 51] = 0xA0; //!< U_EMRRESIZEPALETTE 1 0 1 0 0 0 0 0 - table[ 52] = 0xA0; //!< U_EMRREALIZEPALETTE 1 0 1 0 0 0 0 0 - table[ 53] = 0x82; //!< U_EMREXTFLOODFILL 1 0 0 0 0 0 1 0 - table[ 54] = 0x8B; //!< U_EMRLINETO 1 0 0 0 1 0 1 1 - table[ 55] = 0x8B; //!< U_EMRARCTO 1 0 0 0 1 0 1 1 - table[ 56] = 0x83; //!< U_EMRPOLYDRAW 1 0 0 0 0 0 1 1 - table[ 57] = 0xA0; //!< U_EMRSETARCDIRECTION 1 0 1 0 0 0 0 0 - table[ 58] = 0xA0; //!< U_EMRSETMITERLIMIT 1 0 1 0 0 0 0 0 - table[ 59] = 0xE0; //!< U_EMRBEGINPATH 1 1 1 0 0 0 0 0 - table[ 60] = 0x80; //!< U_EMRENDPATH 1 0 0 0 0 0 0 0 - table[ 61] = 0x84; //!< U_EMRCLOSEFIGURE 1 0 0 0 0 1 0 0 - table[ 62] = 0x94; //!< U_EMRFILLPATH 1 0 0 1 0 1 0 0 - table[ 63] = 0x94; //!< U_EMRSTROKEANDFILLPATH 1 0 0 1 0 1 0 0 - table[ 64] = 0x90; //!< U_EMRSTROKEPATH 1 0 0 1 0 0 0 0 - table[ 65] = 0xA0; //!< U_EMRFLATTENPATH 1 0 1 0 0 0 0 0 - table[ 66] = 0xA0; //!< U_EMRWIDENPATH 1 0 1 0 0 0 0 0 - table[ 67] = 0xA0; //!< U_EMRSELECTCLIPPATH 1 0 1 0 0 0 0 0 - table[ 68] = 0xA0; //!< U_EMRABORTPATH 1 0 1 0 0 0 0 0 - table[ 69] = 0xA0; //!< U_EMRUNDEF69 1 0 1 0 0 0 0 0 - table[ 70] = 0x00; //!< U_EMRCOMMENT 0 0 0 0 0 0 0 0 - table[ 71] = 0x82; //!< U_EMRFILLRGN 1 0 0 0 0 0 1 0 - table[ 72] = 0x82; //!< U_EMRFRAMERGN 1 0 0 0 0 0 1 0 - table[ 73] = 0x82; //!< U_EMRINVERTRGN 1 0 0 0 0 0 1 0 - table[ 74] = 0x82; //!< U_EMRPAINTRGN 1 0 0 0 0 0 1 0 - table[ 75] = 0xA0; //!< U_EMREXTSELECTCLIPRGN 1 0 1 0 0 0 0 0 - table[ 76] = 0x82; //!< U_EMRBITBLT 1 0 0 0 0 0 1 0 - table[ 77] = 0x82; //!< U_EMRSTRETCHBLT 1 0 0 0 0 0 1 0 - table[ 78] = 0x82; //!< U_EMRMASKBLT 1 0 0 0 0 0 1 0 - table[ 79] = 0x82; //!< U_EMRPLGBLT 1 0 0 0 0 0 1 0 - table[ 80] = 0xA0; //!< U_EMRSETDIBITSTODEVICE 1 0 1 0 0 0 0 0 - table[ 81] = 0xA0; //!< U_EMRSTRETCHDIBITS 1 0 1 0 0 0 0 0 - table[ 82] = 0x20; //!< U_EMREXTCREATEFONTINDIRECTW 0 0 1 0 0 0 0 0 - table[ 83] = 0x02; //!< U_EMREXTTEXTOUTA 0 0 0 0 0 0 1 0 - table[ 84] = 0x02; //!< U_EMREXTTEXTOUTW 0 0 0 0 0 0 1 0 - table[ 85] = 0x83; //!< U_EMRPOLYBEZIER16 1 0 0 0 0 0 1 1 - table[ 86] = 0x83; //!< U_EMRPOLYGON16 1 0 0 0 0 0 1 1 - table[ 87] = 0x83; //!< U_EMRPOLYLINE16 1 0 0 0 0 0 1 1 - table[ 88] = 0x8B; //!< U_EMRPOLYBEZIERTO16 1 0 0 0 1 0 1 1 - table[ 89] = 0x8B; //!< U_EMRPOLYLINETO16 1 0 0 0 1 0 1 1 - table[ 90] = 0x83; //!< U_EMRPOLYPOLYLINE16 1 0 0 0 0 0 1 1 - table[ 91] = 0x87; //!< U_EMRPOLYPOLYGON16 1 0 0 0 0 1 1 1 - table[ 92] = 0x83; //!< U_EMRPOLYDRAW16 1 0 0 0 0 0 1 1 - table[ 93] = 0x80; //!< U_EMRCREATEMONOBRUSH 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions - table[ 94] = 0x80; //!< U_EMRCREATEDIBPATTERNBRUSHPT 1 0 0 0 0 0 0 0 " - table[ 95] = 0x00; //!< U_EMREXTCREATEPEN 0 0 0 0 0 0 0 0 " - table[ 96] = 0x02; //!< U_EMRPOLYTEXTOUTA 0 0 0 0 0 0 1 0 - table[ 97] = 0x02; //!< U_EMRPOLYTEXTOUTW 0 0 0 0 0 0 1 0 - table[ 98] = 0xA0; //!< U_EMRSETICMMODE 1 0 1 0 0 0 0 0 - table[ 99] = 0xA0; //!< U_EMRCREATECOLORSPACE 1 0 1 0 0 0 0 0 - table[100] = 0xA0; //!< U_EMRSETCOLORSPACE 1 0 1 0 0 0 0 0 - table[101] = 0xA0; //!< U_EMRDELETECOLORSPACE 1 0 1 0 0 0 0 0 - table[102] = 0xA0; //!< U_EMRGLSRECORD 1 0 1 0 0 0 0 0 - table[103] = 0xA0; //!< U_EMRGLSBOUNDEDRECORD 1 0 1 0 0 0 0 0 - table[104] = 0xA0; //!< U_EMRPIXELFORMAT 1 0 1 0 0 0 0 0 - table[105] = 0xA0; //!< U_EMRDRAWESCAPE 1 0 1 0 0 0 0 0 - table[106] = 0xA0; //!< U_EMREXTESCAPE 1 0 1 0 0 0 0 0 - table[107] = 0xA0; //!< U_EMRUNDEF107 1 0 1 0 0 0 0 0 - table[108] = 0x02; //!< U_EMRSMALLTEXTOUT 0 0 0 0 0 0 1 0 - table[109] = 0xA0; //!< U_EMRFORCEUFIMAPPING 1 0 1 0 0 0 0 0 - table[110] = 0xA0; //!< U_EMRNAMEDESCAPE 1 0 1 0 0 0 0 0 - table[111] = 0xA0; //!< U_EMRCOLORCORRECTPALETTE 1 0 1 0 0 0 0 0 - table[112] = 0xA0; //!< U_EMRSETICMPROFILEA 1 0 1 0 0 0 0 0 - table[113] = 0xA0; //!< U_EMRSETICMPROFILEW 1 0 1 0 0 0 0 0 - table[114] = 0x82; //!< U_EMRALPHABLEND 1 0 0 0 0 0 1 0 - table[115] = 0xA0; //!< U_EMRSETLAYOUT 1 0 1 0 0 0 0 0 - table[116] = 0x82; //!< U_EMRTRANSPARENTBLT 1 0 0 0 0 0 1 0 - table[117] = 0xA0; //!< U_EMRUNDEF117 1 0 1 0 0 0 0 0 - table[118] = 0x82; //!< U_EMRGRADIENTFILL 1 0 0 0 0 0 1 0 - table[119] = 0xA0; //!< U_EMRSETLINKEDUFIS 1 0 1 0 0 0 0 0 - table[120] = 0x20; //!< U_EMRSETTEXTJUSTIFICATION 0 0 1 0 0 0 0 0 - table[121] = 0xA0; //!< U_EMRCOLORMATCHTOTARGETW 1 0 1 0 0 0 0 0 - table[122] = 0xA0; //!< U_EMRCREATECOLORSPACEW 1 0 1 0 0 0 0 0 + table[ 0] = 0x00; // Does not map to any EMR record + table[ 1] = 0x80; // U_EMRHEADER 1 0 0 0 0 0 0 0 + table[ 2] = 0x83; // U_EMRPOLYBEZIER 1 0 0 0 0 0 1 1 + table[ 3] = 0x87; // U_EMRPOLYGON 1 0 0 0 0 1 1 1 + table[ 4] = 0x83; // U_EMRPOLYLINE 1 0 0 0 0 0 1 1 + table[ 5] = 0x8B; // U_EMRPOLYBEZIERTO 1 0 0 0 1 0 1 1 + table[ 6] = 0x8B; // U_EMRPOLYLINETO 1 0 0 0 1 0 1 1 + table[ 7] = 0x83; // U_EMRPOLYPOLYLINE 1 0 0 0 0 0 1 1 + table[ 8] = 0x87; // U_EMRPOLYPOLYGON 1 0 0 0 0 1 1 1 + table[ 9] = 0xA0; // U_EMRSETWINDOWEXTEX 1 0 1 0 0 0 0 0 + table[ 10] = 0xA0; // U_EMRSETWINDOWORGEX 1 0 1 0 0 0 0 0 + table[ 11] = 0xA0; // U_EMRSETVIEWPORTEXTEX 1 0 1 0 0 0 0 0 + table[ 12] = 0xA0; // U_EMRSETVIEWPORTORGEX 1 0 1 0 0 0 0 0 + table[ 13] = 0xA0; // U_EMRSETBRUSHORGEX 1 0 1 0 0 0 0 0 + table[ 14] = 0x82; // U_EMREOF 1 0 1 0 0 0 0 0 Force out any pending draw + table[ 15] = 0x82; // U_EMRSETPIXELV 1 0 0 0 0 0 1 0 + table[ 16] = 0xA0; // U_EMRSETMAPPERFLAGS 1 0 1 0 0 0 0 0 + table[ 17] = 0xA0; // U_EMRSETMAPMODE 1 0 1 0 0 0 0 0 + table[ 18] = 0x20; // U_EMRSETBKMODE 0 0 1 0 0 0 0 0 + table[ 19] = 0xA0; // U_EMRSETPOLYFILLMODE 1 0 1 0 0 0 0 0 + table[ 20] = 0xA0; // U_EMRSETROP2 1 0 1 0 0 0 0 0 + table[ 21] = 0xA0; // U_EMRSETSTRETCHBLTMODE 1 0 1 0 0 0 0 0 + table[ 22] = 0x20; // U_EMRSETTEXTALIGN 0 0 1 0 0 0 0 0 + table[ 23] = 0xA0; // U_EMRSETCOLORADJUSTMENT 1 0 1 0 0 0 0 0 + table[ 24] = 0x20; // U_EMRSETTEXTCOLOR 0 0 1 0 0 0 0 0 + table[ 25] = 0x20; // U_EMRSETBKCOLOR 0 0 1 0 0 0 0 0 + table[ 26] = 0xA0; // U_EMROFFSETCLIPRGN 1 0 1 0 0 0 0 0 + table[ 27] = 0x89; // U_EMRMOVETOEX 1 0 0 0 1 0 0 1 + table[ 28] = 0xA0; // U_EMRSETMETARGN 1 0 1 0 0 0 0 0 + table[ 29] = 0xA0; // U_EMREXCLUDECLIPRECT 1 0 1 0 0 0 0 0 + table[ 30] = 0xA0; // U_EMRINTERSECTCLIPRECT 1 0 1 0 0 0 0 0 + table[ 31] = 0xA0; // U_EMRSCALEVIEWPORTEXTEX 1 0 1 0 0 0 0 0 + table[ 32] = 0xA0; // U_EMRSCALEWINDOWEXTEX 1 0 1 0 0 0 0 0 + table[ 33] = 0xA0; // U_EMRSAVEDC 1 0 1 0 0 0 0 0 + table[ 34] = 0xA0; // U_EMRRESTOREDC 1 0 1 0 0 0 0 0 + table[ 35] = 0xA0; // U_EMRSETWORLDTRANSFORM 1 0 1 0 0 0 0 0 + table[ 36] = 0xA0; // U_EMRMODIFYWORLDTRANSFORM 1 0 1 0 0 0 0 0 + table[ 37] = 0x20; // U_EMRSELECTOBJECT 0 0 1 0 0 0 0 0 + table[ 38] = 0x20; // U_EMRCREATEPEN 0 0 1 0 0 0 0 0 + table[ 39] = 0x20; // U_EMRCREATEBRUSHINDIRECT 0 0 1 0 0 0 0 0 + table[ 40] = 0x20; // U_EMRDELETEOBJECT 0 0 1 0 0 0 0 0 + table[ 41] = 0x83; // U_EMRANGLEARC 1 0 0 0 0 0 1 1 + table[ 42] = 0x87; // U_EMRELLIPSE 1 0 0 0 0 1 1 1 + table[ 43] = 0x87; // U_EMRRECTANGLE 1 0 0 0 0 1 1 1 + table[ 44] = 0x87; // U_EMRROUNDRECT 1 0 0 0 0 1 1 1 + table[ 45] = 0x83; // U_EMRARC 1 0 0 0 0 0 1 1 + table[ 46] = 0x87; // U_EMRCHORD 1 0 0 0 0 1 1 1 + table[ 47] = 0x87; // U_EMRPIE 1 0 0 0 0 1 1 1 + table[ 48] = 0xA0; // U_EMRSELECTPALETTE 1 0 1 0 0 0 0 0 + table[ 49] = 0xA0; // U_EMRCREATEPALETTE 1 0 1 0 0 0 0 0 + table[ 50] = 0xA0; // U_EMRSETPALETTEENTRIES 1 0 1 0 0 0 0 0 + table[ 51] = 0xA0; // U_EMRRESIZEPALETTE 1 0 1 0 0 0 0 0 + table[ 52] = 0xA0; // U_EMRREALIZEPALETTE 1 0 1 0 0 0 0 0 + table[ 53] = 0x82; // U_EMREXTFLOODFILL 1 0 0 0 0 0 1 0 + table[ 54] = 0x8B; // U_EMRLINETO 1 0 0 0 1 0 1 1 + table[ 55] = 0x8B; // U_EMRARCTO 1 0 0 0 1 0 1 1 + table[ 56] = 0x83; // U_EMRPOLYDRAW 1 0 0 0 0 0 1 1 + table[ 57] = 0xA0; // U_EMRSETARCDIRECTION 1 0 1 0 0 0 0 0 + table[ 58] = 0xA0; // U_EMRSETMITERLIMIT 1 0 1 0 0 0 0 0 + table[ 59] = 0xE0; // U_EMRBEGINPATH 1 1 1 0 0 0 0 0 + table[ 60] = 0x80; // U_EMRENDPATH 1 0 0 0 0 0 0 0 + table[ 61] = 0x84; // U_EMRCLOSEFIGURE 1 0 0 0 0 1 0 0 + table[ 62] = 0x94; // U_EMRFILLPATH 1 0 0 1 0 1 0 0 + table[ 63] = 0x94; // U_EMRSTROKEANDFILLPATH 1 0 0 1 0 1 0 0 + table[ 64] = 0x90; // U_EMRSTROKEPATH 1 0 0 1 0 0 0 0 + table[ 65] = 0xA0; // U_EMRFLATTENPATH 1 0 1 0 0 0 0 0 + table[ 66] = 0xA0; // U_EMRWIDENPATH 1 0 1 0 0 0 0 0 + table[ 67] = 0xA0; // U_EMRSELECTCLIPPATH 1 0 1 0 0 0 0 0 + table[ 68] = 0xA0; // U_EMRABORTPATH 1 0 1 0 0 0 0 0 + table[ 69] = 0xA0; // U_EMRUNDEF69 1 0 1 0 0 0 0 0 + table[ 70] = 0x00; // U_EMRCOMMENT 0 0 0 0 0 0 0 0 + table[ 71] = 0x82; // U_EMRFILLRGN 1 0 0 0 0 0 1 0 + table[ 72] = 0x82; // U_EMRFRAMERGN 1 0 0 0 0 0 1 0 + table[ 73] = 0x82; // U_EMRINVERTRGN 1 0 0 0 0 0 1 0 + table[ 74] = 0x82; // U_EMRPAINTRGN 1 0 0 0 0 0 1 0 + table[ 75] = 0xA0; // U_EMREXTSELECTCLIPRGN 1 0 1 0 0 0 0 0 + table[ 76] = 0x82; // U_EMRBITBLT 1 0 0 0 0 0 1 0 + table[ 77] = 0x82; // U_EMRSTRETCHBLT 1 0 0 0 0 0 1 0 + table[ 78] = 0x82; // U_EMRMASKBLT 1 0 0 0 0 0 1 0 + table[ 79] = 0x82; // U_EMRPLGBLT 1 0 0 0 0 0 1 0 + table[ 80] = 0xA0; // U_EMRSETDIBITSTODEVICE 1 0 1 0 0 0 0 0 + table[ 81] = 0xA0; // U_EMRSTRETCHDIBITS 1 0 1 0 0 0 0 0 + table[ 82] = 0x20; // U_EMREXTCREATEFONTINDIRECTW 0 0 1 0 0 0 0 0 + table[ 83] = 0x02; // U_EMREXTTEXTOUTA 0 0 0 0 0 0 1 0 + table[ 84] = 0x02; // U_EMREXTTEXTOUTW 0 0 0 0 0 0 1 0 + table[ 85] = 0x83; // U_EMRPOLYBEZIER16 1 0 0 0 0 0 1 1 + table[ 86] = 0x83; // U_EMRPOLYGON16 1 0 0 0 0 0 1 1 + table[ 87] = 0x83; // U_EMRPOLYLINE16 1 0 0 0 0 0 1 1 + table[ 88] = 0x8B; // U_EMRPOLYBEZIERTO16 1 0 0 0 1 0 1 1 + table[ 89] = 0x8B; // U_EMRPOLYLINETO16 1 0 0 0 1 0 1 1 + table[ 90] = 0x83; // U_EMRPOLYPOLYLINE16 1 0 0 0 0 0 1 1 + table[ 91] = 0x87; // U_EMRPOLYPOLYGON16 1 0 0 0 0 1 1 1 + table[ 92] = 0x83; // U_EMRPOLYDRAW16 1 0 0 0 0 0 1 1 + table[ 93] = 0x80; // U_EMRCREATEMONOBRUSH 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions + table[ 94] = 0x80; // U_EMRCREATEDIBPATTERNBRUSHPT 1 0 0 0 0 0 0 0 " + table[ 95] = 0x00; // U_EMREXTCREATEPEN 0 0 0 0 0 0 0 0 " + table[ 96] = 0x02; // U_EMRPOLYTEXTOUTA 0 0 0 0 0 0 1 0 + table[ 97] = 0x02; // U_EMRPOLYTEXTOUTW 0 0 0 0 0 0 1 0 + table[ 98] = 0xA0; // U_EMRSETICMMODE 1 0 1 0 0 0 0 0 + table[ 99] = 0xA0; // U_EMRCREATECOLORSPACE 1 0 1 0 0 0 0 0 + table[100] = 0xA0; // U_EMRSETCOLORSPACE 1 0 1 0 0 0 0 0 + table[101] = 0xA0; // U_EMRDELETECOLORSPACE 1 0 1 0 0 0 0 0 + table[102] = 0xA0; // U_EMRGLSRECORD 1 0 1 0 0 0 0 0 + table[103] = 0xA0; // U_EMRGLSBOUNDEDRECORD 1 0 1 0 0 0 0 0 + table[104] = 0xA0; // U_EMRPIXELFORMAT 1 0 1 0 0 0 0 0 + table[105] = 0xA0; // U_EMRDRAWESCAPE 1 0 1 0 0 0 0 0 + table[106] = 0xA0; // U_EMREXTESCAPE 1 0 1 0 0 0 0 0 + table[107] = 0xA0; // U_EMRUNDEF107 1 0 1 0 0 0 0 0 + table[108] = 0x02; // U_EMRSMALLTEXTOUT 0 0 0 0 0 0 1 0 + table[109] = 0xA0; // U_EMRFORCEUFIMAPPING 1 0 1 0 0 0 0 0 + table[110] = 0xA0; // U_EMRNAMEDESCAPE 1 0 1 0 0 0 0 0 + table[111] = 0xA0; // U_EMRCOLORCORRECTPALETTE 1 0 1 0 0 0 0 0 + table[112] = 0xA0; // U_EMRSETICMPROFILEA 1 0 1 0 0 0 0 0 + table[113] = 0xA0; // U_EMRSETICMPROFILEW 1 0 1 0 0 0 0 0 + table[114] = 0x82; // U_EMRALPHABLEND 1 0 0 0 0 0 1 0 + table[115] = 0xA0; // U_EMRSETLAYOUT 1 0 1 0 0 0 0 0 + table[116] = 0x82; // U_EMRTRANSPARENTBLT 1 0 0 0 0 0 1 0 + table[117] = 0xA0; // U_EMRUNDEF117 1 0 1 0 0 0 0 0 + table[118] = 0x82; // U_EMRGRADIENTFILL 1 0 0 0 0 0 1 0 + table[119] = 0xA0; // U_EMRSETLINKEDUFIS 1 0 1 0 0 0 0 0 + table[120] = 0x20; // U_EMRSETTEXTJUSTIFICATION 0 0 1 0 0 0 0 0 + table[121] = 0xA0; // U_EMRCOLORMATCHTOTARGETW 1 0 1 0 0 0 0 0 + table[122] = 0xA0; // U_EMRCREATECOLORSPACEW 1 0 1 0 0 0 0 0 } result = table[type]; } @@ -622,13 +765,13 @@ int RGBA_to_DIB( /** \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA() - \return 0 on success, other values on errors. + \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid. \param pEmr pointer to EMR record that has a U_BITMAPINFO and bitmap \param offBitsSrc Offset to the bitmap \param offBmiSrc Offset to the U_BITMAPINFO \param px pointer to DIB pixel array in pEmr \param ct pointer to DIB color table in pEmr - \param numCt DIB color table number of entries + \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 @@ -646,11 +789,12 @@ int get_DIB_params( uint32_t *colortype, uint32_t *invert ){ + uint32_t bic; PU_BITMAPINFO Bmi = (PU_BITMAPINFO)((char *)pEmr + offBmiSrc); - if(Bmi->bmiHeader.biCompression != U_BI_RGB)return(1); + /* 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; - *numCt = Bmi->bmiHeader.biClrUsed; if(Bmi->bmiHeader.biHeight < 0){ *height = -Bmi->bmiHeader.biHeight; *invert = 1; @@ -659,11 +803,23 @@ int get_DIB_params( *height = Bmi->bmiHeader.biHeight; *invert = 0; } - if(numCt){ + 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; } + } + else { + *numCt = Bmi->bmiHeader.biSizeImage; + *ct = NULL; } *px = (char *)((char *)pEmr + offBitsSrc); - return(0); + return(bic); } /** @@ -831,8 +987,8 @@ int DIB_to_RGBA( \param h Height of pixel array in the record \param sl start left position in the pixel array in the record to start extracting \param st start top position in the pixel array in the record to start extracting - \param ew Width of pixel array to extract - \param eh Height of pixel array to extract + \param eew Width of pixel array to extract + \param eeh Height of pixel array to extract */ char *RGBA_to_RGBA( char *rgba_px, @@ -1028,12 +1184,13 @@ FILE *emf_fopen( #endif return(fp); } + /** \brief Retrieve contents of an EMF file by name. \return 0 on success, >=1 on failure \param filename Name of file to open, including the path \param contents Contents of the file. Buffer must be free()'d by caller. - \param Number of bytes in Contents + \param length Number of bytes in Contents */ int emf_readdata( const char *filename, @@ -1149,10 +1306,27 @@ 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. @@ -1491,9 +1665,9 @@ U_XFORM xform_set( \brief Construct a U_XFORM structure. \return U_XFORM structure \param scale Scale factor - \param axesRatio Ratio of minor axis/major axis + \param ratio Ratio of minor axis/major axis \param rot Rotation angle in degrees, positive is counter clockwise from the x axis. - \param axisRot Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis. + \param axisrot Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis. \param eDx Translation element \param eDy Translation element @@ -2181,6 +2355,7 @@ 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 return(U_EMRDELETEOBJECT_set(saveObject)); @@ -2197,6 +2372,7 @@ 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(!eht->table[ihObject])return(NULL); // handle is not in the table, so not active, so cannot be selected @@ -2223,6 +2399,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); return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp )); } @@ -2240,6 +2417,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); return(U_EMRCREATEPEN_set(*ihPen, lopn)); } @@ -2257,6 +2435,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); return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb)); } @@ -2281,6 +2460,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); return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px)); } @@ -2305,6 +2485,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); return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px)); } @@ -2323,6 +2504,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); return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs)); } @@ -2346,6 +2528,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); return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data)); } @@ -2365,6 +2548,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); return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw)); } @@ -2382,6 +2566,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); return(U_EMRCREATEPALETTE_set(*ihPal, lgpl)); } @@ -2403,6 +2588,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); return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries)); } @@ -2422,6 +2608,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); return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData)); } @@ -2443,6 +2630,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); return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData)); } @@ -3388,7 +3576,7 @@ char *U_EMRSETBKCOLOR_set( char *U_EMROFFSETCLIPRGN_set( const U_POINTL ptl ){ - return(U_EMR_CORE7(U_EMR_OFFSETCLIPRGN, (U_PAIR) ptl)); + return(U_EMR_CORE7(U_EMR_OFFSETCLIPRGN, ptl)); } // U_EMRMOVETOEX_set 27 @@ -3400,7 +3588,7 @@ char *U_EMROFFSETCLIPRGN_set( char *U_EMRMOVETOEX_set( const U_POINTL ptl ){ - return(U_EMR_CORE7(U_EMR_MOVETOEX, (U_PAIR) ptl)); + return(U_EMR_CORE7(U_EMR_MOVETOEX, ptl)); } // U_EMRSETMETARGN_set 28 @@ -3899,7 +4087,7 @@ char *U_EMREXTFLOODFILL_set( char *U_EMRLINETO_set( const U_POINTL ptl ){ - return(U_EMR_CORE7(U_EMR_LINETO, (U_PAIR) ptl)); + return(U_EMR_CORE7(U_EMR_LINETO, ptl)); } // U_EMRARCTO_set 55 diff --git a/src/extension/internal/uemf.h b/src/extension/internal/uemf.h index 34823a8e9..a303498e2 100644 --- a/src/extension/internal/uemf.h +++ b/src/extension/internal/uemf.h @@ -8,16 +8,16 @@ If the direct link fails the document may be found by searching for: "[MS-EMF]: Enhanced Metafile Format" - + */ /* File: uemf.h -Version: 0.0.10 -Date: 04-DEC-2012 +Version: 0.0.12 +Date: 17-JAN-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UEMF_ @@ -49,7 +49,16 @@ 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, @@ -193,18 +202,19 @@ extern "C" { #define U_EMR_INVALID 0xFFFFFFFF //!< Not any valid U_EMF_ value /** @} */ -/** \defgroup U_DRAW_PROPERTIES - Used in draw_properties(). These are the bit definitions. +/** \defgroup U_DRAW_PROPERTIES draw properties + Used in emr_properties() and wmr_properties. These are the bit definitions. @{ */ -#define U_DRAW_NOTEMPTY 0x01 //!< Path has at least a MOVETO in it -#define U_DRAW_VISIBLE 0x02 //!< Path has at least a LINE in it -#define U_DRAW_CLOSED 0x04 //!< Path has been closed -#define U_DRAW_ONLYTO 0x08 //!< Path so far contains only *TO operations -#define U_DRAW_FORCE 0x10 //!< Path MUST be drawn -#define U_DRAW_ALTERS 0x20 //!< Alters draw parameters (pen, brush, coordinates...) -#define U_DRAW_PATH 0x40 //!< An explicit path is being used (with a BEGIN and END) -#define U_DRAW_TEXT 0x80 //!< Current record forces all pending text to be drawn first. +#define U_DRAW_NOTEMPTY 0x001 //!< Path has at least a MOVETO in it +#define U_DRAW_VISIBLE 0x002 //!< Path has at least a LINE in it +#define U_DRAW_CLOSED 0x004 //!< Path has been closed +#define U_DRAW_ONLYTO 0x008 //!< Path so far contains only *TO operations +#define U_DRAW_FORCE 0x010 //!< Path MUST be drawn +#define U_DRAW_ALTERS 0x020 //!< Alters draw parameters (pen, brush, coordinates...) +#define U_DRAW_PATH 0x040 //!< An explicit path is being used (with a BEGIN and END) +#define U_DRAW_TEXT 0x080 //!< Current record forces all pending text to be drawn first. +#define U_DRAW_OBJECT 0x100 //!< Creates an Object (only used in WMF) /** @} */ /** \defgroup U_EMRSETARCDIRECTION_Qualifiers ArcDirection Enumeration @@ -272,7 +282,7 @@ extern "C" { #define U_CA_LOG_FILTER 0x0002 /** @} */ -/** \defgroup U_EMRCOLORMATCHTOTARGETW_dwAction_Qualifiers ColorMatchToTarget Enumeration +/** \defgroup U_EMRCOLORMATCHTOTARGETW_dwFlags_Qualifiers ColorMatchToTarget Enumeration For U_EMRCOLORMATCHTOTARGETW dwFlags field @{ */ @@ -311,7 +321,7 @@ extern "C" { #define U_DIB_PAL_COLORS 1 /** @} */ -/** \defgroup U_EMRCOMMENT_* cIdent Qualifiers +/** \defgroup U_EMRCOMMENT_TYPES Comment record types For U_EMRCOMMENT_* cIdent fields @{ */ @@ -321,8 +331,8 @@ extern "C" { #define U_EMR_COMMENT_EMFPLUSRECORD 0x2B464D45 /** @} */ -/** \defgroup U_EMR_COMMENT_PUBLIC, AKA EMRComment Enumeration - For U_EMRCOMMENT_PUBLI pcIdent fields +/** \defgroup U_EMR_COMMENT_PUBLIC EMRComment Enumeration + For U_EMRCOMMENT_PUBLIC pcIdent fields @{ */ #define U_EMR_COMMENT_WINDOWS_METAFILE 0x80000001 @@ -366,8 +376,8 @@ extern "C" { For U_EMREXTFLOODFILL iMode field @{ */ -#define U_FLOODFILLBORDER 0x00000000 -#define U_FLOODFILLSURFACE 0x00000000 +#define U_FLOODFILLBORDER 0x00000000 /* Color specified must be the same as the border - brush fill stops at this color */ +#define U_FLOODFILLSURFACE 0x00000001 /* Color specified must be different from the border - brush fills only this color */ /** @} */ /** \defgroup U_DESIGNVECTOR_Signature_Qualifiers Signature Enumeration @@ -1100,10 +1110,10 @@ extern "C" { #define U_BGRA(r,g,b,a) (U_RGBQUAD){b,g,r,a} //!< Set any BGRA color with an {r,g,b,a} quad #define U_WHITE U_BGR(255,255,255) //!< Set BGR white. #define U_BLACK U_BGR(0,0,0) //!< Set BGR black. -#define U_BGRAGetR(rgb) ((U_RGBQUAD)rgb).Red //!< Color BGR Get Red Macro. -#define U_BGRAGetG(rgb) ((U_RGBQUAD)rgb).Green //!< Color BGR Get Green Macro. -#define U_BGRAGetB(rgb) ((U_RGBQUAD)rgb).Blue //!< Color BGR Get Blue Macro. -#define U_BGRAGetA(rgb) ((U_RGBQUAD)rgb).Reserved //!< Color BGR Get A/reserved Macro. +#define U_BGRAGetR(rgb) (rgb.Red ) //!< Color BGR Get Red Macro. +#define U_BGRAGetG(rgb) (rgb.Green ) //!< Color BGR Get Green Macro. +#define U_BGRAGetB(rgb) (rgb.Blue ) //!< Color BGR Get Blue Macro. +#define U_BGRAGetA(rgb) (rgb.Reserved) //!< Color BGR Get A/reserved Macro. #define U_PALETTERGB(r,g,b) U_RGB(r,g,b,0x02)) //!< Set any Palette RGB color. #define U_PALETTEINDEX(i) ((U_COLORREF)(0x01000000 | (uint16_t)(i)))\ @@ -1147,8 +1157,11 @@ extern "C" { #define U_EMRTYPE(A) (((PU_EMR)A)->iType) //!< Get iType from U_EMR* record #define U_EMRSIZE(A) (((PU_EMR)A)->nSize) //!< Get nSize from U_EMR* record -// Utility macro +// 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; @@ -1699,88 +1712,6 @@ typedef struct { uint32_t biClrImportant; //!< Number of bmciColors needed (0 means all). } U_BITMAPINFOHEADER, *PU_BITMAPINFOHEADER; -#if 0 -// Do EMF files ever use any of these??? - -// Microsoft name: BITMAPV4HEADER Object -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 ? - -// Microsoft name: BITMAPV5HEADER Object -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 ? - -// Microsoft name: BITMAPCOREHEADER Object -typedef struct { - uint32_t bcSize; //!< Structure size in bytes - uint16_t bcWidth; //!< Bitmap width in pixels - uint16_t bcHeight; //!< Bitmap height in pixels - uint16_t bcPlanes; //!< Planes (must be 1) - uint16_t bcBitCount; //!< BitCount Enumeration -} U_BITMAPCOREHEADER, *PU_BITMAPCOREHEADER; //!< For U_BITMAPCOREINFO - -// Microsoft name: BITMAPCOREINFO Object -// Description of a simple Device Independent Bitmap (DIB) - no compression or color maps -typedef struct { - U_BITMAPCOREHEADER bmciHeader; //!< Geometry and pixel properties - U_RGBTRIPLE bmciColors[1]; //!< Color table -} U_BITMAPCOREINFO, *PU_BITMAPCOREINFO; //!< For ? - -// Microsoft name: RGBTRIPLE Object -// NOTE that the color order is BGR, even though the name is RGB! -typedef struct { - uint8_t rgbtBlue; //!< Blue color (0-255) - uint8_t rgbtGreen; //!< Green color (0-255) - uint8_t rgbtRed; //!< Red color (0-255) -} U_RGBTRIPLE, *PU_RGBTRIPLE; //!< For U_BITMAPCOREINFO bmciColors field - - -#endif // elements possibly never used by an EMF file - /** \brief For U_EMR_* OffBmi* fields Description of a Bitmap which in some cases is a Device Independent Bitmap (DIB) @@ -2657,16 +2588,17 @@ 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; /** 2 x 2 matrix, used by xform_alt_set() function. */ typedef struct { - double M11; - double M12; - double M21; - double M22; + double M11; //!< Matrix element 1,1 + double M12; //!< Matrix element 1,2 + double M21; //!< Matrix element 2,1 + double M22; //!< Matrix element 2,2 } U_MAT2X2, *PU_MAT2X2; // ************************************************************************************************ @@ -2680,6 +2612,7 @@ void wchartshow(const wchar_t *src); void dumpeht(char *string, unsigned int *handle, EMFHANDLES *eht); +char *U_emr_names(unsigned int idx); uint32_t *dx_set(int32_t height, uint32_t weight, uint32_t members); uint32_t emr_properties(uint32_t type); int emr_arc_points(PU_ENHMETARECORD record, int *f1, int f2, PU_PAIRF center, PU_PAIRF start, PU_PAIRF end, PU_PAIRF size); @@ -2706,6 +2639,7 @@ 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); U_RECTL rectl_set(U_POINTL ul, U_POINTL lr); U_SIZEL sizel_set(int32_t x, int32_t y); diff --git a/src/extension/internal/uemf_endian.c b/src/extension/internal/uemf_endian.c index 4fae7f7d4..97bd209c0 100644 --- a/src/extension/internal/uemf_endian.c +++ b/src/extension/internal/uemf_endian.c @@ -17,11 +17,11 @@ /* File: uemf_endian.h -Version: 0.0.9 -Date: 19-SEP-2012 +Version: 0.0.10 +Date: 11-JAN-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -42,37 +42,26 @@ extern "C" { *********************************************************************************************** */ void U_swap2(void *ul, unsigned int count){ - union i16 { - uint16_t i16; - uint8_t i8[2]; - }; - register union i16 ltmp; - register uint8_t ctmp; - for(; count; count--,ul+=2){ - ltmp.i16 = *(uint16_t *)ul; - ctmp = ltmp.i8[0]; - ltmp.i8[0] = ltmp.i8[1]; - ltmp.i8[1] = ctmp; - *(uint16_t *)ul = ltmp.i16; + uint8_t ctmp; + uint8_t *cl = (uint8_t *) ul; + for(; count; count--,cl+=2){ + ctmp = *cl; + *cl = *(cl+1); + *(cl+1) = ctmp; } } +/* Note: U_swap4 is also used by uwmf_endian.c, in cases where the 32 bit data is not aligned on a 4 byte boundary */ void U_swap4(void *ul, unsigned int count){ - union i32 { - uint32_t i32; - uint8_t i8[4]; - }; - register union i32 ltmp; - register uint8_t ctmp; - for(;count;count--,ul+=4){ - ltmp.i32 = *(uint32_t *)ul; - ctmp = ltmp.i8[0]; - ltmp.i8[0] = ltmp.i8[3]; - ltmp.i8[3] = ctmp; - ctmp = ltmp.i8[1]; - ltmp.i8[1] = ltmp.i8[2]; - ltmp.i8[2] = ctmp; - *(uint32_t *)ul = ltmp.i32; + uint8_t ctmp; + uint8_t *cl = (uint8_t *) ul; + for(; count; count--,cl+=4){ + ctmp = *(cl+0); + *(cl+0) = *(cl+3); + *(cl+3) = ctmp; + ctmp = *(cl+1); + *(cl+1) = *(cl+2); + *(cl+2) = ctmp; } } diff --git a/src/extension/internal/uemf_print.c b/src/extension/internal/uemf_print.c index 3533090e0..6841e2982 100644 --- a/src/extension/internal/uemf_print.c +++ b/src/extension/internal/uemf_print.c @@ -4,11 +4,11 @@ /* File: uemf_print.c -Version: 0.0.9 -Date: 19-OCT-2012 +Version: 0.0.11 +Date: 22-JAN-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -17,6 +17,7 @@ extern "C" { #include #include +#include /* for offsetof() macro */ #include #include "uemf.h" @@ -90,8 +91,10 @@ void pointl_print( } /** - \brief Print a U_POINT16 object - \param pt U_POINT16 object + \brief Print a pointer to a U_POINT16 object + \param pt pointer to a U_POINT16 object + Warning - WMF data may contain unaligned U_POINT16, do not call + this routine with a pointer to such data! */ void point16_print( U_POINT16 pt @@ -137,7 +140,7 @@ void trivertex_print( /** \brief Print a U_GRADIENT3 object. - \param tv U_GRADIENT3 object. + \param g3 U_GRADIENT3 object. */ void gradient3_print( U_GRADIENT3 g3 @@ -147,7 +150,7 @@ void gradient3_print( /** \brief Print a U_GRADIENT4 object. - \param tv U_GRADIENT4 object. + \param g4 U_GRADIENT4 object. */ void gradient4_print( U_GRADIENT4 g4 @@ -308,41 +311,55 @@ void logfont_panose_print( } /** - \brief Print a U_BITMAPINFOHEADER object. - \param Bmi U_BITMAPINFOHEADER object + \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. */ void bitmapinfoheader_print( - U_BITMAPINFOHEADER Bmi + char *Bmih ){ - printf("biSize:%u " ,Bmi.biSize ); - printf("biWidth:%d " ,Bmi.biWidth ); - printf("biHeight:%d " ,Bmi.biHeight ); - printf("biPlanes:%u " ,Bmi.biPlanes ); - printf("biBitCount:%u " ,Bmi.biBitCount ); - printf("biCompression:%u " ,Bmi.biCompression ); - printf("biSizeImage:%u " ,Bmi.biSizeImage ); - printf("biXPelsPerMeter:%d " ,Bmi.biXPelsPerMeter); - printf("biYPelsPerMeter:%d " ,Bmi.biYPelsPerMeter); - printf("biClrUsed:%u " ,Bmi.biClrUsed ); - printf("biClrImportant:%u " ,Bmi.biClrImportant ); + uint32_t utmp4; + int32_t tmp4; + int16_t tmp2; + + /* 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 ); + memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); printf("biHeight:%d " ,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 ); + 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 ); + memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrImportant), 4); printf("biClrImportant:%u " ,utmp4 ); } /** \brief Print a Pointer to a U_BITMAPINFO object. \param Bmi Pointer to a U_BITMAPINFO object + This may be called from WMF _print routines, where problems could occur + if the data was passed as the struct or a pointer to the struct, as the struct may not + be aligned in memory. */ void bitmapinfo_print( - PU_BITMAPINFO Bmi + char *Bmi ){ - int i; - PU_RGBQUAD BmiColors; - PU_BITMAPINFOHEADER BmiHeader = &(Bmi->bmiHeader); - printf("BmiHeader: "); bitmapinfoheader_print(*BmiHeader); - if(BmiHeader->biClrUsed){ - BmiColors = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); - for(i=0; ibiClrUsed; i++){ - printf("%d:",i); rgbquad_print(BmiColors[i]); + int i,k; + uint32_t biClrUsed; + 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){ + k= offsetof(U_BITMAPINFO,bmiColors); + for(i=0; iiType,(int) off,lpEMFR->nSize); -} // Functions with the same form starting with U_EMRPOLYBEZIER_print -void core1_print(char *name, char *contents, int recnum, size_t off){ +void core1_print(char *name, char *contents){ int i; - PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (contents + off); - core5_print(name, contents, recnum, off); + PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cptl: %d\n",pEmr->cptl ); printf(" Points: "); @@ -626,10 +610,9 @@ void core1_print(char *name, char *contents, int recnum, size_t off){ } // Functions with the same form starting with U_EMRPOLYPOLYLINE_print -void core2_print(char *name, char *contents, int recnum, size_t off){ +void core2_print(char *name, char *contents){ int i; - PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) (contents + off); - core5_print(name, contents, recnum, off); + PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" nPolys: %d\n",pEmr->nPolys ); printf(" cptl: %d\n",pEmr->cptl ); @@ -648,9 +631,8 @@ void core2_print(char *name, char *contents, int recnum, size_t off){ // Functions with the same form starting with U_EMRSETMAPMODE_print -void core3_print(char *name, char *label, char *contents, int recnum, size_t off){ - PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(contents + off); - core5_print(name, contents, recnum, off); +void core3_print(char *name, char *label, char *contents){ + PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(contents); if(!strcmp(label,"crColor:")){ printf(" %-15s ",label); colorref_print(*(U_COLORREF *)&(pEmr->iMode)); printf("\n"); } @@ -663,17 +645,15 @@ void core3_print(char *name, char *label, char *contents, int recnum, size_t off } // 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, int recnum, size_t off){ - PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( contents + off); - core5_print(name, contents, recnum, off); +void core4_print(char *name, 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, int recnum, size_t off){ +void core6_print(char *name, char *contents){ int i; - PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (contents + off); - core5_print(name, contents, recnum, off); + PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cpts: %d\n",pEmr->cpts ); printf(" Points: "); @@ -689,9 +669,8 @@ void core6_print(char *name, char *contents, int recnum, size_t off){ // 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, int recnum, size_t off){ - PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (contents + off); - core5_print(name, contents, recnum, off); +void core7_print(char *name, char *field1, char *field2, char *contents){ + PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (contents); if(*field2){ printf(" %-15s %d\n",field1,pEmr->pair.x); printf(" %-15s %d\n",field2,pEmr->pair.y); @@ -702,32 +681,29 @@ void core7_print(char *name, char *field1, char *field2, char *contents, int rec } // For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one -void core8_print(char *name, char *contents, int recnum, size_t off, int type){ - PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (contents + off); - core5_print(name, contents, recnum, off); +void core8_print(char *name, char *contents, int type){ + PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (contents); printf(" iGraphicsMode: %u\n",pEmr->iGraphicsMode ); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" exScale: %f\n",pEmr->exScale ); printf(" eyScale: %f\n",pEmr->eyScale ); printf(" emrtext: "); - emrtext_print(contents + off + sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT),contents + off,type); + emrtext_print(contents + sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT),contents,type); printf("\n"); } // Functions that take a rect and a pair of points, starting with U_EMRARC_print -void core9_print(char *name, char *contents, int recnum, size_t off){ - PU_EMRARC pEmr = (PU_EMRARC) (contents + off); - core5_print(name, contents, recnum, off); +void core9_print(char *name, char *contents){ + PU_EMRARC pEmr = (PU_EMRARC) (contents); printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); printf(" ptlEnd: "); pointl_print(pEmr->ptlEnd); printf("\n"); } // Functions with the same form starting with U_EMRPOLYPOLYLINE16_print -void core10_print(char *name, char *contents, int recnum, size_t off){ +void core10_print(char *name, char *contents){ int i; - PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (contents + off); - core5_print(name, contents, recnum, off); + PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" nPolys: %d\n",pEmr->nPolys ); printf(" cpts: %d\n",pEmr->cpts ); @@ -746,10 +722,9 @@ void core10_print(char *name, char *contents, int recnum, size_t off){ } // Functions with the same form starting with U_EMRINVERTRGN_print and U_EMRPAINTRGN_print, -void core11_print(char *name, char *contents, int recnum, size_t off){ +void core11_print(char *name, char *contents){ int i,roff; - PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (contents + off); - core5_print(name, contents, recnum, off); + PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %d\n",pEmr->cbRgnData); // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. @@ -766,16 +741,15 @@ void core11_print(char *name, char *contents, int recnum, size_t off){ // common code for U_EMRCREATEMONOBRUSH_print and U_EMRCREATEDIBPATTERNBRUSHPT_print, -void core12_print(char *name, char *contents, int recnum, size_t off){ - PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (contents + off); - core5_print(name, contents, recnum, off); +void core12_print(char *name, char *contents){ + PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (contents); printf(" ihBrush: %u\n",pEmr->ihBrush ); printf(" iUsage : %u\n",pEmr->iUsage ); printf(" offBmi : %u\n",pEmr->offBmi ); printf(" cbBmi : %u\n",pEmr->cbBmi ); if(pEmr->cbBmi){ printf(" bitmap:"); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmi)); + bitmapinfo_print(contents + pEmr->offBmi); printf("\n"); } printf(" offBits: %u\n",pEmr->offBits ); @@ -783,9 +757,8 @@ void core12_print(char *name, char *contents, int recnum, size_t off){ } // common code for U_EMRALPHABLEND_print and U_EMRTRANSPARENTBLT_print, -void core13_print(char *name, char *contents, int recnum, size_t off){ - PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (contents + off); - core5_print(name, contents, recnum, off); +void core13_print(char *name, char *contents){ + PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -798,7 +771,7 @@ void core13_print(char *name, char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n",pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" bitmap:"); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n",pEmr->offBitsSrc ); @@ -816,12 +789,8 @@ They are listed in order by the corresponding U_EMR_* index number. \brief Print a pointer to a U_EMR_whatever record which has not been implemented. \param name name of this type of record \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRNOTIMPLEMENTED_print(char *name, char *contents, int recnum, size_t off){ - PU_ENHMETARECORD lpEMFR = (PU_ENHMETARECORD)(contents + off); - printf("%-30srecord:%5d type:%3d offset:%8d size:%8d\n",name,recnum,lpEMFR->iType,(int) off,lpEMFR->nSize); +void U_EMRNOTIMPLEMENTED_print(char *name, char *contents){ printf(" Not Implemented!\n"); } @@ -829,15 +798,12 @@ void U_EMRNOTIMPLEMENTED_print(char *name, char *contents, int recnum, size_t of /** \brief Print a pointer to a U_EMR_HEADER 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_EMRHEADER_print(char *contents, int recnum, size_t off){ +void U_EMRHEADER_print(char *contents){ char *string; int p1len; - core5_print("U_EMRHEADER", contents, recnum, off); - PU_EMRHEADER pEmr = (PU_EMRHEADER)(contents+off); + PU_EMRHEADER pEmr = (PU_EMRHEADER)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" rclFrame: "); rectl_print( pEmr->rclFrame); printf("\n"); printf(" dSignature: 0x%8.8X\n", pEmr->dSignature ); @@ -867,7 +833,7 @@ void U_EMRHEADER_print(char *contents, int recnum, size_t off){ printf(" offPixelFormat: %d\n", pEmr->offPixelFormat); if(pEmr->cbPixelFormat){ printf(" PFD:"); - pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + off + pEmr->offPixelFormat)); + pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + pEmr->offPixelFormat)); printf("\n"); } printf(" bOpenGL: %d\n",pEmr->bOpenGL ); @@ -884,22 +850,18 @@ void U_EMRHEADER_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_POLYBEZIER 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_EMRPOLYBEZIER_print(char *contents, int recnum, size_t off){ - core1_print("U_EMRPOLYBEZIER", contents, recnum, off); +void U_EMRPOLYBEZIER_print(char *contents){ + core1_print("U_EMRPOLYBEZIER", contents); } // U_EMRPOLYGON 3 /** \brief Print a pointer to a U_EMR_POLYGON record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYGON_print(char *contents, int recnum, size_t off){ - core1_print("U_EMRPOLYGON", contents, recnum, off); +void U_EMRPOLYGON_print(char *contents){ + core1_print("U_EMRPOLYGON", contents); } @@ -907,128 +869,104 @@ void U_EMRPOLYGON_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_POLYLINE 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_EMRPOLYLINE_print(char *contents, int recnum, size_t off){ - core1_print("U_EMRPOLYLINE", contents, recnum, off); +void U_EMRPOLYLINE_print(char *contents){ + core1_print("U_EMRPOLYLINE", contents); } // U_EMRPOLYBEZIERTO 5 /** \brief Print a pointer to a U_EMR_POLYBEZIERTO record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYBEZIERTO_print(char *contents, int recnum, size_t off){ - core1_print("U_EMRPOLYBEZIERTO", contents, recnum, off); +void U_EMRPOLYBEZIERTO_print(char *contents){ + core1_print("U_EMRPOLYBEZIERTO", contents); } // U_EMRPOLYLINETO 6 /** \brief Print a pointer to a U_EMR_POLYLINETO record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYLINETO_print(char *contents, int recnum, size_t off){ - core1_print("U_EMRPOLYLINETO", contents, recnum, off); +void U_EMRPOLYLINETO_print(char *contents){ + core1_print("U_EMRPOLYLINETO", contents); } // U_EMRPOLYPOLYLINE 7 /** \brief Print a pointer to a U_EMR_POLYPOLYLINE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYPOLYLINE_print(char *contents, int recnum, size_t off){ - core2_print("U_EMRPOLYPOLYLINE", contents, recnum, off); +void U_EMRPOLYPOLYLINE_print(char *contents){ + core2_print("U_EMRPOLYPOLYLINE", contents); } // U_EMRPOLYPOLYGON 8 /** \brief Print a pointer to a U_EMR_POLYPOLYGON record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYPOLYGON_print(char *contents, int recnum, size_t off){ - core2_print("U_EMRPOLYPOLYGON", contents, recnum, off); +void U_EMRPOLYPOLYGON_print(char *contents){ + core2_print("U_EMRPOLYPOLYGON", contents); } // U_EMRSETWINDOWEXTEX 9 /** \brief Print a pointer to a U_EMR_SETWINDOWEXTEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETWINDOWEXTEX_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRSETWINDOWEXTEX", "szlExtent:","",contents, recnum, off); +void U_EMRSETWINDOWEXTEX_print(char *contents){ + core7_print("U_EMRSETWINDOWEXTEX", "szlExtent:","",contents); } // U_EMRSETWINDOWORGEX 10 /** \brief Print a pointer to a U_EMR_SETWINDOWORGEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETWINDOWORGEX_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRSETWINDOWORGEX", "ptlOrigin:","",contents, recnum, off); +void U_EMRSETWINDOWORGEX_print(char *contents){ + core7_print("U_EMRSETWINDOWORGEX", "ptlOrigin:","",contents); } // U_EMRSETVIEWPORTEXTEX 11 /** \brief Print a pointer to a U_EMR_SETVIEWPORTEXTEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETVIEWPORTEXTEX_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRSETVIEWPORTEXTEX", "szlExtent:","",contents, recnum, off); +void U_EMRSETVIEWPORTEXTEX_print(char *contents){ + core7_print("U_EMRSETVIEWPORTEXTEX", "szlExtent:","",contents); } // U_EMRSETVIEWPORTORGEX 12 /** \brief Print a pointer to a U_EMR_SETVIEWPORTORGEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETVIEWPORTORGEX_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRSETVIEWPORTORGEX", "ptlOrigin:","",contents, recnum, off); +void U_EMRSETVIEWPORTORGEX_print(char *contents){ + core7_print("U_EMRSETVIEWPORTORGEX", "ptlOrigin:","",contents); } // U_EMRSETBRUSHORGEX 13 /** \brief Print a pointer to a U_EMR_SETBRUSHORGEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETBRUSHORGEX_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRSETBRUSHORGEX", "ptlOrigin:","",contents, recnum, off); +void U_EMRSETBRUSHORGEX_print(char *contents){ + core7_print("U_EMRSETBRUSHORGEX", "ptlOrigin:","",contents); } // U_EMREOF 14 /** \brief Print a pointer to a U_EMR_EOF record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMREOF_print(char *contents, int recnum, size_t off){ - core5_print("U_EMREOF", contents, recnum, off); - - PU_EMREOF pEmr = (PU_EMREOF)(contents+off); +void U_EMREOF_print(char *contents){ + PU_EMREOF pEmr = (PU_EMREOF)(contents); printf(" cbPalEntries: %u\n", pEmr->cbPalEntries ); printf(" offPalEntries: %u\n", pEmr->offPalEntries); if(pEmr->cbPalEntries){ printf(" PE:"); - logpalette_print( (PU_LOGPALETTE)(contents + off + pEmr->offPalEntries)); + logpalette_print( (PU_LOGPALETTE)(contents + pEmr->offPalEntries)); printf("\n"); } } @@ -1038,12 +976,9 @@ void U_EMREOF_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETPIXELV 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_EMRSETPIXELV_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSETPIXELV", contents, recnum, off); - PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(contents+off); +void U_EMRSETPIXELV_print(char *contents){ + PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(contents); printf(" ptlPixel: "); pointl_print( pEmr->ptlPixel); printf("\n"); printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n"); } @@ -1053,12 +988,9 @@ void U_EMRSETPIXELV_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETMAPPERFLAGS 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_EMRSETMAPPERFLAGS_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSETMAPPERFLAGS", contents, recnum, off); - PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(contents+off); +void U_EMRSETMAPPERFLAGS_print(char *contents){ + PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(contents); printf(" dwFlags: %u\n",pEmr->dwFlags); } @@ -1067,78 +999,63 @@ void U_EMRSETMAPPERFLAGS_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETMAPMODE 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_EMRSETMAPMODE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETMAPMODE", "iMode:", contents, recnum, off); +void U_EMRSETMAPMODE_print(char *contents){ + core3_print("U_EMRSETMAPMODE", "iMode:", contents); } // U_EMRSETBKMODE 18 /** \brief Print a pointer to a U_EMR_SETBKMODE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETBKMODE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETBKMODE", "iMode:", contents, recnum, off); +void U_EMRSETBKMODE_print(char *contents){ + core3_print("U_EMRSETBKMODE", "iMode:", contents); } // U_EMRSETPOLYFILLMODE 19 /** \brief Print a pointer to a U_EMR_SETPOLYFILLMODE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETPOLYFILLMODE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETPOLYFILLMODE", "iMode:", contents, recnum, off); +void U_EMRSETPOLYFILLMODE_print(char *contents){ + core3_print("U_EMRSETPOLYFILLMODE", "iMode:", contents); } // U_EMRSETROP2 20 /** \brief Print a pointer to a U_EMR_SETROP2 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETROP2_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETROP2", "dwRop:", contents, recnum, off); +void U_EMRSETROP2_print(char *contents){ + core3_print("U_EMRSETROP2", "dwRop:", contents); } // U_EMRSETSTRETCHBLTMODE 21 /** \brief Print a pointer to a U_EMR_SETSTRETCHBLTMODE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETSTRETCHBLTMODE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETSTRETCHBLTMODE", "iMode:", contents, recnum, off); +void U_EMRSETSTRETCHBLTMODE_print(char *contents){ + core3_print("U_EMRSETSTRETCHBLTMODE", "iMode:", contents); } // U_EMRSETTEXTALIGN 22 /** \brief Print a pointer to a U_EMR_SETTEXTALIGN record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETTEXTALIGN_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETTEXTALIGN", "iMode:", contents, recnum, off); +void U_EMRSETTEXTALIGN_print(char *contents){ + core3_print("U_EMRSETTEXTALIGN", "iMode:", contents); } // U_EMRSETCOLORADJUSTMENT 23 /** \brief Print a pointer to a U_EMR_SETCOLORADJUSTMENT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETCOLORADJUSTMENT_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSETCOLORADJUSTMENT", contents, recnum, off); - PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(contents+off); +void U_EMRSETCOLORADJUSTMENT_print(char *contents){ + PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(contents); printf(" ColorAdjustment:"); coloradjustment_print(pEmr->ColorAdjustment); printf("\n"); @@ -1148,88 +1065,71 @@ void U_EMRSETCOLORADJUSTMENT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETTEXTCOLOR 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_EMRSETTEXTCOLOR_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETTEXTCOLOR", "crColor:", contents, recnum, off); +void U_EMRSETTEXTCOLOR_print(char *contents){ + core3_print("U_EMRSETTEXTCOLOR", "crColor:", contents); } // U_EMRSETBKCOLOR 25 /** \brief Print a pointer to a U_EMR_SETBKCOLOR record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETBKCOLOR_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETBKCOLOR", "crColor:", contents, recnum, off); +void U_EMRSETBKCOLOR_print(char *contents){ + core3_print("U_EMRSETBKCOLOR", "crColor:", contents); } // U_EMROFFSETCLIPRGN 26 /** \brief Print a pointer to a U_EMR_OFFSETCLIPRGN record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMROFFSETCLIPRGN_print(char *contents, int recnum, size_t off){ - core7_print("U_EMROFFSETCLIPRGN", "ptl:","",contents, recnum, off); +void U_EMROFFSETCLIPRGN_print(char *contents){ + core7_print("U_EMROFFSETCLIPRGN", "ptl:","",contents); } // U_EMRMOVETOEX 27 /** \brief Print a pointer to a U_EMR_MOVETOEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRMOVETOEX_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRMOVETOEX", "ptl:","",contents, recnum, off); +void U_EMRMOVETOEX_print(char *contents){ + core7_print("U_EMRMOVETOEX", "ptl:","",contents); } // U_EMRSETMETARGN 28 /** \brief Print a pointer to a U_EMR_SETMETARGN record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETMETARGN_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSETMETARGN", contents, recnum, off); +void U_EMRSETMETARGN_print(char *contents){ } // U_EMREXCLUDECLIPRECT 29 /** \brief Print a pointer to a U_EMR_EXCLUDECLIPRECT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMREXCLUDECLIPRECT_print(char *contents, int recnum, size_t off){ - core4_print("U_EMREXCLUDECLIPRECT", contents, recnum, off); +void U_EMREXCLUDECLIPRECT_print(char *contents){ + core4_print("U_EMREXCLUDECLIPRECT", contents); } // U_EMRINTERSECTCLIPRECT 30 /** \brief Print a pointer to a U_EMR_INTERSECTCLIPRECT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRINTERSECTCLIPRECT_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRINTERSECTCLIPRECT", contents, recnum, off); +void U_EMRINTERSECTCLIPRECT_print(char *contents){ + core4_print("U_EMRINTERSECTCLIPRECT", contents); } // U_EMRSCALEVIEWPORTEXTEX 31 /** \brief Print a pointer to a U_EMR_SCALEVIEWPORTEXTEX record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSCALEVIEWPORTEXTEX_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRSCALEVIEWPORTEXTEX", contents, recnum, off); +void U_EMRSCALEVIEWPORTEXTEX_print(char *contents){ + core4_print("U_EMRSCALEVIEWPORTEXTEX", contents); } @@ -1237,45 +1137,35 @@ void U_EMRSCALEVIEWPORTEXTEX_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SCALEWINDOWEXTEX 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_EMRSCALEWINDOWEXTEX_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRSCALEWINDOWEXTEX", contents, recnum, off); +void U_EMRSCALEWINDOWEXTEX_print(char *contents){ + core4_print("U_EMRSCALEWINDOWEXTEX", contents); } // U_EMRSAVEDC 33 /** \brief Print a pointer to a U_EMR_SAVEDC record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSAVEDC_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSAVEDC", contents, recnum, off); +void U_EMRSAVEDC_print(char *contents){ } // U_EMRRESTOREDC 34 /** \brief Print a pointer to a U_EMR_RESTOREDC record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRRESTOREDC_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRRESTOREDC", "iRelative:", contents, recnum, off); +void U_EMRRESTOREDC_print(char *contents){ + core3_print("U_EMRRESTOREDC", "iRelative:", contents); } // U_EMRSETWORLDTRANSFORM 35 /** \brief Print a pointer to a U_EMR_SETWORLDTRANSFORM record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETWORLDTRANSFORM_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSETWORLDTRANSFORM", contents, recnum, off); - PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(contents+off); +void U_EMRSETWORLDTRANSFORM_print(char *contents){ + PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(contents); printf(" xform:"); xform_print(pEmr->xform); printf("\n"); @@ -1285,12 +1175,9 @@ void U_EMRSETWORLDTRANSFORM_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_MODIFYWORLDTRANSFORM 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_EMRMODIFYWORLDTRANSFORM_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRMODIFYWORLDTRANSFORM", contents, recnum, off); - PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(contents+off); +void U_EMRMODIFYWORLDTRANSFORM_print(char *contents){ + PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(contents); printf(" xform:"); xform_print(pEmr->xform); printf("\n"); @@ -1301,12 +1188,9 @@ void U_EMRMODIFYWORLDTRANSFORM_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SELECTOBJECT 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_EMRSELECTOBJECT_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRSELECTOBJECT", contents, recnum, off); - PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(contents+off); +void U_EMRSELECTOBJECT_print(char *contents){ + PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(contents); if(pEmr->ihObject & U_STOCK_OBJECT){ printf(" StockObject: 0x%8.8X\n", pEmr->ihObject ); } @@ -1319,12 +1203,9 @@ void U_EMRSELECTOBJECT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_CREATEPEN 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_EMRCREATEPEN_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRCREATEPEN", contents, recnum, off); - PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(contents+off); +void U_EMRCREATEPEN_print(char *contents){ + PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(contents); printf(" ihPen: %u\n", pEmr->ihPen ); printf(" lopn: "); logpen_print(pEmr->lopn); printf("\n"); } @@ -1333,12 +1214,9 @@ void U_EMRCREATEPEN_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_CREATEBRUSHINDIRECT 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_EMRCREATEBRUSHINDIRECT_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRCREATEBRUSHINDIRECT", contents, recnum, off); - PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(contents+off); +void U_EMRCREATEBRUSHINDIRECT_print(char *contents){ + PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(contents); printf(" ihBrush: %u\n", pEmr->ihBrush ); printf(" lb: "); logbrush_print(pEmr->lb); printf("\n"); } @@ -1347,12 +1225,9 @@ void U_EMRCREATEBRUSHINDIRECT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_DELETEOBJECT 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_EMRDELETEOBJECT_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRDELETEOBJECT", contents, recnum, off); - PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(contents+off); +void U_EMRDELETEOBJECT_print(char *contents){ + PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(contents); printf(" ihObject: %u\n", pEmr->ihObject ); } @@ -1360,12 +1235,9 @@ void U_EMRDELETEOBJECT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_ANGLEARC 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_EMRANGLEARC_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRANGLEARC", contents, recnum, off); - PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(contents+off); +void U_EMRANGLEARC_print(char *contents){ + PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(contents); printf(" ptlCenter: "), pointl_print(pEmr->ptlCenter ); printf("\n"); printf(" nRadius: %u\n", pEmr->nRadius ); printf(" eStartAngle: %f\n", pEmr->eStartAngle ); @@ -1376,34 +1248,27 @@ void U_EMRANGLEARC_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_ELLIPSE 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_EMRELLIPSE_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRELLIPSE", contents, recnum, off); +void U_EMRELLIPSE_print(char *contents){ + core4_print("U_EMRELLIPSE", contents); } // U_EMRRECTANGLE 43 /** \brief Print a pointer to a U_EMR_RECTANGLE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRRECTANGLE_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRRECTANGLE", contents, recnum, off); +void U_EMRRECTANGLE_print(char *contents){ + core4_print("U_EMRRECTANGLE", contents); } // U_EMRROUNDRECT 44 /** \brief Print a pointer to a U_EMR_ROUNDRECT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRROUNDRECT_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRROUNDRECT", contents, recnum, off); - PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(contents+off); +void U_EMRROUNDRECT_print(char *contents){ + PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(contents); printf(" rclBox: "), rectl_print(pEmr->rclBox ); printf("\n"); printf(" szlCorner: "), sizel_print(pEmr->szlCorner ); printf("\n"); } @@ -1412,56 +1277,45 @@ void U_EMRROUNDRECT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_ARC 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_EMRARC_print(char *contents, int recnum, size_t off){ - core9_print("U_EMRARC", contents, recnum, off); +void U_EMRARC_print(char *contents){ + core9_print("U_EMRARC", contents); } // U_EMRCHORD 46 /** \brief Print a pointer to a U_EMR_CHORD record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCHORD_print(char *contents, int recnum, size_t off){ - core9_print("U_EMRCHORD", contents, recnum, off); +void U_EMRCHORD_print(char *contents){ + core9_print("U_EMRCHORD", contents); } // U_EMRPIE 47 /** \brief Print a pointer to a U_EMR_PIE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPIE_print(char *contents, int recnum, size_t off){ - core9_print("U_EMRPIE", contents, recnum, off); +void U_EMRPIE_print(char *contents){ + core9_print("U_EMRPIE", contents); } // U_EMRSELECTPALETTE 48 /** \brief Print a pointer to a U_EMR_SELECTPALETTE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSELECTPALETTE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSELECTPALETTE", "ihPal:", contents, recnum, off); +void U_EMRSELECTPALETTE_print(char *contents){ + core3_print("U_EMRSELECTPALETTE", "ihPal:", contents); } // U_EMRCREATEPALETTE 49 /** \brief Print a pointer to a U_EMR_CREATEPALETTE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCREATEPALETTE_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRCREATEPALETTE", contents, recnum, off); - PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(contents+off); +void U_EMRCREATEPALETTE_print(char *contents){ + PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(contents); printf(" ihPal: %u\n",pEmr->ihPal); printf(" lgpl: "), logpalette_print( (PU_LOGPALETTE)&(pEmr->lgpl) ); printf("\n"); } @@ -1470,13 +1324,10 @@ void U_EMRCREATEPALETTE_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETPALETTEENTRIES 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_EMRSETPALETTEENTRIES_print(char *contents, int recnum, size_t off){ +void U_EMRSETPALETTEENTRIES_print(char *contents){ int i; - core5_print("U_EMRSETPALETTEENTRIES", contents, recnum, off); - PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents+off); + PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents); printf(" ihPal: %u\n",pEmr->ihPal); printf(" iStart: %u\n",pEmr->iStart); printf(" cEntries: %u\n",pEmr->cEntries); @@ -1494,34 +1345,26 @@ void U_EMRSETPALETTEENTRIES_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_RESIZEPALETTE 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_EMRRESIZEPALETTE_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRRESIZEPALETTE", "ihPal:","cEntries",contents, recnum, off); +void U_EMRRESIZEPALETTE_print(char *contents){ + core7_print("U_EMRRESIZEPALETTE", "ihPal:","cEntries",contents); } // U_EMRREALIZEPALETTE 52 /** \brief Print a pointer to a U_EMR_REALIZEPALETTE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRREALIZEPALETTE_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRREALIZEPALETTE", contents, recnum, off); +void U_EMRREALIZEPALETTE_print(char *contents){ } // U_EMREXTFLOODFILL 53 /** \brief Print a pointer to a U_EMR_EXTFLOODFILL record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMREXTFLOODFILL_print(char *contents, int recnum, size_t off){ - core5_print("U_EMREXTFLOODFILL", contents, recnum, off); - PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(contents+off); +void U_EMREXTFLOODFILL_print(char *contents){ + PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(contents); printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n"); printf(" iMode: %u\n",pEmr->iMode); @@ -1531,35 +1374,28 @@ void U_EMREXTFLOODFILL_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_LINETO 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_EMRLINETO_print(char *contents, int recnum, size_t off){ - core7_print("U_EMRLINETO", "ptl:","",contents, recnum, off); +void U_EMRLINETO_print(char *contents){ + core7_print("U_EMRLINETO", "ptl:","",contents); } // U_EMRARCTO 55 /** \brief Print a pointer to a U_EMR_ARCTO record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRARCTO_print(char *contents, int recnum, size_t off){ - core9_print("U_EMRARCTO", contents, recnum, off); +void U_EMRARCTO_print(char *contents){ + core9_print("U_EMRARCTO", contents); } // U_EMRPOLYDRAW 56 /** \brief Print a pointer to a U_EMR_POLYDRAW record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYDRAW_print(char *contents, int recnum, size_t off){ +void U_EMRPOLYDRAW_print(char *contents){ int i; - core5_print("U_EMRPOLYDRAW", contents, recnum, off); - PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents+off); + PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" cptl: %d\n",pEmr->cptl ); printf(" Points: "); @@ -1579,22 +1415,18 @@ void U_EMRPOLYDRAW_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETARCDIRECTION 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_EMRSETARCDIRECTION_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETARCDIRECTION","arcDirection:", contents, recnum, off); +void U_EMRSETARCDIRECTION_print(char *contents){ + core3_print("U_EMRSETARCDIRECTION","arcDirection:", contents); } // U_EMRSETMITERLIMIT 58 /** \brief Print a pointer to a U_EMR_SETMITERLIMIT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETMITERLIMIT_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETMITERLIMIT", "eMiterLimit:", contents, recnum, off); +void U_EMRSETMITERLIMIT_print(char *contents){ + core3_print("U_EMRSETMITERLIMIT", "eMiterLimit:", contents); } @@ -1602,128 +1434,99 @@ void U_EMRSETMITERLIMIT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_BEGINPATH 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_EMRBEGINPATH_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRBEGINPATH", contents, recnum, off); +void U_EMRBEGINPATH_print(char *contents){ } // U_EMRENDPATH 60 /** \brief Print a pointer to a U_EMR_ENDPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRENDPATH_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRENDPATH", contents, recnum, off); +void U_EMRENDPATH_print(char *contents){ } // U_EMRCLOSEFIGURE 61 /** \brief Print a pointer to a U_EMR_CLOSEFIGURE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCLOSEFIGURE_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRCLOSEFIGURE", contents, recnum, off); +void U_EMRCLOSEFIGURE_print(char *contents){ } // U_EMRFILLPATH 62 /** \brief Print a pointer to a U_EMR_FILLPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRFILLPATH_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRFILLPATH", contents, recnum, off); +void U_EMRFILLPATH_print(char *contents){ + core4_print("U_EMRFILLPATH", contents); } // U_EMRSTROKEANDFILLPATH 63 /** \brief Print a pointer to a U_EMR_STROKEANDFILLPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSTROKEANDFILLPATH_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRSTROKEANDFILLPATH", contents, recnum, off); +void U_EMRSTROKEANDFILLPATH_print(char *contents){ + core4_print("U_EMRSTROKEANDFILLPATH", contents); } // U_EMRSTROKEPATH 64 /** \brief Print a pointer to a U_EMR_STROKEPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSTROKEPATH_print(char *contents, int recnum, size_t off){ - core4_print("U_EMRSTROKEPATH", contents, recnum, off); +void U_EMRSTROKEPATH_print(char *contents){ + core4_print("U_EMRSTROKEPATH", contents); } // U_EMRFLATTENPATH 65 /** \brief Print a pointer to a U_EMR_FLATTENPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRFLATTENPATH_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRFLATTENPATH", contents, recnum, off); +void U_EMRFLATTENPATH_print(char *contents){ } // U_EMRWIDENPATH 66 /** \brief Print a pointer to a U_EMR_WIDENPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRWIDENPATH_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRWIDENPATH", contents, recnum, off); +void U_EMRWIDENPATH_print(char *contents){ } // U_EMRSELECTCLIPPATH 67 /** \brief Print a pointer to a U_EMR_SELECTCLIPPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSELECTCLIPPATH_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSELECTCLIPPATH", "iMode:", contents, recnum, off); +void U_EMRSELECTCLIPPATH_print(char *contents){ + core3_print("U_EMRSELECTCLIPPATH", "iMode:", contents); } // U_EMRABORTPATH 68 /** \brief Print a pointer to a U_EMR_ABORTPATH record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRABORTPATH_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRABORTPATH", contents, recnum, off); +void U_EMRABORTPATH_print(char *contents){ } // U_EMRUNDEF69 69 -#define U_EMRUNDEF69_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF69",A,B,C) +#define U_EMRUNDEF69_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF69",A) // U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific) /** \brief Print a pointer to a U_EMR_COMMENT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCOMMENT_print(char *contents, int recnum, size_t off){ +void U_EMRCOMMENT_print(char *contents){ char *string; char *src; uint32_t cIdent,cbData; - core5_print("U_EMRCOMMENT", contents, recnum, off); - PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(contents+off); + PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(contents); /* There are several different types of comments */ @@ -1770,13 +1573,10 @@ void U_EMRCOMMENT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_FILLRGN 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_EMRFILLRGN_print(char *contents, int recnum, size_t off){ +void U_EMRFILLRGN_print(char *contents){ int i,roff; - core5_print("U_EMRFILLRGN", contents, recnum, off); - PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents+off); + PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" ihBrush: %u\n",pEmr->ihBrush); @@ -1794,13 +1594,10 @@ void U_EMRFILLRGN_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_FRAMERGN 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_EMRFRAMERGN_print(char *contents, int recnum, size_t off){ +void U_EMRFRAMERGN_print(char *contents){ int i,roff; - core5_print("U_EMRFRAMERGN", contents, recnum, off); - PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents+off); + PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" ihBrush: %u\n",pEmr->ihBrush); @@ -1819,35 +1616,28 @@ void U_EMRFRAMERGN_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_INVERTRGN 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_EMRINVERTRGN_print(char *contents, int recnum, size_t off){ - core11_print("U_EMRINVERTRGN", contents, recnum, off); +void U_EMRINVERTRGN_print(char *contents){ + core11_print("U_EMRINVERTRGN", contents); } // U_EMRPAINTRGN 74 /** \brief Print a pointer to a U_EMR_PAINTRGN record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPAINTRGN_print(char *contents, int recnum, size_t off){ - core11_print("U_EMRPAINTRGN", contents, recnum, off); +void U_EMRPAINTRGN_print(char *contents){ + core11_print("U_EMRPAINTRGN", contents); } // U_EMREXTSELECTCLIPRGN 75 /** \brief Print a pointer to a U_EMR_EXTSELECTCLIPRGN record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMREXTSELECTCLIPRGN_print(char *contents, int recnum, size_t off){ +void U_EMREXTSELECTCLIPRGN_print(char *contents){ int i,roff; - PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents + off); - core5_print("U_EMREXTSELECTCLIPRGN", contents, recnum, off); + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents); printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" iMode: %u\n",pEmr->iMode); // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. @@ -1863,12 +1653,9 @@ void U_EMREXTSELECTCLIPRGN_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_BITBLT 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_EMRBITBLT_print(char *contents, int recnum, size_t off){ - PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (contents + off); - core5_print("U_EMRBITBLT", contents, recnum, off); +void U_EMRBITBLT_print(char *contents){ + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -1881,7 +1668,7 @@ void U_EMRBITBLT_print(char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1892,12 +1679,9 @@ void U_EMRBITBLT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_STRETCHBLT 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_EMRSTRETCHBLT_print(char *contents, int recnum, size_t off){ - PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (contents + off); - core5_print("U_EMRSTRETCHBLT", contents, recnum, off); +void U_EMRSTRETCHBLT_print(char *contents){ + PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -1910,7 +1694,7 @@ void U_EMRSTRETCHBLT_print(char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1922,12 +1706,9 @@ void U_EMRSTRETCHBLT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_MASKBLT 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_EMRMASKBLT_print(char *contents, int recnum, size_t off){ - PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (contents + off); - core5_print("U_EMRMASKBLT", contents, recnum, off); +void U_EMRMASKBLT_print(char *contents){ + PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -1940,7 +1721,7 @@ void U_EMRMASKBLT_print(char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1951,7 +1732,7 @@ void U_EMRMASKBLT_print(char *contents, int recnum, size_t off){ printf(" cbBmiMask: %u\n", pEmr->cbBmiMask ); if(pEmr->cbBmiMask){ printf(" Mask bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiMask)); + bitmapinfo_print(contents + pEmr->offBmiMask); printf("\n"); } printf(" offBitsMask: %u\n", pEmr->offBitsMask ); @@ -1962,12 +1743,9 @@ void U_EMRMASKBLT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_PLGBLT 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_EMRPLGBLT_print(char *contents, int recnum, size_t off){ - PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (contents + off); - core5_print("U_EMRPLGBLT", contents, recnum, off); +void U_EMRPLGBLT_print(char *contents){ + PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" aptlDst(UL): "); pointl_print(pEmr->aptlDst[0]); printf("\n"); printf(" aptlDst(UR): "); pointl_print(pEmr->aptlDst[1]); printf("\n"); @@ -1981,7 +1759,7 @@ void U_EMRPLGBLT_print(char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1992,7 +1770,7 @@ void U_EMRPLGBLT_print(char *contents, int recnum, size_t off){ printf(" cbBmiMask: %u\n", pEmr->cbBmiMask ); if(pEmr->cbBmiMask){ printf(" Mask bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiMask)); + bitmapinfo_print(contents + pEmr->offBmiMask); printf("\n"); } printf(" offBitsMask: %u\n", pEmr->offBitsMask ); @@ -2003,12 +1781,9 @@ void U_EMRPLGBLT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMRSETDIBITSTODEVICE 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_EMRSETDIBITSTODEVICE_print(char *contents, int recnum, size_t off){ - PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (contents + off); - core5_print("U_EMRSETDIBITSTODEVICE", contents, recnum, off); +void U_EMRSETDIBITSTODEVICE_print(char *contents){ + PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); @@ -2017,7 +1792,7 @@ void U_EMRSETDIBITSTODEVICE_print(char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -2031,12 +1806,9 @@ void U_EMRSETDIBITSTODEVICE_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_STRETCHDIBITS 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_EMRSTRETCHDIBITS_print(char *contents, int recnum, size_t off){ - PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (contents + off); - core5_print("U_EMRSTRETCHDIBITS", contents, recnum, off); +void U_EMRSTRETCHDIBITS_print(char *contents){ + PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); @@ -2045,7 +1817,7 @@ void U_EMRSTRETCHDIBITS_print(char *contents, int recnum, size_t off){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmiSrc)); + bitmapinfo_print(contents + pEmr->offBmiSrc); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -2059,12 +1831,9 @@ void U_EMRSTRETCHDIBITS_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_EXTCREATEFONTINDIRECTW 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_EMREXTCREATEFONTINDIRECTW_print(char *contents, int recnum, size_t off){ - PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (contents + off); - core5_print("U_EMREXTCREATEFONTINDIRECTW", contents, recnum, off); +void U_EMREXTCREATEFONTINDIRECTW_print(char *contents){ + PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (contents); printf(" ihFont: %u\n",pEmr->ihFont ); printf(" Font: "); if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ // holds logfont_panose @@ -2080,99 +1849,81 @@ void U_EMREXTCREATEFONTINDIRECTW_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_EXTTEXTOUTA 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_EMREXTTEXTOUTA_print(char *contents, int recnum, size_t off){ - core8_print("U_EMREXTTEXTOUTA", contents, recnum, off, 0); +void U_EMREXTTEXTOUTA_print(char *contents){ + core8_print("U_EMREXTTEXTOUTA", contents, 0); } // U_EMREXTTEXTOUTW 84 /** \brief Print a pointer to a U_EMR_EXTTEXTOUTW record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMREXTTEXTOUTW_print(char *contents, int recnum, size_t off){ - core8_print("U_EMREXTTEXTOUTW", contents, recnum, off, 1); +void U_EMREXTTEXTOUTW_print(char *contents){ + core8_print("U_EMREXTTEXTOUTW", contents, 1); } // U_EMRPOLYBEZIER16 85 /** \brief Print a pointer to a U_EMR_POLYBEZIER16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYBEZIER16_print(char *contents, int recnum, size_t off){ - core6_print("U_EMRPOLYBEZIER16", contents, recnum, off); +void U_EMRPOLYBEZIER16_print(char *contents){ + core6_print("U_EMRPOLYBEZIER16", contents); } // U_EMRPOLYGON16 86 /** \brief Print a pointer to a U_EMR_POLYGON16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYGON16_print(char *contents, int recnum, size_t off){ - core6_print("U_EMRPOLYGON16", contents, recnum, off); +void U_EMRPOLYGON16_print(char *contents){ + core6_print("U_EMRPOLYGON16", contents); } // U_EMRPOLYLINE16 87 /** \brief Print a pointer to a U_EMR_POLYLINE16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYLINE16_print(char *contents, int recnum, size_t off){ - core6_print("U_EMRPOLYLINE16", contents, recnum, off); +void U_EMRPOLYLINE16_print(char *contents){ + core6_print("U_EMRPOLYLINE16", contents); } // U_EMRPOLYBEZIERTO16 88 /** \brief Print a pointer to a U_EMR_POLYBEZIERTO16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYBEZIERTO16_print(char *contents, int recnum, size_t off){ - core6_print("U_EMRPOLYBEZIERTO16", contents, recnum, off); +void U_EMRPOLYBEZIERTO16_print(char *contents){ + core6_print("U_EMRPOLYBEZIERTO16", contents); } // U_EMRPOLYLINETO16 89 /** \brief Print a pointer to a U_EMR_POLYLINETO16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYLINETO16_print(char *contents, int recnum, size_t off){ - core6_print("U_EMRPOLYLINETO16", contents, recnum, off); +void U_EMRPOLYLINETO16_print(char *contents){ + core6_print("U_EMRPOLYLINETO16", contents); } // U_EMRPOLYPOLYLINE16 90 /** \brief Print a pointer to a U_EMR_POLYPOLYLINE16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYPOLYLINE16_print(char *contents, int recnum, size_t off){ - core10_print("U_EMRPOLYPOLYLINE16", contents, recnum, off); +void U_EMRPOLYPOLYLINE16_print(char *contents){ + core10_print("U_EMRPOLYPOLYLINE16", contents); } // U_EMRPOLYPOLYGON16 91 /** \brief Print a pointer to a U_EMR_POLYPOLYGON16 record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPOLYPOLYGON16_print(char *contents, int recnum, size_t off){ - core10_print("U_EMRPOLYPOLYGON16", contents, recnum, off); +void U_EMRPOLYPOLYGON16_print(char *contents){ + core10_print("U_EMRPOLYPOLYGON16", contents); } @@ -2180,13 +1931,10 @@ void U_EMRPOLYPOLYGON16_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_POLYDRAW16 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_EMRPOLYDRAW16_print(char *contents, int recnum, size_t off){ +void U_EMRPOLYDRAW16_print(char *contents){ int i; - core5_print("U_EMRPOLYDRAW16", contents, recnum, off); - PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents+off); + PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" cpts: %d\n",pEmr->cpts ); printf(" Points: "); @@ -2206,22 +1954,18 @@ void U_EMRPOLYDRAW16_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_CREATEMONOBRUSH 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_EMRCREATEMONOBRUSH_print(char *contents, int recnum, size_t off){ - core12_print("U_EMRCREATEMONOBRUSH", contents, recnum, off); +void U_EMRCREATEMONOBRUSH_print(char *contents){ + core12_print("U_EMRCREATEMONOBRUSH", contents); } // U_EMRCREATEDIBPATTERNBRUSHPT_print 94 /** \brief Print a pointer to a U_EMR_CREATEDIBPATTERNBRUSHPT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCREATEDIBPATTERNBRUSHPT_print(char *contents, int recnum, size_t off){ - core12_print("U_EMRCREATEDIBPATTERNBRUSHPT", contents, recnum, off); +void U_EMRCREATEDIBPATTERNBRUSHPT_print(char *contents){ + core12_print("U_EMRCREATEDIBPATTERNBRUSHPT", contents); } @@ -2229,18 +1973,15 @@ void U_EMRCREATEDIBPATTERNBRUSHPT_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_EXTCREATEPEN 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_EMREXTCREATEPEN_print(char *contents, int recnum, size_t off){ - core5_print("U_EMREXTCREATEPEN", contents, recnum, off); - PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(contents+off); +void U_EMREXTCREATEPEN_print(char *contents){ + PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(contents); printf(" ihPen: %u\n", pEmr->ihPen ); printf(" offBmi: %u\n", pEmr->offBmi ); printf(" cbBmi: %u\n", pEmr->cbBmi ); if(pEmr->cbBmi){ printf(" bitmap: "); - bitmapinfo_print((PU_BITMAPINFO)(contents + off + pEmr->offBmi)); + bitmapinfo_print(contents + pEmr->offBmi); printf("\n"); } printf(" offBits: %u\n", pEmr->offBits ); @@ -2249,31 +1990,26 @@ void U_EMREXTCREATEPEN_print(char *contents, int recnum, size_t off){ } // U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT -#define U_EMRPOLYTEXTOUTA_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTA",A,B,C) +#define U_EMRPOLYTEXTOUTA_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTA",A) // U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT -#define U_EMRPOLYTEXTOUTW_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTW",A,B,C) +#define U_EMRPOLYTEXTOUTW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTW",A) // U_EMRSETICMMODE 98 /** \brief Print a pointer to a U_EMR_SETICMMODE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETICMMODE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETICMMODE", "iMode:", contents, recnum, off); +void U_EMRSETICMMODE_print(char *contents){ + core3_print("U_EMRSETICMMODE", "iMode:", contents); } // U_EMRCREATECOLORSPACE 99 /** \brief Print a pointer to a U_EMR_CREATECOLORSPACE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCREATECOLORSPACE_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRCREATECOLORSPACE", contents, recnum, off); - PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(contents+off); +void U_EMRCREATECOLORSPACE_print(char *contents){ + PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(contents); printf(" ihCS: %u\n", pEmr->ihCS ); printf(" ColorSpace: "); logcolorspacea_print(pEmr->lcs); printf("\n"); } @@ -2282,61 +2018,51 @@ void U_EMRCREATECOLORSPACE_print(char *contents, int recnum, size_t off){ /** \brief Print a pointer to a U_EMR_SETCOLORSPACE 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_EMRSETCOLORSPACE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETCOLORSPACE", "ihCS:", contents, recnum, off); +void U_EMRSETCOLORSPACE_print(char *contents){ + core3_print("U_EMRSETCOLORSPACE", "ihCS:", contents); } // U_EMRDELETECOLORSPACE 101 /** \brief Print a pointer to a U_EMR_DELETECOLORSPACE record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRDELETECOLORSPACE_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRDELETECOLORSPACE", "ihCS:", contents, recnum, off); +void U_EMRDELETECOLORSPACE_print(char *contents){ + core3_print("U_EMRDELETECOLORSPACE", "ihCS:", contents); } // U_EMRGLSRECORD 102 Not implemented -#define U_EMRGLSRECORD_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRGLSRECORD",A,B,C) +#define U_EMRGLSRECORD_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRGLSRECORD",A) // U_EMRGLSBOUNDEDRECORD 103 Not implemented -#define U_EMRGLSBOUNDEDRECORD_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRGLSBOUNDEDRECORD",A,B,C) +#define U_EMRGLSBOUNDEDRECORD_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRGLSBOUNDEDRECORD",A) // U_EMRPIXELFORMAT 104 /** \brief Print a pointer to a U_EMR_PIXELFORMAT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRPIXELFORMAT_print(char *contents, int recnum, size_t off){ - core5_print("U_EMRPIXELFORMAT", contents, recnum, off); - PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(contents+off); +void U_EMRPIXELFORMAT_print(char *contents){ + PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(contents); printf(" Pfd: "); pixelformatdescriptor_print(pEmr->pfd); printf("\n"); } // U_EMRDRAWESCAPE 105 Not implemented -#define U_EMRDRAWESCAPE_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRDRAWESCAPE",A,B,C) +#define U_EMRDRAWESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRDRAWESCAPE",A) // U_EMREXTESCAPE 106 Not implemented -#define U_EMREXTESCAPE_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMREXTESCAPE",A,B,C) +#define U_EMREXTESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMREXTESCAPE",A) // U_EMRUNDEF107 107 Not implemented -#define U_EMRUNDEF107_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF107",A,B,C) +#define U_EMRUNDEF107_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF107",A) // U_EMRSMALLTEXTOUT 108 /** \brief Print a pointer to a U_EMR_SMALLTEXTOUT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSMALLTEXTOUT_print(char *contents, int recnum, size_t off){ +void U_EMRSMALLTEXTOUT_print(char *contents){ int roff; char *string; - core5_print("U_EMRSMALLTEXTOUT", contents, recnum, off); - PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(contents+off); + PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(contents); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cChars: %u\n", pEmr->cChars ); printf(" fuOptions: 0x%8.8X\n", pEmr->fuOptions ); @@ -2345,99 +2071,90 @@ void U_EMRSMALLTEXTOUT_print(char *contents, int recnum, size_t off){ printf(" eyScale: %f\n", pEmr->eyScale ); roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields if(!(pEmr->fuOptions & U_ETO_NO_RECT)){ - printf(" rclBounds: "); rectl_print( *(PU_RECTL) (contents + off + roff)); printf("\n"); + printf(" rclBounds: "); rectl_print( *(PU_RECTL) (contents + roff)); printf("\n"); roff += sizeof(U_RECTL); } if(pEmr->fuOptions & U_ETO_SMALL_CHARS){ - printf(" Text8: <%s>\n",contents+off+roff); + printf(" Text8: <%.*s>\n",pEmr->cChars,contents+roff); /* May not be null terminated */ } else { - string = U_Utf16leToUtf8((uint16_t *)(contents+off+roff), pEmr->cChars, NULL); - printf(" Text16: <%s>\n",contents+off+roff); + string = U_Utf16leToUtf8((uint16_t *)(contents+roff), pEmr->cChars, NULL); + printf(" Text16: <%s>\n",contents+roff); free(string); } } // U_EMRFORCEUFIMAPPING 109 Not implemented -#define U_EMRFORCEUFIMAPPING_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRFORCEUFIMAPPING",A,B,C) +#define U_EMRFORCEUFIMAPPING_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRFORCEUFIMAPPING",A) // U_EMRNAMEDESCAPE 110 Not implemented -#define U_EMRNAMEDESCAPE_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRNAMEDESCAPE",A,B,C) +#define U_EMRNAMEDESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRNAMEDESCAPE",A) // U_EMRCOLORCORRECTPALETTE 111 Not implemented -#define U_EMRCOLORCORRECTPALETTE_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRCOLORCORRECTPALETTE",A,B,C) +#define U_EMRCOLORCORRECTPALETTE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRCOLORCORRECTPALETTE",A) // U_EMRSETICMPROFILEA 112 Not implemented -#define U_EMRSETICMPROFILEA_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEA",A,B,C) +#define U_EMRSETICMPROFILEA_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEA",A) // U_EMRSETICMPROFILEW 113 Not implemented -#define U_EMRSETICMPROFILEW_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEW",A,B,C) +#define U_EMRSETICMPROFILEW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEW",A) // U_EMRALPHABLEND 114 /** \brief Print a pointer to a U_EMR_ALPHABLEND record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRALPHABLEND_print(char *contents, int recnum, size_t off){ - core13_print("U_EMRALPHABLEND", contents, recnum, off); +void U_EMRALPHABLEND_print(char *contents){ + core13_print("U_EMRALPHABLEND", contents); } // U_EMRSETLAYOUT 115 /** \brief Print a pointer to a U_EMR_SETLAYOUT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRSETLAYOUT_print(char *contents, int recnum, size_t off){ - core3_print("U_EMRSETLAYOUT", "iMode:", contents, recnum, off); +void U_EMRSETLAYOUT_print(char *contents){ + core3_print("U_EMRSETLAYOUT", "iMode:", contents); } // U_EMRTRANSPARENTBLT 116 /** \brief Print a pointer to a U_EMR_TRANSPARENTBLT record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRTRANSPARENTBLT_print(char *contents, int recnum, size_t off){ - core13_print("U_EMRTRANSPARENTBLT", contents, recnum, off); +void U_EMRTRANSPARENTBLT_print(char *contents){ + core13_print("U_EMRTRANSPARENTBLT", contents); } // U_EMRUNDEF117 117 Not implemented -#define U_EMRUNDEF117_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF117",A,B,C) +#define U_EMRUNDEF117_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF117",A) // U_EMRGRADIENTFILL 118 /** \brief Print a pointer to a U_EMR_GRADIENTFILL record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRGRADIENTFILL_print(char *contents, int recnum, size_t off){ +void U_EMRGRADIENTFILL_print(char *contents){ int i; - core5_print("U_EMRGRADIENTFILL", contents, recnum, off); - PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents+off); + PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents); printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" nTriVert: %u\n", pEmr->nTriVert ); printf(" nGradObj: %u\n", pEmr->nGradObj ); printf(" ulMode: %u\n", pEmr->ulMode ); - off += sizeof(U_EMRGRADIENTFILL); + contents += sizeof(U_EMRGRADIENTFILL); if(pEmr->nTriVert){ printf(" TriVert: "); - for(i=0; inTriVert; i++, off+=sizeof(U_TRIVERTEX)){ - trivertex_print(*(PU_TRIVERTEX)(contents + off)); + for(i=0; inTriVert; i++, contents+=sizeof(U_TRIVERTEX)){ + trivertex_print(*(PU_TRIVERTEX)(contents)); } printf("\n"); } if(pEmr->nGradObj){ printf(" GradObj: "); if( pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){ - for(i=0; inGradObj; i++, off+=sizeof(U_GRADIENT3)){ - gradient3_print(*(PU_GRADIENT3)(contents + off)); + for(i=0; inGradObj; i++, contents+=sizeof(U_GRADIENT3)){ + gradient3_print(*(PU_GRADIENT3)(contents)); } } else if(pEmr->ulMode == U_GRADIENT_FILL_RECT_H || pEmr->ulMode == U_GRADIENT_FILL_RECT_V){ - for(i=0; inGradObj; i++, off+=sizeof(U_GRADIENT4)){ - gradient4_print(*(PU_GRADIENT4)(contents + off)); + for(i=0; inGradObj; i++, contents+=sizeof(U_GRADIENT4)){ + gradient4_print(*(PU_GRADIENT4)(contents)); } } else { printf("invalid ulMode value!"); } @@ -2446,23 +2163,20 @@ void U_EMRGRADIENTFILL_print(char *contents, int recnum, size_t off){ } // U_EMRSETLINKEDUFIS 119 Not implemented -#define U_EMRSETLINKEDUFIS_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRSETLINKEDUFIS",A,B,C) +#define U_EMRSETLINKEDUFIS_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_SETLINKEDUFIS",A) // U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated) -#define U_EMRSETTEXTJUSTIFICATION_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRSETTEXTJUSTIFICATION",A,B,C) +#define U_EMRSETTEXTJUSTIFICATION_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_SETTEXTJUSTIFICATION",A) // U_EMRCOLORMATCHTOTARGETW 121 Not implemented -#define U_EMRCOLORMATCHTOTARGETW_print(A,B,C) U_EMRNOTIMPLEMENTED_print("U_EMRCOLORMATCHTOTARGETW",A,B,C) +#define U_EMRCOLORMATCHTOTARGETW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_COLORMATCHTOTARGETW",A) // U_EMRCREATECOLORSPACEW 122 /** \brief Print a pointer to a U_EMR_CREATECOLORSPACEW record. \param contents pointer to a buffer holding all EMR records - \param recnum number of this record in contents - \param off offset to this record in contents */ -void U_EMRCREATECOLORSPACEW_print(char *contents, int recnum, size_t off){ +void U_EMRCREATECOLORSPACEW_print(char *contents){ int i; - core5_print("U_EMRCREATECOLORSPACEW", contents, recnum, off); - PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents+off); + PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents); printf(" ihCS: %u\n", pEmr->ihCS ); printf(" ColorSpace: "); logcolorspacew_print(pEmr->lcs); printf("\n"); printf(" dwFlags: %u\n", pEmr->dwFlags ); @@ -2478,141 +2192,153 @@ void U_EMRCREATECOLORSPACEW_print(char *contents, int recnum, size_t off){ /** \brief Print any record in an emf - \returns 1 for a normal record, 0 for EMREOF + \returns record length for a normal record, 0 for EMREOF, -1 for a bad record \param contents pointer to a buffer holding all EMR records + \param blimit pointer to the byte after the last byte in the buffer holding all EMR records \param recnum number of this record in contents \param off offset to this record in contents */ -int U_emf_onerec_print(char *contents, int recnum, size_t off){ +int U_emf_onerec_print(char *contents, char *blimit, int recnum, size_t off){ PU_ENHMETARECORD lpEMFR = (PU_ENHMETARECORD)(contents + off); - int regular=1; + int size; + + printf("%-30srecord:%5d type:%3d offset:%8d size:%8d\n",U_emr_names(lpEMFR->iType),recnum,lpEMFR->iType,(int) off,lpEMFR->nSize); + size = lpEMFR->nSize; + contents += off; + + /* Check that the record size is OK, abort if not. + Pointer math might wrap, so check both sides of the range */ + if(size < sizeof(U_EMR) || + contents + size - 1 >= blimit || + contents + size - 1 < contents)return(-1); + switch (lpEMFR->iType) { - case U_EMR_HEADER: U_EMRHEADER_print(contents, recnum, off); break; - case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_print(contents, recnum, off); break; - case U_EMR_POLYGON: U_EMRPOLYGON_print(contents, recnum, off); break; - case U_EMR_POLYLINE: U_EMRPOLYLINE_print(contents, recnum, off); break; - case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_print(contents, recnum, off); break; - case U_EMR_POLYLINETO: U_EMRPOLYLINETO_print(contents, recnum, off); break; - case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_print(contents, recnum, off); break; - case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_print(contents, recnum, off); break; - case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_print(contents, recnum, off); break; - case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_print(contents, recnum, off); break; - case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_print(contents, recnum, off); break; - case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_print(contents, recnum, off); break; - case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_print(contents, recnum, off); break; - case U_EMR_EOF: U_EMREOF_print(contents, recnum, off); regular=0; break; - case U_EMR_SETPIXELV: U_EMRSETPIXELV_print(contents, recnum, off); break; - case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_print(contents, recnum, off); break; - case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_print(contents, recnum, off); break; - case U_EMR_SETBKMODE: U_EMRSETBKMODE_print(contents, recnum, off); break; - case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_print(contents, recnum, off); break; - case U_EMR_SETROP2: U_EMRSETROP2_print(contents, recnum, off); break; - case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_print(contents, recnum, off); break; - case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_print(contents, recnum, off); break; - case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_print(contents, recnum, off); break; - case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_print(contents, recnum, off); break; - case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_print(contents, recnum, off); break; - case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_print(contents, recnum, off); break; - case U_EMR_MOVETOEX: U_EMRMOVETOEX_print(contents, recnum, off); break; - case U_EMR_SETMETARGN: U_EMRSETMETARGN_print(contents, recnum, off); break; - case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_print(contents, recnum, off); break; - case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_print(contents, recnum, off); break; - case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_print(contents, recnum, off); break; - case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_print(contents, recnum, off); break; - case U_EMR_SAVEDC: U_EMRSAVEDC_print(contents, recnum, off); break; - case U_EMR_RESTOREDC: U_EMRRESTOREDC_print(contents, recnum, off); break; - case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_print(contents, recnum, off); break; - case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_print(contents, recnum, off); break; - case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_print(contents, recnum, off); break; - case U_EMR_CREATEPEN: U_EMRCREATEPEN_print(contents, recnum, off); break; - case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_print(contents, recnum, off); break; - case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_print(contents, recnum, off); break; - case U_EMR_ANGLEARC: U_EMRANGLEARC_print(contents, recnum, off); break; - case U_EMR_ELLIPSE: U_EMRELLIPSE_print(contents, recnum, off); break; - case U_EMR_RECTANGLE: U_EMRRECTANGLE_print(contents, recnum, off); break; - case U_EMR_ROUNDRECT: U_EMRROUNDRECT_print(contents, recnum, off); break; - case U_EMR_ARC: U_EMRARC_print(contents, recnum, off); break; - case U_EMR_CHORD: U_EMRCHORD_print(contents, recnum, off); break; - case U_EMR_PIE: U_EMRPIE_print(contents, recnum, off); break; - case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_print(contents, recnum, off); break; - case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_print(contents, recnum, off); break; - case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_print(contents, recnum, off); break; - case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_print(contents, recnum, off); break; - case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_print(contents, recnum, off); break; - case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_print(contents, recnum, off); break; - case U_EMR_LINETO: U_EMRLINETO_print(contents, recnum, off); break; - case U_EMR_ARCTO: U_EMRARCTO_print(contents, recnum, off); break; - case U_EMR_POLYDRAW: U_EMRPOLYDRAW_print(contents, recnum, off); break; - case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_print(contents, recnum, off); break; - case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_print(contents, recnum, off); break; - case U_EMR_BEGINPATH: U_EMRBEGINPATH_print(contents, recnum, off); break; - case U_EMR_ENDPATH: U_EMRENDPATH_print(contents, recnum, off); break; - case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_print(contents, recnum, off); break; - case U_EMR_FILLPATH: U_EMRFILLPATH_print(contents, recnum, off); break; - case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_print(contents, recnum, off); break; - case U_EMR_STROKEPATH: U_EMRSTROKEPATH_print(contents, recnum, off); break; - case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_print(contents, recnum, off); break; - case U_EMR_WIDENPATH: U_EMRWIDENPATH_print(contents, recnum, off); break; - case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_print(contents, recnum, off); break; - case U_EMR_ABORTPATH: U_EMRABORTPATH_print(contents, recnum, off); break; - case U_EMR_UNDEF69: U_EMRUNDEF69_print(contents, recnum, off); break; - case U_EMR_COMMENT: U_EMRCOMMENT_print(contents, recnum, off); break; - case U_EMR_FILLRGN: U_EMRFILLRGN_print(contents, recnum, off); break; - case U_EMR_FRAMERGN: U_EMRFRAMERGN_print(contents, recnum, off); break; - case U_EMR_INVERTRGN: U_EMRINVERTRGN_print(contents, recnum, off); break; - case U_EMR_PAINTRGN: U_EMRPAINTRGN_print(contents, recnum, off); break; - case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_print(contents, recnum, off); break; - case U_EMR_BITBLT: U_EMRBITBLT_print(contents, recnum, off); break; - case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_print(contents, recnum, off); break; - case U_EMR_MASKBLT: U_EMRMASKBLT_print(contents, recnum, off); break; - case U_EMR_PLGBLT: U_EMRPLGBLT_print(contents, recnum, off); break; - case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_print(contents, recnum, off); break; - case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_print(contents, recnum, off); break; - case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_print(contents, recnum, off); break; - case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_print(contents, recnum, off); break; - case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_print(contents, recnum, off); break; - case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_print(contents, recnum, off); break; - case U_EMR_POLYGON16: U_EMRPOLYGON16_print(contents, recnum, off); break; - case U_EMR_POLYLINE16: U_EMRPOLYLINE16_print(contents, recnum, off); break; - case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_print(contents, recnum, off); break; - case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_print(contents, recnum, off); break; - case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_print(contents, recnum, off); break; - case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_print(contents, recnum, off); break; - case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_print(contents, recnum, off); break; - case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_print(contents, recnum, off); break; - case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_print(contents, recnum, off); break; - case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_print(contents, recnum, off); break; - case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_print(contents, recnum, off); break; - case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_print(contents, recnum, off); break; - case U_EMR_SETICMMODE: U_EMRSETICMMODE_print(contents, recnum, off); break; - case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_print(contents, recnum, off); break; - case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_print(contents, recnum, off); break; - case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_print(contents, recnum, off); break; - case U_EMR_GLSRECORD: U_EMRGLSRECORD_print(contents, recnum, off); break; - case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_print(contents, recnum, off); break; - case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_print(contents, recnum, off); break; - case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_print(contents, recnum, off); break; - case U_EMR_EXTESCAPE: U_EMREXTESCAPE_print(contents, recnum, off); break; - case U_EMR_UNDEF107: U_EMRUNDEF107_print(contents, recnum, off); break; - case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_print(contents, recnum, off); break; - case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_print(contents, recnum, off); break; - case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_print(contents, recnum, off); break; - case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_print(contents, recnum, off); break; - case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_print(contents, recnum, off); break; - case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_print(contents, recnum, off); break; - case U_EMR_ALPHABLEND: U_EMRALPHABLEND_print(contents, recnum, off); break; - case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_print(contents, recnum, off); break; - case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_print(contents, recnum, off); break; - case U_EMR_UNDEF117: U_EMRUNDEF117_print(contents, recnum, off); break; - case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_print(contents, recnum, off); break; - case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_print(contents, recnum, off); break; - case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_print(contents, recnum, off); break; - case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_print(contents, recnum, off); break; - case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_print(contents, recnum, off); break; - default: U_EMRNOTIMPLEMENTED_print("?",contents, recnum, off); break; + case U_EMR_HEADER: U_EMRHEADER_print(contents); break; + case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_print(contents); break; + case U_EMR_POLYGON: U_EMRPOLYGON_print(contents); break; + case U_EMR_POLYLINE: U_EMRPOLYLINE_print(contents); break; + case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_print(contents); break; + case U_EMR_POLYLINETO: U_EMRPOLYLINETO_print(contents); break; + case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_print(contents); break; + case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_print(contents); break; + case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_print(contents); break; + case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_print(contents); break; + case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_print(contents); break; + case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_print(contents); break; + case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_print(contents); break; + case U_EMR_EOF: U_EMREOF_print(contents); size=0; break; + case U_EMR_SETPIXELV: U_EMRSETPIXELV_print(contents); break; + case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_print(contents); break; + case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_print(contents); break; + case U_EMR_SETBKMODE: U_EMRSETBKMODE_print(contents); break; + case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_print(contents); break; + case U_EMR_SETROP2: U_EMRSETROP2_print(contents); break; + case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_print(contents); break; + case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_print(contents); break; + case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_print(contents); break; + case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_print(contents); break; + case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_print(contents); break; + case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_print(contents); break; + case U_EMR_MOVETOEX: U_EMRMOVETOEX_print(contents); break; + case U_EMR_SETMETARGN: U_EMRSETMETARGN_print(contents); break; + case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_print(contents); break; + case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_print(contents); break; + case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_print(contents); break; + case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_print(contents); break; + case U_EMR_SAVEDC: U_EMRSAVEDC_print(contents); break; + case U_EMR_RESTOREDC: U_EMRRESTOREDC_print(contents); break; + case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_print(contents); break; + case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_print(contents); break; + case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_print(contents); break; + case U_EMR_CREATEPEN: U_EMRCREATEPEN_print(contents); break; + case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_print(contents); break; + case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_print(contents); break; + case U_EMR_ANGLEARC: U_EMRANGLEARC_print(contents); break; + case U_EMR_ELLIPSE: U_EMRELLIPSE_print(contents); break; + case U_EMR_RECTANGLE: U_EMRRECTANGLE_print(contents); break; + case U_EMR_ROUNDRECT: U_EMRROUNDRECT_print(contents); break; + case U_EMR_ARC: U_EMRARC_print(contents); break; + case U_EMR_CHORD: U_EMRCHORD_print(contents); break; + case U_EMR_PIE: U_EMRPIE_print(contents); break; + case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_print(contents); break; + case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_print(contents); break; + case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_print(contents); break; + case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_print(contents); break; + case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_print(contents); break; + case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_print(contents); break; + case U_EMR_LINETO: U_EMRLINETO_print(contents); break; + case U_EMR_ARCTO: U_EMRARCTO_print(contents); break; + case U_EMR_POLYDRAW: U_EMRPOLYDRAW_print(contents); break; + case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_print(contents); break; + case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_print(contents); break; + case U_EMR_BEGINPATH: U_EMRBEGINPATH_print(contents); break; + case U_EMR_ENDPATH: U_EMRENDPATH_print(contents); break; + case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_print(contents); break; + case U_EMR_FILLPATH: U_EMRFILLPATH_print(contents); break; + case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_print(contents); break; + case U_EMR_STROKEPATH: U_EMRSTROKEPATH_print(contents); break; + case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_print(contents); break; + case U_EMR_WIDENPATH: U_EMRWIDENPATH_print(contents); break; + case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_print(contents); break; + case U_EMR_ABORTPATH: U_EMRABORTPATH_print(contents); break; + case U_EMR_UNDEF69: U_EMRUNDEF69_print(contents); break; + case U_EMR_COMMENT: U_EMRCOMMENT_print(contents); break; + case U_EMR_FILLRGN: U_EMRFILLRGN_print(contents); break; + case U_EMR_FRAMERGN: U_EMRFRAMERGN_print(contents); break; + case U_EMR_INVERTRGN: U_EMRINVERTRGN_print(contents); break; + case U_EMR_PAINTRGN: U_EMRPAINTRGN_print(contents); break; + case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_print(contents); break; + case U_EMR_BITBLT: U_EMRBITBLT_print(contents); break; + case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_print(contents); break; + case U_EMR_MASKBLT: U_EMRMASKBLT_print(contents); break; + case U_EMR_PLGBLT: U_EMRPLGBLT_print(contents); break; + case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_print(contents); break; + case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_print(contents); break; + case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_print(contents); break; + case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_print(contents); break; + case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_print(contents); break; + case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_print(contents); break; + case U_EMR_POLYGON16: U_EMRPOLYGON16_print(contents); break; + case U_EMR_POLYLINE16: U_EMRPOLYLINE16_print(contents); break; + case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_print(contents); break; + case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_print(contents); break; + case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_print(contents); break; + case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_print(contents); break; + case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_print(contents); break; + case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_print(contents); break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_print(contents); break; + case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_print(contents); break; + case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_print(contents); break; + case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_print(contents); break; + case U_EMR_SETICMMODE: U_EMRSETICMMODE_print(contents); break; + case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_print(contents); break; + case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_print(contents); break; + case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_print(contents); break; + case U_EMR_GLSRECORD: U_EMRGLSRECORD_print(contents); break; + case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_print(contents); break; + case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_print(contents); break; + case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_print(contents); break; + case U_EMR_EXTESCAPE: U_EMREXTESCAPE_print(contents); break; + case U_EMR_UNDEF107: U_EMRUNDEF107_print(contents); break; + case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_print(contents); break; + case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_print(contents); break; + case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_print(contents); break; + case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_print(contents); break; + case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_print(contents); break; + case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_print(contents); break; + case U_EMR_ALPHABLEND: U_EMRALPHABLEND_print(contents); break; + case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_print(contents); break; + case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_print(contents); break; + case U_EMR_UNDEF117: U_EMRUNDEF117_print(contents); break; + case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_print(contents); break; + case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_print(contents); break; + case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_print(contents); break; + case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_print(contents); break; + case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_print(contents); break; + default: U_EMRNOTIMPLEMENTED_print("?",contents); break; } //end of switch - return(regular); + return(size); } diff --git a/src/extension/internal/uemf_print.h b/src/extension/internal/uemf_print.h index 41158a6cb..6354e49d9 100644 --- a/src/extension/internal/uemf_print.h +++ b/src/extension/internal/uemf_print.h @@ -4,11 +4,11 @@ /* File: uemf_print.h -Version: 0.0.3 -Date: 24-JUL-2012 +Version: 0.0.4 +Date: 13-JAN-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UEMF_PRINT_ @@ -18,7 +18,42 @@ Copyright: 2012 David Mathog and California Institute of Technology (Caltech) extern "C" { #endif -// prototypes +/* prototypes for objects used in EMR records */ +void hexbytes_print(uint8_t *buf,unsigned int num); +void colorref_print(U_COLORREF color); +void rgbquad_print(U_RGBQUAD color); +void rectl_print(U_RECTL rect); +void sizel_print(U_SIZEL sz); +void pointl_print(U_POINTL pt); +void point16_print(U_POINT16 pt); +void lcs_gamma_print(U_LCS_GAMMA lg); +void lcs_gammargb_print(U_LCS_GAMMARGB lgr); +void trivertex_print(U_TRIVERTEX tv); +void gradient3_print(U_GRADIENT3 g3); +void gradient4_print(U_GRADIENT4 g4); +void logbrush_print(U_LOGBRUSH lb); +void xform_print(U_XFORM xform); +void ciexyz_print(U_CIEXYZ ciexyz); +void ciexyztriple_print(U_CIEXYZTRIPLE cie3); +void logcolorspacea_print(U_LOGCOLORSPACEA lcsa); +void logcolorspacew_print(U_LOGCOLORSPACEW lcsa); +void panose_print(U_PANOSE panose); +void logfont_print(U_LOGFONT lf); +void logfont_panose_print(U_LOGFONT_PANOSE lfp); +void bitmapinfoheader_print(char *Bmih); +void bitmapinfo_print(char *Bmi); +void blend_print(U_BLEND blend); +void extlogpen_print(PU_EXTLOGPEN elp); +void logpen_print(U_LOGPEN lp); +void logpltntry_print(U_LOGPLTNTRY lpny); +void logpalette_print(PU_LOGPALETTE lp); +void rgndataheader_print(U_RGNDATAHEADER rdh); +void rgndata_print(PU_RGNDATA rd); +void coloradjustment_print(U_COLORADJUSTMENT ca); +void pixelformatdescriptor_print(U_PIXELFORMATDESCRIPTOR pfd); +void emrtext_print(char *emt, 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); @@ -125,7 +160,7 @@ 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, int recnum, int off); +int U_emf_onerec_print(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 028dcb966..b9f677abe 100644 --- a/src/extension/internal/uemf_utf.c +++ b/src/extension/internal/uemf_utf.c @@ -10,11 +10,11 @@ /* File: uemf_utf.c -Version: 0.0.1 -Date: 04-DEC-2012 +Version: 0.0.3 +Date: 24-JAN-2013 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -32,9 +32,14 @@ extern "C" { #include // for U_ROUND() #include "uemf_utf.h" +/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed +to be used in end user code. */ + +void U_swap2(void *ul, unsigned int count); + /* ******************************************************************************************** */ -//! @cond +/** \cond */ /* iconv() has a funny cast on some older systems, on most recent ones it is just char **. This tries to work around the issue. If you build this on another funky system this code may need to be modified, or define ICONV_CAST @@ -46,7 +51,7 @@ extern "C" { #if !defined(ICONV_CAST) #define ICONV_CAST (char **) #endif //ICONV_CAST -//! @endcond +/** \endcond */ /* ********************************************************************************************** These functions are used for development and debugging and should be be includied in production code. @@ -404,6 +409,69 @@ uint16_t U_Utf16le(const uint16_t src){ return(dst); } +/** + \brief Convert a UTF8 string to a Latin1 string. + \return pointer to new string or NULL if it fails + \param src Latin1 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator + + + WMF uses latin1, others UTF-8, only some utf-8 can be converted to latin1. + +*/ +char *U_Utf8ToLatin1( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, length in BYTES + dstlen = (1 + srclen); // This should always work but might waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("LATIN1//TRANSLIT", "UTF-8"); // translate what can be, fill in with something close for the rest + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + return((uint32_t *) dst2); +} + +/** + \brief Convert a Latin1 string to a UTF8 string. + \return pointer to new string or NULL if it fails + \param src Latin1 string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator + + + WMF uses latin1, others UTF-8, all Latin1 should be able to convert to utf-8. + +*/ +char *U_Latin1ToUtf8( + const char *src, + size_t max, + size_t *len + ){ + char *dst,*dst2; + size_t srclen,dstlen,status; + if(max){ srclen = max; } + else { srclen = strlen(src)+1; } // include terminator, will waste some space + dst2 = dst = calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("UTF-8", "LATIN1"); // everything should translate + if ( conv == (iconv_t) -1)return(NULL); + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status == (size_t) -1)return(NULL); + if(len)*len=strlen(dst2); + return((uint32_t *) dst2); +} + /** \brief Single character replacement in a UTF-16LE string. diff --git a/src/extension/internal/uemf_utf.h b/src/extension/internal/uemf_utf.h index 24ad37f36..20c7bf945 100644 --- a/src/extension/internal/uemf_utf.h +++ b/src/extension/internal/uemf_utf.h @@ -21,6 +21,7 @@ extern "C" { #include #include +#include "uemf_endian.h" void wchar8show(const char *src); void wchar16show(const uint16_t *src); @@ -38,6 +39,8 @@ 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_Utf8ToLatin1( const char *src, size_t max, size_t *len ); +char *U_Latin1ToUtf8( const char *src, size_t max, size_t *len ); uint16_t U_Utf16le(const uint16_t src); int U_Utf16leEdit( uint16_t *src, uint16_t find, uint16_t replace ); char *U_strdup(const char *s); -- cgit v1.2.3 From e298aeb969151e2a523d3aaef737ac04b6e5b0e8 Mon Sep 17 00:00:00 2001 From: David Mathog <> Date: Fri, 8 Mar 2013 09:27:50 +0100 Subject: 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) --- src/extension/CMakeLists.txt | 12 +- src/extension/init.cpp | 4 + src/extension/internal/Makefile_insert | 8 + src/extension/internal/emf-inout.cpp | 271 +- src/extension/internal/emf-inout.h | 145 + src/extension/internal/emf-print.cpp | 111 +- src/extension/internal/emf-print.h | 35 +- src/extension/internal/text_reassemble.c | 20 +- src/extension/internal/text_reassemble.h | 17 +- src/extension/internal/uemf.c | 281 +- src/extension/internal/uemf.h | 58 +- src/extension/internal/uemf_endian.c | 25 +- src/extension/internal/uemf_print.c | 283 +- src/extension/internal/uemf_print.h | 230 +- src/extension/internal/uemf_utf.c | 32 +- src/extension/internal/uemf_utf.h | 1 + src/extension/internal/uwmf.c | 6869 ++++++++++++++++++++++++++++++ src/extension/internal/uwmf.h | 2492 +++++++++++ src/extension/internal/uwmf_endian.c | 1772 ++++++++ src/extension/internal/uwmf_endian.h | 39 + src/extension/internal/uwmf_print.c | 1616 +++++++ src/extension/internal/uwmf_print.h | 48 + src/extension/internal/wmf-inout.cpp | 3051 +++++++++++++ src/extension/internal/wmf-inout.h | 205 + src/extension/internal/wmf-print.cpp | 1953 +++++++++ src/extension/internal/wmf-print.h | 144 + src/helper/geom.cpp | 310 ++ src/helper/geom.h | 5 + 28 files changed, 19365 insertions(+), 672 deletions(-) create mode 100644 src/extension/internal/uwmf.c create mode 100644 src/extension/internal/uwmf.h create mode 100644 src/extension/internal/uwmf_endian.c create mode 100644 src/extension/internal/uwmf_endian.h create mode 100644 src/extension/internal/uwmf_print.c create mode 100644 src/extension/internal/uwmf_print.h create mode 100644 src/extension/internal/wmf-inout.cpp create mode 100644 src/extension/internal/wmf-inout.h create mode 100644 src/extension/internal/wmf-print.cpp create mode 100644 src/extension/internal/wmf-print.h (limited to 'src') 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 //This must precede text_reassemble.h or it blows up in pngconf.h when compiling +#include +#include +#include +#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 //This must precede text_reassemble.h or it blows up in pngconf.h when compiling -#include -#include -#include #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 */ -/* 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 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; ihatches.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 . */ -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; iimages.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; icptl; ) { tmp_str << "\n\tC "; for (j=0; j<3 && icptl; 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; nnPolys && icptl; 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; jaPolyCounts[n] && icptl; 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 << "\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; icpts;) { tmp_path << "\n\tC "; for (j=0; j<3 && icpts; 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; icpts;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; nnPolys && icpts; 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; jaPolyCounts[n] && icpts; 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 #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 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 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;ivector.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 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 @@ -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 #include // for INT_MAX, INT_MIN #include // for U_ROUND() +#include /* for offsetof() macro */ #if 0 #include //Not actually used, looking for collisions #include //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,20 +559,45 @@ 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. @@ -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; @@ -762,6 +791,60 @@ int RGBA_to_DIB( return(0); } +/** + \brief Get the actual number of colors in the color table from the BitMapInfoHeader. + BitmapInfoHeader may list 0 for some types which implies the maximum value. + If the image is big enough, that is set by the bit count, as in 256 for an 8 + bit image. + If the image is smaller it is set by width * height. + Note, this may be called by WMF code, so it is not safe to assume the data is aligned. + + \return Number of entries in the color table. + \param Bmih char * pointer to the U_BITMAPINFOHEADER +*/ +int get_real_color_count( + const char *Bmih + ){ + int Colors, BitCount, Width, Height; + uint32_t utmp4; + uint16_t utmp2; + int32_t tmp4; + char *cBmih = (char *) Bmih; + memcpy(&utmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); Colors = utmp4; + memcpy(&utmp2, cBmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2); BitCount = utmp2; + memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biWidth), 4); Width = tmp4; + memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); Height = tmp4; + return(get_real_color_icount(Colors, BitCount, Width, Height)); +} + +/** + \brief Get the actual number of colors in the color table from the ClrUsed, BitCount, Width, and Height. + BitmapInfoHeader may list 0 for some types which implies the maximum value. + If the image is big enough, that is set by the bit count, as in 256 for an 8 + bit image. + If the image is smaller it is set by width * height. + + \return Number of entries in the color table. + \param PU_BITMAPINFOHEADER pointer to to the U_BITMAPINFOHEADER +*/ +int get_real_color_icount( + int Colors, + int BitCount, + int Width, + int Height + ){ + int area = Width * Height; + if(area < 0){ area = -area; } /* Height might be negative */ + if(Colors == 0){ + if( BitCount == U_BCBM_MONOCHROME){ Colors = 2; } + else if(BitCount == U_BCBM_COLOR4 ){ Colors = 16; } + else if(BitCount == U_BCBM_COLOR8 ){ Colors = 256; } + if(Colors > area){ Colors = area; } + } + return(Colors); +} + + /** \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA() @@ -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,28 +1384,10 @@ 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. @@ -1335,7 +1395,7 @@ int htable_mftype( \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; irclBounds); 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 @@ -391,6 +391,34 @@ char *U_Utf16leToUtf8( return(ret); } +/** + \brief Convert a UTF16LE string to a LATIN1 string. + \return pointer to new UTF8 string or NULL if it fails + \param src UTF16LE string to convert + \param max number of characters to convert, if 0, until terminator + \param len number of characters in new string, NOT including terminator +*/ +char *U_Utf16leToLatin1( + const uint16_t *src, + size_t max, + size_t *len + ){ + char *dst, *dst2; + char *ret=NULL; + size_t srclen,dstlen,status; + if(max){ srclen = 2*max; } + else { srclen = 2*(1 +wchar16len(src)); } //include terminator, length in BYTES + dstlen = 1 + srclen; // this will always work as latin1 is always 1 byte/character + ret = dst2 = dst = (char *) calloc(dstlen,1); + if(!dst)return(NULL); + iconv_t conv = iconv_open("LATIN1//TRANSLIT", "UTF-16LE"); // translate what can be, fill in with something close for the rest + status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); + iconv_close(conv); + if(status != (size_t) -1){ + if(len)*len=strlen(dst2); + } + return(ret); +} /** \brief Put a single 16 bit character into UTF-16LE form. @@ -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 +#include +#include /* for offsetof() */ +#include +#include +#include +#include +#include +#include // for INT_MAX, INT_MIN +#include // for U_ROUND() +#if 0 +#include //Not actually used, looking for collisions +#include //Not actually used, looking for collisions +#include //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_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_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; icount); + 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; irop3w, &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 +#include +#include +#include +#include +#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 +#include +#include /* for offsetof() */ +#include +#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