Code

3eac9e5fc61eb21c6c95ff2572e4320b165a9c51
[inkscape.git] / src / extension / internal / emf-win32-inout.cpp
1 /** \file
2  * Enhanced Metafile Input and Output.
3  */
4 /*
5  * Authors:
6  *   Ulf Erikson <ulferikson@users.sf.net>
7  *
8  * Copyright (C) 2006 Authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
12 /*
13  * References:
14  *  - How to Create & Play Enhanced Metafiles in Win32
15  *      http://support.microsoft.com/kb/q145999/
16  *  - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
17  *      http://support.microsoft.com/kb/q66949/
18  *  - Metafile Functions
19  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
20  *  - Metafile Structures
21  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
22  */
24 #ifdef WIN32
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include "win32.h"
31 #include "emf-win32-print.h"
32 #include "emf-win32-inout.h"
33 #include "inkscape.h"
34 #include "sp-path.h"
35 #include "style.h"
36 #include "color.h"
37 #include "display/curve.h"
38 #include "libnr/n-art-bpath.h"
39 #include "libnr/nr-point-matrix-ops.h"
40 #include "gtk/gtk.h"
41 #include "print.h"
42 #include "glibmm/i18n.h"
43 #include "extension/extension.h"
44 #include "extension/system.h"
45 #include "extension/print.h"
46 #include "extension/db.h"
47 #include "extension/output.h"
48 #include "document.h"
49 #include "display/nr-arena.h"
50 #include "display/nr-arena-item.h"
52 #include "libnr/nr-rect.h"
53 #include "libnr/nr-matrix.h"
54 #include "libnr/nr-pixblock.h"
56 #include <stdio.h>
57 #include <string.h>
59 #include <vector>
60 #include <string>
62 #include "io/sys.h"
64 #include "unit-constants.h"
66 #include "clear-n_.h"
69 #define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32"
71 #ifndef PS_JOIN_MASK
72 #define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND)
73 #endif
76 namespace Inkscape {
77 namespace Extension {
78 namespace Internal {
81 EmfWin32::EmfWin32 (void) // The null constructor
82 {
83     return;
84 }
87 EmfWin32::~EmfWin32 (void) //The destructor
88 {
89     return;
90 }
93 bool
94 EmfWin32::check (Inkscape::Extension::Extension * module)
95 {
96     if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32))
97         return FALSE;
98     return TRUE;
99 }
102 static void
103 emf_print_document_to_file(SPDocument *doc, gchar const *filename)
105     Inkscape::Extension::Print *mod;
106     SPPrintContext context;
107     gchar const *oldconst;
108     gchar *oldoutput;
109     unsigned int ret;
111     sp_document_ensure_up_to_date(doc);
113     mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32);
114     oldconst = mod->get_param_string("destination");
115     oldoutput = g_strdup(oldconst);
116     mod->set_param_string("destination", (gchar *)filename);
118 /* Start */
119     context.module = mod;
120     /* fixme: This has to go into module constructor somehow */
121     /* Create new arena */
122     mod->base = SP_ITEM(sp_document_root(doc));
123     mod->arena = NRArena::create();
124     mod->dkey = sp_item_display_key_new(1);
125     mod->root = sp_item_invoke_show(mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY);
126     /* Print document */
127     ret = mod->begin(doc);
128     if (ret) {
129         throw Inkscape::Extension::Output::save_failed();
130     }
131     sp_item_invoke_print(mod->base, &context);
132     ret = mod->finish();
133     /* Release arena */
134     sp_item_invoke_hide(mod->base, mod->dkey);
135     mod->base = NULL;
136     nr_arena_item_unref(mod->root);
137     mod->root = NULL;
138     nr_object_unref((NRObject *) mod->arena);
139     mod->arena = NULL;
140 /* end */
142     mod->set_param_string("destination", oldoutput);
143     g_free(oldoutput);
145     return;
149 void
150 EmfWin32::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gchar *uri)
152     Inkscape::Extension::Extension * ext;
154     ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32);
155     if (ext == NULL)
156         return;
158     bool old_textToPath  = ext->get_param_bool("textToPath");
159     bool new_val         = mod->get_param_bool("textToPath");
160     ext->set_param_bool("textToPath", new_val);
162     gchar * final_name;
163     final_name = g_strdup_printf("%s", uri);
164     emf_print_document_to_file(doc, final_name);
165     g_free(final_name);
167     ext->set_param_bool("textToPath", old_textToPath);
169     return;
174 typedef struct {
175     int type;
176     ENHMETARECORD *lpEMFR;
177 } EMF_OBJECT, *PEMF_OBJECT;
179 typedef struct emf_callback_data {
180     Glib::ustring *outsvg;
181     Glib::ustring *path;
182     struct SPStyle style;
183     class SPTextStyle tstyle;
184     bool stroke_set;
185     bool fill_set;
186     double xDPI, yDPI;
187     bool pathless_stroke;
189     SIZEL sizeWnd;
190     SIZEL sizeView;
191     float PixelsX;
192     float PixelsY;
193     float MMX;
194     float MMY;
195     float dwInchesX;
196     float dwInchesY;
197     POINTL winorg;
198     POINTL vieworg;
199     double ScaleX, ScaleY;
201     int n_obj;
202     PEMF_OBJECT emf_obj;
203 } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
206 static void
207 output_style(PEMF_CALLBACK_DATA d, int iType)
209     SVGOStringStream tmp_style;
210     char tmp[1024] = {0};
212     float fill_rgb[3];
213     sp_color_get_rgb_floatv( &(d->style.fill.value.color), fill_rgb );
214     
215     float stroke_rgb[3];
216     sp_color_get_rgb_floatv(&(d->style.stroke.value.color), stroke_rgb);
218     *(d->outsvg) += "\n\tstyle=\"";
219     if (iType == EMR_STROKEPATH || !d->fill_set) {
220         tmp_style << "fill:none;";
221     } else {
222         snprintf(tmp, 1023,
223                  "fill:#%02x%02x%02x;",
224                  SP_COLOR_F_TO_U(fill_rgb[0]),
225                  SP_COLOR_F_TO_U(fill_rgb[1]),
226                  SP_COLOR_F_TO_U(fill_rgb[2]));
227         tmp_style << tmp;
228         snprintf(tmp, 1023,
229                  "fill-rule:%s;",
230                  d->style.fill_rule.value != 0 ? "evenodd" : "nonzero");
231         tmp_style << tmp;
232         tmp_style << "fill-opacity:1;";
234         if (d->fill_set && d->stroke_set && d->style.stroke_width.value == 1 &&
235             fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
236         {
237             d->stroke_set = false;
238         }
239     }
241     if (iType == EMR_FILLPATH || !d->stroke_set) {
242         tmp_style << "stroke:none;";
243     } else {
244         snprintf(tmp, 1023,
245                  "stroke:#%02x%02x%02x;",
246                  SP_COLOR_F_TO_U(stroke_rgb[0]),
247                  SP_COLOR_F_TO_U(stroke_rgb[1]),
248                  SP_COLOR_F_TO_U(stroke_rgb[2]));
249         tmp_style << tmp;
251         tmp_style << "stroke-width:" <<
252             MAX( 0.001, d->style.stroke_width.value ) << "px;";
254         tmp_style << "stroke-linejoin:" <<
255             (d->style.stroke_linejoin.computed == 0 ? "miter" :
256              d->style.stroke_linejoin.computed == 1 ? "round" :
257              d->style.stroke_linejoin.computed == 2 ? "bevel" :
258              "unknown") << ";";
260         if (d->style.stroke_linejoin.computed == 0) {
261             tmp_style << "stroke-miterlimit:" <<
262                 MAX( 0.01, d->style.stroke_miterlimit.value ) << ";";
263         }
265         if (d->style.stroke_dasharray_set &&
266             d->style.stroke_dash.n_dash && d->style.stroke_dash.dash)
267         {
268             tmp_style << "stroke-dasharray:";
269             for (int i=0; i<d->style.stroke_dash.n_dash; i++) {
270                 if (i)
271                     tmp_style << ",";
272                 tmp_style << d->style.stroke_dash.dash[i];
273             }
274             tmp_style << ";";
275             tmp_style << "stroke-dashoffset:0;";
276         } else {
277             tmp_style << "stroke-dasharray:none;";
278         }
279         tmp_style << "stroke-opacity:1;";
280     }
281     tmp_style << "\" ";
283     *(d->outsvg) += tmp_style.str().c_str();
287 static double
288 pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
290     double tmp = px - d->winorg.x;
291     tmp *= (double) PX_PER_IN / d->ScaleX;
292     tmp += d->vieworg.x;
293     return tmp;
297 static double
298 pix_y_to_point(PEMF_CALLBACK_DATA d, double px)
300     double tmp = px - d->winorg.y;
301     tmp *= (double) PX_PER_IN / d->ScaleY;
302     tmp += d->vieworg.y;
303     return tmp;
307 static double
308 pix_size_to_point(PEMF_CALLBACK_DATA d, double px)
310     double tmp = px;
311     tmp *= (double) PX_PER_IN / d->ScaleX;
312     return tmp;
316 static void
317 select_pen(PEMF_CALLBACK_DATA d, int index)
319     PEMRCREATEPEN pEmr = NULL;
321     if (index >= 0 && index < d->n_obj)
322         pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;
324     if (!pEmr)
325         return;
327     switch (pEmr->lopn.lopnStyle) {
328         case PS_DASH:
329         case PS_DOT:
330         case PS_DASHDOT:
331         case PS_DASHDOTDOT:
332         {
333             int i = 0;
334             d->style.stroke_dash.n_dash =
335                 PS_DASHDOTDOT ? 6 : PS_DASHDOT ? 4 : 2;
336             if (d->style.stroke_dash.dash)
337                 delete[] d->style.stroke_dash.dash;
338             d->style.stroke_dash.dash = new double[d->style.stroke_dash.n_dash];
339             if (pEmr->lopn.lopnStyle==PS_DASH || pEmr->lopn.lopnStyle==PS_DASHDOT || pEmr->lopn.lopnStyle==PS_DASHDOTDOT) {
340                 d->style.stroke_dash.dash[i++] = 3;
341                 d->style.stroke_dash.dash[i++] = 1;
342             }
343             if (pEmr->lopn.lopnStyle==PS_DOT || pEmr->lopn.lopnStyle==PS_DASHDOT || pEmr->lopn.lopnStyle==PS_DASHDOTDOT) {
344                 d->style.stroke_dash.dash[i++] = 1;
345                 d->style.stroke_dash.dash[i++] = 1;
346             }
347             if (pEmr->lopn.lopnStyle==PS_DASHDOTDOT) {
348                 d->style.stroke_dash.dash[i++] = 1;
349                 d->style.stroke_dash.dash[i++] = 1;
350             }
351             
352             d->style.stroke_dasharray_set = 1;
353             break;
354         }
355         
356         case PS_SOLID:
357         default:
358         {
359             d->style.stroke_dasharray_set = 0;
360             break;
361         }
362     }
364     d->stroke_set = true;
366     if (pEmr->lopn.lopnStyle == PS_NULL) {
367         d->style.stroke_width.value = 0;
368         d->stroke_set = false;
369     } else if (pEmr->lopn.lopnWidth.x) {
370         d->style.stroke_width.value = pix_size_to_point( d, pEmr->lopn.lopnWidth.x );
371     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
372         //d->style.stroke_width.value = 1.0;
373         d->style.stroke_width.value = pix_size_to_point( d, 1 );
374     }
376     double r, g, b;
377     r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );
378     g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );
379     b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );
380     d->style.stroke.value.color.set( r, g, b );
382     d->style.stroke_linejoin.computed = 1;
386 static void
387 select_extpen(PEMF_CALLBACK_DATA d, int index)
389     PEMREXTCREATEPEN pEmr = NULL;
391     if (index >= 0 && index < d->n_obj)
392         pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
394     if (!pEmr)
395         return;
397     switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {
398         case PS_USERSTYLE:
399         {
400             if (pEmr->elp.elpNumEntries) {
401                 d->style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;
402                 if (d->style.stroke_dash.dash)
403                     delete[] d->style.stroke_dash.dash;
404                 d->style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];
405                 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
406                     d->style.stroke_dash.dash[i] = pix_size_to_point( d, pEmr->elp.elpStyleEntry[i] );
407                 }
408                 d->style.stroke_dasharray_set = 1;
409             } else {
410                 d->style.stroke_dasharray_set = 0;
411             }
412             break;
413         }
414         default:
415         {
416             d->style.stroke_dasharray_set = 0;
417             break;
418         }
419     }
421     switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {
422         case PS_ENDCAP_ROUND:
423         {
424             d->style.stroke_linecap.computed = 1;
425             break;
426         }
427         case PS_ENDCAP_SQUARE:
428         {
429             d->style.stroke_linecap.computed = 2;
430             break;
431         }
432         case PS_ENDCAP_FLAT:
433         default:
434         {
435             d->style.stroke_linecap.computed = 0;
436             break;
437         }
438     }
440     switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {
441         case PS_JOIN_BEVEL:
442         {
443             d->style.stroke_linejoin.computed = 2;
444             break;
445         }
446         case PS_JOIN_MITER:
447         {
448             d->style.stroke_linejoin.computed = 0;
449             break;
450         }
451         case PS_JOIN_ROUND:
452         default:
453         {
454             d->style.stroke_linejoin.computed = 1;
455             break;
456         }
457     }
459     d->style.stroke_width.value = pix_size_to_point( d, pEmr->elp.elpWidth );
461     double r, g, b;
462     r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );
463     g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );
464     b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );
466     d->style.stroke.value.color.set( r, g, b );
468     d->stroke_set = true;
472 static void
473 select_brush(PEMF_CALLBACK_DATA d, int index)
475     PEMRCREATEBRUSHINDIRECT pEmr = NULL;
477     if (index >= 0 && index < d->n_obj)
478         pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
480     if (!pEmr)
481         return;
483     if (pEmr->lb.lbStyle == BS_SOLID) {
484         double r, g, b;
485         r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );
486         g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );
487         b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );
488         d->style.fill.value.color.set( r, g, b );
489     }
491     d->fill_set = true;
495 static void
496 select_font(PEMF_CALLBACK_DATA d, int index)
498     PEMREXTCREATEFONTINDIRECTW pEmr = NULL;
500     if (index >= 0 && index < d->n_obj)
501         pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR;
503     if (!pEmr)
504         return;
506     d->style.font_size.computed = pix_size_to_point( d, pEmr->elfw.elfLogFont.lfHeight );
507     d->style.font_weight.value = pEmr->elfw.elfLogFont.lfWeight;
508     d->style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
509     d->style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline;
510     d->style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
511     if (d->tstyle.font_family.value)
512         g_free(d->tstyle.font_family.value);
513     d->tstyle.font_family.value =
514         (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL );
517 static void
518 delete_object(PEMF_CALLBACK_DATA d, int index)
520     if (index >= 0 && index < d->n_obj) {
521         d->emf_obj[index].type = 0;
522         if (d->emf_obj[index].lpEMFR)
523             free(d->emf_obj[index].lpEMFR);
524         d->emf_obj[index].lpEMFR = NULL;
525     }
529 static void
530 insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)
532     if (index >= 0 && index < d->n_obj) {
533         delete_object(d, index);
534         d->emf_obj[index].type = type;
535         d->emf_obj[index].lpEMFR = pObj;
536     }
540 static int CALLBACK
541 myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)
543     PEMF_CALLBACK_DATA d;
544     SVGOStringStream tmp_outsvg;
545     SVGOStringStream tmp_path;
546     SVGOStringStream tmp_str;
548     d = (PEMF_CALLBACK_DATA) lpData;
550     if (d->pathless_stroke) {
551         if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 &&
552             lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 &&
553             lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO)
554         {
555             *(d->outsvg) += "    <path ";
556             output_style(d, EMR_STROKEPATH);
557             *(d->outsvg) += "\n\t";
558             *(d->outsvg) += *(d->path);
559             *(d->outsvg) += " \" /> \n";
560             *(d->path) = "";
561             d->pathless_stroke = false;
562         }
563     }
565     switch (lpEMFR->iType)
566     {
567         case EMR_HEADER:
568         {
569             ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;
570             tmp_outsvg << "<svg\n";
572             d->xDPI = 2540;
573             d->yDPI = 2540;
575             d->PixelsX = pEmr->rclFrame.right - pEmr->rclFrame.left;
576             d->PixelsY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;
578             d->MMX = d->PixelsX / 100.0;
579             d->MMY = d->PixelsY / 100.0;
581             tmp_outsvg <<
582                 "  width=\"" << d->MMX << "mm\"\n" <<
583                 "  height=\"" << d->MMY << "mm\">\n";
585             if (pEmr->nHandles) {
586                 d->n_obj = pEmr->nHandles;
587                 d->emf_obj = new EMF_OBJECT[d->n_obj];
588                 
589                 // Init the new emf_obj list elements to null, provided the
590                 // dynamic allocation succeeded.
591                 if ( d->emf_obj != NULL )
592                 {
593                     for( unsigned int i=0; i < d->n_obj; ++i )
594                         d->emf_obj[i].lpEMFR = NULL;
595                 } //if
597             } else {
598                 d->emf_obj = NULL;
599             }
601             break;
602         }
603         case EMR_POLYBEZIER:
604         {
605             PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;
606             DWORD i,j;
608             if (pEmr->cptl<4)
609                 break;
611             *(d->outsvg) += "    <path ";
612             output_style(d, EMR_STROKEPATH);
613             *(d->outsvg) += "\n\td=\"";
615             tmp_str <<
616                 "\n\tM " <<
617                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<
618                 pix_x_to_point( d, pEmr->aptl[0].y) << " ";
620             for (i=1; i<pEmr->cptl; ) {
621                 tmp_str << "\n\tC ";
622                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
623                     tmp_str <<
624                         pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
625                         pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
626                 }
627             }
629             *(d->outsvg) += tmp_str.str().c_str();
630             *(d->outsvg) += " \" /> \n";
632             break;
633         }
634         case EMR_POLYGON:
635         {
636             EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;
637             DWORD i;
639             if (pEmr->cptl < 2)
640                 break;
642             *(d->outsvg) += "    <path ";
643             output_style(d, EMR_STROKEANDFILLPATH);
644             *(d->outsvg) += "\n\td=\"";
646             tmp_str <<
647                 "\n\tM " <<
648                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<
649                 pix_y_to_point( d, pEmr->aptl[0].y ) << " ";
651             for (i=1; i<pEmr->cptl; i++) {
652                 tmp_str <<
653                     "\n\tL " <<
654                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
655                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
656             }
658             *(d->outsvg) += tmp_str.str().c_str();
659             *(d->outsvg) += " z \" /> \n";
661             break;
662         }
663         case EMR_POLYLINE:
664         {
665             EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;
666             DWORD i;
668             if (pEmr->cptl<2)
669                 break;
671             *(d->outsvg) += "    <path ";
672             output_style(d, EMR_STROKEPATH);
673             *(d->outsvg) += "\n\td=\"";
675             tmp_str <<
676                 "\n\tM " <<
677                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<
678                 pix_y_to_point( d, pEmr->aptl[0].y ) << " ";
680             for (i=1; i<pEmr->cptl; i++) {
681                 tmp_str <<
682                     "\n\tL " <<
683                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
684                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
685             }
687             *(d->outsvg) += tmp_str.str().c_str();
688             *(d->outsvg) += " \" /> \n";
690             break;
691         }
692         case EMR_POLYBEZIERTO:
693         {
694             PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;
695             DWORD i,j;
697             if (d->path->empty())
698                 *(d->path) = "d=\"";
700             for (i=0; i<pEmr->cptl;) {
701                 tmp_path << "\n\tC ";
702                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
703                     tmp_path <<
704                         pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
705                         pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
706                 }
707             }
709             break;
710         }
711         case EMR_POLYLINETO:
712         {
713             PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;
714             DWORD i;
716             if (d->path->empty())
717                 *(d->path) = "d=\"";
719             for (i=0; i<pEmr->cptl;i++) {
720                 tmp_path <<
721                     "\n\tL " <<
722                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
723                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
724             }
726             break;
727         }
728         case EMR_POLYPOLYLINE:
729         case EMR_POLYPOLYGON:
730         {
731             PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR;
732             unsigned int n, i, j;
734             if (lpEMFR->iType == EMR_POLYPOLYGON)
735                 *(d->outsvg) += "<!-- EMR_POLYPOLYGON... -->\n";
736             else
737                 *(d->outsvg) += "<!-- EMR_POLYPOLYLINE... -->\n";
739             *(d->outsvg) += "<path ";
740             output_style(d, lpEMFR->iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
741             *(d->outsvg) += "\n\td=\"";
743             POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys];
745             i = 0;
746             for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
747                 SVGOStringStream poly_path;
749                 poly_path << "\n\tM " <<
750                     pix_x_to_point( d, aptl[i].x ) << " " <<
751                     pix_y_to_point( d, aptl[i].y ) << " ";
752                 i++;
754                 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
755                     poly_path << "\n\tL " <<
756                         pix_x_to_point( d, aptl[i].x ) << " " <<
757                         pix_y_to_point( d, aptl[i].y ) << " ";
758                     i++;
759                 }
761                 *(d->outsvg) += poly_path.str().c_str();
762                 if (lpEMFR->iType == EMR_POLYPOLYGON)
763                     *(d->outsvg) += " z";
764                 *(d->outsvg) += " \n";
765             }
767             *(d->outsvg) += " \" /> \n";
768             break;
769         }
770         case EMR_SETWINDOWEXTEX:
771         {
772             PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;
774             *(d->outsvg) += "<!-- EMR_SETWINDOWEXTEX -->\n";
776             d->sizeWnd = pEmr->szlExtent;
777             d->PixelsX = d->sizeWnd.cx;
778             d->PixelsY = d->sizeWnd.cy;
780             d->ScaleX = d->xDPI / (100*d->MMX / d->PixelsX);
781             d->ScaleY = d->yDPI / (100*d->MMY / d->PixelsY);
783             break;
784         }
785         case EMR_SETWINDOWORGEX:
786         {
787             PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;
788             d->winorg = pEmr->ptlOrigin;
789             break;
790         }
791         case EMR_SETVIEWPORTEXTEX:
792         {
793             PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;
795             *(d->outsvg) += "<!-- EMR_SETVIEWPORTEXTEX -->\n";
797             d->sizeView = pEmr->szlExtent;
799             if (d->sizeWnd.cx && d->sizeWnd.cy) {
800                 HDC hScreenDC = GetDC( NULL );
802                 float scrPixelsX = (float)GetDeviceCaps( hScreenDC, HORZRES );
803                 float scrPixelsY = (float)GetDeviceCaps( hScreenDC, VERTRES );
804                 float scrMMX = (float)GetDeviceCaps( hScreenDC, HORZSIZE );
805                 float scrMMY = (float)GetDeviceCaps( hScreenDC, VERTSIZE );
807                 ReleaseDC( NULL, hScreenDC );
809                 d->dwInchesX = d->sizeView.cx / (25.4f*scrPixelsX/scrMMX);
810                 d->dwInchesY = d->sizeView.cy / (25.4f*scrPixelsY/scrMMY);
811                 d->xDPI = d->sizeWnd.cx / d->dwInchesX;
812                 d->yDPI = d->sizeWnd.cy / d->dwInchesY;
814                 if (1) {
815                     d->xDPI = 2540;
816                     d->yDPI = 2540;
817                     d->dwInchesX = d->PixelsX / d->xDPI;
818                     d->dwInchesY = d->PixelsY / d->yDPI;
819                     d->ScaleX = d->xDPI;
820                     d->ScaleY = d->yDPI;
821                 }
823                 d->MMX = d->dwInchesX * MM_PER_IN;
824                 d->MMY = d->dwInchesY * MM_PER_IN;
825             }
827             break;
828         }
829         case EMR_SETVIEWPORTORGEX:
830         {
831             PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;
832             d->vieworg = pEmr->ptlOrigin;
833             break;
834         }
835         case EMR_SETBRUSHORGEX:
836             *(d->outsvg) += "<!-- EMR_SETBRUSHORGEX -->\n";
837             break;
838         case EMR_EOF:
839         {
840             tmp_outsvg << "</svg>\n";
841             break;
842         }
843         case EMR_SETPIXELV:
844             *(d->outsvg) += "<!-- EMR_SETPIXELV -->\n";
845             break;
846         case EMR_SETMAPPERFLAGS:
847             *(d->outsvg) += "<!-- EMR_SETMAPPERFLAGS -->\n";
848             break;
849         case EMR_SETMAPMODE:
850             *(d->outsvg) += "<!-- EMR_SETMAPMODE -->\n";
851             break;
852         case EMR_SETBKMODE:
853             *(d->outsvg) += "<!-- EMR_SETBKMODE -->\n";
854             break;
855         case EMR_SETPOLYFILLMODE:
856         {
857             PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;
858             d->style.fill_rule.value =
859                 (pEmr->iMode == WINDING ? 0 :
860                  pEmr->iMode == ALTERNATE ? 1 : 0);
861             break;
862         }
863         case EMR_SETROP2:
864             *(d->outsvg) += "<!-- EMR_SETROP2 -->\n";
865             break;
866         case EMR_SETSTRETCHBLTMODE:
867             *(d->outsvg) += "<!-- EMR_SETSTRETCHBLTMODE -->\n";
868             break;
869         case EMR_SETTEXTALIGN:
870             *(d->outsvg) += "<!-- EMR_SETTEXTALIGN -->\n";
871             break;
872         case EMR_SETCOLORADJUSTMENT:
873             *(d->outsvg) += "<!-- EMR_SETCOLORADJUSTMENT -->\n";
874             break;
875         case EMR_SETTEXTCOLOR:
876             *(d->outsvg) += "<!-- EMR_SETTEXTCOLOR -->\n";
877             break;
878         case EMR_SETBKCOLOR:
879             *(d->outsvg) += "<!-- EMR_SETBKCOLOR -->\n";
880             break;
881         case EMR_OFFSETCLIPRGN:
882             *(d->outsvg) += "<!-- EMR_OFFSETCLIPRGN -->\n";
883             break;
884         case EMR_MOVETOEX:
885         {
886             PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;
888             if (d->path->empty()) {
889                 d->pathless_stroke = true;
890                 *(d->path) = "d=\"";
891             }
893             tmp_path <<
894                 "\n\tM " <<
895                 pix_x_to_point( d, pEmr->ptl.x ) << " " <<
896                 pix_y_to_point( d, pEmr->ptl.y ) << " ";
897             break;
898         }
899         case EMR_SETMETARGN:
900             *(d->outsvg) += "<!-- EMR_SETMETARGN -->\n";
901             break;
902         case EMR_EXCLUDECLIPRECT:
903             *(d->outsvg) += "<!-- EMR_EXCLUDECLIPRECT -->\n";
904             break;
905         case EMR_INTERSECTCLIPRECT:
906             *(d->outsvg) += "<!-- EMR_INTERSECTCLIPRECT -->\n";
907             break;
908         case EMR_SCALEVIEWPORTEXTEX:
909             *(d->outsvg) += "<!-- EMR_SCALEVIEWPORTEXTEX -->\n";
910             break;
911         case EMR_SCALEWINDOWEXTEX:
912             *(d->outsvg) += "<!-- EMR_SCALEWINDOWEXTEX -->\n";
913             break;
914         case EMR_SAVEDC:
915             *(d->outsvg) += "<!-- EMR_SAVEDC -->\n";
916             break;
917         case EMR_RESTOREDC:
918             *(d->outsvg) += "<!-- EMR_RESTOREDC -->\n";
919             break;
920         case EMR_SETWORLDTRANSFORM:
921             *(d->outsvg) += "<!-- EMR_SETWORLDTRANSFORM -->\n";
922             break;
923         case EMR_MODIFYWORLDTRANSFORM:
924             *(d->outsvg) += "<!-- EMR_MODIFYWORLDTRANSFORM -->\n";
925             break;
926         case EMR_SELECTOBJECT:
927         {
928             PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;
929             unsigned int index = pEmr->ihObject;
931             if (index >= ENHMETA_STOCK_OBJECT) {
932                 index -= ENHMETA_STOCK_OBJECT;
933                 switch (index) {
934                     case NULL_BRUSH:
935                         d->fill_set = false;
936                         break;
937                     case BLACK_BRUSH:
938                     case DKGRAY_BRUSH:
939                     case GRAY_BRUSH:
940                     case LTGRAY_BRUSH:
941                     case WHITE_BRUSH:
942                     {
943                         float val = 0;
944                         switch (index) {
945                             case BLACK_BRUSH:
946                                 val = 0.0 / 255.0;
947                                 break;
948                             case DKGRAY_BRUSH:
949                                 val = 64.0 / 255.0;
950                                 break;
951                             case GRAY_BRUSH:
952                                 val = 128.0 / 255.0;
953                                 break;
954                             case LTGRAY_BRUSH:
955                                 val = 192.0 / 255.0;
956                                 break;
957                             case WHITE_BRUSH:
958                                 val = 255.0 / 255.0;
959                                 break;
960                         }
961                         d->style.fill.value.color.set( val, val, val );
963                         d->fill_set = true;
964                         break;
965                     }
966                     case NULL_PEN:
967                         d->stroke_set = false;
968                         break;
969                     case BLACK_PEN:
970                     case WHITE_PEN:
971                     {
972                         float val = index == BLACK_PEN ? 0 : 1;
973                         d->style.stroke_dasharray_set = 0;
974                         d->style.stroke_width.value = 1.0;
975                         d->style.stroke.value.color.set( val, val, val );
977                         d->stroke_set = true;
979                         break;
980                     }
981                 }
982             } else {
983                 if (index >= 0 && index < (unsigned int) d->n_obj) {
984                     switch (d->emf_obj[index].type)
985                     {
986                         case EMR_CREATEPEN:
987                             select_pen(d, index);
988                             break;
989                         case EMR_CREATEBRUSHINDIRECT:
990                             select_brush(d, index);
991                             break;
992                         case EMR_EXTCREATEPEN:
993                             select_extpen(d, index);
994                             break;
995                         case EMR_EXTCREATEFONTINDIRECTW:
996                             select_font(d, index);
997                             break;
998                     }
999                 }
1000             }
1001             break;
1002         }
1003         case EMR_CREATEPEN:
1004         {
1005             PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;
1006             int index = pEmr->ihPen;
1008             EMRCREATEPEN *pPen =
1009                 (EMRCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) );
1010             pPen->lopn = pEmr->lopn;
1011             insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);
1013             break;
1014         }
1015         case EMR_CREATEBRUSHINDIRECT:
1016         {
1017             PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;
1018             int index = pEmr->ihBrush;
1020             EMRCREATEBRUSHINDIRECT *pBrush =
1021                 (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );
1022             pBrush->lb = pEmr->lb;
1023             insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);
1025             break;
1026         }
1027         case EMR_DELETEOBJECT:
1028             break;
1029         case EMR_ANGLEARC:
1030             *(d->outsvg) += "<!-- EMR_ANGLEARC -->\n";
1031             break;
1032         case EMR_ELLIPSE:
1033             *(d->outsvg) += "<!-- EMR_ELLIPSE -->\n";
1034             break;
1035         case EMR_RECTANGLE:
1036             *(d->outsvg) += "<!-- EMR_RECTANGLE -->\n";
1037             break;
1038         case EMR_ROUNDRECT:
1039             *(d->outsvg) += "<!-- EMR_ROUNDRECT -->\n";
1040             break;
1041         case EMR_ARC:
1042             *(d->outsvg) += "<!-- EMR_ARC -->\n";
1043             break;
1044         case EMR_CHORD:
1045             *(d->outsvg) += "<!-- EMR_CHORD -->\n";
1046             break;
1047         case EMR_PIE:
1048             *(d->outsvg) += "<!-- EMR_PIE -->\n";
1049             break;
1050         case EMR_SELECTPALETTE:
1051             *(d->outsvg) += "<!-- EMR_SELECTPALETTE -->\n";
1052             break;
1053         case EMR_CREATEPALETTE:
1054             *(d->outsvg) += "<!-- EMR_CREATEPALETTE -->\n";
1055             break;
1056         case EMR_SETPALETTEENTRIES:
1057             *(d->outsvg) += "<!-- EMR_SETPALETTEENTRIES -->\n";
1058             break;
1059         case EMR_RESIZEPALETTE:
1060             *(d->outsvg) += "<!-- EMR_RESIZEPALETTE -->\n";
1061             break;
1062         case EMR_REALIZEPALETTE:
1063             *(d->outsvg) += "<!-- EMR_REALIZEPALETTE -->\n";
1064             break;
1065         case EMR_EXTFLOODFILL:
1066             *(d->outsvg) += "<!-- EMR_EXTFLOODFILL -->\n";
1067             break;
1068         case EMR_LINETO:
1069         {
1070             PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;
1072             if (d->path->empty())
1073                 *(d->path) = "d=\"";
1075             tmp_path <<
1076                 "\n\tL " <<
1077                 pix_x_to_point( d, pEmr->ptl.x ) << " " <<
1078                 pix_y_to_point( d, pEmr->ptl.y ) << " ";
1079             break;
1080         }
1081         case EMR_ARCTO:
1082             *(d->outsvg) += "<!-- EMR_ARCTO -->\n";
1083             break;
1084         case EMR_POLYDRAW:
1085             *(d->outsvg) += "<!-- EMR_POLYDRAW -->\n";
1086             break;
1087         case EMR_SETARCDIRECTION:
1088             *(d->outsvg) += "<!-- EMR_SETARCDIRECTION -->\n";
1089             break;
1090         case EMR_SETMITERLIMIT:
1091         {
1092             PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;
1093             d->style.stroke_miterlimit.value = pix_size_to_point( d, pEmr->eMiterLimit );
1095             if (d->style.stroke_miterlimit.value < 1)
1096                 d->style.stroke_miterlimit.value = 1.0;
1098             break;
1099         }
1100         case EMR_BEGINPATH:
1101         {
1102             tmp_path << "d=\"";
1103             *(d->path) = "";
1104             break;
1105         }
1106         case EMR_ENDPATH:
1107         {
1108             tmp_path << "\"";
1109             break;
1110         }
1111         case EMR_CLOSEFIGURE:
1112         {
1113             tmp_path << "\n\tz";
1114             break;
1115         }
1116         case EMR_FILLPATH:
1117         case EMR_STROKEANDFILLPATH:
1118         case EMR_STROKEPATH:
1119         {
1120             *(d->outsvg) += "    <path ";
1121             output_style(d, lpEMFR->iType);
1122             *(d->outsvg) += "\n\t";
1123             *(d->outsvg) += *(d->path);
1124             *(d->outsvg) += " /> \n";
1125             *(d->path) = "";
1126             break;
1127         }
1128         case EMR_FLATTENPATH:
1129             *(d->outsvg) += "<!-- EMR_FLATTENPATH -->\n";
1130             break;
1131         case EMR_WIDENPATH:
1132             *(d->outsvg) += "<!-- EMR_WIDENPATH -->\n";
1133             break;
1134         case EMR_SELECTCLIPPATH:
1135             *(d->outsvg) += "<!-- EMR_SELECTCLIPPATH -->\n";
1136             break;
1137         case EMR_ABORTPATH:
1138             *(d->outsvg) += "<!-- EMR_ABORTPATH -->\n";
1139             break;
1140         case EMR_GDICOMMENT:
1141             *(d->outsvg) += "<!-- EMR_GDICOMMENT -->\n";
1142             break;
1143         case EMR_FILLRGN:
1144             *(d->outsvg) += "<!-- EMR_FILLRGN -->\n";
1145             break;
1146         case EMR_FRAMERGN:
1147             *(d->outsvg) += "<!-- EMR_FRAMERGN -->\n";
1148             break;
1149         case EMR_INVERTRGN:
1150             *(d->outsvg) += "<!-- EMR_INVERTRGN -->\n";
1151             break;
1152         case EMR_PAINTRGN:
1153             *(d->outsvg) += "<!-- EMR_PAINTRGN -->\n";
1154             break;
1155         case EMR_EXTSELECTCLIPRGN:
1156             *(d->outsvg) += "<!-- EMR_EXTSELECTCLIPRGN -->\n";
1157             break;
1158         case EMR_BITBLT:
1159             *(d->outsvg) += "<!-- EMR_BITBLT -->\n";
1160             break;
1161         case EMR_STRETCHBLT:
1162             *(d->outsvg) += "<!-- EMR_STRETCHBLT -->\n";
1163             break;
1164         case EMR_MASKBLT:
1165             *(d->outsvg) += "<!-- EMR_MASKBLT -->\n";
1166             break;
1167         case EMR_PLGBLT:
1168             *(d->outsvg) += "<!-- EMR_PLGBLT -->\n";
1169             break;
1170         case EMR_SETDIBITSTODEVICE:
1171             *(d->outsvg) += "<!-- EMR_SETDIBITSTODEVICE -->\n";
1172             break;
1173         case EMR_STRETCHDIBITS:
1174             *(d->outsvg) += "<!-- EMR_STRETCHDIBITS -->\n";
1175             break;
1176         case EMR_EXTCREATEFONTINDIRECTW:
1177         {
1178             PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR;
1179             int index = pEmr->ihFont;
1181             EMREXTCREATEFONTINDIRECTW *pFont =
1182                 (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) );
1183             pFont->elfw = pEmr->elfw;
1184             insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont);
1186             break;
1187         }
1188         case EMR_EXTTEXTOUTA:
1189         {
1190             *(d->outsvg) += "<!-- EMR_EXTTEXTOUTA -->\n";
1191             break;
1192         }
1193         case EMR_EXTTEXTOUTW:
1194         {
1195             PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR;
1197             double x = pEmr->emrtext.ptlReference.x;
1198             double y = pEmr->emrtext.ptlReference.y;
1200             x = pix_x_to_point(d, x);
1201             y = pix_y_to_point(d, y);
1203             wchar_t *text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString);
1204 /*
1205             int i;
1206             for (i=0; i<pEmr->emrtext.nChars; i++) {
1207                 if (text[i] < L' ' || text[i] > L'z')
1208                     text[i] = L'?';
1209             }
1210 */
1211             gchar *t =
1212                 (gchar *) g_utf16_to_utf8( (gunichar2 *) text, pEmr->emrtext.nChars, NULL, NULL, NULL );
1214             if (t) {
1215                 SVGOStringStream ts;
1217                 gchar *escaped = g_markup_escape_text(t, -1);
1219                 int j;
1220                 for (j=0; j<strlen(escaped); j++) {
1221                     if (escaped[j] < 32 || escaped[j] > 127)
1222                         escaped[j] = '?';
1223                 }
1225                 float text_rgb[3];
1226                 sp_color_get_rgb_floatv( &(d->style.fill.value.color), text_rgb );
1228                 char tmp[128];
1229                 snprintf(tmp, 127,
1230                          "fill:#%02x%02x%02x;",
1231                          SP_COLOR_F_TO_U(text_rgb[0]),
1232                          SP_COLOR_F_TO_U(text_rgb[1]),
1233                          SP_COLOR_F_TO_U(text_rgb[2]));
1235                 bool i = (d->style.font_style.value == SP_CSS_FONT_STYLE_ITALIC);
1236                 bool o = (d->style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
1237                 bool b = (d->style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
1238                     (d->style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->style.font_weight.value <= SP_CSS_FONT_WEIGHT_900);
1240                 ts << "    <text\n";
1241                 ts << "        xml:space=\"preserve\"\n";
1242                 ts << "        x=\"" << x << "\"\n";
1243                 ts << "        y=\"" << y << "\"\n";
1244                 ts << "        style=\""
1245                    << "font-size:" << d->style.font_size.computed << "px;"
1246                    << tmp
1247                    << "font-style:" << (i ? "italic" : "normal") << ";"
1248                    << "font-weight:" << (b ? "bold" : "normal") << ";"
1249 //                   << "text-align:" << (b ? "start" : "center" : "end") << ";"
1250                    << "font-family:" << d->tstyle.font_family.value << ";"
1251                    << "\"\n";
1252                 ts << "    >";
1253                 ts << escaped;
1254                 ts << "</text>\n";
1255                 
1256                 *(d->outsvg) += ts.str().c_str();
1257                 
1258                 g_free(escaped);
1259                 g_free(t);
1260             }
1261             
1262             break;
1263         }
1264         case EMR_POLYBEZIER16:
1265         {
1266             PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;
1267             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1268             DWORD i,j;
1270             if (pEmr->cpts<4)
1271                 break;
1273             *(d->outsvg) += "    <path ";
1274             output_style(d, EMR_STROKEPATH);
1275             *(d->outsvg) += "\n\td=\"";
1277             tmp_str <<
1278                 "\n\tM " <<
1279                 pix_x_to_point( d, apts[0].x ) << " " <<
1280                 pix_y_to_point( d, apts[0].y ) << " ";
1282             for (i=1; i<pEmr->cpts; ) {
1283                 tmp_str << "\n\tC ";
1284                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1285                     tmp_str <<
1286                         pix_x_to_point( d, apts[i].x ) << " " <<
1287                         pix_y_to_point( d, apts[i].y ) << " ";
1288                 }
1289             }
1291             *(d->outsvg) += tmp_str.str().c_str();
1292             *(d->outsvg) += " \" /> \n";
1294             break;
1295         }
1296         case EMR_POLYGON16:
1297         {
1298             PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;
1299             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1300             unsigned int i;
1302             *(d->outsvg) += "<path ";
1303             output_style(d, EMR_STROKEANDFILLPATH);
1304             *(d->outsvg) += "\n\td=\"";
1306             // skip the first point?
1307             tmp_path << "\n\tM " <<
1308                 pix_x_to_point( d, apts[1].x ) << " " <<
1309                 pix_y_to_point( d, apts[1].y ) << " ";
1311             for (i=2; i<pEmr->cpts; i++) {
1312                 tmp_path << "\n\tL " <<
1313                     pix_x_to_point( d, apts[i].x ) << " " <<
1314                     pix_y_to_point( d, apts[i].y ) << " ";
1315             }
1317             *(d->outsvg) += tmp_path.str().c_str();
1318             *(d->outsvg) += " z \" /> \n";
1320             break;
1321         }
1322         case EMR_POLYLINE16:
1323         {
1324             EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;
1325             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1326             DWORD i;
1328             if (pEmr->cpts<2)
1329                 break;
1331             *(d->outsvg) += "    <path ";
1332             output_style(d, EMR_STROKEPATH);
1333             *(d->outsvg) += "\n\td=\"";
1335             tmp_str <<
1336                 "\n\tM " <<
1337                 pix_x_to_point( d, apts[0].x ) << " " <<
1338                 pix_y_to_point( d, apts[0].y ) << " ";
1340             for (i=1; i<pEmr->cpts; i++) {
1341                 tmp_str <<
1342                     "\n\tL " <<
1343                     pix_x_to_point( d, apts[i].x ) << " " <<
1344                     pix_y_to_point( d, apts[i].y ) << " ";
1345             }
1347             *(d->outsvg) += tmp_str.str().c_str();
1348             *(d->outsvg) += " \" /> \n";
1350             break;
1351         }
1352         case EMR_POLYBEZIERTO16:
1353         {
1354             PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;
1355             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1356             DWORD i,j;
1358             if (d->path->empty())
1359                 *(d->path) = "d=\"";
1361             for (i=0; i<pEmr->cpts;) {
1362                 tmp_path << "\n\tC ";
1363                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1364                     tmp_path <<
1365                         pix_x_to_point( d, apts[i].x ) << " " <<
1366                         pix_y_to_point( d, apts[i].y ) << " ";
1367                 }
1368             }
1370             break;
1371         }
1372         case EMR_POLYLINETO16:
1373         {
1374             PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;
1375             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1376             DWORD i;
1378             if (d->path->empty())
1379                 *(d->path) = "d=\"";
1381             for (i=0; i<pEmr->cpts;i++) {
1382                 tmp_path <<
1383                     "\n\tL " <<
1384                     pix_x_to_point( d, apts[i].x ) << " " <<
1385                     pix_y_to_point( d, apts[i].y ) << " ";
1386             }
1388             break;
1389         }
1390         case EMR_POLYPOLYLINE16:
1391         case EMR_POLYPOLYGON16:
1392         {
1393             PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;
1394             unsigned int n, i, j;
1396             if (lpEMFR->iType == EMR_POLYPOLYGON16)
1397                 *(d->outsvg) += "<!-- EMR_POLYPOLYGON16... -->\n";
1398             else
1399                 *(d->outsvg) += "<!-- EMR_POLYPOLYLINE16... -->\n";
1401             *(d->outsvg) += "<path ";
1402             output_style(d, lpEMFR->iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
1403             *(d->outsvg) += "\n\td=\"";
1405             POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys];
1407             i = 0;
1408             for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
1409                 SVGOStringStream poly_path;
1411                 poly_path << "\n\tM " <<
1412                     pix_x_to_point( d, apts[i].x ) << " " <<
1413                     pix_y_to_point( d, apts[i].y ) << " ";
1414                 i++;
1416                 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
1417                     poly_path << "\n\tL " <<
1418                         pix_x_to_point( d, apts[i].x ) << " " <<
1419                         pix_y_to_point( d, apts[i].y ) << " ";
1420                     i++;
1421                 }
1423                 *(d->outsvg) += poly_path.str().c_str();
1424                 if (lpEMFR->iType == EMR_POLYPOLYGON16)
1425                     *(d->outsvg) += " z";
1426                 *(d->outsvg) += " \n";
1427             }
1429             *(d->outsvg) += " \" /> \n";
1430             break;
1431         }
1432         case EMR_POLYDRAW16:
1433             *(d->outsvg) += "<!-- EMR_POLYDRAW16 -->\n";
1434             break;
1435         case EMR_CREATEMONOBRUSH:
1436             *(d->outsvg) += "<!-- EMR_CREATEMONOBRUSH -->\n";
1437             break;
1438         case EMR_CREATEDIBPATTERNBRUSHPT:
1439             *(d->outsvg) += "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n";
1440             break;
1441         case EMR_EXTCREATEPEN:
1442         {
1443             PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;
1444             int index = pEmr->ihPen;
1446             EMREXTCREATEPEN *pPen =
1447                 (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +
1448                                             sizeof(DWORD) * pEmr->elp.elpNumEntries );
1449             pPen->ihPen = pEmr->ihPen;
1450             pPen->offBmi = pEmr->offBmi;
1451             pPen->cbBmi = pEmr->cbBmi;
1452             pPen->offBits = pEmr->offBits;
1453             pPen->cbBits = pEmr->cbBits;
1454             pPen->elp = pEmr->elp;
1455             for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
1456                 pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];
1457             }
1458             insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);
1460             break;
1461         }
1462         case EMR_POLYTEXTOUTA:
1463             *(d->outsvg) += "<!-- EMR_POLYTEXTOUTA -->\n";
1464             break;
1465         case EMR_POLYTEXTOUTW:
1466             *(d->outsvg) += "<!-- EMR_POLYTEXTOUTW -->\n";
1467             break;
1468         case EMR_SETICMMODE:
1469             *(d->outsvg) += "<!-- EMR_SETICMMODE -->\n";
1470             break;
1471         case EMR_CREATECOLORSPACE:
1472             *(d->outsvg) += "<!-- EMR_CREATECOLORSPACE -->\n";
1473             break;
1474         case EMR_SETCOLORSPACE:
1475             *(d->outsvg) += "<!-- EMR_SETCOLORSPACE -->\n";
1476             break;
1477         case EMR_DELETECOLORSPACE:
1478             *(d->outsvg) += "<!-- EMR_DELETECOLORSPACE -->\n";
1479             break;
1480         case EMR_GLSRECORD:
1481             *(d->outsvg) += "<!-- EMR_GLSRECORD -->\n";
1482             break;
1483         case EMR_GLSBOUNDEDRECORD:
1484             *(d->outsvg) += "<!-- EMR_GLSBOUNDEDRECORD -->\n";
1485             break;
1486         case EMR_PIXELFORMAT:
1487             *(d->outsvg) += "<!-- EMR_PIXELFORMAT -->\n";
1488             break;
1489     }
1490     
1491     *(d->outsvg) += tmp_outsvg.str().c_str();
1492     *(d->path) += tmp_path.str().c_str();
1494     return 1;
1498 // Aldus Placeable Header ===================================================
1499 // Since we are a 32bit app, we have to be sure this structure compiles to
1500 // be identical to a 16 bit app's version. To do this, we use the #pragma
1501 // to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
1502 // for the bbox rectangle.
1503 #pragma pack( push )
1504 #pragma pack( 2 )
1505 typedef struct
1507         DWORD           dwKey;
1508         WORD            hmf;
1509         SMALL_RECT      bbox;
1510         WORD            wInch;
1511         DWORD           dwReserved;
1512         WORD            wCheckSum;
1513 } APMHEADER, *PAPMHEADER;
1514 #pragma pack( pop )
1517 SPDocument *
1518 EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri )
1520     EMF_CALLBACK_DATA d = {0};
1522     gsize bytesRead = 0;
1523     gsize bytesWritten = 0;
1524     GError* error = NULL;
1525     gchar *local_fn =
1526         g_filename_from_utf8( uri, -1,  &bytesRead,  &bytesWritten, &error );
1528     if (local_fn == NULL) {
1529         return NULL;
1530     }
1532     d.outsvg = new Glib::ustring("");
1533     d.path = new Glib::ustring("");
1535     CHAR *ansi_uri = (CHAR *) local_fn;
1536     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
1537     WCHAR *unicode_uri = (WCHAR *) unicode_fn;
1539     // Try open as Enhanced Metafile
1540     HENHMETAFILE hemf;
1541     if (PrintWin32::is_os_wide())
1542         hemf = GetEnhMetaFileW(unicode_uri);
1543     else
1544         hemf = GetEnhMetaFileA(ansi_uri);
1546     if (!hemf) {
1547         // Try open as Windows Metafile
1548         HMETAFILE hmf;
1549         if (PrintWin32::is_os_wide())
1550             hmf = GetMetaFileW(unicode_uri);
1551         else
1552             hmf = GetMetaFileA(ansi_uri);
1554         METAFILEPICT mp;
1555         HDC hDC;
1557         if (!hmf) {
1558             if (PrintWin32::is_os_wide()) {
1559                 WCHAR szTemp[MAX_PATH];
1561                 DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );
1562                 if (dw) {
1563                     hmf = GetMetaFileW( szTemp );
1564                 }
1565             } else {
1566                 CHAR szTemp[MAX_PATH];
1568                 DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );
1569                 if (dw) {
1570                     hmf = GetMetaFileA( szTemp );
1571                 }
1572             }
1573         }
1575         if (hmf) {
1576             DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
1577             if (nSize) {
1578                 BYTE *lpvData = new BYTE[nSize];
1579                 if (lpvData) {
1580                     DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
1581                     if (dw) {
1582                         // Fill out a METAFILEPICT structure
1583                         mp.mm = MM_ANISOTROPIC;
1584                         mp.xExt = 1000;
1585                         mp.yExt = 1000;
1586                         mp.hMF = NULL;
1587                         // Get a reference DC
1588                         hDC = GetDC( NULL );
1589                         // Make an enhanced metafile from the windows metafile
1590                         hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
1591                         // Clean up
1592                         ReleaseDC( NULL, hDC );
1593                     }
1594                     delete[] lpvData;
1595                 }
1596                 DeleteMetaFile( hmf );
1597             }
1598         } else {
1599             // Try open as Aldus Placeable Metafile
1600             HANDLE hFile;
1601             if (PrintWin32::is_os_wide())
1602                 hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1603             else
1604                 hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1605             if (hFile != INVALID_HANDLE_VALUE) {
1606                 DWORD nSize = GetFileSize( hFile, NULL );
1607                 if (nSize) {
1608                     BYTE *lpvData = new BYTE[nSize];
1609                     if (lpvData) {
1610                         DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );
1611                         if (dw) {
1612                             if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {
1613                                 // Fill out a METAFILEPICT structure
1614                                 mp.mm = MM_ANISOTROPIC;
1615                                 mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;
1616                                 mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
1617                                 mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;
1618                                 mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
1619                                 mp.hMF = NULL;
1620                                 // Get a reference DC
1621                                 hDC = GetDC( NULL );
1622                                 // Create an enhanced metafile from the bits
1623                                 hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );
1624                                 // Clean up
1625                                 ReleaseDC( NULL, hDC );
1626                             }
1627                         }
1628                         delete[] lpvData;
1629                     }
1630                 }
1631                 CloseHandle( hFile );
1632             }
1633         }
1634     }
1636     if (!hemf || !d.outsvg || !d.path) {
1637         if (d.outsvg)
1638             delete d.outsvg;
1639         if (d.path)
1640             delete d.path;
1641         if  (local_fn)
1642             g_free(local_fn);
1643         if  (unicode_fn)
1644             g_free(unicode_fn);
1645         return NULL;
1646     }
1648     EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);
1649     DeleteEnhMetaFile(hemf);
1651 //    std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
1653     SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);
1655     delete d.outsvg;
1656     delete d.path;
1658     if (d.emf_obj) {
1659         int i;
1660         for (i=0; i<d.n_obj; i++)
1661             delete_object(&d, i);
1662         delete[] d.emf_obj;
1663     }
1664     
1665     if (d.style.stroke_dash.dash)
1666         delete[] d.style.stroke_dash.dash;
1668     if  (local_fn)
1669         g_free(local_fn);
1670     if  (unicode_fn)
1671         g_free(unicode_fn);
1673     return doc;
1677 void
1678 EmfWin32::init (void)
1680     Inkscape::Extension::Extension * ext;
1682     /* EMF in */
1683     ext = Inkscape::Extension::build_from_mem(
1684         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
1685             "<name>" N_("EMF Input") "</name>\n"
1686             "<id>org.inkscape.input.emf.win32</id>\n"
1687             "<input>\n"
1688                 "<extension>.emf</extension>\n"
1689                 "<mimetype>image/x-emf</mimetype>\n"
1690                 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
1691                 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
1692                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
1693             "</input>\n"
1694         "</inkscape-extension>", new EmfWin32());
1696     /* WMF in */
1697     ext = Inkscape::Extension::build_from_mem(
1698         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
1699             "<name>" N_("WMF Input") "</name>\n"
1700             "<id>org.inkscape.input.wmf.win32</id>\n"
1701             "<input>\n"
1702                 "<extension>.wmf</extension>\n"
1703                 "<mimetype>image/x-wmf</mimetype>\n"
1704                 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
1705                 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
1706                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
1707             "</input>\n"
1708         "</inkscape-extension>", new EmfWin32());
1710     /* EMF out */
1711     ext = Inkscape::Extension::build_from_mem(
1712         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
1713             "<name>" N_("EMF Output") "</name>\n"
1714             "<id>org.inkscape.output.emf.win32</id>\n"
1715             "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
1716             "<output>\n"
1717                 "<extension>.emf</extension>\n"
1718                 "<mimetype>image/x-emf</mimetype>\n"
1719                 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
1720                 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
1721             "</output>\n"
1722         "</inkscape-extension>", new EmfWin32());
1724     return;
1728 } } }  /* namespace Inkscape, Extension, Implementation */
1731 #endif /* WIN32 */
1734 /*
1735   Local Variables:
1736   mode:cpp
1737   c-file-style:"stroustrup"
1738   c-file-offsets:((innamespace . 0)(inline-open . 0))
1739   indent-tabs-mode:nil
1740   fill-column:99
1741   End:
1742 */
1743 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :