1 /** \file
2 * Enhanced Metafile Input and Output.
3 */
4 /*
5 * Authors:
6 * Ulf Erikson <ulferikson@users.sf.net>
7 *
8 * Copyright (C) 2006-2008 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;
188 bool inpath;
190 SIZEL sizeWnd;
191 SIZEL sizeView;
192 float PixelsInX, PixelsInY;
193 float PixelsOutX, PixelsOutY;
194 float MMX;
195 float MMY;
196 float dwInchesX;
197 float dwInchesY;
198 POINTL winorg;
199 POINTL vieworg;
200 double ScaleInX, ScaleInY;
201 double ScaleOutX, ScaleOutY;
202 COLORREF textColor;
203 bool textColorSet;
204 DWORD textAlign;
205 XFORM worldTransform;
206 unsigned int id;
207 CHAR *pDesc;
209 int n_obj;
210 PEMF_OBJECT emf_obj;
211 } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA;
214 static void
215 output_style(PEMF_CALLBACK_DATA d, int iType)
216 {
217 SVGOStringStream tmp_id;
218 SVGOStringStream tmp_style;
219 char tmp[1024] = {0};
221 float fill_rgb[3];
222 sp_color_get_rgb_floatv( &(d->style.fill.value.color), fill_rgb );
224 float stroke_rgb[3];
225 sp_color_get_rgb_floatv(&(d->style.stroke.value.color), stroke_rgb);
227 tmp_id << "\n\tid=\"" << (d->id++) << "\"";
228 *(d->outsvg) += tmp_id.str().c_str();
229 *(d->outsvg) += "\n\tstyle=\"";
230 if (iType == EMR_STROKEPATH || !d->fill_set) {
231 tmp_style << "fill:none;";
232 } else {
233 snprintf(tmp, 1023,
234 "fill:#%02x%02x%02x;",
235 SP_COLOR_F_TO_U(fill_rgb[0]),
236 SP_COLOR_F_TO_U(fill_rgb[1]),
237 SP_COLOR_F_TO_U(fill_rgb[2]));
238 tmp_style << tmp;
239 snprintf(tmp, 1023,
240 "fill-rule:%s;",
241 d->style.fill_rule.value == 0 ? "evenodd" : "nonzero");
242 tmp_style << tmp;
243 tmp_style << "fill-opacity:1;";
245 if (d->fill_set && d->stroke_set && d->style.stroke_width.value == 1 &&
246 fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
247 {
248 d->stroke_set = false;
249 }
250 }
252 if (iType == EMR_FILLPATH || !d->stroke_set) {
253 tmp_style << "stroke:none;";
254 } else {
255 snprintf(tmp, 1023,
256 "stroke:#%02x%02x%02x;",
257 SP_COLOR_F_TO_U(stroke_rgb[0]),
258 SP_COLOR_F_TO_U(stroke_rgb[1]),
259 SP_COLOR_F_TO_U(stroke_rgb[2]));
260 tmp_style << tmp;
262 tmp_style << "stroke-width:" <<
263 MAX( 0.001, d->style.stroke_width.value ) << "px;";
265 tmp_style << "stroke-linecap:" <<
266 (d->style.stroke_linecap.computed == 0 ? "butt" :
267 d->style.stroke_linecap.computed == 1 ? "round" :
268 d->style.stroke_linecap.computed == 2 ? "square" :
269 "unknown") << ";";
271 tmp_style << "stroke-linejoin:" <<
272 (d->style.stroke_linejoin.computed == 0 ? "miter" :
273 d->style.stroke_linejoin.computed == 1 ? "round" :
274 d->style.stroke_linejoin.computed == 2 ? "bevel" :
275 "unknown") << ";";
277 if (d->style.stroke_linejoin.computed == 0) {
278 tmp_style << "stroke-miterlimit:" <<
279 MAX( 0.01, d->style.stroke_miterlimit.value ) << ";";
280 }
282 if (d->style.stroke_dasharray_set &&
283 d->style.stroke_dash.n_dash && d->style.stroke_dash.dash)
284 {
285 tmp_style << "stroke-dasharray:";
286 for (int i=0; i<d->style.stroke_dash.n_dash; i++) {
287 if (i)
288 tmp_style << ",";
289 tmp_style << d->style.stroke_dash.dash[i];
290 }
291 tmp_style << ";";
292 tmp_style << "stroke-dashoffset:0;";
293 } else {
294 tmp_style << "stroke-dasharray:none;";
295 }
296 tmp_style << "stroke-opacity:1;";
297 }
298 tmp_style << "\" ";
300 *(d->outsvg) += tmp_style.str().c_str();
301 }
304 static double
305 _pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
306 {
307 double tmp = px - d->winorg.x;
308 tmp *= d->ScaleInX ? d->ScaleInX : 1.0;
309 tmp += d->vieworg.x;
310 return tmp;
311 }
313 static double
314 _pix_y_to_point(PEMF_CALLBACK_DATA d, double px)
315 {
316 double tmp = px - d->winorg.y;
317 tmp *= d->ScaleInY ? d->ScaleInY : 1.0;
318 tmp += d->vieworg.y;
319 return tmp;
320 }
323 static double
324 pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py)
325 {
326 double ppx = _pix_x_to_point(d, px);
327 double ppy = _pix_y_to_point(d, py);
329 double x = ppx * d->worldTransform.eM11 + ppy * d->worldTransform.eM21 + d->worldTransform.eDx;
330 x *= d->ScaleOutX ? d->ScaleOutX : DEVICESCALE;
332 return x;
333 }
335 static double
336 pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
337 {
338 double ppx = _pix_x_to_point(d, px);
339 double ppy = _pix_y_to_point(d, py);
341 double y = ppx * d->worldTransform.eM12 + ppy * d->worldTransform.eM22 + d->worldTransform.eDy;
342 y *= d->ScaleOutY ? d->ScaleOutY : DEVICESCALE;
344 return y;
345 }
347 static double
348 pix_to_size_point(PEMF_CALLBACK_DATA d, double px)
349 {
350 double dx = pix_to_x_point(d, px, 0);
351 double dy = pix_to_y_point(d, px, 0);
352 double tmp = sqrt(dx * dx + dy * dy);
353 return tmp;
354 }
357 static void
358 select_pen(PEMF_CALLBACK_DATA d, int index)
359 {
360 PEMRCREATEPEN pEmr = NULL;
362 if (index >= 0 && index < d->n_obj)
363 pEmr = (PEMRCREATEPEN) d->emf_obj[index].lpEMFR;
365 if (!pEmr)
366 return;
368 switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) {
369 case PS_DASH:
370 case PS_DOT:
371 case PS_DASHDOT:
372 case PS_DASHDOTDOT:
373 {
374 int i = 0;
375 int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK);
376 d->style.stroke_dash.n_dash =
377 penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
378 if (d->style.stroke_dash.dash)
379 delete[] d->style.stroke_dash.dash;
380 d->style.stroke_dash.dash = new double[d->style.stroke_dash.n_dash];
381 if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
382 d->style.stroke_dash.dash[i++] = 3;
383 d->style.stroke_dash.dash[i++] = 1;
384 }
385 if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
386 d->style.stroke_dash.dash[i++] = 1;
387 d->style.stroke_dash.dash[i++] = 1;
388 }
389 if (penstyle==PS_DASHDOTDOT) {
390 d->style.stroke_dash.dash[i++] = 1;
391 d->style.stroke_dash.dash[i++] = 1;
392 }
394 d->style.stroke_dasharray_set = 1;
395 break;
396 }
398 case PS_SOLID:
399 default:
400 {
401 d->style.stroke_dasharray_set = 0;
402 break;
403 }
404 }
406 switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) {
407 case PS_ENDCAP_ROUND:
408 {
409 d->style.stroke_linecap.computed = 1;
410 break;
411 }
412 case PS_ENDCAP_SQUARE:
413 {
414 d->style.stroke_linecap.computed = 2;
415 break;
416 }
417 case PS_ENDCAP_FLAT:
418 default:
419 {
420 d->style.stroke_linecap.computed = 0;
421 break;
422 }
423 }
425 switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) {
426 case PS_JOIN_BEVEL:
427 {
428 d->style.stroke_linejoin.computed = 2;
429 break;
430 }
431 case PS_JOIN_MITER:
432 {
433 d->style.stroke_linejoin.computed = 0;
434 break;
435 }
436 case PS_JOIN_ROUND:
437 default:
438 {
439 d->style.stroke_linejoin.computed = 1;
440 break;
441 }
442 }
444 d->stroke_set = true;
446 if (pEmr->lopn.lopnStyle == PS_NULL) {
447 d->style.stroke_width.value = 0;
448 d->stroke_set = false;
449 } else if (pEmr->lopn.lopnWidth.x) {
450 d->style.stroke_width.value = pix_to_size_point( d, pEmr->lopn.lopnWidth.x );
451 } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
452 //d->style.stroke_width.value = 1.0;
453 d->style.stroke_width.value = pix_to_size_point( d, 1 );
454 }
456 double r, g, b;
457 r = SP_COLOR_U_TO_F( GetRValue(pEmr->lopn.lopnColor) );
458 g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) );
459 b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) );
460 d->style.stroke.value.color.set( r, g, b );
461 }
464 static void
465 select_extpen(PEMF_CALLBACK_DATA d, int index)
466 {
467 PEMREXTCREATEPEN pEmr = NULL;
469 if (index >= 0 && index < d->n_obj)
470 pEmr = (PEMREXTCREATEPEN) d->emf_obj[index].lpEMFR;
472 if (!pEmr)
473 return;
475 switch (pEmr->elp.elpPenStyle & PS_STYLE_MASK) {
476 case PS_USERSTYLE:
477 {
478 if (pEmr->elp.elpNumEntries) {
479 d->style.stroke_dash.n_dash = pEmr->elp.elpNumEntries;
480 if (d->style.stroke_dash.dash)
481 delete[] d->style.stroke_dash.dash;
482 d->style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries];
483 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
484 d->style.stroke_dash.dash[i] = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] );
485 }
486 d->style.stroke_dasharray_set = 1;
487 } else {
488 d->style.stroke_dasharray_set = 0;
489 }
490 break;
491 }
493 case PS_DASH:
494 case PS_DOT:
495 case PS_DASHDOT:
496 case PS_DASHDOTDOT:
497 {
498 int i = 0;
499 int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK);
500 d->style.stroke_dash.n_dash =
501 penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2;
502 if (d->style.stroke_dash.dash)
503 delete[] d->style.stroke_dash.dash;
504 d->style.stroke_dash.dash = new double[d->style.stroke_dash.n_dash];
505 if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
506 d->style.stroke_dash.dash[i++] = 3;
507 d->style.stroke_dash.dash[i++] = 2;
508 }
509 if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) {
510 d->style.stroke_dash.dash[i++] = 1;
511 d->style.stroke_dash.dash[i++] = 2;
512 }
513 if (penstyle==PS_DASHDOTDOT) {
514 d->style.stroke_dash.dash[i++] = 1;
515 d->style.stroke_dash.dash[i++] = 2;
516 }
518 d->style.stroke_dasharray_set = 1;
519 break;
520 }
522 case PS_SOLID:
523 default:
524 {
525 d->style.stroke_dasharray_set = 0;
526 break;
527 }
528 }
530 switch (pEmr->elp.elpPenStyle & PS_ENDCAP_MASK) {
531 case PS_ENDCAP_ROUND:
532 {
533 d->style.stroke_linecap.computed = 1;
534 break;
535 }
536 case PS_ENDCAP_SQUARE:
537 {
538 d->style.stroke_linecap.computed = 2;
539 break;
540 }
541 case PS_ENDCAP_FLAT:
542 default:
543 {
544 d->style.stroke_linecap.computed = 0;
545 break;
546 }
547 }
549 switch (pEmr->elp.elpPenStyle & PS_JOIN_MASK) {
550 case PS_JOIN_BEVEL:
551 {
552 d->style.stroke_linejoin.computed = 2;
553 break;
554 }
555 case PS_JOIN_MITER:
556 {
557 d->style.stroke_linejoin.computed = 0;
558 break;
559 }
560 case PS_JOIN_ROUND:
561 default:
562 {
563 d->style.stroke_linejoin.computed = 1;
564 break;
565 }
566 }
568 d->stroke_set = true;
570 if (pEmr->elp.elpPenStyle == PS_NULL) {
571 d->style.stroke_width.value = 0;
572 d->stroke_set = false;
573 } else if (pEmr->elp.elpWidth) {
574 d->style.stroke_width.value = pix_to_size_point( d, pEmr->elp.elpWidth );
575 } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
576 //d->style.stroke_width.value = 1.0;
577 d->style.stroke_width.value = pix_to_size_point( d, 1 );
578 }
580 double r, g, b;
581 r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) );
582 g = SP_COLOR_U_TO_F( GetGValue(pEmr->elp.elpColor) );
583 b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) );
585 d->style.stroke.value.color.set( r, g, b );
586 }
589 static void
590 select_brush(PEMF_CALLBACK_DATA d, int index)
591 {
592 PEMRCREATEBRUSHINDIRECT pEmr = NULL;
594 if (index >= 0 && index < d->n_obj)
595 pEmr = (PEMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
597 if (!pEmr)
598 return;
600 if (pEmr->lb.lbStyle == BS_SOLID) {
601 double r, g, b;
602 r = SP_COLOR_U_TO_F( GetRValue(pEmr->lb.lbColor) );
603 g = SP_COLOR_U_TO_F( GetGValue(pEmr->lb.lbColor) );
604 b = SP_COLOR_U_TO_F( GetBValue(pEmr->lb.lbColor) );
605 d->style.fill.value.color.set( r, g, b );
606 }
608 d->fill_set = true;
609 }
612 static void
613 select_font(PEMF_CALLBACK_DATA d, int index)
614 {
615 PEMREXTCREATEFONTINDIRECTW pEmr = NULL;
617 if (index >= 0 && index < d->n_obj)
618 pEmr = (PEMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR;
620 if (!pEmr)
621 return;
623 d->style.font_size.computed = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight );
624 d->style.font_weight.value =
625 pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
626 pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
627 pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
628 pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
629 pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
630 pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
631 pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
632 pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
633 pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
634 pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
635 pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
636 pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
637 pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
638 FW_NORMAL;
639 d->style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
640 d->style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline;
641 d->style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
642 if (d->tstyle.font_family.value)
643 g_free(d->tstyle.font_family.value);
644 d->tstyle.font_family.value =
645 (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL );
646 }
648 static void
649 delete_object(PEMF_CALLBACK_DATA d, int index)
650 {
651 if (index >= 0 && index < d->n_obj) {
652 d->emf_obj[index].type = 0;
653 if (d->emf_obj[index].lpEMFR)
654 free(d->emf_obj[index].lpEMFR);
655 d->emf_obj[index].lpEMFR = NULL;
656 }
657 }
660 static void
661 insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj)
662 {
663 if (index >= 0 && index < d->n_obj) {
664 delete_object(d, index);
665 d->emf_obj[index].type = type;
666 d->emf_obj[index].lpEMFR = pObj;
667 }
668 }
670 static void
671 assert_empty_path(PEMF_CALLBACK_DATA d, const char *fun)
672 {
673 if (!d->path->empty()) {
674 // g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun);
676 *(d->outsvg) += "<!--\n";
677 *(d->outsvg) += " <path \t";
678 output_style(d, EMR_STROKEPATH);
679 if (strstr(d->path->c_str(), "d=\"") == NULL) {
680 *(d->outsvg) += "d=\"";
681 *(d->outsvg) += "\n\t";
682 }
683 *(d->outsvg) += *(d->path);
684 *(d->outsvg) += " \" /> \n";
685 *(d->outsvg) += "-->\n";
687 *(d->path) = "";
688 }
689 }
692 static int CALLBACK
693 myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)
694 {
695 PEMF_CALLBACK_DATA d;
696 SVGOStringStream tmp_outsvg;
697 SVGOStringStream tmp_path;
698 SVGOStringStream tmp_str;
699 SVGOStringStream dbg_str;
701 d = (PEMF_CALLBACK_DATA) lpData;
703 if (d->pathless_stroke) {
704 if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 &&
705 lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 &&
706 lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO &&
707 lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 &&
708 lpEMFR->iType!=EMR_SETBKMODE)
709 {
710 *(d->outsvg) += " <path ";
711 output_style(d, EMR_STROKEPATH);
712 *(d->outsvg) += "\n\t";
713 *(d->outsvg) += *(d->path);
714 *(d->outsvg) += " \" /> \n";
715 *(d->path) = "";
716 d->pathless_stroke = false;
717 }
718 }
720 switch (lpEMFR->iType)
721 {
722 case EMR_HEADER:
723 {
724 dbg_str << "<!-- EMR_HEADER -->\n";
726 *(d->outsvg) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
728 if (d->pDesc) {
729 *(d->outsvg) += "<!-- ";
730 *(d->outsvg) += d->pDesc;
731 *(d->outsvg) += " -->\n";
732 }
734 ENHMETAHEADER *pEmr = (ENHMETAHEADER *) lpEMFR;
735 tmp_outsvg << "<svg\n";
736 tmp_outsvg << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
737 tmp_outsvg << " xmlns=\"http://www.w3.org/2000/svg\"\n";
738 tmp_outsvg << " version=\"1.0\"\n";
740 d->xDPI = 2540;
741 d->yDPI = 2540;
743 d->PixelsInX = pEmr->rclFrame.right - pEmr->rclFrame.left;
744 d->PixelsInY = pEmr->rclFrame.bottom - pEmr->rclFrame.top;
746 d->MMX = d->PixelsInX / 100.0;
747 d->MMY = d->PixelsInY / 100.0;
749 d->PixelsOutX = d->MMX * PX_PER_MM;
750 d->PixelsOutY = d->MMY * PX_PER_MM;
752 tmp_outsvg <<
753 " width=\"" << d->MMX << "mm\"\n" <<
754 " height=\"" << d->MMY << "mm\"\n";
755 tmp_outsvg <<
756 " id=\"" << (d->id++) << "\">\n";
758 tmp_outsvg <<
759 "<g\n" <<
760 " id=\"" << (d->id++) << "\">\n";
762 if (pEmr->nHandles) {
763 d->n_obj = pEmr->nHandles;
764 d->emf_obj = new EMF_OBJECT[d->n_obj];
766 // Init the new emf_obj list elements to null, provided the
767 // dynamic allocation succeeded.
768 if ( d->emf_obj != NULL )
769 {
770 for( unsigned int i=0; i < d->n_obj; ++i )
771 d->emf_obj[i].lpEMFR = NULL;
772 } //if
774 } else {
775 d->emf_obj = NULL;
776 }
778 break;
779 }
780 case EMR_POLYBEZIER:
781 {
782 dbg_str << "<!-- EMR_POLYBEZIER -->\n";
784 PEMRPOLYBEZIER pEmr = (PEMRPOLYBEZIER) lpEMFR;
785 DWORD i,j;
787 if (pEmr->cptl<4)
788 break;
790 if (!d->inpath) {
791 assert_empty_path(d, "EMR_POLYBEZIER");
793 *(d->outsvg) += " <path ";
794 output_style(d, EMR_STROKEPATH);
795 *(d->outsvg) += "\n\td=\"";
796 }
798 tmp_str <<
799 "\n\tM " <<
800 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
801 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " ";
803 for (i=1; i<pEmr->cptl; ) {
804 tmp_str << "\n\tC ";
805 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
806 tmp_str <<
807 pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
808 pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
809 }
810 }
812 if (d->inpath) {
813 tmp_path << tmp_str.str().c_str();
814 }
815 else {
816 *(d->outsvg) += tmp_str.str().c_str();
817 *(d->outsvg) += " \" /> \n";
818 }
820 break;
821 }
822 case EMR_POLYGON:
823 {
824 dbg_str << "<!-- EMR_POLYGON -->\n";
826 EMRPOLYGON *pEmr = (EMRPOLYGON *) lpEMFR;
827 DWORD i;
829 if (pEmr->cptl < 2)
830 break;
832 assert_empty_path(d, "EMR_POLYGON");
834 *(d->outsvg) += " <path ";
835 output_style(d, EMR_STROKEANDFILLPATH);
836 *(d->outsvg) += "\n\td=\"";
838 tmp_str <<
839 "\n\tM " <<
840 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
841 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
843 for (i=1; i<pEmr->cptl; i++) {
844 tmp_str <<
845 "\n\tL " <<
846 pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
847 pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
848 }
850 *(d->outsvg) += tmp_str.str().c_str();
851 *(d->outsvg) += " z \" /> \n";
853 break;
854 }
855 case EMR_POLYLINE:
856 {
857 dbg_str << "<!-- EMR_POLYLINE -->\n";
859 EMRPOLYLINE *pEmr = (EMRPOLYLINE *) lpEMFR;
860 DWORD i;
862 if (pEmr->cptl<2)
863 break;
865 if (!d->inpath) {
866 assert_empty_path(d, "EMR_POLYLINE");
868 *(d->outsvg) += " <path ";
869 output_style(d, EMR_STROKEPATH);
870 *(d->outsvg) += "\n\td=\"";
871 }
873 tmp_str <<
874 "\n\tM " <<
875 pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " <<
876 pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
878 for (i=1; i<pEmr->cptl; i++) {
879 tmp_str <<
880 "\n\tL " <<
881 pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
882 pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
883 }
885 if (d->inpath) {
886 tmp_path << tmp_str.str().c_str();
887 }
888 else {
889 *(d->outsvg) += tmp_str.str().c_str();
890 *(d->outsvg) += " \" /> \n";
891 }
893 break;
894 }
895 case EMR_POLYBEZIERTO:
896 {
897 dbg_str << "<!-- EMR_POLYBEZIERTO -->\n";
899 PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR;
900 DWORD i,j;
902 if (d->path->empty()) {
903 d->pathless_stroke = true;
904 *(d->path) = "d=\"";
905 }
907 for (i=0; i<pEmr->cptl;) {
908 tmp_path << "\n\tC ";
909 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
910 tmp_path <<
911 pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
912 pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
913 }
914 }
916 break;
917 }
918 case EMR_POLYLINETO:
919 {
920 dbg_str << "<!-- EMR_POLYLINETO -->\n";
922 PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR;
923 DWORD i;
925 if (d->path->empty()) {
926 d->pathless_stroke = true;
927 *(d->path) = "d=\"";
928 }
930 for (i=0; i<pEmr->cptl;i++) {
931 tmp_path <<
932 "\n\tL " <<
933 pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " <<
934 pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
935 }
937 break;
938 }
939 case EMR_POLYPOLYLINE:
940 case EMR_POLYPOLYGON:
941 {
942 if (lpEMFR->iType == EMR_POLYPOLYLINE)
943 dbg_str << "<!-- EMR_POLYPOLYLINE -->\n";
944 if (lpEMFR->iType == EMR_POLYPOLYGON)
945 dbg_str << "<!-- EMR_POLYPOLYGON -->\n";
947 PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR;
948 unsigned int n, i, j;
950 if (!d->inpath) {
951 assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE");
953 *(d->outsvg) += " <path ";
954 output_style(d, lpEMFR->iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
955 *(d->outsvg) += "\n\td=\"";
956 }
958 POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys];
960 i = 0;
961 for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
962 SVGOStringStream poly_path;
964 poly_path << "\n\tM " <<
965 pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
966 pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
967 i++;
969 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
970 poly_path << "\n\tL " <<
971 pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " <<
972 pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " ";
973 i++;
974 }
976 tmp_str << poly_path.str().c_str();
977 if (lpEMFR->iType == EMR_POLYPOLYGON)
978 tmp_str << " z";
979 tmp_str << " \n";
980 }
982 if (d->inpath) {
983 tmp_path << tmp_str.str().c_str();
984 }
985 else {
986 *(d->outsvg) += tmp_str.str().c_str();
987 *(d->outsvg) += " \" /> \n";
988 }
990 break;
991 }
992 case EMR_SETWINDOWEXTEX:
993 {
994 dbg_str << "<!-- EMR_SETWINDOWEXTEX -->\n";
996 PEMRSETWINDOWEXTEX pEmr = (PEMRSETWINDOWEXTEX) lpEMFR;
998 d->sizeWnd = pEmr->szlExtent;
1000 if (!d->sizeWnd.cx || !d->sizeWnd.cy) {
1001 d->sizeWnd = d->sizeView;
1002 if (!d->sizeWnd.cx || !d->sizeWnd.cy) {
1003 d->sizeWnd.cx = d->PixelsOutX;
1004 d->sizeWnd.cy = d->PixelsOutY;
1005 }
1006 }
1008 if (!d->sizeView.cx || !d->sizeView.cy) {
1009 d->sizeView = d->sizeWnd;
1010 }
1012 d->PixelsInX = d->sizeWnd.cx;
1013 d->PixelsInY = d->sizeWnd.cy;
1015 if (d->PixelsInX && d->PixelsInY) {
1016 d->ScaleInX = (double) d->sizeView.cx / (double) d->PixelsInX;
1017 d->ScaleInY = (double) d->sizeView.cy / (double) d->PixelsInY;
1018 }
1019 else {
1020 d->ScaleInX = 1;
1021 d->ScaleInY = 1;
1022 }
1024 if (d->sizeView.cx && d->sizeView.cy) {
1025 d->ScaleOutX = (double) d->PixelsOutX / (double) d->sizeView.cx;
1026 d->ScaleOutY = (double) d->PixelsOutY / (double) d->sizeView.cy;
1027 }
1028 else {
1029 d->ScaleOutX = DEVICESCALE;
1030 d->ScaleOutY = DEVICESCALE;
1031 }
1033 break;
1034 }
1035 case EMR_SETWINDOWORGEX:
1036 {
1037 dbg_str << "<!-- EMR_SETWINDOWORGEX -->\n";
1039 PEMRSETWINDOWORGEX pEmr = (PEMRSETWINDOWORGEX) lpEMFR;
1040 d->winorg = pEmr->ptlOrigin;
1041 break;
1042 }
1043 case EMR_SETVIEWPORTEXTEX:
1044 {
1045 dbg_str << "<!-- EMR_SETVIEWPORTEXTEX -->\n";
1047 PEMRSETVIEWPORTEXTEX pEmr = (PEMRSETVIEWPORTEXTEX) lpEMFR;
1049 d->sizeView = pEmr->szlExtent;
1051 if (!d->sizeView.cx || !d->sizeView.cy) {
1052 d->sizeView = d->sizeWnd;
1053 if (!d->sizeView.cx || !d->sizeView.cy) {
1054 d->sizeView.cx = d->PixelsOutX;
1055 d->sizeView.cy = d->PixelsOutY;
1056 }
1057 }
1059 if (!d->sizeWnd.cx || !d->sizeWnd.cy) {
1060 d->sizeWnd = d->sizeView;
1061 }
1063 d->PixelsInX = d->sizeWnd.cx;
1064 d->PixelsInY = d->sizeWnd.cy;
1066 if (d->PixelsInX && d->PixelsInY) {
1067 d->ScaleInX = (double) d->sizeView.cx / (double) d->PixelsInX;
1068 d->ScaleInY = (double) d->sizeView.cy / (double) d->PixelsInY;
1069 }
1070 else {
1071 d->ScaleInX = 1;
1072 d->ScaleInY = 1;
1073 }
1075 if (d->sizeView.cx && d->sizeView.cy) {
1076 d->ScaleOutX = (double) d->PixelsOutX / (double) d->sizeView.cx;
1077 d->ScaleOutY = (double) d->PixelsOutY / (double) d->sizeView.cy;
1078 }
1079 else {
1080 d->ScaleOutX = DEVICESCALE;
1081 d->ScaleOutY = DEVICESCALE;
1082 }
1084 break;
1085 }
1086 case EMR_SETVIEWPORTORGEX:
1087 {
1088 dbg_str << "<!-- EMR_SETVIEWPORTORGEX -->\n";
1090 PEMRSETVIEWPORTORGEX pEmr = (PEMRSETVIEWPORTORGEX) lpEMFR;
1091 d->vieworg = pEmr->ptlOrigin;
1092 break;
1093 }
1094 case EMR_SETBRUSHORGEX:
1095 dbg_str << "<!-- EMR_SETBRUSHORGEX -->\n";
1096 break;
1097 case EMR_EOF:
1098 {
1099 dbg_str << "<!-- EMR_EOF -->\n";
1101 assert_empty_path(d, "EMR_EOF");
1102 tmp_outsvg << "</g>\n";
1103 tmp_outsvg << "</svg>\n";
1104 break;
1105 }
1106 case EMR_SETPIXELV:
1107 dbg_str << "<!-- EMR_SETPIXELV -->\n";
1108 break;
1109 case EMR_SETMAPPERFLAGS:
1110 dbg_str << "<!-- EMR_SETMAPPERFLAGS -->\n";
1111 break;
1112 case EMR_SETMAPMODE:
1113 dbg_str << "<!-- EMR_SETMAPMODE -->\n";
1114 break;
1115 case EMR_SETBKMODE:
1116 dbg_str << "<!-- EMR_SETBKMODE -->\n";
1117 break;
1118 case EMR_SETPOLYFILLMODE:
1119 {
1120 dbg_str << "<!-- EMR_SETPOLYFILLMODE -->\n";
1122 PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR;
1123 d->style.fill_rule.value =
1124 (pEmr->iMode == ALTERNATE ? 0 :
1125 pEmr->iMode == WINDING ? 1 : 0);
1126 break;
1127 }
1128 case EMR_SETROP2:
1129 dbg_str << "<!-- EMR_SETROP2 -->\n";
1130 break;
1131 case EMR_SETSTRETCHBLTMODE:
1132 dbg_str << "<!-- EMR_SETSTRETCHBLTMODE -->\n";
1133 break;
1134 case EMR_SETTEXTALIGN:
1135 {
1136 dbg_str << "<!-- EMR_SETTEXTALIGN -->\n";
1138 PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR;
1139 d->textAlign = pEmr->iMode;
1140 break;
1141 }
1142 case EMR_SETCOLORADJUSTMENT:
1143 dbg_str << "<!-- EMR_SETCOLORADJUSTMENT -->\n";
1144 break;
1145 case EMR_SETTEXTCOLOR:
1146 {
1147 dbg_str << "<!-- EMR_SETTEXTCOLOR -->\n";
1149 PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR;
1150 d->textColor = pEmr->crColor;
1151 d->textColorSet = true;
1152 break;
1153 }
1154 case EMR_SETBKCOLOR:
1155 dbg_str << "<!-- EMR_SETBKCOLOR -->\n";
1156 break;
1157 case EMR_OFFSETCLIPRGN:
1158 dbg_str << "<!-- EMR_OFFSETCLIPRGN -->\n";
1159 break;
1160 case EMR_MOVETOEX:
1161 {
1162 dbg_str << "<!-- EMR_MOVETOEX -->\n";
1164 PEMRMOVETOEX pEmr = (PEMRMOVETOEX) lpEMFR;
1166 if (d->path->empty()) {
1167 d->pathless_stroke = true;
1168 *(d->path) = "d=\"";
1169 }
1171 tmp_path <<
1172 "\n\tM " <<
1173 pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
1174 pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
1175 break;
1176 }
1177 case EMR_SETMETARGN:
1178 dbg_str << "<!-- EMR_SETMETARGN -->\n";
1179 break;
1180 case EMR_EXCLUDECLIPRECT:
1181 dbg_str << "<!-- EMR_EXCLUDECLIPRECT -->\n";
1182 break;
1183 case EMR_INTERSECTCLIPRECT:
1184 dbg_str << "<!-- EMR_INTERSECTCLIPRECT -->\n";
1185 break;
1186 case EMR_SCALEVIEWPORTEXTEX:
1187 dbg_str << "<!-- EMR_SCALEVIEWPORTEXTEX -->\n";
1188 break;
1189 case EMR_SCALEWINDOWEXTEX:
1190 dbg_str << "<!-- EMR_SCALEWINDOWEXTEX -->\n";
1191 break;
1192 case EMR_SAVEDC:
1193 dbg_str << "<!-- EMR_SAVEDC -->\n";
1194 break;
1195 case EMR_RESTOREDC:
1196 dbg_str << "<!-- EMR_RESTOREDC -->\n";
1197 break;
1198 case EMR_SETWORLDTRANSFORM:
1199 {
1200 dbg_str << "<!-- EMR_SETWORLDTRANSFORM -->\n";
1202 PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR;
1203 d->worldTransform = pEmr->xform;
1204 break;
1205 }
1206 case EMR_MODIFYWORLDTRANSFORM:
1207 {
1208 dbg_str << "<!-- EMR_MODIFYWORLDTRANSFORM -->\n";
1210 PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR;
1211 switch (pEmr->iMode)
1212 {
1213 case MWT_IDENTITY:
1214 d->worldTransform.eM11 = 1.0;
1215 d->worldTransform.eM12 = 0.0;
1216 d->worldTransform.eM21 = 0.0;
1217 d->worldTransform.eM22 = 1.0;
1218 d->worldTransform.eDx = 0.0;
1219 d->worldTransform.eDy = 0.0;
1220 break;
1221 case MWT_LEFTMULTIPLY:
1222 {
1223 // d->worldTransform = pEmr->xform * worldTransform;
1225 float a11 = pEmr->xform.eM11;
1226 float a12 = pEmr->xform.eM12;
1227 float a13 = 0.0;
1228 float a21 = pEmr->xform.eM21;
1229 float a22 = pEmr->xform.eM22;
1230 float a23 = 0.0;
1231 float a31 = pEmr->xform.eDx;
1232 float a32 = pEmr->xform.eDy;
1233 float a33 = 1.0;
1235 float b11 = d->worldTransform.eM11;
1236 float b12 = d->worldTransform.eM12;
1237 //float b13 = 0.0;
1238 float b21 = d->worldTransform.eM21;
1239 float b22 = d->worldTransform.eM22;
1240 //float b23 = 0.0;
1241 float b31 = d->worldTransform.eDx;
1242 float b32 = d->worldTransform.eDy;
1243 //float b33 = 1.0;
1245 float c11 = a11*b11 + a12*b21 + a13*b31;;
1246 float c12 = a11*b12 + a12*b22 + a13*b32;;
1247 //float c13 = a11*b13 + a12*b23 + a13*b33;;
1248 float c21 = a21*b11 + a22*b21 + a23*b31;;
1249 float c22 = a21*b12 + a22*b22 + a23*b32;;
1250 //float c23 = a21*b13 + a22*b23 + a23*b33;;
1251 float c31 = a31*b11 + a32*b21 + a33*b31;;
1252 float c32 = a31*b12 + a32*b22 + a33*b32;;
1253 //float c33 = a31*b13 + a32*b23 + a33*b33;;
1255 d->worldTransform.eM11 = c11;;
1256 d->worldTransform.eM12 = c12;;
1257 d->worldTransform.eM21 = c21;;
1258 d->worldTransform.eM22 = c22;;
1259 d->worldTransform.eDx = c31;
1260 d->worldTransform.eDy = c32;
1262 break;
1263 }
1264 case MWT_RIGHTMULTIPLY:
1265 {
1266 // d->worldTransform = worldTransform * pEmr->xform;
1268 float a11 = d->worldTransform.eM11;
1269 float a12 = d->worldTransform.eM12;
1270 float a13 = 0.0;
1271 float a21 = d->worldTransform.eM21;
1272 float a22 = d->worldTransform.eM22;
1273 float a23 = 0.0;
1274 float a31 = d->worldTransform.eDx;
1275 float a32 = d->worldTransform.eDy;
1276 float a33 = 1.0;
1278 float b11 = pEmr->xform.eM11;
1279 float b12 = pEmr->xform.eM12;
1280 //float b13 = 0.0;
1281 float b21 = pEmr->xform.eM21;
1282 float b22 = pEmr->xform.eM22;
1283 //float b23 = 0.0;
1284 float b31 = pEmr->xform.eDx;
1285 float b32 = pEmr->xform.eDy;
1286 //float b33 = 1.0;
1288 float c11 = a11*b11 + a12*b21 + a13*b31;;
1289 float c12 = a11*b12 + a12*b22 + a13*b32;;
1290 //float c13 = a11*b13 + a12*b23 + a13*b33;;
1291 float c21 = a21*b11 + a22*b21 + a23*b31;;
1292 float c22 = a21*b12 + a22*b22 + a23*b32;;
1293 //float c23 = a21*b13 + a22*b23 + a23*b33;;
1294 float c31 = a31*b11 + a32*b21 + a33*b31;;
1295 float c32 = a31*b12 + a32*b22 + a33*b32;;
1296 //float c33 = a31*b13 + a32*b23 + a33*b33;;
1298 d->worldTransform.eM11 = c11;;
1299 d->worldTransform.eM12 = c12;;
1300 d->worldTransform.eM21 = c21;;
1301 d->worldTransform.eM22 = c22;;
1302 d->worldTransform.eDx = c31;
1303 d->worldTransform.eDy = c32;
1305 break;
1306 }
1307 // case MWT_SET:
1308 default:
1309 d->worldTransform = pEmr->xform;
1310 break;
1311 }
1312 break;
1313 }
1314 case EMR_SELECTOBJECT:
1315 {
1316 dbg_str << "<!-- EMR_SELECTOBJECT -->\n";
1318 PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR;
1319 unsigned int index = pEmr->ihObject;
1321 if (index >= ENHMETA_STOCK_OBJECT) {
1322 index -= ENHMETA_STOCK_OBJECT;
1323 switch (index) {
1324 case NULL_BRUSH:
1325 d->fill_set = false;
1326 break;
1327 case BLACK_BRUSH:
1328 case DKGRAY_BRUSH:
1329 case GRAY_BRUSH:
1330 case LTGRAY_BRUSH:
1331 case WHITE_BRUSH:
1332 {
1333 float val = 0;
1334 switch (index) {
1335 case BLACK_BRUSH:
1336 val = 0.0 / 255.0;
1337 break;
1338 case DKGRAY_BRUSH:
1339 val = 64.0 / 255.0;
1340 break;
1341 case GRAY_BRUSH:
1342 val = 128.0 / 255.0;
1343 break;
1344 case LTGRAY_BRUSH:
1345 val = 192.0 / 255.0;
1346 break;
1347 case WHITE_BRUSH:
1348 val = 255.0 / 255.0;
1349 break;
1350 }
1351 d->style.fill.value.color.set( val, val, val );
1353 d->fill_set = true;
1354 break;
1355 }
1356 case NULL_PEN:
1357 d->stroke_set = false;
1358 break;
1359 case BLACK_PEN:
1360 case WHITE_PEN:
1361 {
1362 float val = index == BLACK_PEN ? 0 : 1;
1363 d->style.stroke_dasharray_set = 0;
1364 d->style.stroke_width.value = 1.0;
1365 d->style.stroke.value.color.set( val, val, val );
1367 d->stroke_set = true;
1369 break;
1370 }
1371 }
1372 } else {
1373 if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
1374 switch (d->emf_obj[index].type)
1375 {
1376 case EMR_CREATEPEN:
1377 select_pen(d, index);
1378 break;
1379 case EMR_CREATEBRUSHINDIRECT:
1380 select_brush(d, index);
1381 break;
1382 case EMR_EXTCREATEPEN:
1383 select_extpen(d, index);
1384 break;
1385 case EMR_EXTCREATEFONTINDIRECTW:
1386 select_font(d, index);
1387 break;
1388 }
1389 }
1390 }
1391 break;
1392 }
1393 case EMR_CREATEPEN:
1394 {
1395 dbg_str << "<!-- EMR_CREATEPEN -->\n";
1397 PEMRCREATEPEN pEmr = (PEMRCREATEPEN) lpEMFR;
1398 int index = pEmr->ihPen;
1400 EMRCREATEPEN *pPen =
1401 (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) );
1402 pPen->lopn = pEmr->lopn;
1403 insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen);
1405 break;
1406 }
1407 case EMR_CREATEBRUSHINDIRECT:
1408 {
1409 dbg_str << "<!-- EMR_CREATEBRUSHINDIRECT -->\n";
1411 PEMRCREATEBRUSHINDIRECT pEmr = (PEMRCREATEBRUSHINDIRECT) lpEMFR;
1412 int index = pEmr->ihBrush;
1414 EMRCREATEBRUSHINDIRECT *pBrush =
1415 (EMRCREATEBRUSHINDIRECT *) malloc( sizeof(EMRCREATEBRUSHINDIRECT) );
1416 pBrush->lb = pEmr->lb;
1417 insert_object(d, index, EMR_CREATEBRUSHINDIRECT, (ENHMETARECORD *) pBrush);
1419 break;
1420 }
1421 case EMR_DELETEOBJECT:
1422 dbg_str << "<!-- EMR_DELETEOBJECT -->\n";
1423 break;
1424 case EMR_ANGLEARC:
1425 dbg_str << "<!-- EMR_ANGLEARC -->\n";
1426 break;
1427 case EMR_ELLIPSE:
1428 {
1429 dbg_str << "<!-- EMR_ELLIPSE -->\n";
1431 PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR;
1432 RECTL rclBox = pEmr->rclBox;
1434 double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
1435 double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top );
1436 double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
1437 double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom );
1439 double cx = (l + r) / 2.0;
1440 double cy = (t + b) / 2.0;
1441 double rx = fabs(l - r) / 2.0;
1442 double ry = fabs(t - b) / 2.0;
1444 SVGOStringStream tmp_ellipse;
1445 tmp_ellipse << "cx=\"" << cx << "\" ";
1446 tmp_ellipse << "cy=\"" << cy << "\" ";
1447 tmp_ellipse << "rx=\"" << rx << "\" ";
1448 tmp_ellipse << "ry=\"" << ry << "\" ";
1450 assert_empty_path(d, "EMR_ELLIPSE");
1452 *(d->outsvg) += " <ellipse ";
1453 output_style(d, lpEMFR->iType);
1454 *(d->outsvg) += "\n\t";
1455 *(d->outsvg) += tmp_ellipse.str().c_str();
1456 *(d->outsvg) += "/> \n";
1457 *(d->path) = "";
1458 break;
1459 }
1460 case EMR_RECTANGLE:
1461 {
1462 dbg_str << "<!-- EMR_RECTANGLE -->\n";
1464 PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR;
1465 RECTL rc = pEmr->rclBox;
1467 double l = pix_to_x_point( d, rc.left, rc.top );
1468 double t = pix_to_y_point( d, rc.left, rc.top );
1469 double r = pix_to_x_point( d, rc.right, rc.bottom );
1470 double b = pix_to_y_point( d, rc.right, rc.bottom );
1472 SVGOStringStream tmp_rectangle;
1473 tmp_rectangle << "d=\"";
1474 tmp_rectangle << "\n\tM " << l << " " << t << " ";
1475 tmp_rectangle << "\n\tL " << r << " " << t << " ";
1476 tmp_rectangle << "\n\tL " << r << " " << b << " ";
1477 tmp_rectangle << "\n\tL " << l << " " << b << " ";
1478 tmp_rectangle << "\n\tz";
1480 assert_empty_path(d, "EMR_RECTANGLE");
1482 *(d->outsvg) += " <path ";
1483 output_style(d, lpEMFR->iType);
1484 *(d->outsvg) += "\n\t";
1485 *(d->outsvg) += tmp_rectangle.str().c_str();
1486 *(d->outsvg) += " \" /> \n";
1487 *(d->path) = "";
1488 break;
1489 }
1490 case EMR_ROUNDRECT:
1491 dbg_str << "<!-- EMR_ROUNDRECT -->\n";
1492 break;
1493 case EMR_ARC:
1494 dbg_str << "<!-- EMR_ARC -->\n";
1495 break;
1496 case EMR_CHORD:
1497 dbg_str << "<!-- EMR_CHORD -->\n";
1498 break;
1499 case EMR_PIE:
1500 dbg_str << "<!-- EMR_PIE -->\n";
1501 break;
1502 case EMR_SELECTPALETTE:
1503 dbg_str << "<!-- EMR_SELECTPALETTE -->\n";
1504 break;
1505 case EMR_CREATEPALETTE:
1506 dbg_str << "<!-- EMR_CREATEPALETTE -->\n";
1507 break;
1508 case EMR_SETPALETTEENTRIES:
1509 dbg_str << "<!-- EMR_SETPALETTEENTRIES -->\n";
1510 break;
1511 case EMR_RESIZEPALETTE:
1512 dbg_str << "<!-- EMR_RESIZEPALETTE -->\n";
1513 break;
1514 case EMR_REALIZEPALETTE:
1515 dbg_str << "<!-- EMR_REALIZEPALETTE -->\n";
1516 break;
1517 case EMR_EXTFLOODFILL:
1518 dbg_str << "<!-- EMR_EXTFLOODFILL -->\n";
1519 break;
1520 case EMR_LINETO:
1521 {
1522 dbg_str << "<!-- EMR_LINETO -->\n";
1524 PEMRLINETO pEmr = (PEMRLINETO) lpEMFR;
1526 if (d->path->empty()) {
1527 d->pathless_stroke = true;
1528 *(d->path) = "d=\"";
1529 }
1531 tmp_path <<
1532 "\n\tL " <<
1533 pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " <<
1534 pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
1535 break;
1536 }
1537 case EMR_ARCTO:
1538 dbg_str << "<!-- EMR_ARCTO -->\n";
1539 break;
1540 case EMR_POLYDRAW:
1541 dbg_str << "<!-- EMR_POLYDRAW -->\n";
1542 break;
1543 case EMR_SETARCDIRECTION:
1544 dbg_str << "<!-- EMR_SETARCDIRECTION -->\n";
1545 break;
1546 case EMR_SETMITERLIMIT:
1547 {
1548 dbg_str << "<!-- EMR_SETMITERLIMIT -->\n";
1550 PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR;
1551 d->style.stroke_miterlimit.value = pix_to_size_point( d, pEmr->eMiterLimit );
1553 if (d->style.stroke_miterlimit.value < 1)
1554 d->style.stroke_miterlimit.value = 1.0;
1556 break;
1557 }
1558 case EMR_BEGINPATH:
1559 {
1560 dbg_str << "<!-- EMR_BEGINPATH -->\n";
1562 tmp_path << "d=\"";
1563 *(d->path) = "";
1564 d->inpath = true;
1565 break;
1566 }
1567 case EMR_ENDPATH:
1568 {
1569 dbg_str << "<!-- EMR_ENDPATH -->\n";
1571 tmp_path << "\"";
1572 d->inpath = false;
1573 break;
1574 }
1575 case EMR_CLOSEFIGURE:
1576 {
1577 dbg_str << "<!-- EMR_CLOSEFIGURE -->\n";
1579 tmp_path << "\n\tz";
1580 break;
1581 }
1582 case EMR_FILLPATH:
1583 case EMR_STROKEANDFILLPATH:
1584 case EMR_STROKEPATH:
1585 {
1586 if (lpEMFR->iType == EMR_FILLPATH)
1587 dbg_str << "<!-- EMR_FILLPATH -->\n";
1588 if (lpEMFR->iType == EMR_STROKEANDFILLPATH)
1589 dbg_str << "<!-- EMR_STROKEANDFILLPATH -->\n";
1590 if (lpEMFR->iType == EMR_STROKEPATH)
1591 dbg_str << "<!-- EMR_STROKEPATH -->\n";
1593 *(d->outsvg) += " <path ";
1594 output_style(d, lpEMFR->iType);
1595 *(d->outsvg) += "\n\t";
1596 *(d->outsvg) += *(d->path);
1597 *(d->outsvg) += " /> \n";
1598 *(d->path) = "";
1599 break;
1600 }
1601 case EMR_FLATTENPATH:
1602 dbg_str << "<!-- EMR_FLATTENPATH -->\n";
1603 break;
1604 case EMR_WIDENPATH:
1605 dbg_str << "<!-- EMR_WIDENPATH -->\n";
1606 break;
1607 case EMR_SELECTCLIPPATH:
1608 dbg_str << "<!-- EMR_SELECTCLIPPATH -->\n";
1609 break;
1610 case EMR_ABORTPATH:
1611 dbg_str << "<!-- EMR_ABORTPATH -->\n";
1612 break;
1613 case EMR_GDICOMMENT:
1614 {
1615 dbg_str << "<!-- EMR_GDICOMMENT -->\n";
1617 PEMRGDICOMMENT pEmr = (PEMRGDICOMMENT) lpEMFR;
1619 CHAR *szTxt = (CHAR *) pEmr->Data;
1621 for (DWORD i = 0; i < pEmr->cbData; i++) {
1622 if ( *szTxt) {
1623 if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) {
1624 tmp_str << *szTxt;
1625 }
1626 szTxt++;
1627 }
1628 }
1630 if (0 && strlen(tmp_str.str().c_str())) {
1631 tmp_outsvg << " <!-- \"";
1632 tmp_outsvg << tmp_str.str().c_str();
1633 tmp_outsvg << "\" -->\n";
1634 }
1636 break;
1637 }
1638 case EMR_FILLRGN:
1639 dbg_str << "<!-- EMR_FILLRGN -->\n";
1640 break;
1641 case EMR_FRAMERGN:
1642 dbg_str << "<!-- EMR_FRAMERGN -->\n";
1643 break;
1644 case EMR_INVERTRGN:
1645 dbg_str << "<!-- EMR_INVERTRGN -->\n";
1646 break;
1647 case EMR_PAINTRGN:
1648 dbg_str << "<!-- EMR_PAINTRGN -->\n";
1649 break;
1650 case EMR_EXTSELECTCLIPRGN:
1651 dbg_str << "<!-- EMR_EXTSELECTCLIPRGN -->\n";
1652 break;
1653 case EMR_BITBLT:
1654 dbg_str << "<!-- EMR_BITBLT -->\n";
1655 break;
1656 case EMR_STRETCHBLT:
1657 dbg_str << "<!-- EMR_STRETCHBLT -->\n";
1658 break;
1659 case EMR_MASKBLT:
1660 dbg_str << "<!-- EMR_MASKBLT -->\n";
1661 break;
1662 case EMR_PLGBLT:
1663 dbg_str << "<!-- EMR_PLGBLT -->\n";
1664 break;
1665 case EMR_SETDIBITSTODEVICE:
1666 dbg_str << "<!-- EMR_SETDIBITSTODEVICE -->\n";
1667 break;
1668 case EMR_STRETCHDIBITS:
1669 dbg_str << "<!-- EMR_STRETCHDIBITS -->\n";
1670 break;
1671 case EMR_EXTCREATEFONTINDIRECTW:
1672 {
1673 dbg_str << "<!-- EMR_EXTCREATEFONTINDIRECTW -->\n";
1675 PEMREXTCREATEFONTINDIRECTW pEmr = (PEMREXTCREATEFONTINDIRECTW) lpEMFR;
1676 int index = pEmr->ihFont;
1678 EMREXTCREATEFONTINDIRECTW *pFont =
1679 (EMREXTCREATEFONTINDIRECTW *) malloc( sizeof(EMREXTCREATEFONTINDIRECTW) );
1680 pFont->elfw = pEmr->elfw;
1681 insert_object(d, index, EMR_EXTCREATEFONTINDIRECTW, (ENHMETARECORD *) pFont);
1683 break;
1684 }
1685 case EMR_EXTTEXTOUTA:
1686 {
1687 dbg_str << "<!-- EMR_EXTTEXTOUTA -->\n";
1688 break;
1689 }
1690 case EMR_EXTTEXTOUTW:
1691 {
1692 dbg_str << "<!-- EMR_EXTTEXTOUTW -->\n";
1694 PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR;
1696 double x1 = pEmr->emrtext.ptlReference.x;
1697 double y1 = pEmr->emrtext.ptlReference.y;
1699 if (!(d->textAlign & TA_BOTTOM))
1700 y1 += fabs(d->style.font_size.computed);
1702 double x = pix_to_x_point(d, x1, y1);
1703 double y = pix_to_y_point(d, x1, y1);
1705 wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString);
1707 gchar *ansi_text =
1708 (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL );
1710 if (ansi_text) {
1711 gchar *p = ansi_text;
1712 while (*p) {
1713 if (*p < 32 || *p >= 127) {
1714 g_free(ansi_text);
1715 ansi_text = g_strdup("");
1716 break;
1717 }
1718 p++;
1719 }
1721 SVGOStringStream ts;
1723 gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
1725 float text_rgb[3];
1726 sp_color_get_rgb_floatv( &(d->style.fill.value.color), text_rgb );
1728 if (!d->textColorSet) {
1729 d->textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]),
1730 SP_COLOR_F_TO_U(text_rgb[1]),
1731 SP_COLOR_F_TO_U(text_rgb[2]));
1732 }
1734 char tmp[128];
1735 snprintf(tmp, 127,
1736 "fill:#%02x%02x%02x;",
1737 GetRValue(d->textColor),
1738 GetGValue(d->textColor),
1739 GetBValue(d->textColor));
1741 bool i = (d->style.font_style.value == SP_CSS_FONT_STYLE_ITALIC);
1742 //bool o = (d->style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
1743 bool b = (d->style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
1744 (d->style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->style.font_weight.value <= SP_CSS_FONT_WEIGHT_900);
1745 int lcr = ((d->textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0;
1747 assert_empty_path(d, "EMR_EXTTEXTOUTW");
1749 ts << " <text\n";
1750 ts << " id=\"" << (d->id++) << "\"\n";
1751 ts << " xml:space=\"preserve\"\n";
1752 ts << " x=\"" << x << "\"\n";
1753 ts << " y=\"" << y << "\"\n";
1754 ts << " style=\""
1755 << "font-size:" << fabs(d->style.font_size.computed) << "px;"
1756 << tmp
1757 << "font-style:" << (i ? "italic" : "normal") << ";"
1758 << "font-weight:" << (b ? "bold" : "normal") << ";"
1759 << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";"
1760 << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";"
1761 << "font-family:" << d->tstyle.font_family.value << ";"
1762 << "\"\n";
1763 ts << " >";
1764 ts << escaped_text;
1765 ts << "</text>\n";
1767 *(d->outsvg) += ts.str().c_str();
1769 g_free(escaped_text);
1770 g_free(ansi_text);
1771 }
1773 break;
1774 }
1775 case EMR_POLYBEZIER16:
1776 {
1777 dbg_str << "<!-- EMR_POLYBEZIER16 -->\n";
1779 PEMRPOLYBEZIER16 pEmr = (PEMRPOLYBEZIER16) lpEMFR;
1780 POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1781 DWORD i,j;
1783 if (pEmr->cpts<4)
1784 break;
1786 if (!d->inpath) {
1787 assert_empty_path(d, "EMR_POLYBEZIER16");
1789 *(d->outsvg) += " <path ";
1790 output_style(d, EMR_STROKEPATH);
1791 *(d->outsvg) += "\n\td=\"";
1792 }
1794 tmp_str <<
1795 "\n\tM " <<
1796 pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
1797 pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
1799 for (i=1; i<pEmr->cpts; ) {
1800 tmp_str << "\n\tC ";
1801 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1802 tmp_str <<
1803 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1804 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1805 }
1806 }
1808 if (d->inpath) {
1809 tmp_path << tmp_str.str().c_str();
1810 }
1811 else {
1812 *(d->outsvg) += tmp_str.str().c_str();
1813 *(d->outsvg) += " \" /> \n";
1814 }
1816 break;
1817 }
1818 case EMR_POLYGON16:
1819 {
1820 dbg_str << "<!-- EMR_POLYGON16 -->\n";
1822 PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR;
1823 POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1824 SVGOStringStream tmp_poly;
1825 unsigned int i;
1826 unsigned int first = 0;
1828 assert_empty_path(d, "EMR_POLYGON16");
1830 *(d->outsvg) += " <path ";
1831 output_style(d, EMR_STROKEANDFILLPATH);
1832 *(d->outsvg) += "\n\td=\"";
1834 // skip the first point?
1835 tmp_poly << "\n\tM " <<
1836 pix_to_x_point( d, apts[first].x, apts[first].y ) << " " <<
1837 pix_to_y_point( d, apts[first].x, apts[first].y ) << " ";
1839 for (i=first+1; i<pEmr->cpts; i++) {
1840 tmp_poly << "\n\tL " <<
1841 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1842 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1843 }
1845 *(d->outsvg) += tmp_poly.str().c_str();
1846 *(d->outsvg) += " z \" /> \n";
1848 break;
1849 }
1850 case EMR_POLYLINE16:
1851 {
1852 dbg_str << "<!-- EMR_POLYLINE16 -->\n";
1854 EMRPOLYLINE16 *pEmr = (EMRPOLYLINE16 *) lpEMFR;
1855 POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1856 DWORD i;
1858 if (pEmr->cpts<2)
1859 break;
1861 if (!d->inpath) {
1862 assert_empty_path(d, "EMR_POLYLINE16");
1864 *(d->outsvg) += " <path ";
1865 output_style(d, EMR_STROKEPATH);
1866 *(d->outsvg) += "\n\td=\"";
1867 }
1869 tmp_str <<
1870 "\n\tM " <<
1871 pix_to_x_point( d, apts[0].x, apts[0].y ) << " " <<
1872 pix_to_y_point( d, apts[0].x, apts[0].y ) << " ";
1874 for (i=1; i<pEmr->cpts; i++) {
1875 tmp_str <<
1876 "\n\tL " <<
1877 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1878 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1879 }
1881 if (d->inpath) {
1882 tmp_path << tmp_str.str().c_str();
1883 }
1884 else {
1885 *(d->outsvg) += tmp_str.str().c_str();
1886 *(d->outsvg) += " \" /> \n";
1887 }
1889 break;
1890 }
1891 case EMR_POLYBEZIERTO16:
1892 {
1893 dbg_str << "<!-- EMR_POLYBEZIERTO16 -->\n";
1895 PEMRPOLYBEZIERTO16 pEmr = (PEMRPOLYBEZIERTO16) lpEMFR;
1896 POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1897 DWORD i,j;
1899 if (d->path->empty()) {
1900 d->pathless_stroke = true;
1901 *(d->path) = "d=\"";
1902 }
1904 for (i=0; i<pEmr->cpts;) {
1905 tmp_path << "\n\tC ";
1906 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
1907 tmp_path <<
1908 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1909 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1910 }
1911 }
1913 break;
1914 }
1915 case EMR_POLYLINETO16:
1916 {
1917 dbg_str << "<!-- EMR_POLYLINETO16 -->\n";
1919 PEMRPOLYLINETO16 pEmr = (PEMRPOLYLINETO16) lpEMFR;
1920 POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ?
1921 DWORD i;
1923 if (d->path->empty()) {
1924 d->pathless_stroke = true;
1925 *(d->path) = "d=\"";
1926 }
1928 for (i=0; i<pEmr->cpts;i++) {
1929 tmp_path <<
1930 "\n\tL " <<
1931 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1932 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1933 }
1935 break;
1936 }
1937 case EMR_POLYPOLYLINE16:
1938 case EMR_POLYPOLYGON16:
1939 {
1940 if (lpEMFR->iType == EMR_POLYPOLYLINE16)
1941 dbg_str << "<!-- EMR_POLYPOLYLINE16 -->\n";
1942 if (lpEMFR->iType == EMR_POLYPOLYGON16)
1943 dbg_str << "<!-- EMR_POLYPOLYGON16 -->\n";
1945 PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR;
1946 unsigned int n, i, j;
1948 if (!d->inpath) {
1949 assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16");
1951 *(d->outsvg) += " <path ";
1952 output_style(d, lpEMFR->iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH);
1953 *(d->outsvg) += "\n\td=\"";
1954 }
1956 POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys];
1958 i = 0;
1959 for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
1960 SVGOStringStream poly_path;
1962 poly_path << "\n\tM " <<
1963 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1964 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1965 i++;
1967 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
1968 poly_path << "\n\tL " <<
1969 pix_to_x_point( d, apts[i].x, apts[i].y ) << " " <<
1970 pix_to_y_point( d, apts[i].x, apts[i].y ) << " ";
1971 i++;
1972 }
1974 tmp_str << poly_path.str().c_str();
1975 if (lpEMFR->iType == EMR_POLYPOLYGON16)
1976 tmp_str << " z";
1977 tmp_str << " \n";
1978 }
1980 if (d->inpath) {
1981 tmp_path << tmp_str.str().c_str();
1982 }
1983 else {
1984 *(d->outsvg) += tmp_str.str().c_str();
1985 *(d->outsvg) += " \" /> \n";
1986 }
1988 break;
1989 }
1990 case EMR_POLYDRAW16:
1991 dbg_str << "<!-- EMR_POLYDRAW16 -->\n";
1992 break;
1993 case EMR_CREATEMONOBRUSH:
1994 dbg_str << "<!-- EMR_CREATEMONOBRUSH -->\n";
1995 break;
1996 case EMR_CREATEDIBPATTERNBRUSHPT:
1997 dbg_str << "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n";
1998 break;
1999 case EMR_EXTCREATEPEN:
2000 {
2001 dbg_str << "<!-- EMR_EXTCREATEPEN -->\n";
2003 PEMREXTCREATEPEN pEmr = (PEMREXTCREATEPEN) lpEMFR;
2004 int index = pEmr->ihPen;
2006 EMREXTCREATEPEN *pPen =
2007 (EMREXTCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) +
2008 sizeof(DWORD) * pEmr->elp.elpNumEntries );
2009 pPen->ihPen = pEmr->ihPen;
2010 pPen->offBmi = pEmr->offBmi;
2011 pPen->cbBmi = pEmr->cbBmi;
2012 pPen->offBits = pEmr->offBits;
2013 pPen->cbBits = pEmr->cbBits;
2014 pPen->elp = pEmr->elp;
2015 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
2016 pPen->elp.elpStyleEntry[i] = pEmr->elp.elpStyleEntry[i];
2017 }
2018 insert_object(d, index, EMR_EXTCREATEPEN, (ENHMETARECORD *) pPen);
2020 break;
2021 }
2022 case EMR_POLYTEXTOUTA:
2023 dbg_str << "<!-- EMR_POLYTEXTOUTA -->\n";
2024 break;
2025 case EMR_POLYTEXTOUTW:
2026 dbg_str << "<!-- EMR_POLYTEXTOUTW -->\n";
2027 break;
2028 case EMR_SETICMMODE:
2029 dbg_str << "<!-- EMR_SETICMMODE -->\n";
2030 break;
2031 case EMR_CREATECOLORSPACE:
2032 dbg_str << "<!-- EMR_CREATECOLORSPACE -->\n";
2033 break;
2034 case EMR_SETCOLORSPACE:
2035 dbg_str << "<!-- EMR_SETCOLORSPACE -->\n";
2036 break;
2037 case EMR_DELETECOLORSPACE:
2038 dbg_str << "<!-- EMR_DELETECOLORSPACE -->\n";
2039 break;
2040 case EMR_GLSRECORD:
2041 dbg_str << "<!-- EMR_GLSRECORD -->\n";
2042 break;
2043 case EMR_GLSBOUNDEDRECORD:
2044 dbg_str << "<!-- EMR_GLSBOUNDEDRECORD -->\n";
2045 break;
2046 case EMR_PIXELFORMAT:
2047 dbg_str << "<!-- EMR_PIXELFORMAT -->\n";
2048 break;
2049 default:
2050 dbg_str << "<!-- EMR_??? -->\n";
2051 break;
2052 }
2054 // *(d->outsvg) += dbg_str.str().c_str();
2055 *(d->outsvg) += tmp_outsvg.str().c_str();
2056 *(d->path) += tmp_path.str().c_str();
2058 return 1;
2059 }
2061 static int CALLBACK
2062 myMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, METARECORD *lpMFR, int nObj, LPARAM lpData)
2063 {
2064 g_warning("Unable to import Windows Meta File.\n");
2065 return 0;
2066 }
2068 // Aldus Placeable Header ===================================================
2069 // Since we are a 32bit app, we have to be sure this structure compiles to
2070 // be identical to a 16 bit app's version. To do this, we use the #pragma
2071 // to adjust packing, we use a WORD for the hmf handle, and a SMALL_RECT
2072 // for the bbox rectangle.
2073 #pragma pack( push )
2074 #pragma pack( 2 )
2075 typedef struct
2076 {
2077 DWORD dwKey;
2078 WORD hmf;
2079 SMALL_RECT bbox;
2080 WORD wInch;
2081 DWORD dwReserved;
2082 WORD wCheckSum;
2083 } APMHEADER, *PAPMHEADER;
2084 #pragma pack( pop )
2087 SPDocument *
2088 EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri )
2089 {
2090 EMF_CALLBACK_DATA d;
2092 memset(&d, 0, sizeof(d));
2094 d.worldTransform.eM11 = 1.0;
2095 d.worldTransform.eM12 = 0.0;
2096 d.worldTransform.eM21 = 0.0;
2097 d.worldTransform.eM22 = 1.0;
2098 d.worldTransform.eDx = 0.0;
2099 d.worldTransform.eDy = 0.0;
2101 gsize bytesRead = 0;
2102 gsize bytesWritten = 0;
2103 GError* error = NULL;
2104 gchar *local_fn =
2105 g_filename_from_utf8( uri, -1, &bytesRead, &bytesWritten, &error );
2107 if (local_fn == NULL) {
2108 return NULL;
2109 }
2111 d.outsvg = new Glib::ustring("");
2112 d.path = new Glib::ustring("");
2114 CHAR *ansi_uri = (CHAR *) local_fn;
2115 gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
2116 WCHAR *unicode_uri = (WCHAR *) unicode_fn;
2118 DWORD filesize = 0;
2119 HANDLE fp = NULL;
2121 HMETAFILE hmf;
2122 HENHMETAFILE hemf;
2124 if (PrintWin32::is_os_wide()) {
2125 fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2126 }
2127 else {
2128 fp = CreateFileA(ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2129 }
2131 if ( fp != INVALID_HANDLE_VALUE ) {
2132 filesize = GetFileSize(fp, NULL);
2133 CloseHandle(fp);
2134 }
2136 // Try open as Enhanced Metafile
2137 if (PrintWin32::is_os_wide())
2138 hemf = GetEnhMetaFileW(unicode_uri);
2139 else
2140 hemf = GetEnhMetaFileA(ansi_uri);
2142 if (!hemf) {
2143 // Try open as Windows Metafile
2144 if (PrintWin32::is_os_wide())
2145 hmf = GetMetaFileW(unicode_uri);
2146 else
2147 hmf = GetMetaFileA(ansi_uri);
2149 METAFILEPICT mp;
2150 HDC hDC;
2152 if (!hmf) {
2153 if (PrintWin32::is_os_wide()) {
2154 WCHAR szTemp[MAX_PATH];
2156 DWORD dw = GetShortPathNameW( unicode_uri, szTemp, MAX_PATH );
2157 if (dw) {
2158 hmf = GetMetaFileW( szTemp );
2159 }
2160 } else {
2161 CHAR szTemp[MAX_PATH];
2163 DWORD dw = GetShortPathNameA( ansi_uri, szTemp, MAX_PATH );
2164 if (dw) {
2165 hmf = GetMetaFileA( szTemp );
2166 }
2167 }
2168 }
2170 if (hmf) {
2171 DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
2173 if (!nSize)
2174 nSize = filesize;
2176 if (nSize) {
2177 BYTE *lpvData = new BYTE[nSize];
2178 if (lpvData) {
2179 DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
2180 if (dw) {
2181 // Fill out a METAFILEPICT structure
2182 mp.mm = MM_ANISOTROPIC;
2183 mp.xExt = 1000;
2184 mp.yExt = 1000;
2185 mp.hMF = NULL;
2186 // Get a reference DC
2187 hDC = GetDC( NULL );
2188 // Make an enhanced metafile from the windows metafile
2189 hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
2190 // Clean up
2191 ReleaseDC( NULL, hDC );
2192 DeleteMetaFile( hmf );
2193 hmf = NULL;
2194 }
2195 else {
2196 // EnumMetaFile
2197 }
2198 delete[] lpvData;
2199 }
2200 else {
2201 DeleteMetaFile( hmf );
2202 hmf = NULL;
2203 }
2204 }
2205 else {
2206 DeleteMetaFile( hmf );
2207 hmf = NULL;
2208 }
2209 }
2210 else {
2211 // Try open as Aldus Placeable Metafile
2212 HANDLE hFile;
2213 if (PrintWin32::is_os_wide())
2214 hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2215 else
2216 hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2218 if (hFile != INVALID_HANDLE_VALUE) {
2219 DWORD nSize = GetFileSize( hFile, NULL );
2220 if (nSize) {
2221 BYTE *lpvData = new BYTE[nSize];
2222 if (lpvData) {
2223 DWORD dw = ReadFile( hFile, lpvData, nSize, &nSize, NULL );
2224 if (dw) {
2225 if ( ((PAPMHEADER)lpvData)->dwKey == 0x9ac6cdd7l ) {
2226 // Fill out a METAFILEPICT structure
2227 mp.mm = MM_ANISOTROPIC;
2228 mp.xExt = ((PAPMHEADER)lpvData)->bbox.Right - ((PAPMHEADER)lpvData)->bbox.Left;
2229 mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
2230 mp.yExt = ((PAPMHEADER)lpvData)->bbox.Bottom - ((PAPMHEADER)lpvData)->bbox.Top;
2231 mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(((PAPMHEADER)lpvData)->wInch);
2232 mp.hMF = NULL;
2233 // Get a reference DC
2234 hDC = GetDC( NULL );
2235 // Create an enhanced metafile from the bits
2236 hemf = SetWinMetaFileBits( nSize, lpvData+sizeof(APMHEADER), hDC, &mp );
2237 // Clean up
2238 ReleaseDC( NULL, hDC );
2239 }
2240 }
2241 delete[] lpvData;
2242 }
2243 }
2244 CloseHandle( hFile );
2245 }
2246 }
2247 }
2249 if ((!hemf && !hmf) || !d.outsvg || !d.path) {
2250 if (d.outsvg)
2251 delete d.outsvg;
2252 if (d.path)
2253 delete d.path;
2254 if (local_fn)
2255 g_free(local_fn);
2256 if (unicode_fn)
2257 g_free(unicode_fn);
2258 if (hemf)
2259 DeleteEnhMetaFile(hemf);
2260 if (hmf)
2261 DeleteMetaFile(hmf);
2262 return NULL;
2263 }
2265 d.pDesc = NULL;
2267 if (hemf) {
2268 DWORD dwNeeded = GetEnhMetaFileDescriptionA( hemf, 0, NULL );
2269 if ( dwNeeded > 0 ) {
2270 d.pDesc = (CHAR *) malloc( dwNeeded + 1 );
2271 if ( GetEnhMetaFileDescription( hemf, dwNeeded, d.pDesc ) == 0 )
2272 lstrcpy( d.pDesc, "" );
2273 if ( lstrlen( d.pDesc ) > 1 )
2274 d.pDesc[lstrlen(d.pDesc)] = '#';
2275 }
2277 EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL);
2278 DeleteEnhMetaFile(hemf);
2279 }
2280 else {
2281 EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d);
2282 DeleteMetaFile(hmf);
2283 }
2285 if (d.pDesc)
2286 free( d.pDesc );
2288 // std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
2290 SPDocument *doc = sp_document_new_from_mem(d.outsvg->c_str(), d.outsvg->length(), TRUE);
2292 delete d.outsvg;
2293 delete d.path;
2295 if (d.emf_obj) {
2296 int i;
2297 for (i=0; i<d.n_obj; i++)
2298 delete_object(&d, i);
2299 delete[] d.emf_obj;
2300 }
2302 if (d.style.stroke_dash.dash)
2303 delete[] d.style.stroke_dash.dash;
2305 if (local_fn)
2306 g_free(local_fn);
2307 if (unicode_fn)
2308 g_free(unicode_fn);
2310 return doc;
2311 }
2314 void
2315 EmfWin32::init (void)
2316 {
2317 Inkscape::Extension::Extension * ext;
2319 /* EMF in */
2320 ext = Inkscape::Extension::build_from_mem(
2321 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2322 "<name>" N_("EMF Input") "</name>\n"
2323 "<id>org.inkscape.input.emf.win32</id>\n"
2324 "<input>\n"
2325 "<extension>.emf</extension>\n"
2326 "<mimetype>image/x-emf</mimetype>\n"
2327 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
2328 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
2329 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
2330 "</input>\n"
2331 "</inkscape-extension>", new EmfWin32());
2333 /* WMF in */
2334 ext = Inkscape::Extension::build_from_mem(
2335 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2336 "<name>" N_("WMF Input") "</name>\n"
2337 "<id>org.inkscape.input.wmf.win32</id>\n"
2338 "<input>\n"
2339 "<extension>.wmf</extension>\n"
2340 "<mimetype>image/x-wmf</mimetype>\n"
2341 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
2342 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
2343 "<output_extension>org.inkscape.output.emf.win32</output_extension>\n"
2344 "</input>\n"
2345 "</inkscape-extension>", new EmfWin32());
2347 /* EMF out */
2348 ext = Inkscape::Extension::build_from_mem(
2349 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
2350 "<name>" N_("EMF Output") "</name>\n"
2351 "<id>org.inkscape.output.emf.win32</id>\n"
2352 "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
2353 "<output>\n"
2354 "<extension>.emf</extension>\n"
2355 "<mimetype>image/x-emf</mimetype>\n"
2356 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
2357 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
2358 "</output>\n"
2359 "</inkscape-extension>", new EmfWin32());
2361 return;
2362 }
2365 } } } /* namespace Inkscape, Extension, Implementation */
2368 #endif /* WIN32 */
2371 /*
2372 Local Variables:
2373 mode:cpp
2374 c-file-style:"stroustrup"
2375 c-file-offsets:((innamespace . 0)(inline-open . 0))
2376 indent-tabs-mode:nil
2377 fill-column:99
2378 End:
2379 */
2380 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :