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