Code

patch for emf export on win32
authorbuliabyak <buliabyak@users.sourceforge.net>
Mon, 13 Nov 2006 22:05:28 +0000 (22:05 +0000)
committerbuliabyak <buliabyak@users.sourceforge.net>
Mon, 13 Nov 2006 22:05:28 +0000 (22:05 +0000)
src/extension/init.cpp
src/extension/internal/Makefile_insert
src/extension/internal/emf-win32-inout.cpp [new file with mode: 0644]
src/extension/internal/emf-win32-inout.h [new file with mode: 0644]
src/extension/internal/emf-win32-print.cpp [new file with mode: 0644]
src/extension/internal/emf-win32-print.h [new file with mode: 0644]

index a10f21913dbe561a58b952106da95c11a498f5e5..ddbf308eecef18290b2a95b59d10d9fefa570eef 100644 (file)
@@ -33,6 +33,8 @@
 #endif
 #ifdef WIN32
 # include "internal/win32.h"
+# include "internal/emf-win32-inout.h"
+# include "internal/emf-win32-print.h"
 #endif
 #include "internal/ps-out.h"
 #ifdef HAVE_CAIRO_PDF
@@ -125,6 +127,8 @@ init()
 #endif
 #ifdef WIN32
     Internal::PrintWin32::init();
+    Internal::PrintEmfWin32::init();
+    Internal::EmfWin32::init();
 #endif
     Internal::PovOutput::init();
     Internal::OdfOutput::init();
index eff097c95abd6bf65180979526e01896811699ef..c89c1e77f2a156e3522fbf3a2e0797df95443d17 100644 (file)
@@ -11,6 +11,16 @@ extension_internal_gnome_print_sources =     \
        extension/internal/gnome.h
 endif
 
+if WIN32
+extension_internal_win32_sources =     \
+       extension/internal/win32.cpp    \
+       extension/internal/win32.h      \
+       extension/internal/emf-win32-inout.cpp  \
+       extension/internal/emf-win32-inout.h    \
+       extension/internal/emf-win32-print.cpp  \
+       extension/internal/emf-win32-print.h
+endif
+
 extension_internal_libinternal_a_SOURCES =     \
        extension/internal/bluredge.h   \
        extension/internal/bluredge.cpp \
@@ -53,5 +63,5 @@ extension_internal_libinternal_a_SOURCES =    \
        extension/internal/latex-pstricks-out.h \
        extension/internal/wpg-input.cpp        \
        extension/internal/wpg-input.h  \
-       $(extension_internal_gnome_print_sources)
-
+       $(extension_internal_gnome_print_sources) \
+       $(extension_internal_win32_sources)
diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp
new file mode 100644 (file)
index 0000000..a39d1fb
--- /dev/null
@@ -0,0 +1,1430 @@
+/** \file\r
+ * Enhanced Metafile Input and Output.\r
+ */\r
+/*\r
+ * Authors:\r
+ *   Ulf Erikson <ulferikson@users.sf.net>\r
+ *\r
+ * Copyright (C) 2006 Authors\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+/*\r
+ * References:\r
+ *  - How to Create & Play Enhanced Metafiles in Win32\r
+ *      http://support.microsoft.com/kb/q145999/\r
+ *  - INFO: Windows Metafile Functions & Aldus Placeable Metafiles\r
+ *      http://support.microsoft.com/kb/q66949/\r
+ *  - Metafile Functions\r
+ *      http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp\r
+ *  - Metafile Structures\r
+ *      http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp\r
+ */\r
+\r
+#ifdef WIN32\r
+\r
+#ifdef HAVE_CONFIG_H\r
+# include "config.h"\r
+#endif\r
+\r
+#include "win32.h"\r
+#include "emf-win32-print.h"\r
+#include "emf-win32-inout.h"\r
+#include "inkscape.h"\r
+#include "sp-path.h"\r
+#include "style.h"\r
+#include "color.h"\r
+#include "display/curve.h"\r
+#include "libnr/n-art-bpath.h"\r
+#include "libnr/nr-point-matrix-ops.h"\r
+#include "gtk/gtk.h"\r
+#include "print.h"\r
+#include "glibmm/i18n.h"\r
+#include "extension/extension.h"\r
+#include "extension/system.h"\r
+#include "extension/print.h"\r
+#include "extension/db.h"\r
+#include "extension/output.h"\r
+#include "document.h"\r
+#include "display/nr-arena.h"\r
+#include "display/nr-arena-item.h"\r
+\r
+#include "libnr/nr-rect.h"\r
+#include "libnr/nr-matrix.h"\r
+#include "libnr/nr-pixblock.h"\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include <vector>\r
+#include <string>\r
+\r
+#include "io/sys.h"\r
+\r
+#include "unit-constants.h"\r
+\r
+#include "clear-n_.h"\r
+\r
+\r
+#define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32"\r
+\r
+#ifndef PS_JOIN_MASK\r
+#define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND)\r
+#endif\r
+\r
+\r
+namespace Inkscape {\r
+namespace Extension {\r
+namespace Internal {\r
+\r
+\r
+EmfWin32::EmfWin32 (void) // The null constructor\r
+{\r
+    return;\r
+}\r
+\r
+\r
+EmfWin32::~EmfWin32 (void) //The destructor\r
+{\r
+    return;\r
+}\r
+\r
+\r
+bool\r
+EmfWin32::check (Inkscape::Extension::Extension * module)\r
+{\r
+    if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32))\r
+        return FALSE;\r
+    return TRUE;\r
+}\r
+\r
+\r
+static void\r
+emf_print_document_to_file(SPDocument *doc, gchar const *filename)\r
+{\r
+    Inkscape::Extension::Print *mod;\r
+    SPPrintContext context;\r
+    gchar const *oldconst;\r
+    gchar *oldoutput;\r
+    unsigned int ret;\r
+\r
+    sp_document_ensure_up_to_date(doc);\r
+\r
+    mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32);\r
+    oldconst = mod->get_param_string("destination");\r
+    oldoutput = g_strdup(oldconst);\r
+    mod->set_param_string("destination", (gchar *)filename);\r
+\r
+/* Start */\r
+    context.module = mod;\r
+    /* fixme: This has to go into module constructor somehow */\r
+    /* Create new arena */\r
+    mod->base = SP_ITEM(sp_document_root(doc));\r
+    mod->arena = NRArena::create();\r
+    mod->dkey = sp_item_display_key_new(1);\r
+    mod->root = sp_item_invoke_show(mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY);\r
+    /* Print document */\r
+    ret = mod->begin(doc);\r
+    if (ret) {\r
+        throw Inkscape::Extension::Output::save_failed();\r
+    }\r
+    sp_item_invoke_print(mod->base, &context);\r
+    ret = mod->finish();\r
+    /* Release arena */\r
+    sp_item_invoke_hide(mod->base, mod->dkey);\r
+    mod->base = NULL;\r
+    nr_arena_item_unref(mod->root);\r
+    mod->root = NULL;\r
+    nr_object_unref((NRObject *) mod->arena);\r
+    mod->arena = NULL;\r
+/* end */\r
+\r
+    mod->set_param_string("destination", oldoutput);\r
+    g_free(oldoutput);\r
+\r
+    return;\r
+}\r
+\r
+\r
+void\r
+EmfWin32::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gchar *uri)\r
+{\r
+    Inkscape::Extension::Extension * ext;\r
+\r
+    ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32);\r
+    if (ext == NULL)\r
+        return;\r
+\r
+//    bool old_textToPath  = ext->get_param_bool("textToPath");\r
+//    bool new_val         = mod->get_param_bool("textToPath");\r
+//    ext->set_param_bool("textToPath", new_val);\r
+\r
+    gchar * final_name;\r
+    final_name = g_strdup_printf("%s", uri);\r
+    emf_print_document_to_file(doc, final_name);\r
+    g_free(final_name);\r
+\r
+//    ext->set_param_bool("textToPath", old_textToPath);\r
+\r
+    return;\r
+}\r
+\r
+\r
+\r
+typedef struct {\r
+    int type;\r
+    ENHMETARECORD *lpEMFR;\r
+} EMF_OBJECT, *PEMF_OBJECT;\r
+\r
+typedef struct emf_callback_data {\r
+    Glib::ustring *outsvg;\r
+    Glib::ustring *path;\r
+    struct SPStyle style;\r
+    bool stroke_set;\r
+    bool fill_set;\r
+    double xDPI, yDPI;\r
+\r
+    SIZEL sizeWnd;\r
+    SIZEL sizeView;\r
+    float PixelsX;\r
+    float PixelsY;\r
+    float MMX;\r
+    float MMY;\r
+    float dwInchesX;\r
+    float dwInchesY;\r
+    POINTL winorg;\r
+    POINTL vieworg;\r
+    double ScaleX, ScaleY;\r
+\r
+    int n_obj;\r
+    PEMF_OBJECT emf_obj;\r
+} EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;\r
+\r
+\r
+static void\r
+output_style(PEMF_CALLBACK_DATA d, int iType)\r
+{\r
+    SVGOStringStream tmp_style;\r
+    char tmp[1024] = {0};\r
+\r
+    *(d->outsvg) += "\n\tstyle=\"";\r
+    if (iType == EMR_STROKEPATH || !d->fill_set) {\r
+        tmp_style << "fill:none;";\r
+    } else {\r
+        float rgb[3];\r
+        sp_color_get_rgb_floatv( &(d->style.fill.value.color), rgb );\r
+        snprintf(tmp, 1023,\r
+                 "fill:#%02x%02x%02x;",\r
+                 SP_COLOR_F_TO_U(rgb[0]),\r
+                 SP_COLOR_F_TO_U(rgb[1]),\r
+                 SP_COLOR_F_TO_U(rgb[2]));\r
+        tmp_style << tmp;\r
+        snprintf(tmp, 1023,\r
+                 "fill-rule:%s;",\r
+                 d->style.fill_rule.value != 0 ? "evenodd" : "nonzero");\r
+        tmp_style << tmp;\r
+        tmp_style << "fill-opacity:1;";\r
+    }\r
+\r
+    if (iType == EMR_FILLPATH || !d->stroke_set) {\r
+        tmp_style << "stroke:none;";\r
+    } else {\r
+        float rgb[3];\r
+        sp_color_get_rgb_floatv(&(d->style.stroke.value.color), rgb);\r
+        snprintf(tmp, 1023,\r
+                 "stroke:#%02x%02x%02x;",\r
+                 SP_COLOR_F_TO_U(rgb[0]),\r
+                 SP_COLOR_F_TO_U(rgb[1]),\r
+                 SP_COLOR_F_TO_U(rgb[2]));\r
+        tmp_style << tmp;\r
+\r
+        tmp_style << "stroke-width:" <<\r
+            MAX( 0.001, d->style.stroke_width.value ) << "px;";\r
+\r
+        tmp_style << "stroke-linejoin:" <<\r
+            (d->style.stroke_linejoin.computed == 0 ? "miter" :\r
+             d->style.stroke_linejoin.computed == 1 ? "round" :\r
+             d->style.stroke_linejoin.computed == 2 ? "bevel" :\r
+             "unknown") << ";";\r
+\r
+        if (d->style.stroke_linejoin.computed == 0) {\r
+            tmp_style << "stroke-miterlimit:" <<\r
+                MAX( 0.01, d->style.stroke_miterlimit.value ) << ";";\r
+        }\r
+\r
+        if (d->style.stroke_dasharray_set &&\r
+            d->style.stroke_dash.n_dash && d->style.stroke_dash.dash)\r
+        {\r
+            tmp_style << "stroke-dasharray:";\r
+            for (int i=0; i<d->style.stroke_dash.n_dash; i++) {\r
+                if (i)\r
+                    tmp_style << ",";\r
+                tmp_style << d->style.stroke_dash.dash[i];\r
+            }\r
+            tmp_style << ";";\r
+            tmp_style << "stroke-dashoffset:0;";\r
+        } else {\r
+            tmp_style << "stroke-dasharray:none;";\r
+        }\r
+        tmp_style << "stroke-opacity:1;";\r
+    }\r
+    tmp_style << "\" ";\r
+\r
+    *(d->outsvg) += tmp_style.str().c_str();\r
+}\r
+\r
+\r
+static double\r
+pix_x_to_point(PEMF_CALLBACK_DATA d, double px)\r
+{\r
+    double tmp = px - d->winorg.x;\r
+    tmp *= (double) PX_PER_IN / d->ScaleX;\r
+    tmp += d->vieworg.x;\r
+    return tmp;\r
+}\r
+\r
+\r
+static double\r
+pix_y_to_point(PEMF_CALLBACK_DATA d, double px)\r
+{\r
+    double tmp = px - d->winorg.y;\r
+    tmp *= (double) PX_PER_IN / d->ScaleY;\r
+    tmp += d->vieworg.y;\r
+    return tmp;\r
+}\r
+\r
+\r
+static double\r
+pix_size_to_point(PEMF_CALLBACK_DATA d, double px)\r
+{\r
+    double tmp = px;\r
+    tmp *= (double) PX_PER_IN / d->ScaleX;\r
+    return tmp;\r
+}\r
+\r
+\r
+static void\r
+select_pen(PEMF_CALLBACK_DATA d, int index)\r
+{\r
+    PEMRCREATEPEN pEmr = NULL;\r
+\r
+    if (index >= 0 && index < d->n_obj)\r
+        pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;\r
+\r
+    if (!pEmr)\r
+        return;\r
+\r
+    switch (pEmr->lopn.lopnStyle) {\r
+        default:\r
+        {\r
+            d->style.stroke_dasharray_set = 0;\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (pEmr->lopn.lopnWidth.x) {\r
+        d->style.stroke_width.value = pix_size_to_point( d, pEmr->lopn.lopnWidth.x );\r
+    } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)\r
+        d->style.stroke_width.value = 1.0;\r
+    }\r
+\r
+    double r, g, b;\r
+    r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );\r
+    g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );\r
+    b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );\r
+    sp_color_set_rgb_float( &(d->style.stroke.value.color), r,g,b );\r
+\r
+    d->style.stroke_linejoin.computed = 1;\r
+\r
+    d->stroke_set = true;\r
+}\r
+\r
+\r
+static void\r
+select_extpen(PEMF_CALLBACK_DATA d, int index)\r
+{\r
+    PEMREXTCREATEPEN pEmr = NULL;\r
+\r
+    if (index >= 0 && index < d->n_obj)\r
+        pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;\r
+\r
+    if (!pEmr)\r
+        return;\r
+\r
+    switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {\r
+        case PS_USERSTYLE:\r
+        {\r
+            if (pEmr->elp.elpNumEntries) {\r
+                d->style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;\r
+                if (d->style.stroke_dash.dash)\r
+                    delete[] d->style.stroke_dash.dash;\r
+                d->style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];\r
+                for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {\r
+                    d->style.stroke_dash.dash[i] = pix_size_to_point( d, pEmr->elp.elpStyleEntry[i] );\r
+                }\r
+                d->style.stroke_dasharray_set = 1;\r
+            } else {\r
+                d->style.stroke_dasharray_set = 0;\r
+            }\r
+            break;\r
+        }\r
+        default:\r
+        {\r
+            d->style.stroke_dasharray_set = 0;\r
+            break;\r
+        }\r
+    }\r
+\r
+    switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {\r
+        case PS_ENDCAP_ROUND:\r
+        {\r
+            d->style.stroke_linecap.computed = 1;\r
+            break;\r
+        }\r
+        case PS_ENDCAP_SQUARE:\r
+        {\r
+            d->style.stroke_linecap.computed = 2;\r
+            break;\r
+        }\r
+        case PS_ENDCAP_FLAT:\r
+        default:\r
+        {\r
+            d->style.stroke_linecap.computed = 0;\r
+            break;\r
+        }\r
+    }\r
+\r
+    switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {\r
+        case PS_JOIN_BEVEL:\r
+        {\r
+            d->style.stroke_linejoin.computed = 2;\r
+            break;\r
+        }\r
+        case PS_JOIN_MITER:\r
+        {\r
+            d->style.stroke_linejoin.computed = 0;\r
+            break;\r
+        }\r
+        case PS_JOIN_ROUND:\r
+        default:\r
+        {\r
+            d->style.stroke_linejoin.computed = 1;\r
+            break;\r
+        }\r
+    }\r
+\r
+    d->style.stroke_width.value = pix_size_to_point( d, pEmr->elp.elpWidth );\r
+\r
+    double r, g, b;\r
+    r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );\r
+    g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );\r
+    b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );\r
+\r
+    sp_color_set_rgb_float( &(d->style.stroke.value.color), r,g,b );\r
+\r
+    d->stroke_set = true;\r
+}\r
+\r
+\r
+static void\r
+select_brush(PEMF_CALLBACK_DATA d, int index)\r
+{\r
+    PEMRCREATEBRUSHINDIRECT pEmr = NULL;\r
+\r
+    if (index >= 0 && index < d->n_obj)\r
+        pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;\r
+\r
+    if (!pEmr)\r
+        return;\r
+\r
+    if (pEmr->lb.lbStyle == BS_SOLID) {\r
+        double r, g, b;\r
+        r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );\r
+        g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );\r
+        b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );\r
+        sp_color_set_rgb_float( &(d->style.fill.value.color), r,g,b );\r
+    }\r
+\r
+    d->fill_set = true;\r
+}\r
+\r
+\r
+static void\r
+delete_object(PEMF_CALLBACK_DATA d, int index)\r
+{\r
+    if (index >= 0 && index < d->n_obj) {\r
+        d->emf_obj[index].type = 0;\r
+        if (d->emf_obj[index].lpEMFR)\r
+            free(d->emf_obj[index].lpEMFR);\r
+        d->emf_obj[index].lpEMFR = NULL;\r
+    }\r
+}\r
+\r
+\r
+static void\r
+insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)\r
+{\r
+    if (index >= 0 && index < d->n_obj) {\r
+        delete_object(d, index);\r
+        d->emf_obj[index].type = type;\r
+        d->emf_obj[index].lpEMFR = pObj;\r
+    }\r
+}\r
+\r
+\r
+static int CALLBACK\r
+myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)\r
+{\r
+    PEMF_CALLBACK_DATA d;\r
+    SVGOStringStream tmp_outsvg;\r
+    SVGOStringStream tmp_path;\r
+    SVGOStringStream tmp_str;\r
+\r
+    d = (PEMF_CALLBACK_DATA) lpData;\r
+\r
+    switch (lpEMFR->iType)\r
+    {\r
+        case EMR_HEADER:\r
+        {\r
+            ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;\r
+            tmp_outsvg << "<svg\n";\r
+\r
+            d->xDPI = 2540;\r
+            d->yDPI = 2540;\r
+\r
+            d->PixelsX = pEmr->rclFrame.right - pEmr->rclFrame.left;\r
+            d->PixelsY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;\r
+\r
+            d->MMX = d->PixelsX / 100.0;\r
+            d->MMY = d->PixelsY / 100.0;\r
+\r
+            tmp_outsvg <<\r
+                "  width=\"" << d->MMX << "mm\"\n" <<\r
+                "  height=\"" << d->MMY << "mm\">\n";\r
+\r
+            if (pEmr->nHandles) {\r
+                d->n_obj = pEmr->nHandles;\r
+                d->emf_obj = new EMF_OBJECT[d->n_obj];\r
+            } else {\r
+                d->emf_obj = NULL;\r
+            }\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYBEZIER:\r
+        {\r
+            PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;\r
+            DWORD i,j;\r
+\r
+            if (pEmr->cptl<4)\r
+                break;\r
+\r
+            *(d->outsvg) += "    <path ";\r
+            output_style(d, EMR_STROKEPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            tmp_str <<\r
+                "\n\tM " <<\r
+                pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<\r
+                pix_x_to_point( d, pEmr->aptl[0].y) << " ";\r
+\r
+            for (i=1; i<pEmr->cptl; ) {\r
+                tmp_str << "\n\tC ";\r
+                for (j=0; j<3 && i<pEmr->cptl; j++,i++) {\r
+                    tmp_str <<\r
+                        pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
+                        pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
+                }\r
+            }\r
+\r
+            *(d->outsvg) += tmp_str.str().c_str();\r
+            *(d->outsvg) += " \" /> \n";\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYGON:\r
+        {\r
+            EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;\r
+            DWORD i;\r
+\r
+            if (pEmr->cptl < 2)\r
+                break;\r
+\r
+            *(d->outsvg) += "    <path ";\r
+            output_style(d, EMR_STROKEANDFILLPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            tmp_str <<\r
+                "\n\tM " <<\r
+                pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<\r
+                pix_y_to_point( d, pEmr->aptl[0].y ) << " ";\r
+\r
+            for (i=1; i<pEmr->cptl; i++) {\r
+                tmp_str <<\r
+                    "\n\tL " <<\r
+                    pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
+                    pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
+            }\r
+\r
+            *(d->outsvg) += tmp_str.str().c_str();\r
+            *(d->outsvg) += " z \" /> \n";\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYLINE:\r
+        {\r
+            EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;\r
+            DWORD i;\r
+\r
+            if (pEmr->cptl<2)\r
+                break;\r
+\r
+            *(d->outsvg) += "    <path ";\r
+            output_style(d, EMR_STROKEPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            tmp_str <<\r
+                "\n\tM " <<\r
+                pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<\r
+                pix_y_to_point( d, pEmr->aptl[0].y ) << " ";\r
+\r
+            for (i=1; i<pEmr->cptl; i++) {\r
+                tmp_str <<\r
+                    "\n\tL " <<\r
+                    pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
+                    pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
+            }\r
+\r
+            *(d->outsvg) += tmp_str.str().c_str();\r
+            *(d->outsvg) += " \" /> \n";\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYBEZIERTO:\r
+        {\r
+            PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;\r
+            DWORD i,j;\r
+\r
+            for (i=0; i<pEmr->cptl;) {\r
+                tmp_path << "\n\tC ";\r
+                for (j=0; j<3 && i<pEmr->cptl; j++,i++) {\r
+                    tmp_path <<\r
+                        pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
+                        pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
+                }\r
+            }\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYLINETO:\r
+        {\r
+            PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;\r
+            DWORD i;\r
+\r
+            for (i=0; i<pEmr->cptl;i++) {\r
+                tmp_path <<\r
+                    "\n\tL " <<\r
+                    pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
+                    pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
+            }\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYPOLYLINE:\r
+            break;\r
+        case EMR_POLYPOLYGON:\r
+            break;\r
+        case EMR_SETWINDOWEXTEX:\r
+        {\r
+            PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;\r
+\r
+            d->sizeWnd = pEmr->szlExtent;\r
+            d->PixelsX = d->sizeWnd.cx;\r
+            d->PixelsY = d->sizeWnd.cy;\r
+\r
+            d->ScaleX = d->xDPI / (100*d->MMX / d->PixelsX);\r
+            d->ScaleY = d->yDPI / (100*d->MMY / d->PixelsY);\r
+\r
+            break;\r
+        }\r
+        case EMR_SETWINDOWORGEX:\r
+        {\r
+            PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;\r
+            d->winorg = pEmr->ptlOrigin;\r
+            break;\r
+        }\r
+        case EMR_SETVIEWPORTEXTEX:\r
+        {\r
+            PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;\r
+\r
+            d->sizeView = pEmr->szlExtent;\r
+\r
+            if (d->sizeWnd.cx && d->sizeWnd.cy) {\r
+                HDC hScreenDC = GetDC( NULL );\r
+\r
+                float scrPixelsX = (float)GetDeviceCaps( hScreenDC, HORZRES );\r
+                float scrPixelsY = (float)GetDeviceCaps( hScreenDC, VERTRES );\r
+                float scrMMX = (float)GetDeviceCaps( hScreenDC, HORZSIZE );\r
+                float scrMMY = (float)GetDeviceCaps( hScreenDC, VERTSIZE );\r
+\r
+                ReleaseDC( NULL, hScreenDC );\r
+\r
+                d->dwInchesX = d->sizeView.cx / (25.4f*scrPixelsX/scrMMX);\r
+                d->dwInchesY = d->sizeView.cy / (25.4f*scrPixelsY/scrMMY);\r
+                d->xDPI = d->sizeWnd.cx / d->dwInchesX;\r
+                d->yDPI = d->sizeWnd.cy / d->dwInchesY;\r
+\r
+                if (1) {\r
+                    d->xDPI = 2540;\r
+                    d->yDPI = 2540;\r
+                    d->dwInchesX = d->PixelsX / d->xDPI;\r
+                    d->dwInchesY = d->PixelsY / d->yDPI;\r
+                    d->ScaleX = d->xDPI;\r
+                    d->ScaleY = d->yDPI;\r
+                }\r
+\r
+                d->MMX = d->dwInchesX * MM_PER_IN;\r
+                d->MMY = d->dwInchesY * MM_PER_IN;\r
+            }\r
+\r
+            break;\r
+        }\r
+        case EMR_SETVIEWPORTORGEX:\r
+        {\r
+            PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;\r
+            d->vieworg = pEmr->ptlOrigin;\r
+            break;\r
+        }\r
+        case EMR_SETBRUSHORGEX:\r
+            break;\r
+        case EMR_EOF:\r
+        {\r
+            tmp_outsvg << "</svg>\n";\r
+            break;\r
+        }\r
+        case EMR_SETPIXELV:\r
+            break;\r
+        case EMR_SETMAPPERFLAGS:\r
+            break;\r
+        case EMR_SETMAPMODE:\r
+            break;\r
+        case EMR_SETBKMODE:\r
+            break;\r
+        case EMR_SETPOLYFILLMODE:\r
+        {\r
+            PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;\r
+            d->style.fill_rule.value =\r
+                (pEmr->iMode == WINDING ? 0 :\r
+                 pEmr->iMode == ALTERNATE ? 1 : 0);\r
+            break;\r
+        }\r
+        case EMR_SETROP2:\r
+            break;\r
+        case EMR_SETSTRETCHBLTMODE:\r
+            break;\r
+        case EMR_SETTEXTALIGN:\r
+            break;\r
+        case EMR_SETCOLORADJUSTMENT:\r
+            break;\r
+        case EMR_SETTEXTCOLOR:\r
+            break;\r
+        case EMR_SETBKCOLOR:\r
+            break;\r
+        case EMR_OFFSETCLIPRGN:\r
+            break;\r
+        case EMR_MOVETOEX:\r
+        {\r
+            PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;\r
+            tmp_path <<\r
+                "\n\tM " <<\r
+                pix_x_to_point( d, pEmr->ptl.x ) << " " <<\r
+                pix_y_to_point( d, pEmr->ptl.y ) << " ";\r
+            break;\r
+        }\r
+        case EMR_SETMETARGN:\r
+            break;\r
+        case EMR_EXCLUDECLIPRECT:\r
+            break;\r
+        case EMR_INTERSECTCLIPRECT:\r
+            break;\r
+        case EMR_SCALEVIEWPORTEXTEX:\r
+            break;\r
+        case EMR_SCALEWINDOWEXTEX:\r
+            break;\r
+        case EMR_SAVEDC:\r
+            break;\r
+        case EMR_RESTOREDC:\r
+            break;\r
+        case EMR_SETWORLDTRANSFORM:\r
+            break;\r
+        case EMR_MODIFYWORLDTRANSFORM:\r
+            break;\r
+        case EMR_SELECTOBJECT:\r
+        {\r
+            PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;\r
+            unsigned int index = pEmr->ihObject;\r
+\r
+            if (index >= ENHMETA_STOCK_OBJECT) {\r
+                index -= ENHMETA_STOCK_OBJECT;\r
+                switch (index) {\r
+                    case NULL_BRUSH:\r
+                        d->fill_set = false;\r
+                        break;\r
+                    case BLACK_BRUSH:\r
+                    case DKGRAY_BRUSH:\r
+                    case GRAY_BRUSH:\r
+                    case LTGRAY_BRUSH:\r
+                    case WHITE_BRUSH:\r
+                    {\r
+                        float val = 0;\r
+                        switch (index) {\r
+                            case BLACK_BRUSH:\r
+                                val = 0.0 / 255.0;\r
+                                break;\r
+                            case DKGRAY_BRUSH:\r
+                                val = 64.0 / 255.0;\r
+                                break;\r
+                            case GRAY_BRUSH:\r
+                                val = 128.0 / 255.0;\r
+                                break;\r
+                            case LTGRAY_BRUSH:\r
+                                val = 192.0 / 255.0;\r
+                                break;\r
+                            case WHITE_BRUSH:\r
+                                val = 255.0 / 255.0;\r
+                                break;\r
+                        }\r
+                        sp_color_set_rgb_float( &(d->style.fill.value.color), val,val,val );\r
+\r
+                        d->fill_set = true;\r
+                        break;\r
+                    }\r
+                    case NULL_PEN:\r
+                        d->stroke_set = false;\r
+                        break;\r
+                    case BLACK_PEN:\r
+                    case WHITE_PEN:\r
+                    {\r
+                        float val = index == BLACK_PEN ? 0 : 1;\r
+                        d->style.stroke_dasharray_set = 0;\r
+                        d->style.stroke_width.value = 1.0;\r
+                        sp_color_set_rgb_float( &(d->style.stroke.value.color), val,val,val );\r
+\r
+                        d->stroke_set = true;\r
+\r
+                        break;\r
+                    }\r
+                }\r
+            } else {\r
+                if (index >= 0 && index < d->n_obj) {\r
+                    switch (d->emf_obj[index].type)\r
+                    {\r
+                        case EMR_CREATEPEN:\r
+                            select_pen(d, index);\r
+                            break;\r
+                        case EMR_CREATEBRUSHINDIRECT:\r
+                            select_brush(d, index);\r
+                            break;\r
+                        case EMR_EXTCREATEPEN:\r
+                            select_extpen(d, index);\r
+                            break;\r
+                    }\r
+                }\r
+            }\r
+            break;\r
+        }\r
+        case EMR_CREATEPEN:\r
+        {\r
+            PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;\r
+            int index = pEmr->ihPen;\r
+\r
+            EMRCREATEPEN *pPen =\r
+                (EMRCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) );\r
+            pPen->lopn = pEmr->lopn;\r
+            insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);\r
+\r
+            break;\r
+        }\r
+        case EMR_CREATEBRUSHINDIRECT:\r
+        {\r
+            PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;\r
+            int index = pEmr->ihBrush;\r
+\r
+            EMRCREATEBRUSHINDIRECT *pBrush =\r
+                (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );\r
+            pBrush->lb = pEmr->lb;\r
+            insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);\r
+\r
+            break;\r
+        }\r
+        case EMR_DELETEOBJECT:\r
+            break;\r
+        case EMR_ANGLEARC:\r
+            break;\r
+        case EMR_ELLIPSE:\r
+            break;\r
+        case EMR_RECTANGLE:\r
+            break;\r
+        case EMR_ROUNDRECT:\r
+            break;\r
+        case EMR_ARC:\r
+            break;\r
+        case EMR_CHORD:\r
+            break;\r
+        case EMR_PIE:\r
+            break;\r
+        case EMR_SELECTPALETTE:\r
+            break;\r
+        case EMR_CREATEPALETTE:\r
+            break;\r
+        case EMR_SETPALETTEENTRIES:\r
+            break;\r
+        case EMR_RESIZEPALETTE:\r
+            break;\r
+        case EMR_REALIZEPALETTE:\r
+            break;\r
+        case EMR_EXTFLOODFILL:\r
+            break;\r
+        case EMR_LINETO:\r
+        {\r
+            PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;\r
+            tmp_path <<\r
+                "\n\tL " <<\r
+                pix_x_to_point( d, pEmr->ptl.x ) << " " <<\r
+                pix_y_to_point( d, pEmr->ptl.y ) << " ";\r
+            break;\r
+        }\r
+        case EMR_ARCTO:\r
+            break;\r
+        case EMR_POLYDRAW:\r
+            break;\r
+        case EMR_SETARCDIRECTION:\r
+            break;\r
+        case EMR_SETMITERLIMIT:\r
+        {\r
+            PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;\r
+            d->style.stroke_miterlimit.value = pix_size_to_point( d, pEmr->eMiterLimit );\r
+\r
+            if (d->style.stroke_miterlimit.value < 1)\r
+                d->style.stroke_miterlimit.value = 1.0;\r
+\r
+            break;\r
+        }\r
+        case EMR_BEGINPATH:\r
+        {\r
+            tmp_path << " d=\"";\r
+            *(d->path) = "";\r
+            break;\r
+        }\r
+        case EMR_ENDPATH:\r
+        {\r
+            tmp_path << "\"";\r
+            break;\r
+        }\r
+        case EMR_CLOSEFIGURE:\r
+        {\r
+            tmp_path << "\n\tz";\r
+            break;\r
+        }\r
+        case EMR_FILLPATH:\r
+        case EMR_STROKEANDFILLPATH:\r
+        case EMR_STROKEPATH:\r
+        {\r
+            *(d->outsvg) += "    <path ";\r
+            output_style(d, lpEMFR->iType);\r
+            *(d->outsvg) += "\n\t";\r
+            *(d->outsvg) += *(d->path);\r
+            *(d->outsvg) += " /> \n";\r
+            break;\r
+        }\r
+        case EMR_FLATTENPATH:\r
+            break;\r
+        case EMR_WIDENPATH:\r
+            break;\r
+        case EMR_SELECTCLIPPATH:\r
+            break;\r
+        case EMR_ABORTPATH:\r
+            break;\r
+        case EMR_GDICOMMENT:\r
+            break;\r
+        case EMR_FILLRGN:\r
+            break;\r
+        case EMR_FRAMERGN:\r
+            break;\r
+        case EMR_INVERTRGN:\r
+            break;\r
+        case EMR_PAINTRGN:\r
+            break;\r
+        case EMR_EXTSELECTCLIPRGN:\r
+            break;\r
+        case EMR_BITBLT:\r
+            break;\r
+        case EMR_STRETCHBLT:\r
+            break;\r
+        case EMR_MASKBLT:\r
+            break;\r
+        case EMR_PLGBLT:\r
+            break;\r
+        case EMR_SETDIBITSTODEVICE:\r
+            break;\r
+        case EMR_STRETCHDIBITS:\r
+            break;\r
+        case EMR_EXTCREATEFONTINDIRECTW:\r
+            break;\r
+        case EMR_EXTTEXTOUTA:\r
+            break;\r
+        case EMR_EXTTEXTOUTW:\r
+            break;\r
+        case EMR_POLYBEZIER16:\r
+        {\r
+            PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;\r
+            POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
+            DWORD i,j;\r
+\r
+            if (pEmr->cpts<4)\r
+                break;\r
+\r
+            *(d->outsvg) += "    <path ";\r
+            output_style(d, EMR_STROKEPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            tmp_str <<\r
+                "\n\tM " <<\r
+                pix_x_to_point( d, apts[0].x ) << " " <<\r
+                pix_y_to_point( d, apts[0].y ) << " ";\r
+\r
+            for (i=1; i<pEmr->cpts; ) {\r
+                tmp_str << "\n\tC ";\r
+                for (j=0; j<3 && i<pEmr->cpts; j++,i++) {\r
+                    tmp_str <<\r
+                        pix_x_to_point( d, apts[i].x ) << " " <<\r
+                        pix_y_to_point( d, apts[i].y ) << " ";\r
+                }\r
+            }\r
+\r
+            *(d->outsvg) += tmp_str.str().c_str();\r
+            *(d->outsvg) += " \" /> \n";\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYGON16:\r
+        {\r
+            PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;\r
+            POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
+            unsigned int i;\r
+\r
+            *(d->outsvg) += "<path ";\r
+            output_style(d, EMR_STROKEANDFILLPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            // skip the first point?\r
+            tmp_path << "\n\tM " <<\r
+                pix_x_to_point( d, apts[1].x ) << " " <<\r
+                pix_y_to_point( d, apts[1].y ) << " ";\r
+\r
+            for (i=2; i<pEmr->cpts; i++) {\r
+                tmp_path << "\n\tL " <<\r
+                    pix_x_to_point( d, apts[i].x ) << " " <<\r
+                    pix_y_to_point( d, apts[i].y ) << " ";\r
+            }\r
+\r
+            *(d->outsvg) += tmp_path.str().c_str();\r
+            *(d->outsvg) += " z \" /> \n";\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYLINE16:\r
+        {\r
+            EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;\r
+            POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
+            DWORD i;\r
+\r
+            if (pEmr->cpts<2)\r
+                break;\r
+\r
+            *(d->outsvg) += "    <path ";\r
+            output_style(d, EMR_STROKEPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            tmp_str <<\r
+                "\n\tM " <<\r
+                pix_x_to_point( d, apts[0].x ) << " " <<\r
+                pix_y_to_point( d, apts[0].y ) << " ";\r
+\r
+            for (i=1; i<pEmr->cpts; i++) {\r
+                tmp_str <<\r
+                    "\n\tL " <<\r
+                    pix_x_to_point( d, apts[i].x ) << " " <<\r
+                    pix_y_to_point( d, apts[i].y ) << " ";\r
+            }\r
+\r
+            *(d->outsvg) += tmp_str.str().c_str();\r
+            *(d->outsvg) += " \" /> \n";\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYBEZIERTO16:\r
+        {\r
+            PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;\r
+            POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
+            DWORD i,j;\r
+\r
+            for (i=0; i<pEmr->cpts;) {\r
+                tmp_path << "\n\tC ";\r
+                for (j=0; j<3 && i<pEmr->cpts; j++,i++) {\r
+                    tmp_path <<\r
+                        pix_x_to_point( d, apts[i].x ) << " " <<\r
+                        pix_y_to_point( d, apts[i].y ) << " ";\r
+                }\r
+            }\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYLINETO16:\r
+        {\r
+            PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;\r
+            POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
+            DWORD i;\r
+\r
+            for (i=0; i<pEmr->cpts;i++) {\r
+                tmp_path <<\r
+                    "\n\tL " <<\r
+                    pix_x_to_point( d, apts[i].x ) << " " <<\r
+                    pix_y_to_point( d, apts[i].y ) << " ";\r
+            }\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYPOLYLINE16:\r
+            break;\r
+        case EMR_POLYPOLYGON16:\r
+        {\r
+            PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;\r
+            unsigned int n, i, j;\r
+\r
+            *(d->outsvg) += "<path ";\r
+            output_style(d, EMR_STROKEANDFILLPATH);\r
+            *(d->outsvg) += "\n\td=\"";\r
+\r
+            i = pEmr->nPolys-1; // ???\r
+            for (n=0; n<pEmr->nPolys /*&& i<pEmr->cpts*/; n++) {\r
+                SVGOStringStream poly_path;\r
+\r
+                poly_path << "\n\tM " <<\r
+                    pix_x_to_point( d, pEmr->apts[i].x ) << " " <<\r
+                    pix_y_to_point( d, pEmr->apts[i].y ) << " ";\r
+                i++;\r
+\r
+                for (j=1; j<pEmr->aPolyCounts[n] /*&& i<pEmr->cpts*/; j++) {\r
+                    poly_path << "\n\tL " <<\r
+                        pix_x_to_point( d, pEmr->apts[i].x ) << " " <<\r
+                        pix_y_to_point( d, pEmr->apts[i].y ) << " ";\r
+                    i++;\r
+                }\r
+\r
+                *(d->outsvg) += poly_path.str().c_str();\r
+                *(d->outsvg) += " z \n";\r
+            }\r
+\r
+            *(d->outsvg) += " \" /> \n";\r
+            break;\r
+        }\r
+        case EMR_POLYDRAW16:\r
+            break;\r
+        case EMR_CREATEMONOBRUSH:\r
+            break;\r
+        case EMR_CREATEDIBPATTERNBRUSHPT:\r
+            break;\r
+        case EMR_EXTCREATEPEN:\r
+        {\r
+            PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;\r
+            int index = pEmr->ihPen;\r
+\r
+            EMREXTCREATEPEN *pPen =\r
+                (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +\r
+                                            sizeof(DWORD) * pEmr->elp.elpNumEntries );\r
+            pPen->ihPen = pEmr->ihPen;\r
+            pPen->offBmi = pEmr->offBmi;\r
+            pPen->cbBmi = pEmr->cbBmi;\r
+            pPen->offBits = pEmr->offBits;\r
+            pPen->cbBits = pEmr->cbBits;\r
+            pPen->elp = pEmr->elp;\r
+            for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {\r
+                pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];\r
+            }\r
+            insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);\r
+\r
+            break;\r
+        }\r
+        case EMR_POLYTEXTOUTA:\r
+            break;\r
+        case EMR_POLYTEXTOUTW:\r
+            break;\r
+        case EMR_SETICMMODE:\r
+            break;\r
+        case EMR_CREATECOLORSPACE:\r
+            break;\r
+        case EMR_SETCOLORSPACE:\r
+            break;\r
+        case EMR_DELETECOLORSPACE:\r
+            break;\r
+        case EMR_GLSRECORD:\r
+            break;\r
+        case EMR_GLSBOUNDEDRECORD:\r
+            break;\r
+        case EMR_PIXELFORMAT:\r
+            break;\r
+    }\r
+\r
+    *(d->outsvg) += tmp_outsvg.str().c_str();\r
+    *(d->path) += tmp_path.str().c_str();\r
+\r
+    return 1;\r
+}\r
+\r
+\r
+// Aldus Placeable Header ===================================================\r
+// Since we are a 32bit app, we have to be sure this structure compiles to\r
+// be identical to a 16 bit app's version. To do this, we use the #pragma\r
+// to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT\r
+// for the bbox rectangle.\r
+#pragma pack( push )\r
+#pragma pack( 2 )\r
+typedef struct\r
+{\r
+       DWORD           dwKey;\r
+       WORD            hmf;\r
+       SMALL_RECT      bbox;\r
+       WORD            wInch;\r
+       DWORD           dwReserved;\r
+       WORD            wCheckSum;\r
+} APMHEADER, *PAPMHEADER;\r
+#pragma pack( pop )\r
+\r
+\r
+SPDocument *\r
+EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri )\r
+{\r
+    EMF_CALLBACK_DATA d = {0};\r
+\r
+    gsize bytesRead = 0;\r
+    gsize bytesWritten = 0;\r
+    GError* error = NULL;\r
+    gchar *local_fn =\r
+        g_filename_from_utf8( uri, -1,  &bytesRead,  &bytesWritten, &error );\r
+\r
+    if (local_fn == NULL) {\r
+        return NULL;\r
+    }\r
+\r
+    d.outsvg = new Glib::ustring("");\r
+    d.path = new Glib::ustring("");\r
+\r
+    CHAR *ansi_uri = (CHAR *) local_fn;\r
+    gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );\r
+    WCHAR *unicode_uri = (WCHAR *) unicode_fn;\r
+\r
+    // Try open as Enhanced Metafile\r
+    HENHMETAFILE hemf;\r
+    if (PrintWin32::is_os_wide())\r
+        hemf = GetEnhMetaFileW(unicode_uri);\r
+    else\r
+        hemf = GetEnhMetaFileA(ansi_uri);\r
+\r
+    if (!hemf) {\r
+        // Try open as Windows Metafile\r
+        HMETAFILE hmf;\r
+        if (PrintWin32::is_os_wide())\r
+            hmf = GetMetaFileW(unicode_uri);\r
+        else\r
+            hmf = GetMetaFileA(ansi_uri);\r
+\r
+       METAFILEPICT mp;\r
+       HDC hDC;\r
+\r
+        if (!hmf) {\r
+            if (PrintWin32::is_os_wide()) {\r
+                WCHAR szTemp[MAX_PATH];\r
+\r
+                DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );\r
+                if (dw) {\r
+                    hmf = GetMetaFileW( szTemp );\r
+                }\r
+            } else {\r
+                CHAR szTemp[MAX_PATH];\r
+\r
+                DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );\r
+                if (dw) {\r
+                    hmf = GetMetaFileA( szTemp );\r
+                }\r
+            }\r
+        }\r
+\r
+        if (hmf) {\r
+            DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );\r
+            if (nSize) {\r
+                BYTE *lpvData = new BYTE[nSize];\r
+                if (lpvData) {\r
+                    DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );\r
+                    if (dw) {\r
+                        // Fill out a METAFILEPICT structure\r
+                        mp.mm = MM_ANISOTROPIC;\r
+                        mp.xExt = 1000;\r
+                        mp.yExt = 1000;\r
+                        mp.hMF = NULL;\r
+                        // Get a reference DC\r
+                        hDC = GetDC( NULL );\r
+                        // Make an enhanced metafile from the windows metafile\r
+                        hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );\r
+                        // Clean up\r
+                        ReleaseDC( NULL, hDC );\r
+                    }\r
+                    delete[] lpvData;\r
+                }\r
+                DeleteMetaFile( hmf );\r
+            }\r
+        } else {\r
+            // Try open as Aldus Placeable Metafile\r
+            HANDLE hFile;\r
+            if (PrintWin32::is_os_wide())\r
+                hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
+            else\r
+                hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
+            if (hFile != INVALID_HANDLE_VALUE) {\r
+                DWORD nSize = GetFileSize( hFile, NULL );\r
+                if (nSize) {\r
+                    BYTE *lpvData = new BYTE[nSize];\r
+                    if (lpvData) {\r
+                        DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );\r
+                        if (dw) {\r
+                            if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {\r
+                                // Fill out a METAFILEPICT structure\r
+                                mp.mm = MM_ANISOTROPIC;\r
+                                mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;\r
+                                mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);\r
+                                mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;\r
+                                mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);\r
+                                mp.hMF = NULL;\r
+                                // Get a reference DC\r
+                                hDC = GetDC( NULL );\r
+                                // Create an enhanced metafile from the bits\r
+                                hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );\r
+                                // Clean up\r
+                                ReleaseDC( NULL, hDC );\r
+                            }\r
+                        }\r
+                        delete[] lpvData;\r
+                    }\r
+                }\r
+                CloseHandle( hFile );\r
+            }\r
+        }\r
+    }\r
+\r
+    if (!hemf || !d.outsvg || !d.path) {\r
+        if (d.outsvg)\r
+            delete d.outsvg;\r
+        if (d.path)\r
+            delete d.path;\r
+        if  (local_fn)\r
+            g_free(local_fn);\r
+        if  (unicode_fn)\r
+            g_free(unicode_fn);\r
+        return NULL;\r
+    }\r
+\r
+    EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);\r
+    DeleteEnhMetaFile(hemf);\r
+\r
+//    std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;\r
+\r
+    SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);\r
+\r
+    delete d.outsvg;\r
+    delete d.path;\r
+\r
+    if (d.emf_obj) {\r
+        int i;\r
+        for (i=0; i<d.n_obj; i++)\r
+            delete_object(&d, i);\r
+        delete[] d.emf_obj;\r
+    }\r
+    \r
+    if (d.style.stroke_dash.dash)\r
+        delete[] d.style.stroke_dash.dash;\r
+\r
+    if  (local_fn)\r
+        g_free(local_fn);\r
+    if  (unicode_fn)\r
+        g_free(unicode_fn);\r
+\r
+    return doc;\r
+}\r
+\r
+\r
+void\r
+EmfWin32::init (void)\r
+{\r
+    Inkscape::Extension::Extension * ext;\r
+\r
+    /* EMF in */\r
+    ext = Inkscape::Extension::build_from_mem(\r
+        "<inkscape-extension>\n"\r
+            "<name>" N_("EMF Input") "</name>\n"\r
+            "<id>org.inkscape.input.emf.win32</id>\n"\r
+            "<input>\n"\r
+                "<extension>.emf</extension>\n"\r
+                "<mimetype>image/x-emf</mimetype>\n"\r
+                "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"\r
+                "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"\r
+                "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"\r
+            "</input>\n"\r
+        "</inkscape-extension>", new EmfWin32());\r
+\r
+    /* WMF in */\r
+    ext = Inkscape::Extension::build_from_mem(\r
+        "<inkscape-extension>\n"\r
+            "<name>" N_("WMF Input") "</name>\n"\r
+            "<id>org.inkscape.input.wmf.win32</id>\n"\r
+            "<input>\n"\r
+                "<extension>.wmf</extension>\n"\r
+                "<mimetype>image/x-wmf</mimetype>\n"\r
+                "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"\r
+                "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"\r
+                "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"\r
+            "</input>\n"\r
+        "</inkscape-extension>", new EmfWin32());\r
+\r
+    /* EMF out */\r
+    ext = Inkscape::Extension::build_from_mem(\r
+        "<inkscape-extension>\n"\r
+            "<name>" N_("EMF Output") "</name>\n"\r
+            "<id>org.inkscape.output.emf.win32</id>\n"\r
+            "<output>\n"\r
+                "<extension>.emf</extension>\n"\r
+                "<mimetype>image/x-emf</mimetype>\n"\r
+                "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"\r
+                "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"\r
+            "</output>\n"\r
+        "</inkscape-extension>", new EmfWin32());\r
+\r
+    return;\r
+}\r
+\r
+\r
+} } }  /* namespace Inkscape, Extension, Implementation */\r
+\r
+\r
+#endif /* WIN32 */\r
+\r
+\r
+/*\r
+  Local Variables:\r
+  mode:cpp\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
diff --git a/src/extension/internal/emf-win32-inout.h b/src/extension/internal/emf-win32-inout.h
new file mode 100644 (file)
index 0000000..eff8500
--- /dev/null
@@ -0,0 +1,60 @@
+/*\r
+ * Enhanced Metafile Input/Output.\r
+ *\r
+ * Authors:\r
+ *   Ulf Erikson <ulferikson@users.sf.net>\r
+ *\r
+ * Copyright (C) 2006 Authors\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#ifndef EXTENSION_INTERNAL_EMF_WIN32_H\r
+#define EXTENSION_INTERNAL_EMF_WIN32_H\r
+\r
+#ifdef WIN32\r
+\r
+#include "extension/implementation/implementation.h"\r
+#include "style.h"\r
+\r
+namespace Inkscape {\r
+namespace Extension {\r
+namespace Internal {\r
+\r
+class EmfWin32 : Inkscape::Extension::Implementation::Implementation { //This is a derived class\r
+\r
+public:\r
+    EmfWin32(); // Empty constructor\r
+\r
+    virtual ~EmfWin32();//Destructor\r
+\r
+    bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now)\r
+\r
+    void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename\r
+              SPDocument *doc,\r
+              gchar const *uri);\r
+\r
+    virtual SPDocument *open( Inkscape::Extension::Input *mod,\r
+                                const gchar *uri );\r
+\r
+    static void init(void);//Initialize the class\r
+\r
+private:\r
+};\r
+\r
+} } }  /* namespace Inkscape, Extension, Implementation */\r
+\r
+#endif /* WIN32 */\r
+\r
+#endif /* EXTENSION_INTERNAL_EMF_WIN32_H */\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp
new file mode 100644 (file)
index 0000000..b40eec4
--- /dev/null
@@ -0,0 +1,629 @@
+/** \file\r
+ * Enhanced Metafile Printing.\r
+ */\r
+/*\r
+ * Authors:\r
+ *   Ulf Erikson <ulferikson@users.sf.net>\r
+ *\r
+ * Copyright (C) 2006 Authors\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+/*\r
+ * References:\r
+ *  - How to Create & Play Enhanced Metafiles in Win32\r
+ *      http://support.microsoft.com/kb/q145999/\r
+ *  - INFO: Windows Metafile Functions & Aldus Placeable Metafiles\r
+ *      http://support.microsoft.com/kb/q66949/\r
+ *  - Metafile Functions\r
+ *      http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp\r
+ *  - Metafile Structures\r
+ *      http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp\r
+ */\r
+\r
+#ifdef WIN32\r
+\r
+#ifdef HAVE_CONFIG_H\r
+# include "config.h"\r
+#endif\r
+\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <errno.h>\r
+\r
+#include "libnr/n-art-bpath.h"\r
+#include "libnr/nr-point-matrix-ops.h"\r
+#include "libnr/nr-rect.h"\r
+#include "libnr/nr-matrix.h"\r
+#include "libnr/nr-matrix-fns.h"\r
+#include "libnr/nr-path.h"\r
+#include "libnr/nr-pixblock.h"\r
+#include "display/canvas-bpath.h"\r
+#include "sp-item.h"\r
+\r
+#include "glib.h"\r
+#include "gtk/gtkdialog.h"\r
+#include "gtk/gtkbox.h"\r
+#include "gtk/gtkstock.h"\r
+\r
+#include "glibmm/i18n.h"\r
+#include "enums.h"\r
+#include "document.h"\r
+#include "style.h"\r
+#include "sp-paint-server.h"\r
+#include "inkscape_version.h"\r
+\r
+#include "win32.h"\r
+#include "emf-win32-print.h"\r
+\r
+#include "unit-constants.h"\r
+\r
+#include "extension/extension.h"\r
+#include "extension/system.h"\r
+#include "extension/print.h"\r
+\r
+#include "io/sys.h"\r
+\r
+#include "macros.h"\r
+\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+\r
+namespace Inkscape {\r
+namespace Extension {\r
+namespace Internal {\r
+\r
+static float dwDPI = 2540;\r
+\r
+\r
+PrintEmfWin32::PrintEmfWin32 (void):\r
+    hdc(NULL),\r
+    hbrush(NULL),\r
+    hpen(NULL),\r
+    fill_path(NULL)\r
+{\r
+}\r
+\r
+\r
+PrintEmfWin32::~PrintEmfWin32 (void)\r
+{\r
+    if (hdc) {\r
+        HENHMETAFILE metafile = CloseEnhMetaFile( hdc );\r
+        if ( metafile ) {\r
+            DeleteEnhMetaFile( metafile );\r
+        }\r
+        DeleteDC( hdc );\r
+    }\r
+\r
+    /* restore default signal handling for SIGPIPE */\r
+#if !defined(_WIN32) && !defined(__WIN32__)\r
+    (void) signal(SIGPIPE, SIG_DFL);\r
+#endif\r
+       return;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::setup (Inkscape::Extension::Print *mod)\r
+{\r
+    return TRUE;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)\r
+{\r
+    gchar const *utf8_fn = mod->get_param_string("destination");\r
+\r
+    gsize bytesRead = 0;\r
+    gsize bytesWritten = 0;\r
+    GError* error = NULL;\r
+    gchar *local_fn =\r
+        g_filename_from_utf8( utf8_fn, -1,  &bytesRead,  &bytesWritten, &error );\r
+\r
+    if (local_fn == NULL) {\r
+        return 1;\r
+    }\r
+\r
+    CHAR *ansi_uri = (CHAR *) local_fn;\r
+    gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );\r
+    WCHAR *unicode_uri = (WCHAR *) unicode_fn;\r
+\r
+    // width and height in px\r
+    _width = sp_document_width(doc);\r
+    _height = sp_document_height(doc);\r
+\r
+    NRRect d;\r
+    bool pageBoundingBox;\r
+    pageBoundingBox = mod->get_param_bool("pageBoundingBox");\r
+    if (pageBoundingBox) {\r
+        d.x0 = d.y0 = 0;\r
+        d.x1 = _width;\r
+        d.y1 = _height;\r
+    } else {\r
+        SPItem* doc_item = SP_ITEM(sp_document_root(doc));\r
+        sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);\r
+    }\r
+\r
+    d.x0 *= IN_PER_PX;\r
+    d.y0 *= IN_PER_PX;\r
+    d.x1 *= IN_PER_PX;\r
+    d.y1 *= IN_PER_PX;\r
+\r
+    float dwInchesX = (d.x1 - d.x0);\r
+    float dwInchesY = (d.y1 - d.y0);\r
+\r
+    // dwInchesX x dwInchesY in .01mm units\r
+    SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) );\r
+\r
+    // Get a Reference DC\r
+    HDC hScreenDC = GetDC( NULL );\r
+\r
+    // Get the physical characteristics of the reference DC\r
+    float PixelsX = (float) GetDeviceCaps( hScreenDC, HORZRES );\r
+    float PixelsY = (float) GetDeviceCaps( hScreenDC, VERTRES );\r
+    float MMX = (float) GetDeviceCaps( hScreenDC, HORZSIZE );\r
+    float MMY = (float) GetDeviceCaps( hScreenDC, VERTSIZE );\r
+\r
+    // Create the Metafile\r
+    if (PrintWin32::is_os_wide())\r
+        hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, NULL );\r
+    else\r
+        hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, NULL );\r
+\r
+    // Release the reference DC\r
+    ReleaseDC( NULL, hScreenDC );\r
+\r
+    // Did we get a good metafile?\r
+    if (hdc == NULL)\r
+    {\r
+        g_free(local_fn);\r
+        g_free(unicode_fn);\r
+        return 1;\r
+    }\r
+\r
+    // Anisotropic mapping mode\r
+    SetMapMode( hdc, MM_ANISOTROPIC );\r
+\r
+    // Set the Windows extent\r
+    SetWindowExtEx( hdc, (int) (dwInchesX*dwDPI), (int) (dwInchesY*dwDPI), NULL );\r
+\r
+    // Set the viewport extent to reflect\r
+    // dwInchesX" x dwInchesY" in device units\r
+    SetViewportExtEx( hdc,\r
+                      (int) ((float) dwInchesX*25.4f*PixelsX/MMX),\r
+                      (int) ((float) dwInchesY*25.4f*PixelsY/MMY),\r
+                      NULL );\r
+\r
+    SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );\r
+\r
+    g_free(local_fn);\r
+    g_free(unicode_fn);\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::finish (Inkscape::Extension::Print *mod)\r
+{\r
+    if (!hdc) return 0;\r
+\r
+    flush_fill(); // flush any pending fills\r
+\r
+    HENHMETAFILE metafile = CloseEnhMetaFile( hdc );\r
+    if ( metafile ) {\r
+        DeleteEnhMetaFile( metafile );\r
+    }\r
+    DeleteDC( hdc );\r
+\r
+    hdc = NULL;\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::comment (Inkscape::Extension::Print * module,\r
+                                const char *comment)\r
+{\r
+    if (!hdc) return 0;\r
+\r
+    flush_fill(); // flush any pending fills\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+void\r
+PrintEmfWin32::create_brush(SPStyle const *style)\r
+{\r
+    float rgb[3];\r
+\r
+    if (style) {\r
+        sp_color_get_rgb_floatv( &style->fill.value.color, rgb );\r
+        hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );\r
+        hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );\r
+\r
+        SetPolyFillMode( hdc,\r
+                         style->fill_rule.computed == 0 ? WINDING :\r
+                         style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );\r
+    } else { // if (!style)\r
+        hbrush = CreateSolidBrush( RGB(255, 255, 255) );\r
+        hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );\r
+        SetPolyFillMode( hdc, ALTERNATE );\r
+    }\r
+}\r
+\r
+\r
+void\r
+PrintEmfWin32::destroy_brush()\r
+{\r
+    SelectObject( hdc, hbrushOld );\r
+    if (hbrush)\r
+        DeleteObject( hbrush );\r
+    hbrush = NULL;\r
+}\r
+\r
+\r
+void\r
+PrintEmfWin32::create_pen(SPStyle const *style)\r
+{\r
+    if (style) {\r
+        float rgb[3];\r
+\r
+        sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);\r
+\r
+        LOGBRUSH lb = {0};\r
+        lb.lbStyle = BS_SOLID;\r
+        lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );\r
+\r
+        int linestyle = PS_SOLID;\r
+        int linecap = 0;\r
+        int linejoin = 0;\r
+        DWORD n_dash = 0;\r
+        DWORD *dash = NULL;\r
+        float oldmiterlimit;\r
+\r
+        DWORD linewidth = MAX( 1, (DWORD) (style->stroke_width.computed * IN_PER_PX * dwDPI) );\r
+\r
+        if (style->stroke_linecap.computed == 0) {\r
+            linecap = PS_ENDCAP_FLAT;\r
+        }\r
+        else if (style->stroke_linecap.computed == 1) {\r
+            linecap = PS_ENDCAP_ROUND;\r
+        }\r
+        else if (style->stroke_linecap.computed == 2) {\r
+            linecap = PS_ENDCAP_SQUARE;\r
+        }\r
+\r
+        if (style->stroke_linejoin.computed == 0) {\r
+            linejoin = PS_JOIN_MITER;\r
+        }\r
+        else if (style->stroke_linejoin.computed == 1) {\r
+            linejoin = PS_JOIN_ROUND;\r
+        }\r
+        else if (style->stroke_linejoin.computed == 2) {\r
+            linejoin = PS_JOIN_BEVEL;\r
+        }\r
+\r
+        if (style->stroke_dash.n_dash   &&\r
+            style->stroke_dash.dash       )\r
+        {\r
+            int i = 0;\r
+            while (linestyle != PS_USERSTYLE &&\r
+                   (i < style->stroke_dash.n_dash)) {\r
+                if (style->stroke_dash.dash[i] > 0.00000001)\r
+                    linestyle = PS_USERSTYLE;\r
+                i++;\r
+            }\r
+\r
+            if (linestyle == PS_USERSTYLE) {\r
+                n_dash = style->stroke_dash.n_dash;\r
+                dash = new DWORD[n_dash];\r
+                for (i = 0; i < style->stroke_dash.n_dash; i++) {\r
+                    dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);\r
+                }\r
+            }\r
+        }\r
+\r
+        hpen = ExtCreatePen(\r
+            PS_GEOMETRIC | linestyle | linecap | linejoin,\r
+            linewidth,\r
+            &lb,\r
+            n_dash,\r
+            dash );\r
+\r
+        if ( !hpen && linestyle == PS_USERSTYLE ) {\r
+            hpen = ExtCreatePen(\r
+                PS_GEOMETRIC | PS_SOLID | linecap | linejoin,\r
+                linewidth,\r
+                &lb,\r
+                0,\r
+                NULL );\r
+        }\r
+\r
+        if ( !hpen ) {\r
+            hpen = CreatePen(\r
+                PS_SOLID,\r
+                linewidth,\r
+                lb.lbColor );\r
+        }\r
+\r
+        hpenOld = (HPEN) SelectObject( hdc, hpen );\r
+\r
+        if (linejoin == PS_JOIN_MITER) {\r
+            float miterlimit = style->stroke_miterlimit.value;\r
+            if (miterlimit < 1)\r
+                miterlimit = 4.0;\r
+            SetMiterLimit(\r
+                hdc,\r
+                miterlimit * IN_PER_PX * dwDPI,\r
+                &oldmiterlimit );\r
+        }\r
+\r
+        if (n_dash) {\r
+            delete[] dash;\r
+        }\r
+    }\r
+    else { // if (!style)\r
+        hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );\r
+        hpenOld = (HPEN) SelectObject( hdc, hpen );\r
+    }\r
+}\r
+\r
+\r
+void\r
+PrintEmfWin32::destroy_pen()\r
+{\r
+    SelectObject( hdc, hpenOld );\r
+    if (hpen)\r
+        DeleteObject( hpen );\r
+    hpen = NULL;\r
+}\r
+\r
+\r
+void\r
+PrintEmfWin32::flush_fill()\r
+{\r
+    if (fill_path) {\r
+        print_bpath(fill_path, &fill_transform, &fill_pbox);\r
+        FillPath( hdc );\r
+        destroy_brush();\r
+        delete[] fill_path;\r
+        fill_path = NULL;\r
+    }\r
+}\r
+\r
+\r
+NArtBpath *\r
+PrintEmfWin32::copy_bpath(const NArtBpath *bp)\r
+{\r
+    NArtBpath *tmp = (NArtBpath *) bp;\r
+    int num = 1;\r
+    \r
+    while (tmp->code != NR_END) {\r
+        num++;\r
+        tmp += 1;\r
+    }\r
+\r
+    tmp = new NArtBpath[num];\r
+    while (num--) {\r
+        tmp[num] = bp[num];\r
+    }\r
+\r
+    return tmp;\r
+}\r
+\r
+\r
+int\r
+PrintEmfWin32::cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2)\r
+{\r
+    if (!bp1 || !bp2) {\r
+        return 1;\r
+    }\r
+    \r
+    while (bp1->code != NR_END && bp2->code != NR_END) {\r
+        if (bp1->code != bp2->code) {\r
+            return 1;\r
+        }\r
+\r
+        if ( fabs(bp1->x1 - bp2->x1) > 0.00000001 ||\r
+             fabs(bp1->y1 - bp2->y1) > 0.00000001 ||\r
+             fabs(bp1->x2 - bp2->x2) > 0.00000001 ||\r
+             fabs(bp1->y2 - bp2->y2) > 0.00000001 ||\r
+             fabs(bp1->x3 - bp2->x3) > 0.00000001 ||\r
+             fabs(bp1->y3 - bp2->y3) > 0.00000001 )\r
+        {\r
+            return 1;\r
+        }\r
+        \r
+        bp1 += 1;\r
+        bp2 += 1;\r
+    }\r
+    \r
+    return bp1->code != NR_END || bp2->code != NR_END;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::fill(Inkscape::Extension::Print *mod,\r
+               NRBPath const *bpath, NRMatrix const *transform, SPStyle const *style,\r
+               NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)\r
+{\r
+    if (!hdc) return 0;\r
+\r
+    flush_fill(); // flush any pending fills\r
+\r
+    if (style->fill.type == SP_PAINT_TYPE_COLOR) {\r
+        create_brush(style);\r
+    } else {\r
+        // create_brush(NULL);\r
+        return 0;\r
+    }\r
+\r
+    fill_path = copy_bpath( bpath->path );\r
+    fill_transform = *transform;\r
+    fill_pbox = *pbox;\r
+\r
+    // postpone fill in case of stroke-and-fill\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::stroke (Inkscape::Extension::Print *mod,\r
+                  const NRBPath *bpath, const NRMatrix *transform, const SPStyle *style,\r
+                  const NRRect *pbox, const NRRect *dbox, const NRRect *bbox)\r
+{\r
+    if (!hdc) return 0;\r
+\r
+    bool stroke_and_fill = ( cmp_bpath( bpath->path, fill_path ) == 0 );\r
+\r
+    if (!stroke_and_fill) {\r
+        flush_fill(); // flush any pending fills\r
+    }\r
+\r
+    if (style->stroke.type == SP_PAINT_TYPE_COLOR) {\r
+        create_pen(style);\r
+    } else {\r
+        // create_pen(NULL);\r
+        return 0;\r
+    }\r
+\r
+    print_bpath(bpath->path, transform, pbox);\r
+\r
+    if (stroke_and_fill) {\r
+        StrokeAndFillPath( hdc );\r
+        destroy_brush();\r
+        delete[] fill_path;\r
+        fill_path = NULL;\r
+    } else {\r
+        StrokePath( hdc );\r
+    }\r
+\r
+    destroy_pen();\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+unsigned int\r
+PrintEmfWin32::print_bpath(const NArtBpath *bp, const NRMatrix *transform, NRRect const *pbox)\r
+{\r
+    unsigned int closed;\r
+    NR::Matrix tf = *transform;\r
+\r
+    BeginPath( hdc );\r
+    closed = FALSE;\r
+    while (bp->code != NR_END) {\r
+        using NR::X;\r
+        using NR::Y;\r
+\r
+        NR::Point p1(bp->c(1) * tf);\r
+        NR::Point p2(bp->c(2) * tf);\r
+        NR::Point p3(bp->c(3) * tf);\r
+\r
+        p1[X] = (p1[X] * IN_PER_PX * dwDPI);\r
+        p2[X] = (p2[X] * IN_PER_PX * dwDPI);\r
+        p3[X] = (p3[X] * IN_PER_PX * dwDPI);\r
+        p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);\r
+        p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);\r
+        p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);\r
+\r
+        LONG const x1 = (LONG) round(p1[X]);\r
+        LONG const y1 = (LONG) round(rc.bottom-p1[Y]);\r
+        LONG const x2 = (LONG) round(p2[X]);\r
+        LONG const y2 = (LONG) round(rc.bottom-p2[Y]);\r
+        LONG const x3 = (LONG) round(p3[X]);\r
+        LONG const y3 = (LONG) round(rc.bottom-p3[Y]);\r
+\r
+        switch (bp->code) {\r
+            case NR_MOVETO:\r
+                if (closed) {\r
+                    CloseFigure( hdc );\r
+                }\r
+                closed = TRUE;\r
+                MoveToEx( hdc, x3, y3, NULL );\r
+                break;\r
+            case NR_MOVETO_OPEN:\r
+                if (closed) {\r
+                    CloseFigure( hdc );\r
+                }\r
+                closed = FALSE;\r
+                MoveToEx( hdc, x3, y3, NULL );\r
+                break;\r
+            case NR_LINETO:\r
+                LineTo( hdc, x3, y3 );\r
+                break;\r
+            case NR_CURVETO:\r
+            {\r
+                POINT pt[3];\r
+                pt[0].x = x1;\r
+                pt[0].y = y1;\r
+                pt[1].x = x2;\r
+                pt[1].y = y2;\r
+                pt[2].x = x3;\r
+                pt[2].y = y3;\r
+\r
+                PolyBezierTo( hdc, pt, 3 );\r
+                break;\r
+            }\r
+            default:\r
+                break;\r
+        }\r
+        bp += 1;\r
+    }\r
+    if (closed) {\r
+        CloseFigure( hdc );\r
+    }\r
+    EndPath( hdc );\r
+\r
+    return closed;\r
+}\r
+\r
+\r
+bool\r
+PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)\r
+{\r
+    return ext->get_param_bool("textToPath");\r
+}\r
+\r
+\r
+void\r
+PrintEmfWin32::init (void)\r
+{\r
+    Inkscape::Extension::Extension * ext;\r
+\r
+    /* EMF print */\r
+    ext = Inkscape::Extension::build_from_mem(\r
+        "<inkscape-extension>\n"\r
+        "<name>Enhanced Metafile Print</name>\n"\r
+        "<id>org.inkscape.print.emf.win32</id>\n"\r
+        "<param name=\"destination\" type=\"string\"></param>\n"\r
+        "<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"\r
+        "<param name=\"pageBoundingBox\" type=\"boolean\">TRUE</param>\n"\r
+        "<print/>\n"\r
+        "</inkscape-extension>", new PrintEmfWin32());\r
+\r
+    return;\r
+}\r
+\r
+\r
+}  /* namespace Internal */\r
+}  /* namespace Extension */\r
+}  /* namespace Inkscape */\r
+\r
+#endif /* WIN32 */\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/emf-win32-print.h
new file mode 100644 (file)
index 0000000..d1ac819
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__\r
+#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__\r
+\r
+/*\r
+ * Enhanced Metafile Printing.\r
+ *\r
+ * Author:\r
+ *   Ulf Erikson <ulferikson@users.sf.net>\r
+ *\r
+ * Copyright (C) 2006 Authors\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
+\r
+#ifdef WIN32\r
+\r
+#ifdef HAVE_CONFIG_H\r
+# include "config.h"\r
+#endif\r
+\r
+#include "extension/implementation/implementation.h"\r
+#include "extension/extension.h"\r
+\r
+#include "svg/stringstream.h"\r
+#include "libnr/nr-matrix.h"\r
+#include "libnr/nr-rect.h"\r
+\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+\r
+namespace Inkscape {\r
+namespace Extension {\r
+namespace Internal {\r
+\r
+class PrintEmfWin32 : public Inkscape::Extension::Implementation::Implementation\r
+{\r
+    double  _width;\r
+    double  _height;\r
+    HDC    hdc;\r
+    RECT   rc;\r
+\r
+    HBRUSH hbrush, hbrushOld;\r
+    HPEN hpen, hpenOld;\r
+\r
+    NArtBpath *fill_path;\r
+    NArtBpath *fill_path_copy;\r
+    NRMatrix fill_transform;\r
+    NRRect fill_pbox;\r
+\r
+    unsigned int print_bpath (const NArtBpath *bp, const NRMatrix *transform, NRRect const *pbox);\r
+\r
+public:\r
+    PrintEmfWin32 (void);\r
+    virtual ~PrintEmfWin32 (void);\r
+\r
+    /* Print functions */\r
+    virtual unsigned int setup (Inkscape::Extension::Print * module);\r
+\r
+    virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc);\r
+    virtual unsigned int finish (Inkscape::Extension::Print * module);\r
+\r
+    /* Rendering methods */\r
+    virtual unsigned int fill (Inkscape::Extension::Print * module,\r
+                               const NRBPath *bpath, const NRMatrix *ctm, const SPStyle *style,\r
+                               const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);\r
+    virtual unsigned int stroke (Inkscape::Extension::Print * module,\r
+                                 const NRBPath *bpath, const NRMatrix *transform, const SPStyle *style,\r
+                                 const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);\r
+    virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment);\r
+    bool textToPath (Inkscape::Extension::Print * ext);\r
+\r
+    static void init (void);\r
+\r
+protected:\r
+    void create_brush(SPStyle const *style);\r
+\r
+    void destroy_brush();\r
+\r
+    void create_pen(SPStyle const *style);\r
+\r
+    void destroy_pen();\r
+\r
+    void flush_fill();\r
+\r
+    NArtBpath *copy_bpath(const NArtBpath *bp);\r
+    int cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2);\r
+\r
+};\r
+\r
+}  /* namespace Internal */\r
+}  /* namespace Extension */\r
+}  /* namespace Inkscape */\r
+\r
+#endif /* WIN32 */\r
+\r
+#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_EMF_WIN32_H__ */\r
+\r
+/*\r
+  Local Variables:\r
+  mode:cpp\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r