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