Code

a39d1fb1dffe6dcf14baaf0b8bd8d96c85414560
[inkscape.git] / src / extension / internal / emf-win32-inout.cpp
1 /** \file\r
2  * Enhanced Metafile Input and Output.\r
3  */\r
4 /*\r
5  * Authors:\r
6  *   Ulf Erikson <ulferikson@users.sf.net>\r
7  *\r
8  * Copyright (C) 2006 Authors\r
9  *\r
10  * Released under GNU GPL, read the file 'COPYING' for more information\r
11  */\r
12 /*\r
13  * References:\r
14  *  - How to Create & Play Enhanced Metafiles in Win32\r
15  *      http://support.microsoft.com/kb/q145999/\r
16  *  - INFO: Windows Metafile Functions & Aldus Placeable Metafiles\r
17  *      http://support.microsoft.com/kb/q66949/\r
18  *  - Metafile Functions\r
19  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp\r
20  *  - Metafile Structures\r
21  *      http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp\r
22  */\r
23 \r
24 #ifdef WIN32\r
25 \r
26 #ifdef HAVE_CONFIG_H\r
27 # include "config.h"\r
28 #endif\r
29 \r
30 #include "win32.h"\r
31 #include "emf-win32-print.h"\r
32 #include "emf-win32-inout.h"\r
33 #include "inkscape.h"\r
34 #include "sp-path.h"\r
35 #include "style.h"\r
36 #include "color.h"\r
37 #include "display/curve.h"\r
38 #include "libnr/n-art-bpath.h"\r
39 #include "libnr/nr-point-matrix-ops.h"\r
40 #include "gtk/gtk.h"\r
41 #include "print.h"\r
42 #include "glibmm/i18n.h"\r
43 #include "extension/extension.h"\r
44 #include "extension/system.h"\r
45 #include "extension/print.h"\r
46 #include "extension/db.h"\r
47 #include "extension/output.h"\r
48 #include "document.h"\r
49 #include "display/nr-arena.h"\r
50 #include "display/nr-arena-item.h"\r
51 \r
52 #include "libnr/nr-rect.h"\r
53 #include "libnr/nr-matrix.h"\r
54 #include "libnr/nr-pixblock.h"\r
55 \r
56 #include <stdio.h>\r
57 #include <string.h>\r
58 \r
59 #include <vector>\r
60 #include <string>\r
61 \r
62 #include "io/sys.h"\r
63 \r
64 #include "unit-constants.h"\r
65 \r
66 #include "clear-n_.h"\r
67 \r
68 \r
69 #define PRINT_EMF_WIN32 "org.inkscape.print.emf.win32"\r
70 \r
71 #ifndef PS_JOIN_MASK\r
72 #define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND)\r
73 #endif\r
74 \r
75 \r
76 namespace Inkscape {\r
77 namespace Extension {\r
78 namespace Internal {\r
79 \r
80 \r
81 EmfWin32::EmfWin32 (void) // The null constructor\r
82 {\r
83     return;\r
84 }\r
85 \r
86 \r
87 EmfWin32::~EmfWin32 (void) //The destructor\r
88 {\r
89     return;\r
90 }\r
91 \r
92 \r
93 bool\r
94 EmfWin32::check (Inkscape::Extension::Extension * module)\r
95 {\r
96     if (NULL == Inkscape::Extension::db.get(PRINT_EMF_WIN32))\r
97         return FALSE;\r
98     return TRUE;\r
99 }\r
100 \r
101 \r
102 static void\r
103 emf_print_document_to_file(SPDocument *doc, gchar const *filename)\r
104 {\r
105     Inkscape::Extension::Print *mod;\r
106     SPPrintContext context;\r
107     gchar const *oldconst;\r
108     gchar *oldoutput;\r
109     unsigned int ret;\r
110 \r
111     sp_document_ensure_up_to_date(doc);\r
112 \r
113     mod = Inkscape::Extension::get_print(PRINT_EMF_WIN32);\r
114     oldconst = mod->get_param_string("destination");\r
115     oldoutput = g_strdup(oldconst);\r
116     mod->set_param_string("destination", (gchar *)filename);\r
117 \r
118 /* Start */\r
119     context.module = mod;\r
120     /* fixme: This has to go into module constructor somehow */\r
121     /* Create new arena */\r
122     mod->base = SP_ITEM(sp_document_root(doc));\r
123     mod->arena = NRArena::create();\r
124     mod->dkey = sp_item_display_key_new(1);\r
125     mod->root = sp_item_invoke_show(mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY);\r
126     /* Print document */\r
127     ret = mod->begin(doc);\r
128     if (ret) {\r
129         throw Inkscape::Extension::Output::save_failed();\r
130     }\r
131     sp_item_invoke_print(mod->base, &context);\r
132     ret = mod->finish();\r
133     /* Release arena */\r
134     sp_item_invoke_hide(mod->base, mod->dkey);\r
135     mod->base = NULL;\r
136     nr_arena_item_unref(mod->root);\r
137     mod->root = NULL;\r
138     nr_object_unref((NRObject *) mod->arena);\r
139     mod->arena = NULL;\r
140 /* end */\r
141 \r
142     mod->set_param_string("destination", oldoutput);\r
143     g_free(oldoutput);\r
144 \r
145     return;\r
146 }\r
147 \r
148 \r
149 void\r
150 EmfWin32::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gchar *uri)\r
151 {\r
152     Inkscape::Extension::Extension * ext;\r
153 \r
154     ext = Inkscape::Extension::db.get(PRINT_EMF_WIN32);\r
155     if (ext == NULL)\r
156         return;\r
157 \r
158 //    bool old_textToPath  = ext->get_param_bool("textToPath");\r
159 //    bool new_val         = mod->get_param_bool("textToPath");\r
160 //    ext->set_param_bool("textToPath", new_val);\r
161 \r
162     gchar * final_name;\r
163     final_name = g_strdup_printf("%s", uri);\r
164     emf_print_document_to_file(doc, final_name);\r
165     g_free(final_name);\r
166 \r
167 //    ext->set_param_bool("textToPath", old_textToPath);\r
168 \r
169     return;\r
170 }\r
171 \r
172 \r
173 \r
174 typedef struct {\r
175     int type;\r
176     ENHMETARECORD *lpEMFR;\r
177 } EMF_OBJECT, *PEMF_OBJECT;\r
178 \r
179 typedef struct emf_callback_data {\r
180     Glib::ustring *outsvg;\r
181     Glib::ustring *path;\r
182     struct SPStyle style;\r
183     bool stroke_set;\r
184     bool fill_set;\r
185     double xDPI, yDPI;\r
186 \r
187     SIZEL sizeWnd;\r
188     SIZEL sizeView;\r
189     float PixelsX;\r
190     float PixelsY;\r
191     float MMX;\r
192     float MMY;\r
193     float dwInchesX;\r
194     float dwInchesY;\r
195     POINTL winorg;\r
196     POINTL vieworg;\r
197     double ScaleX, ScaleY;\r
198 \r
199     int n_obj;\r
200     PEMF_OBJECT emf_obj;\r
201 } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;\r
202 \r
203 \r
204 static void\r
205 output_style(PEMF_CALLBACK_DATA d, int iType)\r
206 {\r
207     SVGOStringStream tmp_style;\r
208     char tmp[1024] = {0};\r
209 \r
210     *(d->outsvg) += "\n\tstyle=\"";\r
211     if (iType == EMR_STROKEPATH || !d->fill_set) {\r
212         tmp_style << "fill:none;";\r
213     } else {\r
214         float rgb[3];\r
215         sp_color_get_rgb_floatv( &(d->style.fill.value.color), rgb );\r
216         snprintf(tmp, 1023,\r
217                  "fill:#%02x%02x%02x;",\r
218                  SP_COLOR_F_TO_U(rgb[0]),\r
219                  SP_COLOR_F_TO_U(rgb[1]),\r
220                  SP_COLOR_F_TO_U(rgb[2]));\r
221         tmp_style << tmp;\r
222         snprintf(tmp, 1023,\r
223                  "fill-rule:%s;",\r
224                  d->style.fill_rule.value != 0 ? "evenodd" : "nonzero");\r
225         tmp_style << tmp;\r
226         tmp_style << "fill-opacity:1;";\r
227     }\r
228 \r
229     if (iType == EMR_FILLPATH || !d->stroke_set) {\r
230         tmp_style << "stroke:none;";\r
231     } else {\r
232         float rgb[3];\r
233         sp_color_get_rgb_floatv(&(d->style.stroke.value.color), rgb);\r
234         snprintf(tmp, 1023,\r
235                  "stroke:#%02x%02x%02x;",\r
236                  SP_COLOR_F_TO_U(rgb[0]),\r
237                  SP_COLOR_F_TO_U(rgb[1]),\r
238                  SP_COLOR_F_TO_U(rgb[2]));\r
239         tmp_style << tmp;\r
240 \r
241         tmp_style << "stroke-width:" <<\r
242             MAX( 0.001, d->style.stroke_width.value ) << "px;";\r
243 \r
244         tmp_style << "stroke-linejoin:" <<\r
245             (d->style.stroke_linejoin.computed == 0 ? "miter" :\r
246              d->style.stroke_linejoin.computed == 1 ? "round" :\r
247              d->style.stroke_linejoin.computed == 2 ? "bevel" :\r
248              "unknown") << ";";\r
249 \r
250         if (d->style.stroke_linejoin.computed == 0) {\r
251             tmp_style << "stroke-miterlimit:" <<\r
252                 MAX( 0.01, d->style.stroke_miterlimit.value ) << ";";\r
253         }\r
254 \r
255         if (d->style.stroke_dasharray_set &&\r
256             d->style.stroke_dash.n_dash && d->style.stroke_dash.dash)\r
257         {\r
258             tmp_style << "stroke-dasharray:";\r
259             for (int i=0; i<d->style.stroke_dash.n_dash; i++) {\r
260                 if (i)\r
261                     tmp_style << ",";\r
262                 tmp_style << d->style.stroke_dash.dash[i];\r
263             }\r
264             tmp_style << ";";\r
265             tmp_style << "stroke-dashoffset:0;";\r
266         } else {\r
267             tmp_style << "stroke-dasharray:none;";\r
268         }\r
269         tmp_style << "stroke-opacity:1;";\r
270     }\r
271     tmp_style << "\" ";\r
272 \r
273     *(d->outsvg) += tmp_style.str().c_str();\r
274 }\r
275 \r
276 \r
277 static double\r
278 pix_x_to_point(PEMF_CALLBACK_DATA d, double px)\r
279 {\r
280     double tmp = px - d->winorg.x;\r
281     tmp *= (double) PX_PER_IN / d->ScaleX;\r
282     tmp += d->vieworg.x;\r
283     return tmp;\r
284 }\r
285 \r
286 \r
287 static double\r
288 pix_y_to_point(PEMF_CALLBACK_DATA d, double px)\r
289 {\r
290     double tmp = px - d->winorg.y;\r
291     tmp *= (double) PX_PER_IN / d->ScaleY;\r
292     tmp += d->vieworg.y;\r
293     return tmp;\r
294 }\r
295 \r
296 \r
297 static double\r
298 pix_size_to_point(PEMF_CALLBACK_DATA d, double px)\r
299 {\r
300     double tmp = px;\r
301     tmp *= (double) PX_PER_IN / d->ScaleX;\r
302     return tmp;\r
303 }\r
304 \r
305 \r
306 static void\r
307 select_pen(PEMF_CALLBACK_DATA d, int index)\r
308 {\r
309     PEMRCREATEPEN pEmr = NULL;\r
310 \r
311     if (index >= 0 && index < d->n_obj)\r
312         pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;\r
313 \r
314     if (!pEmr)\r
315         return;\r
316 \r
317     switch (pEmr->lopn.lopnStyle) {\r
318         default:\r
319         {\r
320             d->style.stroke_dasharray_set = 0;\r
321             break;\r
322         }\r
323     }\r
324 \r
325     if (pEmr->lopn.lopnWidth.x) {\r
326         d->style.stroke_width.value = pix_size_to_point( d, pEmr->lopn.lopnWidth.x );\r
327     } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)\r
328         d->style.stroke_width.value = 1.0;\r
329     }\r
330 \r
331     double r, g, b;\r
332     r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );\r
333     g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );\r
334     b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );\r
335     sp_color_set_rgb_float( &(d->style.stroke.value.color), r,g,b );\r
336 \r
337     d->style.stroke_linejoin.computed = 1;\r
338 \r
339     d->stroke_set = true;\r
340 }\r
341 \r
342 \r
343 static void\r
344 select_extpen(PEMF_CALLBACK_DATA d, int index)\r
345 {\r
346     PEMREXTCREATEPEN pEmr = NULL;\r
347 \r
348     if (index >= 0 && index < d->n_obj)\r
349         pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;\r
350 \r
351     if (!pEmr)\r
352         return;\r
353 \r
354     switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {\r
355         case PS_USERSTYLE:\r
356         {\r
357             if (pEmr->elp.elpNumEntries) {\r
358                 d->style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;\r
359                 if (d->style.stroke_dash.dash)\r
360                     delete[] d->style.stroke_dash.dash;\r
361                 d->style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];\r
362                 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {\r
363                     d->style.stroke_dash.dash[i] = pix_size_to_point( d, pEmr->elp.elpStyleEntry[i] );\r
364                 }\r
365                 d->style.stroke_dasharray_set = 1;\r
366             } else {\r
367                 d->style.stroke_dasharray_set = 0;\r
368             }\r
369             break;\r
370         }\r
371         default:\r
372         {\r
373             d->style.stroke_dasharray_set = 0;\r
374             break;\r
375         }\r
376     }\r
377 \r
378     switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {\r
379         case PS_ENDCAP_ROUND:\r
380         {\r
381             d->style.stroke_linecap.computed = 1;\r
382             break;\r
383         }\r
384         case PS_ENDCAP_SQUARE:\r
385         {\r
386             d->style.stroke_linecap.computed = 2;\r
387             break;\r
388         }\r
389         case PS_ENDCAP_FLAT:\r
390         default:\r
391         {\r
392             d->style.stroke_linecap.computed = 0;\r
393             break;\r
394         }\r
395     }\r
396 \r
397     switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {\r
398         case PS_JOIN_BEVEL:\r
399         {\r
400             d->style.stroke_linejoin.computed = 2;\r
401             break;\r
402         }\r
403         case PS_JOIN_MITER:\r
404         {\r
405             d->style.stroke_linejoin.computed = 0;\r
406             break;\r
407         }\r
408         case PS_JOIN_ROUND:\r
409         default:\r
410         {\r
411             d->style.stroke_linejoin.computed = 1;\r
412             break;\r
413         }\r
414     }\r
415 \r
416     d->style.stroke_width.value = pix_size_to_point( d, pEmr->elp.elpWidth );\r
417 \r
418     double r, g, b;\r
419     r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );\r
420     g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );\r
421     b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );\r
422 \r
423     sp_color_set_rgb_float( &(d->style.stroke.value.color), r,g,b );\r
424 \r
425     d->stroke_set = true;\r
426 }\r
427 \r
428 \r
429 static void\r
430 select_brush(PEMF_CALLBACK_DATA d, int index)\r
431 {\r
432     PEMRCREATEBRUSHINDIRECT pEmr = NULL;\r
433 \r
434     if (index >= 0 && index < d->n_obj)\r
435         pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;\r
436 \r
437     if (!pEmr)\r
438         return;\r
439 \r
440     if (pEmr->lb.lbStyle == BS_SOLID) {\r
441         double r, g, b;\r
442         r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );\r
443         g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );\r
444         b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );\r
445         sp_color_set_rgb_float( &(d->style.fill.value.color), r,g,b );\r
446     }\r
447 \r
448     d->fill_set = true;\r
449 }\r
450 \r
451 \r
452 static void\r
453 delete_object(PEMF_CALLBACK_DATA d, int index)\r
454 {\r
455     if (index >= 0 && index < d->n_obj) {\r
456         d->emf_obj[index].type = 0;\r
457         if (d->emf_obj[index].lpEMFR)\r
458             free(d->emf_obj[index].lpEMFR);\r
459         d->emf_obj[index].lpEMFR = NULL;\r
460     }\r
461 }\r
462 \r
463 \r
464 static void\r
465 insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)\r
466 {\r
467     if (index >= 0 && index < d->n_obj) {\r
468         delete_object(d, index);\r
469         d->emf_obj[index].type = type;\r
470         d->emf_obj[index].lpEMFR = pObj;\r
471     }\r
472 }\r
473 \r
474 \r
475 static int CALLBACK\r
476 myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)\r
477 {\r
478     PEMF_CALLBACK_DATA d;\r
479     SVGOStringStream tmp_outsvg;\r
480     SVGOStringStream tmp_path;\r
481     SVGOStringStream tmp_str;\r
482 \r
483     d = (PEMF_CALLBACK_DATA) lpData;\r
484 \r
485     switch (lpEMFR->iType)\r
486     {\r
487         case EMR_HEADER:\r
488         {\r
489             ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;\r
490             tmp_outsvg << "<svg\n";\r
491 \r
492             d->xDPI = 2540;\r
493             d->yDPI = 2540;\r
494 \r
495             d->PixelsX = pEmr->rclFrame.right - pEmr->rclFrame.left;\r
496             d->PixelsY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;\r
497 \r
498             d->MMX = d->PixelsX / 100.0;\r
499             d->MMY = d->PixelsY / 100.0;\r
500 \r
501             tmp_outsvg <<\r
502                 "  width=\"" << d->MMX << "mm\"\n" <<\r
503                 "  height=\"" << d->MMY << "mm\">\n";\r
504 \r
505             if (pEmr->nHandles) {\r
506                 d->n_obj = pEmr->nHandles;\r
507                 d->emf_obj = new EMF_OBJECT[d->n_obj];\r
508             } else {\r
509                 d->emf_obj = NULL;\r
510             }\r
511 \r
512             break;\r
513         }\r
514         case EMR_POLYBEZIER:\r
515         {\r
516             PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;\r
517             DWORD i,j;\r
518 \r
519             if (pEmr->cptl<4)\r
520                 break;\r
521 \r
522             *(d->outsvg) += "    <path ";\r
523             output_style(d, EMR_STROKEPATH);\r
524             *(d->outsvg) += "\n\td=\"";\r
525 \r
526             tmp_str <<\r
527                 "\n\tM " <<\r
528                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<\r
529                 pix_x_to_point( d, pEmr->aptl[0].y) << " ";\r
530 \r
531             for (i=1; i<pEmr->cptl; ) {\r
532                 tmp_str << "\n\tC ";\r
533                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {\r
534                     tmp_str <<\r
535                         pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
536                         pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
537                 }\r
538             }\r
539 \r
540             *(d->outsvg) += tmp_str.str().c_str();\r
541             *(d->outsvg) += " \" /> \n";\r
542 \r
543             break;\r
544         }\r
545         case EMR_POLYGON:\r
546         {\r
547             EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;\r
548             DWORD i;\r
549 \r
550             if (pEmr->cptl < 2)\r
551                 break;\r
552 \r
553             *(d->outsvg) += "    <path ";\r
554             output_style(d, EMR_STROKEANDFILLPATH);\r
555             *(d->outsvg) += "\n\td=\"";\r
556 \r
557             tmp_str <<\r
558                 "\n\tM " <<\r
559                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<\r
560                 pix_y_to_point( d, pEmr->aptl[0].y ) << " ";\r
561 \r
562             for (i=1; i<pEmr->cptl; i++) {\r
563                 tmp_str <<\r
564                     "\n\tL " <<\r
565                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
566                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
567             }\r
568 \r
569             *(d->outsvg) += tmp_str.str().c_str();\r
570             *(d->outsvg) += " z \" /> \n";\r
571 \r
572             break;\r
573         }\r
574         case EMR_POLYLINE:\r
575         {\r
576             EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;\r
577             DWORD i;\r
578 \r
579             if (pEmr->cptl<2)\r
580                 break;\r
581 \r
582             *(d->outsvg) += "    <path ";\r
583             output_style(d, EMR_STROKEPATH);\r
584             *(d->outsvg) += "\n\td=\"";\r
585 \r
586             tmp_str <<\r
587                 "\n\tM " <<\r
588                 pix_x_to_point( d, pEmr->aptl[0].x ) << " " <<\r
589                 pix_y_to_point( d, pEmr->aptl[0].y ) << " ";\r
590 \r
591             for (i=1; i<pEmr->cptl; i++) {\r
592                 tmp_str <<\r
593                     "\n\tL " <<\r
594                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
595                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
596             }\r
597 \r
598             *(d->outsvg) += tmp_str.str().c_str();\r
599             *(d->outsvg) += " \" /> \n";\r
600 \r
601             break;\r
602         }\r
603         case EMR_POLYBEZIERTO:\r
604         {\r
605             PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;\r
606             DWORD i,j;\r
607 \r
608             for (i=0; i<pEmr->cptl;) {\r
609                 tmp_path << "\n\tC ";\r
610                 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {\r
611                     tmp_path <<\r
612                         pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
613                         pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
614                 }\r
615             }\r
616 \r
617             break;\r
618         }\r
619         case EMR_POLYLINETO:\r
620         {\r
621             PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;\r
622             DWORD i;\r
623 \r
624             for (i=0; i<pEmr->cptl;i++) {\r
625                 tmp_path <<\r
626                     "\n\tL " <<\r
627                     pix_x_to_point( d, pEmr->aptl[i].x ) << " " <<\r
628                     pix_y_to_point( d, pEmr->aptl[i].y ) << " ";\r
629             }\r
630 \r
631             break;\r
632         }\r
633         case EMR_POLYPOLYLINE:\r
634             break;\r
635         case EMR_POLYPOLYGON:\r
636             break;\r
637         case EMR_SETWINDOWEXTEX:\r
638         {\r
639             PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;\r
640 \r
641             d->sizeWnd = pEmr->szlExtent;\r
642             d->PixelsX = d->sizeWnd.cx;\r
643             d->PixelsY = d->sizeWnd.cy;\r
644 \r
645             d->ScaleX = d->xDPI / (100*d->MMX / d->PixelsX);\r
646             d->ScaleY = d->yDPI / (100*d->MMY / d->PixelsY);\r
647 \r
648             break;\r
649         }\r
650         case EMR_SETWINDOWORGEX:\r
651         {\r
652             PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;\r
653             d->winorg = pEmr->ptlOrigin;\r
654             break;\r
655         }\r
656         case EMR_SETVIEWPORTEXTEX:\r
657         {\r
658             PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;\r
659 \r
660             d->sizeView = pEmr->szlExtent;\r
661 \r
662             if (d->sizeWnd.cx && d->sizeWnd.cy) {\r
663                 HDC hScreenDC = GetDC( NULL );\r
664 \r
665                 float scrPixelsX = (float)GetDeviceCaps( hScreenDC, HORZRES );\r
666                 float scrPixelsY = (float)GetDeviceCaps( hScreenDC, VERTRES );\r
667                 float scrMMX = (float)GetDeviceCaps( hScreenDC, HORZSIZE );\r
668                 float scrMMY = (float)GetDeviceCaps( hScreenDC, VERTSIZE );\r
669 \r
670                 ReleaseDC( NULL, hScreenDC );\r
671 \r
672                 d->dwInchesX = d->sizeView.cx / (25.4f*scrPixelsX/scrMMX);\r
673                 d->dwInchesY = d->sizeView.cy / (25.4f*scrPixelsY/scrMMY);\r
674                 d->xDPI = d->sizeWnd.cx / d->dwInchesX;\r
675                 d->yDPI = d->sizeWnd.cy / d->dwInchesY;\r
676 \r
677                 if (1) {\r
678                     d->xDPI = 2540;\r
679                     d->yDPI = 2540;\r
680                     d->dwInchesX = d->PixelsX / d->xDPI;\r
681                     d->dwInchesY = d->PixelsY / d->yDPI;\r
682                     d->ScaleX = d->xDPI;\r
683                     d->ScaleY = d->yDPI;\r
684                 }\r
685 \r
686                 d->MMX = d->dwInchesX * MM_PER_IN;\r
687                 d->MMY = d->dwInchesY * MM_PER_IN;\r
688             }\r
689 \r
690             break;\r
691         }\r
692         case EMR_SETVIEWPORTORGEX:\r
693         {\r
694             PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;\r
695             d->vieworg = pEmr->ptlOrigin;\r
696             break;\r
697         }\r
698         case EMR_SETBRUSHORGEX:\r
699             break;\r
700         case EMR_EOF:\r
701         {\r
702             tmp_outsvg << "</svg>\n";\r
703             break;\r
704         }\r
705         case EMR_SETPIXELV:\r
706             break;\r
707         case EMR_SETMAPPERFLAGS:\r
708             break;\r
709         case EMR_SETMAPMODE:\r
710             break;\r
711         case EMR_SETBKMODE:\r
712             break;\r
713         case EMR_SETPOLYFILLMODE:\r
714         {\r
715             PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;\r
716             d->style.fill_rule.value =\r
717                 (pEmr->iMode == WINDING ? 0 :\r
718                  pEmr->iMode == ALTERNATE ? 1 : 0);\r
719             break;\r
720         }\r
721         case EMR_SETROP2:\r
722             break;\r
723         case EMR_SETSTRETCHBLTMODE:\r
724             break;\r
725         case EMR_SETTEXTALIGN:\r
726             break;\r
727         case EMR_SETCOLORADJUSTMENT:\r
728             break;\r
729         case EMR_SETTEXTCOLOR:\r
730             break;\r
731         case EMR_SETBKCOLOR:\r
732             break;\r
733         case EMR_OFFSETCLIPRGN:\r
734             break;\r
735         case EMR_MOVETOEX:\r
736         {\r
737             PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;\r
738             tmp_path <<\r
739                 "\n\tM " <<\r
740                 pix_x_to_point( d, pEmr->ptl.x ) << " " <<\r
741                 pix_y_to_point( d, pEmr->ptl.y ) << " ";\r
742             break;\r
743         }\r
744         case EMR_SETMETARGN:\r
745             break;\r
746         case EMR_EXCLUDECLIPRECT:\r
747             break;\r
748         case EMR_INTERSECTCLIPRECT:\r
749             break;\r
750         case EMR_SCALEVIEWPORTEXTEX:\r
751             break;\r
752         case EMR_SCALEWINDOWEXTEX:\r
753             break;\r
754         case EMR_SAVEDC:\r
755             break;\r
756         case EMR_RESTOREDC:\r
757             break;\r
758         case EMR_SETWORLDTRANSFORM:\r
759             break;\r
760         case EMR_MODIFYWORLDTRANSFORM:\r
761             break;\r
762         case EMR_SELECTOBJECT:\r
763         {\r
764             PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;\r
765             unsigned int index = pEmr->ihObject;\r
766 \r
767             if (index >= ENHMETA_STOCK_OBJECT) {\r
768                 index -= ENHMETA_STOCK_OBJECT;\r
769                 switch (index) {\r
770                     case NULL_BRUSH:\r
771                         d->fill_set = false;\r
772                         break;\r
773                     case BLACK_BRUSH:\r
774                     case DKGRAY_BRUSH:\r
775                     case GRAY_BRUSH:\r
776                     case LTGRAY_BRUSH:\r
777                     case WHITE_BRUSH:\r
778                     {\r
779                         float val = 0;\r
780                         switch (index) {\r
781                             case BLACK_BRUSH:\r
782                                 val = 0.0 / 255.0;\r
783                                 break;\r
784                             case DKGRAY_BRUSH:\r
785                                 val = 64.0 / 255.0;\r
786                                 break;\r
787                             case GRAY_BRUSH:\r
788                                 val = 128.0 / 255.0;\r
789                                 break;\r
790                             case LTGRAY_BRUSH:\r
791                                 val = 192.0 / 255.0;\r
792                                 break;\r
793                             case WHITE_BRUSH:\r
794                                 val = 255.0 / 255.0;\r
795                                 break;\r
796                         }\r
797                         sp_color_set_rgb_float( &(d->style.fill.value.color), val,val,val );\r
798 \r
799                         d->fill_set = true;\r
800                         break;\r
801                     }\r
802                     case NULL_PEN:\r
803                         d->stroke_set = false;\r
804                         break;\r
805                     case BLACK_PEN:\r
806                     case WHITE_PEN:\r
807                     {\r
808                         float val = index == BLACK_PEN ? 0 : 1;\r
809                         d->style.stroke_dasharray_set = 0;\r
810                         d->style.stroke_width.value = 1.0;\r
811                         sp_color_set_rgb_float( &(d->style.stroke.value.color), val,val,val );\r
812 \r
813                         d->stroke_set = true;\r
814 \r
815                         break;\r
816                     }\r
817                 }\r
818             } else {\r
819                 if (index >= 0 && index < d->n_obj) {\r
820                     switch (d->emf_obj[index].type)\r
821                     {\r
822                         case EMR_CREATEPEN:\r
823                             select_pen(d, index);\r
824                             break;\r
825                         case EMR_CREATEBRUSHINDIRECT:\r
826                             select_brush(d, index);\r
827                             break;\r
828                         case EMR_EXTCREATEPEN:\r
829                             select_extpen(d, index);\r
830                             break;\r
831                     }\r
832                 }\r
833             }\r
834             break;\r
835         }\r
836         case EMR_CREATEPEN:\r
837         {\r
838             PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;\r
839             int index = pEmr->ihPen;\r
840 \r
841             EMRCREATEPEN *pPen =\r
842                 (EMRCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) );\r
843             pPen->lopn = pEmr->lopn;\r
844             insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);\r
845 \r
846             break;\r
847         }\r
848         case EMR_CREATEBRUSHINDIRECT:\r
849         {\r
850             PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;\r
851             int index = pEmr->ihBrush;\r
852 \r
853             EMRCREATEBRUSHINDIRECT *pBrush =\r
854                 (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );\r
855             pBrush->lb = pEmr->lb;\r
856             insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);\r
857 \r
858             break;\r
859         }\r
860         case EMR_DELETEOBJECT:\r
861             break;\r
862         case EMR_ANGLEARC:\r
863             break;\r
864         case EMR_ELLIPSE:\r
865             break;\r
866         case EMR_RECTANGLE:\r
867             break;\r
868         case EMR_ROUNDRECT:\r
869             break;\r
870         case EMR_ARC:\r
871             break;\r
872         case EMR_CHORD:\r
873             break;\r
874         case EMR_PIE:\r
875             break;\r
876         case EMR_SELECTPALETTE:\r
877             break;\r
878         case EMR_CREATEPALETTE:\r
879             break;\r
880         case EMR_SETPALETTEENTRIES:\r
881             break;\r
882         case EMR_RESIZEPALETTE:\r
883             break;\r
884         case EMR_REALIZEPALETTE:\r
885             break;\r
886         case EMR_EXTFLOODFILL:\r
887             break;\r
888         case EMR_LINETO:\r
889         {\r
890             PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;\r
891             tmp_path <<\r
892                 "\n\tL " <<\r
893                 pix_x_to_point( d, pEmr->ptl.x ) << " " <<\r
894                 pix_y_to_point( d, pEmr->ptl.y ) << " ";\r
895             break;\r
896         }\r
897         case EMR_ARCTO:\r
898             break;\r
899         case EMR_POLYDRAW:\r
900             break;\r
901         case EMR_SETARCDIRECTION:\r
902             break;\r
903         case EMR_SETMITERLIMIT:\r
904         {\r
905             PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;\r
906             d->style.stroke_miterlimit.value = pix_size_to_point( d, pEmr->eMiterLimit );\r
907 \r
908             if (d->style.stroke_miterlimit.value < 1)\r
909                 d->style.stroke_miterlimit.value = 1.0;\r
910 \r
911             break;\r
912         }\r
913         case EMR_BEGINPATH:\r
914         {\r
915             tmp_path << " d=\"";\r
916             *(d->path) = "";\r
917             break;\r
918         }\r
919         case EMR_ENDPATH:\r
920         {\r
921             tmp_path << "\"";\r
922             break;\r
923         }\r
924         case EMR_CLOSEFIGURE:\r
925         {\r
926             tmp_path << "\n\tz";\r
927             break;\r
928         }\r
929         case EMR_FILLPATH:\r
930         case EMR_STROKEANDFILLPATH:\r
931         case EMR_STROKEPATH:\r
932         {\r
933             *(d->outsvg) += "    <path ";\r
934             output_style(d, lpEMFR->iType);\r
935             *(d->outsvg) += "\n\t";\r
936             *(d->outsvg) += *(d->path);\r
937             *(d->outsvg) += " /> \n";\r
938             break;\r
939         }\r
940         case EMR_FLATTENPATH:\r
941             break;\r
942         case EMR_WIDENPATH:\r
943             break;\r
944         case EMR_SELECTCLIPPATH:\r
945             break;\r
946         case EMR_ABORTPATH:\r
947             break;\r
948         case EMR_GDICOMMENT:\r
949             break;\r
950         case EMR_FILLRGN:\r
951             break;\r
952         case EMR_FRAMERGN:\r
953             break;\r
954         case EMR_INVERTRGN:\r
955             break;\r
956         case EMR_PAINTRGN:\r
957             break;\r
958         case EMR_EXTSELECTCLIPRGN:\r
959             break;\r
960         case EMR_BITBLT:\r
961             break;\r
962         case EMR_STRETCHBLT:\r
963             break;\r
964         case EMR_MASKBLT:\r
965             break;\r
966         case EMR_PLGBLT:\r
967             break;\r
968         case EMR_SETDIBITSTODEVICE:\r
969             break;\r
970         case EMR_STRETCHDIBITS:\r
971             break;\r
972         case EMR_EXTCREATEFONTINDIRECTW:\r
973             break;\r
974         case EMR_EXTTEXTOUTA:\r
975             break;\r
976         case EMR_EXTTEXTOUTW:\r
977             break;\r
978         case EMR_POLYBEZIER16:\r
979         {\r
980             PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;\r
981             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
982             DWORD i,j;\r
983 \r
984             if (pEmr->cpts<4)\r
985                 break;\r
986 \r
987             *(d->outsvg) += "    <path ";\r
988             output_style(d, EMR_STROKEPATH);\r
989             *(d->outsvg) += "\n\td=\"";\r
990 \r
991             tmp_str <<\r
992                 "\n\tM " <<\r
993                 pix_x_to_point( d, apts[0].x ) << " " <<\r
994                 pix_y_to_point( d, apts[0].y ) << " ";\r
995 \r
996             for (i=1; i<pEmr->cpts; ) {\r
997                 tmp_str << "\n\tC ";\r
998                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {\r
999                     tmp_str <<\r
1000                         pix_x_to_point( d, apts[i].x ) << " " <<\r
1001                         pix_y_to_point( d, apts[i].y ) << " ";\r
1002                 }\r
1003             }\r
1004 \r
1005             *(d->outsvg) += tmp_str.str().c_str();\r
1006             *(d->outsvg) += " \" /> \n";\r
1007 \r
1008             break;\r
1009         }\r
1010         case EMR_POLYGON16:\r
1011         {\r
1012             PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;\r
1013             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
1014             unsigned int i;\r
1015 \r
1016             *(d->outsvg) += "<path ";\r
1017             output_style(d, EMR_STROKEANDFILLPATH);\r
1018             *(d->outsvg) += "\n\td=\"";\r
1019 \r
1020             // skip the first point?\r
1021             tmp_path << "\n\tM " <<\r
1022                 pix_x_to_point( d, apts[1].x ) << " " <<\r
1023                 pix_y_to_point( d, apts[1].y ) << " ";\r
1024 \r
1025             for (i=2; i<pEmr->cpts; i++) {\r
1026                 tmp_path << "\n\tL " <<\r
1027                     pix_x_to_point( d, apts[i].x ) << " " <<\r
1028                     pix_y_to_point( d, apts[i].y ) << " ";\r
1029             }\r
1030 \r
1031             *(d->outsvg) += tmp_path.str().c_str();\r
1032             *(d->outsvg) += " z \" /> \n";\r
1033 \r
1034             break;\r
1035         }\r
1036         case EMR_POLYLINE16:\r
1037         {\r
1038             EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;\r
1039             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
1040             DWORD i;\r
1041 \r
1042             if (pEmr->cpts<2)\r
1043                 break;\r
1044 \r
1045             *(d->outsvg) += "    <path ";\r
1046             output_style(d, EMR_STROKEPATH);\r
1047             *(d->outsvg) += "\n\td=\"";\r
1048 \r
1049             tmp_str <<\r
1050                 "\n\tM " <<\r
1051                 pix_x_to_point( d, apts[0].x ) << " " <<\r
1052                 pix_y_to_point( d, apts[0].y ) << " ";\r
1053 \r
1054             for (i=1; i<pEmr->cpts; i++) {\r
1055                 tmp_str <<\r
1056                     "\n\tL " <<\r
1057                     pix_x_to_point( d, apts[i].x ) << " " <<\r
1058                     pix_y_to_point( d, apts[i].y ) << " ";\r
1059             }\r
1060 \r
1061             *(d->outsvg) += tmp_str.str().c_str();\r
1062             *(d->outsvg) += " \" /> \n";\r
1063 \r
1064             break;\r
1065         }\r
1066         case EMR_POLYBEZIERTO16:\r
1067         {\r
1068             PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;\r
1069             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
1070             DWORD i,j;\r
1071 \r
1072             for (i=0; i<pEmr->cpts;) {\r
1073                 tmp_path << "\n\tC ";\r
1074                 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {\r
1075                     tmp_path <<\r
1076                         pix_x_to_point( d, apts[i].x ) << " " <<\r
1077                         pix_y_to_point( d, apts[i].y ) << " ";\r
1078                 }\r
1079             }\r
1080 \r
1081             break;\r
1082         }\r
1083         case EMR_POLYLINETO16:\r
1084         {\r
1085             PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;\r
1086             POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?\r
1087             DWORD i;\r
1088 \r
1089             for (i=0; i<pEmr->cpts;i++) {\r
1090                 tmp_path <<\r
1091                     "\n\tL " <<\r
1092                     pix_x_to_point( d, apts[i].x ) << " " <<\r
1093                     pix_y_to_point( d, apts[i].y ) << " ";\r
1094             }\r
1095 \r
1096             break;\r
1097         }\r
1098         case EMR_POLYPOLYLINE16:\r
1099             break;\r
1100         case EMR_POLYPOLYGON16:\r
1101         {\r
1102             PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;\r
1103             unsigned int n, i, j;\r
1104 \r
1105             *(d->outsvg) += "<path ";\r
1106             output_style(d, EMR_STROKEANDFILLPATH);\r
1107             *(d->outsvg) += "\n\td=\"";\r
1108 \r
1109             i = pEmr->nPolys-1; // ???\r
1110             for (n=0; n<pEmr->nPolys /*&& i<pEmr->cpts*/; n++) {\r
1111                 SVGOStringStream poly_path;\r
1112 \r
1113                 poly_path << "\n\tM " <<\r
1114                     pix_x_to_point( d, pEmr->apts[i].x ) << " " <<\r
1115                     pix_y_to_point( d, pEmr->apts[i].y ) << " ";\r
1116                 i++;\r
1117 \r
1118                 for (j=1; j<pEmr->aPolyCounts[n] /*&& i<pEmr->cpts*/; j++) {\r
1119                     poly_path << "\n\tL " <<\r
1120                         pix_x_to_point( d, pEmr->apts[i].x ) << " " <<\r
1121                         pix_y_to_point( d, pEmr->apts[i].y ) << " ";\r
1122                     i++;\r
1123                 }\r
1124 \r
1125                 *(d->outsvg) += poly_path.str().c_str();\r
1126                 *(d->outsvg) += " z \n";\r
1127             }\r
1128 \r
1129             *(d->outsvg) += " \" /> \n";\r
1130             break;\r
1131         }\r
1132         case EMR_POLYDRAW16:\r
1133             break;\r
1134         case EMR_CREATEMONOBRUSH:\r
1135             break;\r
1136         case EMR_CREATEDIBPATTERNBRUSHPT:\r
1137             break;\r
1138         case EMR_EXTCREATEPEN:\r
1139         {\r
1140             PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;\r
1141             int index = pEmr->ihPen;\r
1142 \r
1143             EMREXTCREATEPEN *pPen =\r
1144                 (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +\r
1145                                             sizeof(DWORD) * pEmr->elp.elpNumEntries );\r
1146             pPen->ihPen = pEmr->ihPen;\r
1147             pPen->offBmi = pEmr->offBmi;\r
1148             pPen->cbBmi = pEmr->cbBmi;\r
1149             pPen->offBits = pEmr->offBits;\r
1150             pPen->cbBits = pEmr->cbBits;\r
1151             pPen->elp = pEmr->elp;\r
1152             for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {\r
1153                 pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];\r
1154             }\r
1155             insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);\r
1156 \r
1157             break;\r
1158         }\r
1159         case EMR_POLYTEXTOUTA:\r
1160             break;\r
1161         case EMR_POLYTEXTOUTW:\r
1162             break;\r
1163         case EMR_SETICMMODE:\r
1164             break;\r
1165         case EMR_CREATECOLORSPACE:\r
1166             break;\r
1167         case EMR_SETCOLORSPACE:\r
1168             break;\r
1169         case EMR_DELETECOLORSPACE:\r
1170             break;\r
1171         case EMR_GLSRECORD:\r
1172             break;\r
1173         case EMR_GLSBOUNDEDRECORD:\r
1174             break;\r
1175         case EMR_PIXELFORMAT:\r
1176             break;\r
1177     }\r
1178 \r
1179     *(d->outsvg) += tmp_outsvg.str().c_str();\r
1180     *(d->path) += tmp_path.str().c_str();\r
1181 \r
1182     return 1;\r
1183 }\r
1184 \r
1185 \r
1186 // Aldus Placeable Header ===================================================\r
1187 // Since we are a 32bit app, we have to be sure this structure compiles to\r
1188 // be identical to a 16 bit app's version. To do this, we use the #pragma\r
1189 // to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT\r
1190 // for the bbox rectangle.\r
1191 #pragma pack( push )\r
1192 #pragma pack( 2 )\r
1193 typedef struct\r
1194 {\r
1195         DWORD           dwKey;\r
1196         WORD            hmf;\r
1197         SMALL_RECT      bbox;\r
1198         WORD            wInch;\r
1199         DWORD           dwReserved;\r
1200         WORD            wCheckSum;\r
1201 } APMHEADER, *PAPMHEADER;\r
1202 #pragma pack( pop )\r
1203 \r
1204 \r
1205 SPDocument *\r
1206 EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri )\r
1207 {\r
1208     EMF_CALLBACK_DATA d = {0};\r
1209 \r
1210     gsize bytesRead = 0;\r
1211     gsize bytesWritten = 0;\r
1212     GError* error = NULL;\r
1213     gchar *local_fn =\r
1214         g_filename_from_utf8( uri, -1,  &bytesRead,  &bytesWritten, &error );\r
1215 \r
1216     if (local_fn == NULL) {\r
1217         return NULL;\r
1218     }\r
1219 \r
1220     d.outsvg = new Glib::ustring("");\r
1221     d.path = new Glib::ustring("");\r
1222 \r
1223     CHAR *ansi_uri = (CHAR *) local_fn;\r
1224     gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );\r
1225     WCHAR *unicode_uri = (WCHAR *) unicode_fn;\r
1226 \r
1227     // Try open as Enhanced Metafile\r
1228     HENHMETAFILE hemf;\r
1229     if (PrintWin32::is_os_wide())\r
1230         hemf = GetEnhMetaFileW(unicode_uri);\r
1231     else\r
1232         hemf = GetEnhMetaFileA(ansi_uri);\r
1233 \r
1234     if (!hemf) {\r
1235         // Try open as Windows Metafile\r
1236         HMETAFILE hmf;\r
1237         if (PrintWin32::is_os_wide())\r
1238             hmf = GetMetaFileW(unicode_uri);\r
1239         else\r
1240             hmf = GetMetaFileA(ansi_uri);\r
1241 \r
1242         METAFILEPICT mp;\r
1243         HDC hDC;\r
1244 \r
1245         if (!hmf) {\r
1246             if (PrintWin32::is_os_wide()) {\r
1247                 WCHAR szTemp[MAX_PATH];\r
1248 \r
1249                 DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );\r
1250                 if (dw) {\r
1251                     hmf = GetMetaFileW( szTemp );\r
1252                 }\r
1253             } else {\r
1254                 CHAR szTemp[MAX_PATH];\r
1255 \r
1256                 DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );\r
1257                 if (dw) {\r
1258                     hmf = GetMetaFileA( szTemp );\r
1259                 }\r
1260             }\r
1261         }\r
1262 \r
1263         if (hmf) {\r
1264             DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );\r
1265             if (nSize) {\r
1266                 BYTE *lpvData = new BYTE[nSize];\r
1267                 if (lpvData) {\r
1268                     DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );\r
1269                     if (dw) {\r
1270                         // Fill out a METAFILEPICT structure\r
1271                         mp.mm = MM_ANISOTROPIC;\r
1272                         mp.xExt = 1000;\r
1273                         mp.yExt = 1000;\r
1274                         mp.hMF = NULL;\r
1275                         // Get a reference DC\r
1276                         hDC = GetDC( NULL );\r
1277                         // Make an enhanced metafile from the windows metafile\r
1278                         hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );\r
1279                         // Clean up\r
1280                         ReleaseDC( NULL, hDC );\r
1281                     }\r
1282                     delete[] lpvData;\r
1283                 }\r
1284                 DeleteMetaFile( hmf );\r
1285             }\r
1286         } else {\r
1287             // Try open as Aldus Placeable Metafile\r
1288             HANDLE hFile;\r
1289             if (PrintWin32::is_os_wide())\r
1290                 hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
1291             else\r
1292                 hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
1293             if (hFile != INVALID_HANDLE_VALUE) {\r
1294                 DWORD nSize = GetFileSize( hFile, NULL );\r
1295                 if (nSize) {\r
1296                     BYTE *lpvData = new BYTE[nSize];\r
1297                     if (lpvData) {\r
1298                         DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );\r
1299                         if (dw) {\r
1300                             if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {\r
1301                                 // Fill out a METAFILEPICT structure\r
1302                                 mp.mm = MM_ANISOTROPIC;\r
1303                                 mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;\r
1304                                 mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);\r
1305                                 mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;\r
1306                                 mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);\r
1307                                 mp.hMF = NULL;\r
1308                                 // Get a reference DC\r
1309                                 hDC = GetDC( NULL );\r
1310                                 // Create an enhanced metafile from the bits\r
1311                                 hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );\r
1312                                 // Clean up\r
1313                                 ReleaseDC( NULL, hDC );\r
1314                             }\r
1315                         }\r
1316                         delete[] lpvData;\r
1317                     }\r
1318                 }\r
1319                 CloseHandle( hFile );\r
1320             }\r
1321         }\r
1322     }\r
1323 \r
1324     if (!hemf || !d.outsvg || !d.path) {\r
1325         if (d.outsvg)\r
1326             delete d.outsvg;\r
1327         if (d.path)\r
1328             delete d.path;\r
1329         if  (local_fn)\r
1330             g_free(local_fn);\r
1331         if  (unicode_fn)\r
1332             g_free(unicode_fn);\r
1333         return NULL;\r
1334     }\r
1335 \r
1336     EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);\r
1337     DeleteEnhMetaFile(hemf);\r
1338 \r
1339 //    std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;\r
1340 \r
1341     SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);\r
1342 \r
1343     delete d.outsvg;\r
1344     delete d.path;\r
1345 \r
1346     if (d.emf_obj) {\r
1347         int i;\r
1348         for (i=0; i<d.n_obj; i++)\r
1349             delete_object(&d, i);\r
1350         delete[] d.emf_obj;\r
1351     }\r
1352     \r
1353     if (d.style.stroke_dash.dash)\r
1354         delete[] d.style.stroke_dash.dash;\r
1355 \r
1356     if  (local_fn)\r
1357         g_free(local_fn);\r
1358     if  (unicode_fn)\r
1359         g_free(unicode_fn);\r
1360 \r
1361     return doc;\r
1362 }\r
1363 \r
1364 \r
1365 void\r
1366 EmfWin32::init (void)\r
1367 {\r
1368     Inkscape::Extension::Extension * ext;\r
1369 \r
1370     /* EMF in */\r
1371     ext = Inkscape::Extension::build_from_mem(\r
1372         "<inkscape-extension>\n"\r
1373             "<name>" N_("EMF Input") "</name>\n"\r
1374             "<id>org.inkscape.input.emf.win32</id>\n"\r
1375             "<input>\n"\r
1376                 "<extension>.emf</extension>\n"\r
1377                 "<mimetype>image/x-emf</mimetype>\n"\r
1378                 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"\r
1379                 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"\r
1380                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"\r
1381             "</input>\n"\r
1382         "</inkscape-extension>", new EmfWin32());\r
1383 \r
1384     /* WMF in */\r
1385     ext = Inkscape::Extension::build_from_mem(\r
1386         "<inkscape-extension>\n"\r
1387             "<name>" N_("WMF Input") "</name>\n"\r
1388             "<id>org.inkscape.input.wmf.win32</id>\n"\r
1389             "<input>\n"\r
1390                 "<extension>.wmf</extension>\n"\r
1391                 "<mimetype>image/x-wmf</mimetype>\n"\r
1392                 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"\r
1393                 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"\r
1394                 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"\r
1395             "</input>\n"\r
1396         "</inkscape-extension>", new EmfWin32());\r
1397 \r
1398     /* EMF out */\r
1399     ext = Inkscape::Extension::build_from_mem(\r
1400         "<inkscape-extension>\n"\r
1401             "<name>" N_("EMF Output") "</name>\n"\r
1402             "<id>org.inkscape.output.emf.win32</id>\n"\r
1403             "<output>\n"\r
1404                 "<extension>.emf</extension>\n"\r
1405                 "<mimetype>image/x-emf</mimetype>\n"\r
1406                 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"\r
1407                 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"\r
1408             "</output>\n"\r
1409         "</inkscape-extension>", new EmfWin32());\r
1410 \r
1411     return;\r
1412 }\r
1413 \r
1414 \r
1415 } } }  /* namespace Inkscape, Extension, Implementation */\r
1416 \r
1417 \r
1418 #endif /* WIN32 */\r
1419 \r
1420 \r
1421 /*\r
1422   Local Variables:\r
1423   mode:cpp\r
1424   c-file-style:"stroustrup"\r
1425   c-file-offsets:((innamespace . 0)(inline-open . 0))\r
1426   indent-tabs-mode:nil\r
1427   fill-column:99\r
1428   End:\r
1429 */\r
1430 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r