Code

Avoid transforming a group with an already set clip-path
[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     bool stroke_set;
184     bool fill_set;
185     double xDPI, yDPI;
187     SIZEL sizeWnd;
188     SIZEL sizeView;
189     float PixelsX;
190     float PixelsY;
191     float MMX;
192     float MMY;
193     float dwInchesX;
194     float dwInchesY;
195     POINTL winorg;
196     POINTL vieworg;
197     double ScaleX, ScaleY;
199     int n_obj;
200     PEMF_OBJECT emf_obj;
201 } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
204 static void
205 output_style(PEMF_CALLBACK_DATA d, int iType)
207     SVGOStringStream tmp_style;
208     char tmp[1024] = {0};
210     *(d->outsvg) += "\n\tstyle=\"";
211     if (iType == EMR_STROKEPATH || !d->fill_set) {
212         tmp_style << "fill:none;";
213     } else {
214         float rgb[3];
215         sp_color_get_rgb_floatv( &(d->style.fill.value.color), rgb );
216         snprintf(tmp, 1023,
217                  "fill:#%02x%02x%02x;",
218                  SP_COLOR_F_TO_U(rgb[0]),
219                  SP_COLOR_F_TO_U(rgb[1]),
220                  SP_COLOR_F_TO_U(rgb[2]));
221         tmp_style << tmp;
222         snprintf(tmp, 1023,
223                  "fill-rule:%s;",
224                  d->style.fill_rule.value != 0 ? "evenodd" : "nonzero");
225         tmp_style << tmp;
226         tmp_style << "fill-opacity:1;";
227     }
229     if (iType == EMR_FILLPATH || !d->stroke_set) {
230         tmp_style << "stroke:none;";
231     } else {
232         float rgb[3];
233         sp_color_get_rgb_floatv(&(d->style.stroke.value.color), rgb);
234         snprintf(tmp, 1023,
235                  "stroke:#%02x%02x%02x;",
236                  SP_COLOR_F_TO_U(rgb[0]),
237                  SP_COLOR_F_TO_U(rgb[1]),
238                  SP_COLOR_F_TO_U(rgb[2]));
239         tmp_style << tmp;
241         tmp_style << "stroke-width:" <<
242             MAX( 0.001, d->style.stroke_width.value ) << "px;";
244         tmp_style << "stroke-linejoin:" <<
245             (d->style.stroke_linejoin.computed == 0 ? "miter" :
246              d->style.stroke_linejoin.computed == 1 ? "round" :
247              d->style.stroke_linejoin.computed == 2 ? "bevel" :
248              "unknown") << ";";
250         if (d->style.stroke_linejoin.computed == 0) {
251             tmp_style << "stroke-miterlimit:" <<
252                 MAX( 0.01, d->style.stroke_miterlimit.value ) << ";";
253         }
255         if (d->style.stroke_dasharray_set &&
256             d->style.stroke_dash.n_dash && d->style.stroke_dash.dash)
257         {
258             tmp_style << "stroke-dasharray:";
259             for (int i=0; i<d->style.stroke_dash.n_dash; i++) {
260                 if (i)
261                     tmp_style << ",";
262                 tmp_style << d->style.stroke_dash.dash[i];
263             }
264             tmp_style << ";";
265             tmp_style << "stroke-dashoffset:0;";
266         } else {
267             tmp_style << "stroke-dasharray:none;";
268         }
269         tmp_style << "stroke-opacity:1;";
270     }
271     tmp_style << "\" ";
273     *(d->outsvg) += tmp_style.str().c_str();
277 static double
278 pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
280     double tmp = px - d->winorg.x;
281     tmp *= (double) PX_PER_IN / d->ScaleX;
282     tmp += d->vieworg.x;
283     return tmp;
287 static double
288 pix_y_to_point(PEMF_CALLBACK_DATA d, double px)
290     double tmp = px - d->winorg.y;
291     tmp *= (double) PX_PER_IN / d->ScaleY;
292     tmp += d->vieworg.y;
293     return tmp;
297 static double
298 pix_size_to_point(PEMF_CALLBACK_DATA d, double px)
300     double tmp = px;
301     tmp *= (double) PX_PER_IN / d->ScaleX;
302     return tmp;
306 static void
307 select_pen(PEMF_CALLBACK_DATA d, int index)
309     PEMRCREATEPEN pEmr = NULL;
311     if (index >= 0 && index < d->n_obj)
312         pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;
314     if (!pEmr)
315         return;
317     switch (pEmr->lopn.lopnStyle) {
318         default:
319         {
320             d->style.stroke_dasharray_set = 0;
321             break;
322         }
323     }
325     if (pEmr->lopn.lopnWidth.x) {
326         d->style.stroke_width.value = pix_size_to_point( d, pEmr->lopn.lopnWidth.x );
327     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
328         d->style.stroke_width.value = 1.0;
329     }
331     double r, g, b;
332     r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );
333     g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );
334     b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );
335     sp_color_set_rgb_float( &(d->style.stroke.value.color), r,g,b );
337     d->style.stroke_linejoin.computed = 1;
339     d->stroke_set = true;
343 static void
344 select_extpen(PEMF_CALLBACK_DATA d, int index)
346     PEMREXTCREATEPEN pEmr = NULL;
348     if (index >= 0 && index < d->n_obj)
349         pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
351     if (!pEmr)
352         return;
354     switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {
355         case PS_USERSTYLE:
356         {
357             if (pEmr->elp.elpNumEntries) {
358                 d->style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;
359                 if (d->style.stroke_dash.dash)
360                     delete[] d->style.stroke_dash.dash;
361                 d->style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];
362                 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
363                     d->style.stroke_dash.dash[i] = pix_size_to_point( d, pEmr->elp.elpStyleEntry[i] );
364                 }
365                 d->style.stroke_dasharray_set = 1;
366             } else {
367                 d->style.stroke_dasharray_set = 0;
368             }
369             break;
370         }
371         default:
372         {
373             d->style.stroke_dasharray_set = 0;
374             break;
375         }
376     }
378     switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {
379         case PS_ENDCAP_ROUND:
380         {
381             d->style.stroke_linecap.computed = 1;
382             break;
383         }
384         case PS_ENDCAP_SQUARE:
385         {
386             d->style.stroke_linecap.computed = 2;
387             break;
388         }
389         case PS_ENDCAP_FLAT:
390         default:
391         {
392             d->style.stroke_linecap.computed = 0;
393             break;
394         }
395     }
397     switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {
398         case PS_JOIN_BEVEL:
399         {
400             d->style.stroke_linejoin.computed = 2;
401             break;
402         }
403         case PS_JOIN_MITER:
404         {
405             d->style.stroke_linejoin.computed = 0;
406             break;
407         }
408         case PS_JOIN_ROUND:
409         default:
410         {
411             d->style.stroke_linejoin.computed = 1;
412             break;
413         }
414     }
416     d->style.stroke_width.value = pix_size_to_point( d, pEmr->elp.elpWidth );
418     double r, g, b;
419     r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );
420     g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );
421     b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );
423     sp_color_set_rgb_float( &(d->style.stroke.value.color), r,g,b );
425     d->stroke_set = true;
429 static void
430 select_brush(PEMF_CALLBACK_DATA d, int index)
432     PEMRCREATEBRUSHINDIRECT pEmr = NULL;
434     if (index >= 0 && index < d->n_obj)
435         pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
437     if (!pEmr)
438         return;
440     if (pEmr->lb.lbStyle == BS_SOLID) {
441         double r, g, b;
442         r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );
443         g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );
444         b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );
445         sp_color_set_rgb_float( &(d->style.fill.value.color), r,g,b );
446     }
448     d->fill_set = true;
452 static void
453 delete_object(PEMF_CALLBACK_DATA d, int index)
455     if (index >= 0 && index < d->n_obj) {
456         d->emf_obj[index].type = 0;
457         if (d->emf_obj[index].lpEMFR)
458             free(d->emf_obj[index].lpEMFR);
459         d->emf_obj[index].lpEMFR = NULL;
460     }
464 static void
465 insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)
467     if (index >= 0 && index < d->n_obj) {
468         delete_object(d, index);
469         d->emf_obj[index].type = type;
470         d->emf_obj[index].lpEMFR = pObj;
471     }
475 static int CALLBACK
476 myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)
478     PEMF_CALLBACK_DATA d;
479     SVGOStringStream tmp_outsvg;
480     SVGOStringStream tmp_path;
481     SVGOStringStream tmp_str;
483     d = (PEMF_CALLBACK_DATA) lpData;
485     switch (lpEMFR->iType)
486     {
487         case EMR_HEADER:
488         {
489             ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;
490             tmp_outsvg << "<svg\n";
492             d->xDPI = 2540;
493             d->yDPI = 2540;
495             d->PixelsX = pEmr->rclFrame.right - pEmr->rclFrame.left;
496             d->PixelsY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;
498             d->MMX = d->PixelsX / 100.0;
499             d->MMY = d->PixelsY / 100.0;
501             tmp_outsvg <<
502                 "  width=\"" << d->MMX << "mm\"\n" <<
503                 "  height=\"" << d->MMY << "mm\">\n";
505             if (pEmr->nHandles) {
506                 d->n_obj = pEmr->nHandles;
507                 d->emf_obj = new EMF_OBJECT[d->n_obj];
509                 // Init the new emf_obj list elements to null, provided the
510                 // dynamic allocation succeeded.
511                 if ( d->emf_obj != NULL )
512                 {
513                     for( unsigned int i=0; i < d->n_obj; ++i )
514                         d->emf_obj[i].lpEMFR = NULL;
515                 } //if
517             } else {
518                 d->emf_obj = NULL;
519             }
521             break;
522         }
523         case EMR_POLYBEZIER:
524         {
525             PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;
526             DWORD i,j;
528             if (pEmr->cptl<4)
529                 break;
531             *(d->outsvg) += "    <path ";
532             output_style(d, EMR_STROKEPATH);
533             *(d->outsvg) += "\n\td=\"";
535             tmp_str <<
536                 "\n\tM " <<
537                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<
538                 pix_x_to_point( d, pEmr->aptl[0].y) << " ";
540             for (i=1; i<pEmr->cptl; ) {
541                 tmp_str << "\n\tC ";
542                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
543                     tmp_str <<
544                         pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
545                         pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
546                 }
547             }
549             *(d->outsvg) += tmp_str.str().c_str();
550             *(d->outsvg) += " \" /> \n";
552             break;
553         }
554         case EMR_POLYGON:
555         {
556             EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;
557             DWORD i;
559             if (pEmr->cptl < 2)
560                 break;
562             *(d->outsvg) += "    <path ";
563             output_style(d, EMR_STROKEANDFILLPATH);
564             *(d->outsvg) += "\n\td=\"";
566             tmp_str <<
567                 "\n\tM " <<
568                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<
569                 pix_y_to_point( d, pEmr->aptl[0].y ) << " ";
571             for (i=1; i<pEmr->cptl; i++) {
572                 tmp_str <<
573                     "\n\tL " <<
574                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
575                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
576             }
578             *(d->outsvg) += tmp_str.str().c_str();
579             *(d->outsvg) += " z \" /> \n";
581             break;
582         }
583         case EMR_POLYLINE:
584         {
585             EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;
586             DWORD i;
588             if (pEmr->cptl<2)
589                 break;
591             *(d->outsvg) += "    <path ";
592             output_style(d, EMR_STROKEPATH);
593             *(d->outsvg) += "\n\td=\"";
595             tmp_str <<
596                 "\n\tM " <<
597                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<
598                 pix_y_to_point( d, pEmr->aptl[0].y ) << " ";
600             for (i=1; i<pEmr->cptl; i++) {
601                 tmp_str <<
602                     "\n\tL " <<
603                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
604                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
605             }
607             *(d->outsvg) += tmp_str.str().c_str();
608             *(d->outsvg) += " \" /> \n";
610             break;
611         }
612         case EMR_POLYBEZIERTO:
613         {
614             PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;
615             DWORD i,j;
617             for (i=0; i<pEmr->cptl;) {
618                 tmp_path << "\n\tC ";
619                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
620                     tmp_path <<
621                         pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
622                         pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
623                 }
624             }
626             break;
627         }
628         case EMR_POLYLINETO:
629         {
630             PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;
631             DWORD i;
633             for (i=0; i<pEmr->cptl;i++) {
634                 tmp_path <<
635                     "\n\tL " <<
636                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<
637                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";
638             }
640             break;
641         }
642         case EMR_POLYPOLYLINE:
643             break;
644         case EMR_POLYPOLYGON:
645             break;
646         case EMR_SETWINDOWEXTEX:
647         {
648             PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;
650             d->sizeWnd = pEmr->szlExtent;
651             d->PixelsX = d->sizeWnd.cx;
652             d->PixelsY = d->sizeWnd.cy;
654             d->ScaleX = d->xDPI / (100*d->MMX / d->PixelsX);
655             d->ScaleY = d->yDPI / (100*d->MMY / d->PixelsY);
657             break;
658         }
659         case EMR_SETWINDOWORGEX:
660         {
661             PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;
662             d->winorg = pEmr->ptlOrigin;
663             break;
664         }
665         case EMR_SETVIEWPORTEXTEX:
666         {
667             PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;
669             d->sizeView = pEmr->szlExtent;
671             if (d->sizeWnd.cx && d->sizeWnd.cy) {
672                 HDC hScreenDC = GetDC( NULL );
674                 float scrPixelsX = (float)GetDeviceCaps( hScreenDC, HORZRES );
675                 float scrPixelsY = (float)GetDeviceCaps( hScreenDC, VERTRES );
676                 float scrMMX = (float)GetDeviceCaps( hScreenDC, HORZSIZE );
677                 float scrMMY = (float)GetDeviceCaps( hScreenDC, VERTSIZE );
679                 ReleaseDC( NULL, hScreenDC );
681                 d->dwInchesX = d->sizeView.cx / (25.4f*scrPixelsX/scrMMX);
682                 d->dwInchesY = d->sizeView.cy / (25.4f*scrPixelsY/scrMMY);
683                 d->xDPI = d->sizeWnd.cx / d->dwInchesX;
684                 d->yDPI = d->sizeWnd.cy / d->dwInchesY;
686                 if (1) {
687                     d->xDPI = 2540;
688                     d->yDPI = 2540;
689                     d->dwInchesX = d->PixelsX / d->xDPI;
690                     d->dwInchesY = d->PixelsY / d->yDPI;
691                     d->ScaleX = d->xDPI;
692                     d->ScaleY = d->yDPI;
693                 }
695                 d->MMX = d->dwInchesX * MM_PER_IN;
696                 d->MMY = d->dwInchesY * MM_PER_IN;
697             }
699             break;
700         }
701         case EMR_SETVIEWPORTORGEX:
702         {
703             PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;
704             d->vieworg = pEmr->ptlOrigin;
705             break;
706         }
707         case EMR_SETBRUSHORGEX:
708             break;
709         case EMR_EOF:
710         {
711             tmp_outsvg << "</svg>\n";
712             break;
713         }
714         case EMR_SETPIXELV:
715             break;
716         case EMR_SETMAPPERFLAGS:
717             break;
718         case EMR_SETMAPMODE:
719             break;
720         case EMR_SETBKMODE:
721             break;
722         case EMR_SETPOLYFILLMODE:
723         {
724             PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;
725             d->style.fill_rule.value =
726                 (pEmr->iMode == WINDING ? 0 :
727                  pEmr->iMode == ALTERNATE ? 1 : 0);
728             break;
729         }
730         case EMR_SETROP2:
731             break;
732         case EMR_SETSTRETCHBLTMODE:
733             break;
734         case EMR_SETTEXTALIGN:
735             break;
736         case EMR_SETCOLORADJUSTMENT:
737             break;
738         case EMR_SETTEXTCOLOR:
739             break;
740         case EMR_SETBKCOLOR:
741             break;
742         case EMR_OFFSETCLIPRGN:
743             break;
744         case EMR_MOVETOEX:
745         {
746             PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;
747             tmp_path <<
748                 "\n\tM " <<
749                 pix_x_to_point( d, pEmr->ptl.x ) << " " <<
750                 pix_y_to_point( d, pEmr->ptl.y ) << " ";
751             break;
752         }
753         case EMR_SETMETARGN:
754             break;
755         case EMR_EXCLUDECLIPRECT:
756             break;
757         case EMR_INTERSECTCLIPRECT:
758             break;
759         case EMR_SCALEVIEWPORTEXTEX:
760             break;
761         case EMR_SCALEWINDOWEXTEX:
762             break;
763         case EMR_SAVEDC:
764             break;
765         case EMR_RESTOREDC:
766             break;
767         case EMR_SETWORLDTRANSFORM:
768             break;
769         case EMR_MODIFYWORLDTRANSFORM:
770             break;
771         case EMR_SELECTOBJECT:
772         {
773             PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;
774             unsigned int index = pEmr->ihObject;
776             if (index >= ENHMETA_STOCK_OBJECT) {
777                 index -= ENHMETA_STOCK_OBJECT;
778                 switch (index) {
779                     case NULL_BRUSH:
780                         d->fill_set = false;
781                         break;
782                     case BLACK_BRUSH:
783                     case DKGRAY_BRUSH:
784                     case GRAY_BRUSH:
785                     case LTGRAY_BRUSH:
786                     case WHITE_BRUSH:
787                     {
788                         float val = 0;
789                         switch (index) {
790                             case BLACK_BRUSH:
791                                 val = 0.0 / 255.0;
792                                 break;
793                             case DKGRAY_BRUSH:
794                                 val = 64.0 / 255.0;
795                                 break;
796                             case GRAY_BRUSH:
797                                 val = 128.0 / 255.0;
798                                 break;
799                             case LTGRAY_BRUSH:
800                                 val = 192.0 / 255.0;
801                                 break;
802                             case WHITE_BRUSH:
803                                 val = 255.0 / 255.0;
804                                 break;
805                         }
806                         sp_color_set_rgb_float( &(d->style.fill.value.color), val,val,val );
808                         d->fill_set = true;
809                         break;
810                     }
811                     case NULL_PEN:
812                         d->stroke_set = false;
813                         break;
814                     case BLACK_PEN:
815                     case WHITE_PEN:
816                     {
817                         float val = index == BLACK_PEN ? 0 : 1;
818                         d->style.stroke_dasharray_set = 0;
819                         d->style.stroke_width.value = 1.0;
820                         sp_color_set_rgb_float( &(d->style.stroke.value.color), val,val,val );
822                         d->stroke_set = true;
824                         break;
825                     }
826                 }
827             } else {
828                 if (index >= 0 && index < (unsigned int)d->n_obj) {
829                     switch (d->emf_obj[index].type)
830                     {
831                         case EMR_CREATEPEN:
832                             select_pen(d, index);
833                             break;
834                         case EMR_CREATEBRUSHINDIRECT:
835                             select_brush(d, index);
836                             break;
837                         case EMR_EXTCREATEPEN:
838                             select_extpen(d, index);
839                             break;
840                     }
841                 }
842             }
843             break;
844         }
845         case EMR_CREATEPEN:
846         {
847             PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;
848             int index = pEmr->ihPen;
850             EMRCREATEPEN *pPen =
851                 (EMRCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) );
852             pPen->lopn = pEmr->lopn;
853             insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);
855             break;
856         }
857         case EMR_CREATEBRUSHINDIRECT:
858         {
859             PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;
860             int index = pEmr->ihBrush;
862             EMRCREATEBRUSHINDIRECT *pBrush =
863                 (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );
864             pBrush->lb = pEmr->lb;
865             insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);
867             break;
868         }
869         case EMR_DELETEOBJECT:
870             break;
871         case EMR_ANGLEARC:
872             break;
873         case EMR_ELLIPSE:
874             break;
875         case EMR_RECTANGLE:
876             break;
877         case EMR_ROUNDRECT:
878             break;
879         case EMR_ARC:
880             break;
881         case EMR_CHORD:
882             break;
883         case EMR_PIE:
884             break;
885         case EMR_SELECTPALETTE:
886             break;
887         case EMR_CREATEPALETTE:
888             break;
889         case EMR_SETPALETTEENTRIES:
890             break;
891         case EMR_RESIZEPALETTE:
892             break;
893         case EMR_REALIZEPALETTE:
894             break;
895         case EMR_EXTFLOODFILL:
896             break;
897         case EMR_LINETO:
898         {
899             PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;
900             tmp_path <<
901                 "\n\tL " <<
902                 pix_x_to_point( d, pEmr->ptl.x ) << " " <<
903                 pix_y_to_point( d, pEmr->ptl.y ) << " ";
904             break;
905         }
906         case EMR_ARCTO:
907             break;
908         case EMR_POLYDRAW:
909             break;
910         case EMR_SETARCDIRECTION:
911             break;
912         case EMR_SETMITERLIMIT:
913         {
914             PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;
915             d->style.stroke_miterlimit.value = pix_size_to_point( d, pEmr->eMiterLimit );
917             if (d->style.stroke_miterlimit.value < 1)
918                 d->style.stroke_miterlimit.value = 1.0;
920             break;
921         }
922         case EMR_BEGINPATH:
923         {
924             tmp_path << " d=\"";
925             *(d->path) = "";
926             break;
927         }
928         case EMR_ENDPATH:
929         {
930             tmp_path << "\"";
931             break;
932         }
933         case EMR_CLOSEFIGURE:
934         {
935             tmp_path << "\n\tz";
936             break;
937         }
938         case EMR_FILLPATH:
939         case EMR_STROKEANDFILLPATH:
940         case EMR_STROKEPATH:
941         {
942             *(d->outsvg) += "    <path ";
943             output_style(d, lpEMFR->iType);
944             *(d->outsvg) += "\n\t";
945             *(d->outsvg) += *(d->path);
946             *(d->outsvg) += " /> \n";
947             break;
948         }
949         case EMR_FLATTENPATH:
950             break;
951         case EMR_WIDENPATH:
952             break;
953         case EMR_SELECTCLIPPATH:
954             break;
955         case EMR_ABORTPATH:
956             break;
957         case EMR_GDICOMMENT:
958             break;
959         case EMR_FILLRGN:
960             break;
961         case EMR_FRAMERGN:
962             break;
963         case EMR_INVERTRGN:
964             break;
965         case EMR_PAINTRGN:
966             break;
967         case EMR_EXTSELECTCLIPRGN:
968             break;
969         case EMR_BITBLT:
970             break;
971         case EMR_STRETCHBLT:
972             break;
973         case EMR_MASKBLT:
974             break;
975         case EMR_PLGBLT:
976             break;
977         case EMR_SETDIBITSTODEVICE:
978             break;
979         case EMR_STRETCHDIBITS:
980             break;
981         case EMR_EXTCREATEFONTINDIRECTW:
982             break;
983         case EMR_EXTTEXTOUTA:
984             break;
985         case EMR_EXTTEXTOUTW:
986             break;
987         case EMR_POLYBEZIER16:
988         {
989             PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;
990             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
991             DWORD i,j;
993             if (pEmr->cpts<4)
994                 break;
996             *(d->outsvg) += "    <path ";
997             output_style(d, EMR_STROKEPATH);
998             *(d->outsvg) += "\n\td=\"";
1000             tmp_str <<
1001                 "\n\tM " <<
1002                 pix_x_to_point( d, apts[0].x ) << " " <<
1003                 pix_y_to_point( d, apts[0].y ) << " ";
1005             for (i=1; i<pEmr->cpts; ) {
1006                 tmp_str << "\n\tC ";
1007                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1008                     tmp_str <<
1009                         pix_x_to_point( d, apts[i].x ) << " " <<
1010                         pix_y_to_point( d, apts[i].y ) << " ";
1011                 }
1012             }
1014             *(d->outsvg) += tmp_str.str().c_str();
1015             *(d->outsvg) += " \" /> \n";
1017             break;
1018         }
1019         case EMR_POLYGON16:
1020         {
1021             PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;
1022             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1023             unsigned int i;
1025             *(d->outsvg) += "<path ";
1026             output_style(d, EMR_STROKEANDFILLPATH);
1027             *(d->outsvg) += "\n\td=\"";
1029             // skip the first point?
1030             tmp_path << "\n\tM " <<
1031                 pix_x_to_point( d, apts[1].x ) << " " <<
1032                 pix_y_to_point( d, apts[1].y ) << " ";
1034             for (i=2; i<pEmr->cpts; i++) {
1035                 tmp_path << "\n\tL " <<
1036                     pix_x_to_point( d, apts[i].x ) << " " <<
1037                     pix_y_to_point( d, apts[i].y ) << " ";
1038             }
1040             *(d->outsvg) += tmp_path.str().c_str();
1041             *(d->outsvg) += " z \" /> \n";
1043             break;
1044         }
1045         case EMR_POLYLINE16:
1046         {
1047             EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;
1048             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1049             DWORD i;
1051             if (pEmr->cpts<2)
1052                 break;
1054             *(d->outsvg) += "    <path ";
1055             output_style(d, EMR_STROKEPATH);
1056             *(d->outsvg) += "\n\td=\"";
1058             tmp_str <<
1059                 "\n\tM " <<
1060                 pix_x_to_point( d, apts[0].x ) << " " <<
1061                 pix_y_to_point( d, apts[0].y ) << " ";
1063             for (i=1; i<pEmr->cpts; i++) {
1064                 tmp_str <<
1065                     "\n\tL " <<
1066                     pix_x_to_point( d, apts[i].x ) << " " <<
1067                     pix_y_to_point( d, apts[i].y ) << " ";
1068             }
1070             *(d->outsvg) += tmp_str.str().c_str();
1071             *(d->outsvg) += " \" /> \n";
1073             break;
1074         }
1075         case EMR_POLYBEZIERTO16:
1076         {
1077             PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;
1078             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1079             DWORD i,j;
1081             for (i=0; i<pEmr->cpts;) {
1082                 tmp_path << "\n\tC ";
1083                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1084                     tmp_path <<
1085                         pix_x_to_point( d, apts[i].x ) << " " <<
1086                         pix_y_to_point( d, apts[i].y ) << " ";
1087                 }
1088             }
1090             break;
1091         }
1092         case EMR_POLYLINETO16:
1093         {
1094             PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;
1095             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1096             DWORD i;
1098             for (i=0; i<pEmr->cpts;i++) {
1099                 tmp_path <<
1100                     "\n\tL " <<
1101                     pix_x_to_point( d, apts[i].x ) << " " <<
1102                     pix_y_to_point( d, apts[i].y ) << " ";
1103             }
1105             break;
1106         }
1107         case EMR_POLYPOLYLINE16:
1108             break;
1109         case EMR_POLYPOLYGON16:
1110         {
1111             PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;
1112             unsigned int n, i, j;
1114             *(d->outsvg) += "<path ";
1115             output_style(d, EMR_STROKEANDFILLPATH);
1116             *(d->outsvg) += "\n\td=\"";
1118             i = pEmr->nPolys-1; // ???
1119             for (n=0; n<pEmr->nPolys /*&& i<pEmr->cpts*/; n++) {
1120                 SVGOStringStream poly_path;
1122                 poly_path << "\n\tM " <<
1123                     pix_x_to_point( d, pEmr->apts[i].x ) << " " <<
1124                     pix_y_to_point( d, pEmr->apts[i].y ) << " ";
1125                 i++;
1127                 for (j=1; j<pEmr->aPolyCounts[n] /*&& i<pEmr->cpts*/; j++) {
1128                     poly_path << "\n\tL " <<
1129                         pix_x_to_point( d, pEmr->apts[i].x ) << " " <<
1130                         pix_y_to_point( d, pEmr->apts[i].y ) << " ";
1131                     i++;
1132                 }
1134                 *(d->outsvg) += poly_path.str().c_str();
1135                 *(d->outsvg) += " z \n";
1136             }
1138             *(d->outsvg) += " \" /> \n";
1139             break;
1140         }
1141         case EMR_POLYDRAW16:
1142             break;
1143         case EMR_CREATEMONOBRUSH:
1144             break;
1145         case EMR_CREATEDIBPATTERNBRUSHPT:
1146             break;
1147         case EMR_EXTCREATEPEN:
1148         {
1149             PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;
1150             int index = pEmr->ihPen;
1152             EMREXTCREATEPEN *pPen =
1153                 (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +
1154                                             sizeof(DWORD) * pEmr->elp.elpNumEntries );
1155             pPen->ihPen = pEmr->ihPen;
1156             pPen->offBmi = pEmr->offBmi;
1157             pPen->cbBmi = pEmr->cbBmi;
1158             pPen->offBits = pEmr->offBits;
1159             pPen->cbBits = pEmr->cbBits;
1160             pPen->elp = pEmr->elp;
1161             for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
1162                 pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];
1163             }
1164             insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);
1166             break;
1167         }
1168         case EMR_POLYTEXTOUTA:
1169             break;
1170         case EMR_POLYTEXTOUTW:
1171             break;
1172         case EMR_SETICMMODE:
1173             break;
1174         case EMR_CREATECOLORSPACE:
1175             break;
1176         case EMR_SETCOLORSPACE:
1177             break;
1178         case EMR_DELETECOLORSPACE:
1179             break;
1180         case EMR_GLSRECORD:
1181             break;
1182         case EMR_GLSBOUNDEDRECORD:
1183             break;
1184         case EMR_PIXELFORMAT:
1185             break;
1186     }
1188     *(d->outsvg) += tmp_outsvg.str().c_str();
1189     *(d->path) += tmp_path.str().c_str();
1191     return 1;
1195 // Aldus Placeable Header ===================================================
1196 // Since we are a 32bit app, we have to be sure this structure compiles to
1197 // be identical to a 16 bit app's version. To do this, we use the #pragma
1198 // to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
1199 // for the bbox rectangle.
1200 #pragma pack( push )
1201 #pragma pack( 2 )
1202 typedef struct
1204         DWORD           dwKey;
1205         WORD            hmf;
1206         SMALL_RECT      bbox;
1207         WORD            wInch;
1208         DWORD           dwReserved;
1209         WORD            wCheckSum;
1210 } APMHEADER, *PAPMHEADER;
1211 #pragma pack( pop )
1214 SPDocument *
1215 EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri )
1217     EMF_CALLBACK_DATA d = {0};
1219     gsize bytesRead = 0;
1220     gsize bytesWritten = 0;
1221     GError* error = NULL;
1222     gchar *local_fn =
1223         g_filename_from_utf8( uri, -1,  &bytesRead,  &bytesWritten, &error );
1225     if (local_fn == NULL) {
1226         return NULL;
1227     }
1229     d.outsvg = new Glib::ustring("");
1230     d.path = new Glib::ustring("");
1232     CHAR *ansi_uri = (CHAR *) local_fn;
1233     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
1234     WCHAR *unicode_uri = (WCHAR *) unicode_fn;
1236     // Try open as Enhanced Metafile
1237     HENHMETAFILE hemf;
1238     if (PrintWin32::is_os_wide())
1239         hemf = GetEnhMetaFileW(unicode_uri);
1240     else
1241         hemf = GetEnhMetaFileA(ansi_uri);
1243     if (!hemf) {
1244         // Try open as Windows Metafile
1245         HMETAFILE hmf;
1246         if (PrintWin32::is_os_wide())
1247             hmf = GetMetaFileW(unicode_uri);
1248         else
1249             hmf = GetMetaFileA(ansi_uri);
1251         METAFILEPICT mp;
1252         HDC hDC;
1254         if (!hmf) {
1255             if (PrintWin32::is_os_wide()) {
1256                 WCHAR szTemp[MAX_PATH];
1258                 DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );
1259                 if (dw) {
1260                     hmf = GetMetaFileW( szTemp );
1261                 }
1262             } else {
1263                 CHAR szTemp[MAX_PATH];
1265                 DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );
1266                 if (dw) {
1267                     hmf = GetMetaFileA( szTemp );
1268                 }
1269             }
1270         }
1272         if (hmf) {
1273             DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
1274             if (nSize) {
1275                 BYTE *lpvData = new BYTE[nSize];
1276                 if (lpvData) {
1277                     DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
1278                     if (dw) {
1279                         // Fill out a METAFILEPICT structure
1280                         mp.mm = MM_ANISOTROPIC;
1281                         mp.xExt = 1000;
1282                         mp.yExt = 1000;
1283                         mp.hMF = NULL;
1284                         // Get a reference DC
1285                         hDC = GetDC( NULL );
1286                         // Make an enhanced metafile from the windows metafile
1287                         hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
1288                         // Clean up
1289                         ReleaseDC( NULL, hDC );
1290                     }
1291                     delete[] lpvData;
1292                 }
1293                 DeleteMetaFile( hmf );
1294             }
1295         } else {
1296             // Try open as Aldus Placeable Metafile
1297             HANDLE hFile;
1298             if (PrintWin32::is_os_wide())
1299                 hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1300             else
1301                 hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
1302             if (hFile != INVALID_HANDLE_VALUE) {
1303                 DWORD nSize = GetFileSize( hFile, NULL );
1304                 if (nSize) {
1305                     BYTE *lpvData = new BYTE[nSize];
1306                     if (lpvData) {
1307                         DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );
1308                         if (dw) {
1309                             if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {
1310                                 // Fill out a METAFILEPICT structure
1311                                 mp.mm = MM_ANISOTROPIC;
1312                                 mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;
1313                                 mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
1314                                 mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;
1315                                 mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
1316                                 mp.hMF = NULL;
1317                                 // Get a reference DC
1318                                 hDC = GetDC( NULL );
1319                                 // Create an enhanced metafile from the bits
1320                                 hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );
1321                                 // Clean up
1322                                 ReleaseDC( NULL, hDC );
1323                             }
1324                         }
1325                         delete[] lpvData;
1326                     }
1327                 }
1328                 CloseHandle( hFile );
1329             }
1330         }
1331     }
1333     if (!hemf || !d.outsvg || !d.path) {
1334         if (d.outsvg)
1335             delete d.outsvg;
1336         if (d.path)
1337             delete d.path;
1338         if  (local_fn)
1339             g_free(local_fn);
1340         if  (unicode_fn)
1341             g_free(unicode_fn);
1342         return NULL;
1343     }
1345     EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);
1346     DeleteEnhMetaFile(hemf);
1348 //    std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
1350     SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);
1352     delete d.outsvg;
1353     delete d.path;
1355     if (d.emf_obj) {
1356         int i;
1357         for (i=0; i<d.n_obj; i++)
1358             delete_object(&d, i);
1359         delete[] d.emf_obj;
1360     }
1362     if (d.style.stroke_dash.dash)
1363         delete[] d.style.stroke_dash.dash;
1365     if  (local_fn)
1366         g_free(local_fn);
1367     if  (unicode_fn)
1368         g_free(unicode_fn);
1370     return doc;
1374 void
1375 EmfWin32::init (void)
1377     Inkscape::Extension::Extension * ext;
1379     /* EMF in */
1380     ext = Inkscape::Extension::build_from_mem(
1381         "<inkscape-extension>\n"
1382             "<name>" N_("EMF Input") "</name>\n"
1383             "<id>org.inkscape.input.emf.win32</id>\n"
1384             "<input>\n"
1385                 "<extension>.emf</extension>\n"
1386                 "<mimetype>image/x-emf</mimetype>\n"
1387                 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
1388                 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
1389                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
1390             "</input>\n"
1391         "</inkscape-extension>", new EmfWin32());
1393     /* WMF in */
1394     ext = Inkscape::Extension::build_from_mem(
1395         "<inkscape-extension>\n"
1396             "<name>" N_("WMF Input") "</name>\n"
1397             "<id>org.inkscape.input.wmf.win32</id>\n"
1398             "<input>\n"
1399                 "<extension>.wmf</extension>\n"
1400                 "<mimetype>image/x-wmf</mimetype>\n"
1401                 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
1402                 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
1403                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
1404             "</input>\n"
1405         "</inkscape-extension>", new EmfWin32());
1407     /* EMF out */
1408     ext = Inkscape::Extension::build_from_mem(
1409         "<inkscape-extension>\n"
1410             "<name>" N_("EMF Output") "</name>\n"
1411             "<id>org.inkscape.output.emf.win32</id>\n"
1412             "<output>\n"
1413                 "<extension>.emf</extension>\n"
1414                 "<mimetype>image/x-emf</mimetype>\n"
1415                 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
1416                 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
1417             "</output>\n"
1418         "</inkscape-extension>", new EmfWin32());
1420     return;
1424 } } }  /* namespace Inkscape, Extension, Implementation */
1427 #endif /* WIN32 */
1430 /*
1431   Local Variables:
1432   mode:cpp
1433   c-file-style:"stroustrup"
1434   c-file-offsets:((innamespace . 0)(inline-open . 0))
1435   indent-tabs-mode:nil
1436   fill-column:99
1437   End:
1438 */
1439 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :