1 /** \file
2 * Enhanced Metafile Printing.
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 <string.h>
31 //#include <signal.h>
32 //#include <errno.h>
34 //#include "libnr/n-art-bpath.h"
35 //#include "libnr/nr-point-matrix-ops.h"
36 //#include "libnr/nr-rect.h"
37 //#include "libnr/nr-matrix.h"
38 #include "libnr/nr-matrix-ops.h"
39 //#include "libnr/nr-matrix-scale-ops.h"
40 //#include "libnr/nr-matrix-translate-ops.h"
41 #include "libnr/nr-scale-translate-ops.h"
42 //#include "libnr/nr-translate-scale-ops.h"
43 //#include "libnr/nr-matrix-fns.h"
44 //#include "libnr/nr-pixblock.h"
45 #include "libnr/n-art-bpath-2geom.h"
46 #include <2geom/pathvector.h>
47 #include <2geom/rect.h>
48 #include <2geom/bezier-curve.h>
49 #include <2geom/hvlinesegment.h>
50 #include "helper/geom.h"
51 #include "helper/geom-curves.h"
52 //#include "display/canvas-bpath.h"
53 #include "sp-item.h"
55 //#include "glib.h"
56 //#include "gtk/gtkdialog.h"
57 //#include "gtk/gtkbox.h"
58 //#include "gtk/gtkstock.h"
60 //#include "glibmm/i18n.h"
61 //#include "enums.h"
62 //#include "document.h"
63 #include "style.h"
64 //#include "sp-paint-server.h"
65 #include "inkscape_version.h"
67 //#include "libnrtype/FontFactory.h"
68 //#include "libnrtype/font-instance.h"
69 //#include "libnrtype/font-style-to-pos.h"
71 #define WIN32_LEAN_AND_MEAN
72 #include <windows.h>
74 #include "win32.h"
75 #include "emf-win32-print.h"
77 #include "unit-constants.h"
79 //#include "extension/extension.h"
80 #include "extension/system.h"
81 #include "extension/print.h"
83 //#include "io/sys.h"
85 //#include "macros.h"
87 namespace Inkscape {
88 namespace Extension {
89 namespace Internal {
91 static float dwDPI = 2540;
94 PrintEmfWin32::PrintEmfWin32 (void):
95 hdc(NULL),
96 hbrush(NULL),
97 hbrushOld(NULL),
98 hpen(NULL),
99 stroke_and_fill(false),
100 fill_only(false),
101 simple_shape(false)
102 {
103 }
106 PrintEmfWin32::~PrintEmfWin32 (void)
107 {
108 if (hdc) {
109 HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
110 if ( metafile ) {
111 DeleteEnhMetaFile( metafile );
112 }
113 DeleteDC( hdc );
114 }
116 /* restore default signal handling for SIGPIPE */
117 #if !defined(_WIN32) && !defined(__WIN32__)
118 (void) signal(SIGPIPE, SIG_DFL);
119 #endif
120 return;
121 }
124 unsigned int
125 PrintEmfWin32::setup (Inkscape::Extension::Print * /*mod*/)
126 {
127 return TRUE;
128 }
131 unsigned int
132 PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
133 {
134 gchar const *utf8_fn = mod->get_param_string("destination");
136 gsize bytesRead = 0;
137 gsize bytesWritten = 0;
138 GError* error = NULL;
139 gchar *local_fn =
140 g_filename_from_utf8( utf8_fn, -1, &bytesRead, &bytesWritten, &error );
142 if (local_fn == NULL) {
143 return 1;
144 }
146 CHAR *ansi_uri = (CHAR *) local_fn;
147 gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL );
148 WCHAR *unicode_uri = (WCHAR *) unicode_fn;
150 // width and height in px
151 _width = sp_document_width(doc);
152 _height = sp_document_height(doc);
154 NRRect d;
155 bool pageBoundingBox;
156 pageBoundingBox = mod->get_param_bool("pageBoundingBox");
157 if (pageBoundingBox) {
158 d.x0 = d.y0 = 0;
159 d.x1 = _width;
160 d.y1 = _height;
161 } else {
162 SPItem* doc_item = SP_ITEM(sp_document_root(doc));
163 sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);
164 }
166 d.x0 *= IN_PER_PX;
167 d.y0 *= IN_PER_PX;
168 d.x1 *= IN_PER_PX;
169 d.y1 *= IN_PER_PX;
171 float dwInchesX = (d.x1 - d.x0);
172 float dwInchesY = (d.y1 - d.y0);
174 // dwInchesX x dwInchesY in .01mm units
175 SetRect( &rc, 0, 0, (int) ceil(dwInchesX*2540), (int) ceil(dwInchesY*2540) );
177 // Get a Reference DC
178 HDC hScreenDC = GetDC( NULL );
180 // Get the physical characteristics of the reference DC
181 int PixelsX = GetDeviceCaps( hScreenDC, HORZRES );
182 int PixelsY = GetDeviceCaps( hScreenDC, VERTRES );
183 int MMX = GetDeviceCaps( hScreenDC, HORZSIZE );
184 int MMY = GetDeviceCaps( hScreenDC, VERTSIZE );
186 CHAR buff[1024];
187 ZeroMemory(buff, sizeof(buff));
188 snprintf(buff, sizeof(buff)-1, "Inkscape %s (%s)", INKSCAPE_VERSION, __DATE__);
189 INT len = strlen(buff);
190 CHAR *p1 = strrchr(ansi_uri, '\\');
191 CHAR *p2 = strrchr(ansi_uri, '/');
192 CHAR *p = MAX(p1, p2);
193 if (p)
194 p++;
195 else
196 p = ansi_uri;
197 snprintf(buff+len+1, sizeof(buff)-len-2, "%s", p);
199 // Create the Metafile
200 if (PrintWin32::is_os_wide()) {
201 WCHAR wbuff[1024];
202 ZeroMemory(wbuff, sizeof(wbuff));
203 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, sizeof(buff)/sizeof(buff[0]), wbuff, sizeof(wbuff)/sizeof(wbuff[0]));
204 hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, wbuff );
205 }
206 else {
207 hdc = CreateEnhMetaFileA( hScreenDC, ansi_uri, &rc, buff );
208 }
210 // Release the reference DC
211 ReleaseDC( NULL, hScreenDC );
213 // Did we get a good metafile?
214 if (hdc == NULL)
215 {
216 g_free(local_fn);
217 g_free(unicode_fn);
218 return 1;
219 }
221 // Anisotropic mapping mode
222 SetMapMode( hdc, MM_ANISOTROPIC );
224 // Set the Windows extent
225 int windowextX = (int) ceil(dwInchesX*dwDPI);
226 int windowextY = (int) ceil(dwInchesY*dwDPI);
227 SetWindowExtEx( hdc, windowextX, windowextY, NULL );
229 // Set the viewport extent to reflect
230 // dwInchesX" x dwInchesY" in device units
231 int viewportextX = (int)((float)dwInchesX*25.4f*(float)PixelsX/(float)MMX);
232 int viewportextY = (int)((float)dwInchesY*25.4f*(float)PixelsY/(float)MMY);
233 SetViewportExtEx( hdc, viewportextX, viewportextY, NULL );
235 if (1) {
236 snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
237 GdiComment(hdc, strlen(buff), (BYTE*) buff);
239 snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN);
240 GdiComment(hdc, strlen(buff), (BYTE*) buff);
241 }
243 SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) );
245 g_free(local_fn);
246 g_free(unicode_fn);
248 m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, sp_document_height(doc)));
250 return 0;
251 }
254 unsigned int
255 PrintEmfWin32::finish (Inkscape::Extension::Print * /*mod*/)
256 {
257 if (!hdc) return 0;
259 flush_fill(); // flush any pending fills
261 HENHMETAFILE metafile = CloseEnhMetaFile( hdc );
262 if ( metafile ) {
263 DeleteEnhMetaFile( metafile );
264 }
265 DeleteDC( hdc );
267 hdc = NULL;
269 return 0;
270 }
273 unsigned int
274 PrintEmfWin32::comment (Inkscape::Extension::Print * /*module*/,
275 const char * /*comment*/)
276 {
277 if (!hdc) return 0;
279 flush_fill(); // flush any pending fills
281 return 0;
282 }
285 int
286 PrintEmfWin32::create_brush(SPStyle const *style)
287 {
288 float rgb[3];
290 if (style) {
291 float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
292 if (opacity <= 0.0)
293 return 1;
295 sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
296 hbrush = CreateSolidBrush( RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]) );
297 hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
299 SetPolyFillMode( hdc,
300 style->fill_rule.computed == 0 ? WINDING :
301 style->fill_rule.computed == 2 ? ALTERNATE : ALTERNATE );
302 } else { // if (!style)
303 hbrush = CreateSolidBrush( RGB(255, 255, 255) );
304 hbrushOld = (HBRUSH) SelectObject( hdc, hbrush );
305 SetPolyFillMode( hdc, ALTERNATE );
306 }
308 return 0;
309 }
312 void
313 PrintEmfWin32::destroy_brush()
314 {
315 SelectObject( hdc, hbrushOld );
316 if (hbrush)
317 DeleteObject( hbrush );
318 hbrush = NULL;
319 hbrushOld = NULL;
320 }
323 void
324 PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Matrix &transform)
325 {
326 if (style) {
327 float rgb[3];
329 sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
331 LOGBRUSH lb;
332 ZeroMemory(&lb, sizeof(lb));
333 lb.lbStyle = BS_SOLID;
334 lb.lbColor = RGB( 255*rgb[0], 255*rgb[1], 255*rgb[2] );
336 int linestyle = PS_SOLID;
337 int linecap = 0;
338 int linejoin = 0;
339 DWORD n_dash = 0;
340 DWORD *dash = NULL;
342 using Geom::X;
343 using Geom::Y;
345 Geom::Point zero(0, 0);
346 Geom::Point one(1, 1);
347 Geom::Point p0(zero * transform);
348 Geom::Point p1(one * transform);
349 Geom::Point p(p1 - p0);
351 double scale = sqrt( (p[X]*p[X]) + (p[Y]*p[Y]) ) / sqrt(2);
353 DWORD linewidth = MAX( 1, (DWORD) (scale * style->stroke_width.computed * IN_PER_PX * dwDPI) );
355 if (style->stroke_linecap.computed == 0) {
356 linecap = PS_ENDCAP_FLAT;
357 }
358 else if (style->stroke_linecap.computed == 1) {
359 linecap = PS_ENDCAP_ROUND;
360 }
361 else if (style->stroke_linecap.computed == 2) {
362 linecap = PS_ENDCAP_SQUARE;
363 }
365 if (style->stroke_linejoin.computed == 0) {
366 linejoin = PS_JOIN_MITER;
367 }
368 else if (style->stroke_linejoin.computed == 1) {
369 linejoin = PS_JOIN_ROUND;
370 }
371 else if (style->stroke_linejoin.computed == 2) {
372 linejoin = PS_JOIN_BEVEL;
373 }
375 if (style->stroke_dash.n_dash &&
376 style->stroke_dash.dash )
377 {
378 int i = 0;
379 while (linestyle != PS_USERSTYLE &&
380 (i < style->stroke_dash.n_dash)) {
381 if (style->stroke_dash.dash[i] > 0.00000001)
382 linestyle = PS_USERSTYLE;
383 i++;
384 }
386 if (linestyle == PS_USERSTYLE) {
387 n_dash = style->stroke_dash.n_dash;
388 dash = new DWORD[n_dash];
389 for (i = 0; i < style->stroke_dash.n_dash; i++) {
390 dash[i] = (DWORD) (style->stroke_dash.dash[i] * IN_PER_PX * dwDPI);
391 }
392 }
393 }
395 hpen = ExtCreatePen(
396 PS_GEOMETRIC | linestyle | linecap | linejoin,
397 linewidth,
398 &lb,
399 n_dash,
400 dash );
402 if ( !hpen && linestyle == PS_USERSTYLE ) {
403 hpen = ExtCreatePen(
404 PS_GEOMETRIC | PS_SOLID | linecap | linejoin,
405 linewidth,
406 &lb,
407 0,
408 NULL );
409 }
411 if ( !hpen ) {
412 hpen = CreatePen(
413 PS_SOLID,
414 linewidth,
415 lb.lbColor );
416 }
418 hpenOld = (HPEN) SelectObject( hdc, hpen );
420 if (linejoin == PS_JOIN_MITER) {
421 float oldmiterlimit;
422 float miterlimit = style->stroke_miterlimit.value;
424 miterlimit = miterlimit * 10.0 / 4.0;
425 if (miterlimit < 1)
426 miterlimit = 10.0;
428 miterlimit = miterlimit * IN_PER_PX * dwDPI;
430 SetMiterLimit(
431 hdc,
432 miterlimit,
433 &oldmiterlimit );
434 }
436 if (n_dash) {
437 delete[] dash;
438 }
439 }
440 else { // if (!style)
441 hpen = CreatePen( PS_SOLID, 1, RGB(0, 0, 0) );
442 hpenOld = (HPEN) SelectObject( hdc, hpen );
443 }
444 }
447 void
448 PrintEmfWin32::destroy_pen()
449 {
450 SelectObject( hdc, hpenOld );
451 if (hpen)
452 DeleteObject( hpen );
453 hpen = NULL;
454 }
457 void
458 PrintEmfWin32::flush_fill()
459 {
460 if (!fill_pathv.empty()) {
461 stroke_and_fill = false;
462 fill_only = true;
463 print_pathv(fill_pathv, fill_transform);
464 fill_only = false;
465 if (!simple_shape)
466 FillPath( hdc );
467 destroy_brush();
468 fill_pathv.clear();
469 }
470 }
472 unsigned int
473 PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Matrix const *transform, float /*opacity*/)
474 {
475 Geom::Matrix tr = *transform;
477 if (m_tr_stack.size()) {
478 Geom::Matrix tr_top = m_tr_stack.top();
479 m_tr_stack.push(tr * tr_top);
480 } else {
481 m_tr_stack.push(tr);
482 }
484 return 1;
485 }
487 unsigned int
488 PrintEmfWin32::release(Inkscape::Extension::Print * /*mod*/)
489 {
490 m_tr_stack.pop();
491 return 1;
492 }
494 unsigned int
495 PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/,
496 Geom::PathVector const &pathv, Geom::Matrix const * /*transform*/, SPStyle const *style,
497 NRRect const * /*pbox*/, NRRect const * /*dbox*/, NRRect const * /*bbox*/)
498 {
499 if (!hdc) return 0;
501 Geom::Matrix tf = m_tr_stack.top();
503 flush_fill(); // flush any pending fills
505 if (style->fill.isColor()) {
506 if (create_brush(style))
507 return 0;
508 } else {
509 // create_brush(NULL);
510 return 0;
511 }
513 fill_pathv.clear();
514 std::copy(pathv.begin(), pathv.end(), std::back_inserter(fill_pathv));
515 fill_transform = tf;
517 // postpone fill in case of stroke-and-fill
519 return 0;
520 }
523 unsigned int
524 PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/,
525 Geom::PathVector const &pathv, const Geom::Matrix * /*transform*/, const SPStyle *style,
526 const NRRect * /*pbox*/, const NRRect * /*dbox*/, const NRRect * /*bbox*/)
527 {
528 if (!hdc) return 0;
530 Geom::Matrix tf = m_tr_stack.top();
532 stroke_and_fill = ( pathv == fill_pathv );
534 if (!stroke_and_fill) {
535 flush_fill(); // flush any pending fills
536 }
538 if (style->stroke.isColor()) {
539 create_pen(style, tf);
540 } else {
541 // create_pen(NULL, tf);
542 return 0;
543 }
545 print_pathv(pathv, tf);
547 if (stroke_and_fill) {
548 if (!simple_shape)
549 StrokeAndFillPath( hdc );
550 destroy_brush();
551 fill_pathv.clear();
552 } else {
553 if (!simple_shape)
554 StrokePath( hdc );
555 }
557 destroy_pen();
559 return 0;
560 }
563 bool
564 PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Matrix &transform)
565 {
566 Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
568 int nodes = 0;
569 int moves = 0;
570 int lines = 0;
571 int curves = 0;
573 for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
574 {
575 moves++;
576 nodes++;
578 for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
579 {
580 nodes++;
582 if ( is_straight_curve(*cit) ) {
583 lines++;
584 }
585 else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit)) {
586 cubic = cubic;
587 curves++;
588 }
589 }
590 }
592 if (!nodes)
593 return false;
595 POINT *lpPoints = new POINT[moves + lines + curves*3];
596 int i = 0;
598 /**
599 * For all Subpaths in the <path>
600 */
601 for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
602 {
603 using Geom::X;
604 using Geom::Y;
606 Geom::Point p0 = pit->initialPoint();
608 p0[X] = (p0[X] * IN_PER_PX * dwDPI);
609 p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
611 LONG const x0 = (LONG) round(p0[X]);
612 LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
614 lpPoints[i].x = x0;
615 lpPoints[i].y = y0;
616 i = i + 1;
618 /**
619 * For all segments in the subpath
620 */
621 for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
622 {
623 if ( is_straight_curve(*cit) )
624 {
625 //Geom::Point p0 = cit->initialPoint();
626 Geom::Point p1 = cit->finalPoint();
628 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
629 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
630 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
631 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
633 //LONG const x0 = (LONG) round(p0[X]);
634 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
635 LONG const x1 = (LONG) round(p1[X]);
636 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
638 lpPoints[i].x = x1;
639 lpPoints[i].y = y1;
640 i = i + 1;
641 }
642 else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
643 {
644 std::vector<Geom::Point> points = cubic->points();
645 //Geom::Point p0 = points[0];
646 Geom::Point p1 = points[1];
647 Geom::Point p2 = points[2];
648 Geom::Point p3 = points[3];
650 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
651 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
652 p2[X] = (p2[X] * IN_PER_PX * dwDPI);
653 p3[X] = (p3[X] * IN_PER_PX * dwDPI);
654 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
655 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
656 p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
657 p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
659 //LONG const x0 = (LONG) round(p0[X]);
660 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
661 LONG const x1 = (LONG) round(p1[X]);
662 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
663 LONG const x2 = (LONG) round(p2[X]);
664 LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
665 LONG const x3 = (LONG) round(p3[X]);
666 LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
668 POINT pt[3];
669 pt[0].x = x1;
670 pt[0].y = y1;
671 pt[1].x = x2;
672 pt[1].y = y2;
673 pt[2].x = x3;
674 pt[2].y = y3;
676 lpPoints[i].x = x1;
677 lpPoints[i].y = y1;
678 lpPoints[i+1].x = x2;
679 lpPoints[i+1].y = y2;
680 lpPoints[i+2].x = x3;
681 lpPoints[i+2].y = y3;
682 i = i + 3;
683 }
684 }
685 }
687 bool done = false;
688 bool closed = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y);
689 bool polygon = false;
690 bool polyline = false;
691 bool rectangle = false;
692 bool ellipse = false;
694 if (moves == 1 && moves+lines == nodes && closed) {
695 polygon = true;
696 if (nodes==5) {
697 if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x &&
698 lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y)
699 {
700 rectangle = true;
701 }
702 }
703 }
704 else if (moves == 1 && moves+lines == nodes) {
705 polyline = true;
706 }
707 else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) {
708 if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x &&
709 lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x &&
710 lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x &&
711 lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y &&
712 lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y &&
713 lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y)
714 {
715 ellipse = true;
716 }
717 }
719 if (polygon || polyline || ellipse) {
720 HPEN hpenTmp = NULL;
721 HPEN hpenOld = NULL;
722 HBRUSH hbrushTmp = NULL;
723 HBRUSH hbrushOld = NULL;
725 if (!stroke_and_fill) {
726 if (fill_only) {
727 hpenTmp = (HPEN) GetStockObject(NULL_PEN);
728 hpenOld = (HPEN) SelectObject( hdc, hpenTmp );
729 }
730 else { // if (stroke_only)
731 hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH);
732 hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp );
733 }
734 }
736 if (polygon) {
737 if (rectangle)
738 Rectangle( hdc, lpPoints[0].x, lpPoints[0].y, lpPoints[2].x, lpPoints[2].y );
739 else
740 Polygon( hdc, lpPoints, nodes );
741 }
742 else if (polyline) {
743 Polyline( hdc, lpPoints, nodes );
744 }
745 else if (ellipse) {
746 Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y);
747 }
749 done = true;
751 if (hpenOld)
752 SelectObject( hdc, hpenOld );
753 if (hpenTmp)
754 DeleteObject( hpenTmp );
755 if (hbrushOld)
756 SelectObject( hdc, hbrushOld );
757 if (hbrushTmp)
758 DeleteObject( hbrushTmp );
759 }
761 delete[] lpPoints;
763 return done;
764 }
766 unsigned int
767 PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Matrix &transform)
768 {
769 simple_shape = print_simple_shape(pathv, transform);
771 if (simple_shape)
772 return TRUE;
774 Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
776 BeginPath( hdc );
778 /**
779 * For all Subpaths in the <path>
780 */
781 for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
782 {
783 using Geom::X;
784 using Geom::Y;
786 Geom::Point p0 = pit->initialPoint();
788 p0[X] = (p0[X] * IN_PER_PX * dwDPI);
789 p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
791 LONG const x0 = (LONG) round(p0[X]);
792 LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
794 MoveToEx( hdc, x0, y0, NULL );
796 /**
797 * For all segments in the subpath
798 */
799 for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
800 {
801 if ( is_straight_curve(*cit) )
802 {
803 //Geom::Point p0 = cit->initialPoint();
804 Geom::Point p1 = cit->finalPoint();
806 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
807 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
808 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
809 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
811 //LONG const x0 = (LONG) round(p0[X]);
812 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
813 LONG const x1 = (LONG) round(p1[X]);
814 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
816 LineTo( hdc, x1, y1 );
817 }
818 else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
819 {
820 std::vector<Geom::Point> points = cubic->points();
821 //Geom::Point p0 = points[0];
822 Geom::Point p1 = points[1];
823 Geom::Point p2 = points[2];
824 Geom::Point p3 = points[3];
826 //p0[X] = (p0[X] * IN_PER_PX * dwDPI);
827 p1[X] = (p1[X] * IN_PER_PX * dwDPI);
828 p2[X] = (p2[X] * IN_PER_PX * dwDPI);
829 p3[X] = (p3[X] * IN_PER_PX * dwDPI);
830 //p0[Y] = (p0[Y] * IN_PER_PX * dwDPI);
831 p1[Y] = (p1[Y] * IN_PER_PX * dwDPI);
832 p2[Y] = (p2[Y] * IN_PER_PX * dwDPI);
833 p3[Y] = (p3[Y] * IN_PER_PX * dwDPI);
835 //LONG const x0 = (LONG) round(p0[X]);
836 //LONG const y0 = (LONG) round(rc.bottom-p0[Y]);
837 LONG const x1 = (LONG) round(p1[X]);
838 LONG const y1 = (LONG) round(rc.bottom-p1[Y]);
839 LONG const x2 = (LONG) round(p2[X]);
840 LONG const y2 = (LONG) round(rc.bottom-p2[Y]);
841 LONG const x3 = (LONG) round(p3[X]);
842 LONG const y3 = (LONG) round(rc.bottom-p3[Y]);
844 POINT pt[3];
845 pt[0].x = x1;
846 pt[0].y = y1;
847 pt[1].x = x2;
848 pt[1].y = y2;
849 pt[2].x = x3;
850 pt[2].y = y3;
852 PolyBezierTo( hdc, pt, 3 );
853 }
854 else
855 {
856 g_warning("logical error, because pathv_to_linear_and_cubic_beziers was used");
857 }
858 }
860 if (pit->end_default() == pit->end_closed()) {
861 CloseFigure( hdc );
862 }
863 }
865 EndPath( hdc );
867 return TRUE;
868 }
871 bool
872 PrintEmfWin32::textToPath(Inkscape::Extension::Print * ext)
873 {
874 return ext->get_param_bool("textToPath");
875 }
877 unsigned int
878 PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point p,
879 SPStyle const *const style)
880 {
881 if (!hdc) return 0;
883 HFONT hfont = NULL;
885 #ifdef USE_PANGO_WIN32
886 /*
887 font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
888 if (tf) {
889 LOGFONT *lf = pango_win32_font_logfont(tf->pFont);
890 tf->Unref();
891 hfont = CreateFontIndirect(lf);
892 g_free(lf);
893 }
894 */
895 #endif
897 if (!hfont) {
898 if (PrintWin32::is_os_wide()) {
899 LOGFONTW *lf = (LOGFONTW*)g_malloc(sizeof(LOGFONTW));
900 g_assert(lf != NULL);
902 lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
903 lf->lfWidth = 0;
904 lf->lfEscapement = 0;
905 lf->lfOrientation = 0;
906 lf->lfWeight =
907 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
908 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
909 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
910 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
911 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
912 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
913 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
914 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
915 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
916 FW_NORMAL;
917 lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
918 lf->lfUnderline = style->text_decoration.underline;
919 lf->lfStrikeOut = style->text_decoration.line_through;
920 lf->lfCharSet = DEFAULT_CHARSET;
921 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
922 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
923 lf->lfQuality = DEFAULT_QUALITY;
924 lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
926 gunichar2 *unicode_name = g_utf8_to_utf16( style->text->font_family.value, -1, NULL, NULL, NULL );
927 wcsncpy(lf->lfFaceName, (wchar_t*) unicode_name, LF_FACESIZE-1);
928 g_free(unicode_name);
930 hfont = CreateFontIndirectW(lf);
932 g_free(lf);
933 }
934 else {
935 LOGFONTA *lf = (LOGFONTA*)g_malloc(sizeof(LOGFONTA));
936 g_assert(lf != NULL);
938 lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI;
939 lf->lfWidth = 0;
940 lf->lfEscapement = 0;
941 lf->lfOrientation = 0;
942 lf->lfWeight =
943 style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN :
944 style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT :
945 style->font_weight.computed == SP_CSS_FONT_WEIGHT_300 ? FW_LIGHT :
946 style->font_weight.computed == SP_CSS_FONT_WEIGHT_400 ? FW_NORMAL :
947 style->font_weight.computed == SP_CSS_FONT_WEIGHT_500 ? FW_MEDIUM :
948 style->font_weight.computed == SP_CSS_FONT_WEIGHT_600 ? FW_SEMIBOLD :
949 style->font_weight.computed == SP_CSS_FONT_WEIGHT_700 ? FW_BOLD :
950 style->font_weight.computed == SP_CSS_FONT_WEIGHT_800 ? FW_EXTRABOLD :
951 style->font_weight.computed == SP_CSS_FONT_WEIGHT_900 ? FW_HEAVY :
952 FW_NORMAL;
953 lf->lfItalic = (style->font_style.computed == SP_CSS_FONT_STYLE_ITALIC);
954 lf->lfUnderline = style->text_decoration.underline;
955 lf->lfStrikeOut = style->text_decoration.line_through;
956 lf->lfCharSet = DEFAULT_CHARSET;
957 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
958 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
959 lf->lfQuality = DEFAULT_QUALITY;
960 lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
962 strncpy(lf->lfFaceName, (char*) style->text->font_family.value, LF_FACESIZE-1);
964 hfont = CreateFontIndirectA(lf);
966 g_free(lf);
967 }
968 }
970 HFONT hfontOld = (HFONT) SelectObject(hdc, hfont);
972 float rgb[3];
973 sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
974 SetTextColor(hdc, RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
976 // Text alignment:
977 // - (x,y) coordinates received by this filter are those of the point where the text
978 // actually starts, and already takes into account the text object's alignment;
979 // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
980 SetTextAlign(hdc, TA_BASELINE | TA_LEFT);
982 // Transparent text background
983 SetBkMode(hdc, TRANSPARENT);
985 Geom::Matrix tf = m_tr_stack.top();
987 p = p * tf;
988 p[Geom::X] = (p[Geom::X] * IN_PER_PX * dwDPI);
989 p[Geom::Y] = (p[Geom::Y] * IN_PER_PX * dwDPI);
991 LONG const xpos = (LONG) round(p[Geom::X]);
992 LONG const ypos = (LONG) round(rc.bottom-p[Geom::Y]);
994 if (PrintWin32::is_os_wide()) {
995 gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL );
996 TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text));
997 }
998 else {
999 TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text));
1000 }
1002 SelectObject(hdc, hfontOld);
1003 DeleteObject(hfont);
1005 return 0;
1006 }
1008 void
1009 PrintEmfWin32::init (void)
1010 {
1011 Inkscape::Extension::Extension * ext;
1013 /* EMF print */
1014 ext = Inkscape::Extension::build_from_mem(
1015 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
1016 "<name>Enhanced Metafile Print</name>\n"
1017 "<id>org.inkscape.print.emf.win32</id>\n"
1018 "<param name=\"destination\" type=\"string\"></param>\n"
1019 "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
1020 "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
1021 "<print/>\n"
1022 "</inkscape-extension>", new PrintEmfWin32());
1024 return;
1025 }
1028 } /* namespace Internal */
1029 } /* namespace Extension */
1030 } /* namespace Inkscape */
1032 #endif /* WIN32 */
1034 /*
1035 Local Variables:
1036 mode:c++
1037 c-file-style:"stroustrup"
1038 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1039 indent-tabs-mode:nil
1040 fill-column:99
1041 End:
1042 */
1043 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :