Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
wmf-inout.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/* Authors:
6 * Ulf Erikson <ulferikson@users.sf.net>
7 * Jon A. Cruz <jon@joncruz.org>
8 * David Mathog
9 * Abhishek Sharma
10 *
11 * Copyright (C) 2006-2008 Authors
12 *
13 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
14 *
15 * References:
16 * - How to Create & Play Enhanced Metafiles in Win32
17 * http://support.microsoft.com/kb/q145999/
18 * - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
19 * http://support.microsoft.com/kb/q66949/
20 * - Metafile Functions
21 * http://msdn.microsoft.com/library/en-us/gdi/metafile_0whf.asp
22 * - Metafile Structures
23 * http://msdn.microsoft.com/library/en-us/gdi/metafile_5hkj.asp
24 */
25
26#include "wmf-inout.h"
27
28#include <cstdio>
29#include <cstdlib>
30#include <cstdint>
32
33#include "clear-n_.h"
34#include "document.h"
35#include "print.h"
36#include "metafile-print.h"
37
38#include "display/drawing.h"
39#include "extension/db.h"
40#include "extension/input.h"
41#include "extension/output.h"
42#include "extension/print.h"
43#include "extension/system.h"
44#include "object/sp-root.h"
45#include "path/path-boolop.h"
46#include "svg/svg.h"
47#include "util/safe-printf.h"
48#include "util/units.h"
49
50constexpr auto PRINT_WMF = "org.inkscape.print.wmf";
51
52#ifndef U_PS_JOIN_MASK
53#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND)
54#endif
55
57
58static bool clipset = false;
59static uint32_t BLTmode = 0;
60
65
66void
67Wmf::print_document_to_file(SPDocument *doc, const gchar *filename)
68{
70 SPPrintContext context;
71 const gchar *oldconst;
72 gchar *oldoutput;
73
74 doc->ensureUpToDate();
75
77 oldconst = mod->get_param_string("destination");
78 oldoutput = g_strdup(oldconst);
79 mod->set_param_string("destination", filename);
80
81/* Start */
82 context.module = mod;
83 /* fixme: This has to go into module constructor somehow */
84 /* Create new arena */
85 mod->base = doc->getRoot();
86 Inkscape::Drawing drawing;
87 mod->dkey = SPItem::display_key_new(1);
88 mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY);
89 drawing.setRoot(mod->root);
90 /* Print document */
91 if (mod->begin(doc)) {
92 g_free(oldoutput);
93 mod->base->invoke_hide(mod->dkey);
94 mod->base = nullptr;
95 mod->root = nullptr;
97 }
98 mod->base->invoke_print(&context);
99 mod->finish();
100 /* Release arena */
101 mod->base->invoke_hide(mod->dkey);
102 mod->base = nullptr;
103 mod->root = nullptr; // deleted by invoke_hide
104/* end */
105
106 mod->set_param_string("destination", oldoutput);
107 g_free(oldoutput);
108
109 return;
110}
111
112
113void
114Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
115{
117
119 if (ext == nullptr)
120 return;
121
122 bool new_val = mod->get_param_bool("textToPath");
123 bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug
124 // reserve FixPPT2 for opacity bug. Currently WMF does not export opacity values
125 bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug
126 bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug
127 bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard WMF hatch
128
129 TableGen( //possibly regenerate the unicode-convert tables
130 mod->get_param_bool("TnrToSymbol"),
131 mod->get_param_bool("TnrToWingdings"),
132 mod->get_param_bool("TnrToZapfDingbats"),
133 mod->get_param_bool("UsePUA")
134 );
135
136 ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintWmf::init or a mysterious failure will result!
137 ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine);
138 ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys);
139 ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch);
140 ext->set_param_bool("textToPath", new_val);
141
142 // ensure usage of dot as decimal separator in scanf/printf functions (independently of current locale)
143 char *oldlocale = g_strdup(setlocale(LC_NUMERIC, nullptr));
144 setlocale(LC_NUMERIC, "C");
145
146 print_document_to_file(doc, filename);
147
148 // restore decimal separator used in scanf/printf functions to initial value
149 setlocale(LC_NUMERIC, oldlocale);
150 g_free(oldlocale);
151
152 return;
153}
154
155
156/* WMF has no worldTransform, so this always returns 1.0. Retain it to keep WMF and WMF in sync as much as possible.*/
158 return 1.0;
159}
160
161/* WMF has no worldTransform, so this always returns an Identity rotation matrix, but the offsets may have values.*/
162std::string Wmf::current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset){
163 SVGOStringStream cxform;
164 double scale = current_scale(d);
165 cxform << "\"matrix(";
166 cxform << 1.0/scale; cxform << ",";
167 cxform << 0.0; cxform << ",";
168 cxform << 0.0; cxform << ",";
169 cxform << 1.0/scale; cxform << ",";
170 if(useoffset){ cxform << x; cxform << ","; cxform << y; }
171 else { cxform << "0,0"; }
172 cxform << ")\"";
173 return(cxform.str());
174}
175
176/* WMF has no worldTransform, so this always returns 0. Retain it to keep WMF and WMF in sync as much as possible.*/
178 return 0.0;
179}
180
181/* Add another 100 blank slots to the hatches array.
182*/
184 d->hatches.size += 100;
185 d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *));
186}
187
188/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
189*/
191 int i;
192 for(i=0; i<d->hatches.count; i++){
193 if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
194 }
195 return(0);
196}
197
198class TagEmitter
199{
200public:
201 TagEmitter(Glib::ustring & p_defs, char * p_tmpcolor, char * p_hpathname):
202 defs(p_defs), tmpcolor(p_tmpcolor), hpathname(p_hpathname)
203 {
204 };
205 void append(const char *prefix, const char * inner)
206 {
207 defs += " ";
208 defs += prefix;
209 defs += hpathname;
210 defs += inner;
211 defs += tmpcolor;
212 defs += "\" />\n";
213 }
214
215protected:
216 Glib::ustring & defs;
217 char * tmpcolor, * hpathname;
218};
219
220/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one
221 does not exist it is added to the hatches list and also entered into <defs>.
222 This is also used to add the path part of the hatches, which they reference with a xlink:href
223*/
224uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){
225 char hatchname[64]; // big enough
226 char hpathname[64]; // big enough
227 char hbkname[64]; // big enough
228 char tmpcolor[8];
229 char bkcolor[8];
230 uint32_t idx;
231
232 switch(hatchType){
233 case U_HS_SOLIDTEXTCLR:
234 case U_HS_DITHEREDTEXTCLR:
235 safeprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
236 break;
237 case U_HS_SOLIDBKCLR:
238 case U_HS_DITHEREDBKCLR:
239 safeprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
240 break;
241 default:
242 safeprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
243 break;
244 }
245 auto & defs = d->defs;
246 TagEmitter a(defs, tmpcolor, hpathname);
247
248 /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch.
249 This will be used late to compose, or recompose the transparent or opaque final hatch.*/
250
251 std::string refpath; // used to reference later the path pieces which are about to be created
252 safeprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor);
253 idx = in_hatches(d,hpathname);
254 if(!idx){ // add path/color if not already present
255 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
256 d->hatches.strings[d->hatches.count++]=strdup(hpathname);
257
258 defs += "\n";
259 switch(hatchType){
260 case U_HS_HORIZONTAL:
261 a.append("<path id=\"",
262 "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#");
263 break;
264 case U_HS_VERTICAL:
265 a.append("<path id=\"",
266 "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#");
267 break;
268 case U_HS_FDIAGONAL:
269 a.append("<line id=\"sub",
270 "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#");
271 break;
272 case U_HS_BDIAGONAL:
273 a.append("<line id=\"sub",
274 "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#");
275 break;
276 case U_HS_CROSS:
277 a.append("<path id=\"",
278 "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#");
279 break;
280 case U_HS_DIAGCROSS:
281 a.append("<line id=\"subfd",
282 "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#");
283 a.append("<line id=\"subbd",
284 "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#");
285 break;
286 case U_HS_SOLIDCLR:
287 case U_HS_DITHEREDCLR:
288 case U_HS_SOLIDTEXTCLR:
289 case U_HS_DITHEREDTEXTCLR:
290 case U_HS_SOLIDBKCLR:
291 case U_HS_DITHEREDBKCLR:
292 default:
293 a.append("<path id=\"",
294 "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"stroke:none;fill:#");
295 break;
296 }
297 }
298
299 // References to paths possibly just created above. These will be used in the actual patterns.
300 switch(hatchType){
301 case U_HS_HORIZONTAL:
302 case U_HS_VERTICAL:
303 case U_HS_CROSS:
304 case U_HS_SOLIDCLR:
305 case U_HS_DITHEREDCLR:
306 case U_HS_SOLIDTEXTCLR:
307 case U_HS_DITHEREDTEXTCLR:
308 case U_HS_SOLIDBKCLR:
309 case U_HS_DITHEREDBKCLR:
310 default:
311 refpath += " <use xlink:href=\"#";
312 refpath += hpathname;
313 refpath += "\" />\n";
314 break;
315 case U_HS_FDIAGONAL:
316 case U_HS_BDIAGONAL:
317 refpath += " <use xlink:href=\"#sub";
318 refpath += hpathname;
319 refpath += "\" />\n";
320 refpath += " <use xlink:href=\"#sub";
321 refpath += hpathname;
322 refpath += "\" transform=\"translate(6,0)\" />\n";
323 refpath += " <use xlink:href=\"#sub";
324 refpath += hpathname;
325 refpath += "\" transform=\"translate(-6,0)\" />\n";
326 break;
327 case U_HS_DIAGCROSS:
328 refpath += " <use xlink:href=\"#subfd";
329 refpath += hpathname;
330 refpath += "\" />\n";
331 refpath += " <use xlink:href=\"#subfd";
332 refpath += hpathname;
333 refpath += "\" transform=\"translate(6,0)\"/>\n";
334 refpath += " <use xlink:href=\"#subfd";
335 refpath += hpathname;
336 refpath += "\" transform=\"translate(-6,0)\"/>\n";
337 refpath += " <use xlink:href=\"#subbd";
338 refpath += hpathname;
339 refpath += "\" />\n";
340 refpath += " <use xlink:href=\"#subbd";
341 refpath += hpathname;
342 refpath += "\" transform=\"translate(6,0)\"/>\n";
343 refpath += " <use xlink:href=\"#subbd";
344 refpath += hpathname;
345 refpath += "\" transform=\"translate(-6,0)\"/>\n";
346 break;
347 }
348
349 if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){
350 safeprintf(hatchname,"WMFhatch%d_%s",hatchType,tmpcolor);
351 safeprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor);
352 idx = in_hatches(d,hatchname);
353 if(!idx){ // add it if not already present
354 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
355 d->hatches.strings[d->hatches.count++]=strdup(hatchname);
356 defs += "\n";
357 defs += " <pattern id=\"";
358 defs += hatchname;
359 defs += "\" xlink:href=\"#WMFhbasepattern\">\n";
360 defs += refpath;
361 defs += " </pattern>\n";
362 idx = d->hatches.count;
363 }
364 }
365 else { // bkMode==U_OPAQUE
366 /* Set up an object in the defs for this background, if there is not one already there */
367 safeprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
368 safeprintf(hbkname,"WMFhbkclr_%s",bkcolor);
369 idx = in_hatches(d,hbkname);
370 if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name.
371 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
372 d->hatches.strings[d->hatches.count++]=strdup(hbkname);
373
374 defs += "\n";
375 defs += " <rect id=\"";
376 defs += hbkname;
377 defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
378 defs += bkcolor;
379 defs += "\" />\n";
380 }
381
382 // this is the pattern, its name will show up in Inkscape's pattern selector
383 safeprintf(hatchname,"WMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor);
384 idx = in_hatches(d,hatchname);
385 if(!idx){ // add it if not already present
386 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
387 d->hatches.strings[d->hatches.count++]=strdup(hatchname);
388 defs += "\n";
389 defs += " <pattern id=\"";
390 defs += hatchname;
391 defs += "\" xlink:href=\"#WMFhbasepattern\">\n";
392 defs += " <use xlink:href=\"#";
393 defs += hbkname;
394 defs += "\" />\n";
395 defs += refpath;
396 defs += " </pattern>\n";
397 idx = d->hatches.count;
398 }
399 }
400 return(idx-1);
401}
402
403/* Add another 100 blank slots to the images array.
404*/
406 d->images.size += 100;
407 d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *));
408}
409
410/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
411*/
413 int i;
414 for(i=0; i<d->images.count; i++){
415 if(strcmp(test,d->images.strings[i])==0)return(i+1);
416 }
417 return(0);
418}
419
420/* (Conditionally) add an image from a DIB. If a matching image already exists nothing happens. If one
421 does not exist it is added to the images list and also entered into <defs>.
422
423*/
424uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage){
425
426 uint32_t idx;
427 char imagename[64]; // big enough
428 char xywh[64]; // big enough
429 int dibparams = U_BI_UNKNOWN; // type of image not yet determined
430
431 MEMPNG mempng; // PNG in memory comes back in this
432 mempng.buffer = nullptr;
433
434 char *rgba_px = nullptr; // RGBA pixels
435 const char *px = nullptr; // DIB pixels
436 const U_RGBQUAD *ct = nullptr; // DIB color table
437 uint32_t numCt;
438 int32_t width, height, colortype, invert; // if needed these values will be set by wget_DIB_params
439 if(iUsage == U_DIB_RGB_COLORS){
440 // next call returns pointers and values, but allocates no memory
441 dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert);
442 if(dibparams == U_BI_RGB){
443 if(!DIB_to_RGBA(
444 px, // DIB pixel array
445 ct, // DIB color table
446 numCt, // DIB color table number of entries
447 &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
448 width, // Width of pixel array in record
449 height, // Height of pixel array in record
450 colortype, // DIB BitCount Enumeration
451 numCt, // Color table used if not 0
452 invert // If DIB rows are in opposite order from RGBA rows
453 )){
454 toPNG( // Get the image from the RGBA px into mempng
455 &mempng,
456 width, height, // of the SRC bitmap
457 rgba_px
458 );
459 free(rgba_px);
460 }
461 }
462 }
463
464 gchar *base64String=nullptr;
465 if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ // image was binary png or jpg in source file
466 base64String = g_base64_encode((guchar*) px, numCt );
467 }
468 else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
469 base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
470 free(mempng.buffer);
471 }
472 else { // failed conversion, insert the common bad image picture
473 width = 3;
474 height = 4;
475 base64String = bad_image_png();
476 }
477 idx = in_images(d, (char *) base64String);
478 auto & defs = d->defs;
479 if(!idx){ // add it if not already present - we looked at the actual data for comparison
480 if(d->images.count == d->images.size){ enlarge_images(d); }
481 idx = d->images.count;
482 d->images.strings[d->images.count++]=strdup(base64String);
483
484 safeprintf(imagename,"WMFimage%d",idx++);
485 safeprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
486
487 defs += "\n";
488 defs += " <image id=\"";
489 defs += imagename;
490 defs += "\"\n ";
491 defs += xywh;
492 defs += "\n";
493 if(dibparams == U_BI_JPEG){ defs += " xlink:href=\"data:image/jpeg;base64,"; }
494 else { defs += " xlink:href=\"data:image/png;base64,"; }
495 defs += base64String;
496 defs += "\"\n";
497 defs += " preserveAspectRatio=\"none\"\n";
498 defs += " />\n";
499
500
501 defs += "\n";
502 defs += " <pattern id=\"";
503 defs += imagename;
504 defs += "_ref\"\n ";
505 defs += xywh;
506 defs += "\n patternUnits=\"userSpaceOnUse\"";
507 defs += " >\n";
508 defs += " <use id=\"";
509 defs += imagename;
510 defs += "_ign\" ";
511 defs += " xlink:href=\"#";
512 defs += imagename;
513 defs += "\" />\n";
514 defs += " ";
515 defs += " </pattern>\n";
516 }
517 g_free(base64String); //wait until this point to free because it might be a duplicate image
518 return(idx-1);
519}
520
521/* (Conditionally) add an image from a Bitmap16. If a matching image already exists nothing happens. If one
522 does not exist it is added to the images list and also entered into <defs>.
523
524*/
525uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px){
526
527 uint32_t idx;
528 char imagename[64]; // big enough
529 char xywh[64]; // big enough
530
531 MEMPNG mempng; // PNG in memory comes back in this
532 mempng.buffer = nullptr;
533
534 char *rgba_px = nullptr; // RGBA pixels
535 const U_RGBQUAD *ct = nullptr; // color table, always NULL here
536 int32_t width, height, colortype, numCt, invert;
537 numCt = 0;
538 width = Bm16.Width; // bitmap width in pixels.
539 height = Bm16.Height; // bitmap height in scan lines.
540 colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
541 invert = 0;
542 if(colortype < 16)return(U_WMR_INVALID); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
543
544 if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works.
545 px, // DIB pixel array
546 ct, // DIB color table (always NULL here)
547 numCt, // DIB color table number of entries (always 0)
548 &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
549 width, // Width of pixel array
550 height, // Height of pixel array
551 colortype, // DIB BitCount Enumeration
552 numCt, // Color table used if not 0
553 invert // If DIB rows are in opposite order from RGBA rows
554 )){
555 toPNG( // Get the image from the RGBA px into mempng
556 &mempng,
557 width, height, // of the SRC bitmap
558 rgba_px
559 );
560 free(rgba_px);
561 }
562
563 gchar *base64String=nullptr;
564 if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine
565 base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
566 free(mempng.buffer);
567 }
568 else { // failed conversion, insert the common bad image picture
569 width = 3;
570 height = 4;
571 base64String = bad_image_png();
572 }
573
574 idx = in_images(d, (char *) base64String);
575 auto & defs = d->defs;
576 if(!idx){ // add it if not already present - we looked at the actual data for comparison
577 if(d->images.count == d->images.size){ enlarge_images(d); }
578 idx = d->images.count;
579 d->images.strings[d->images.count++]=g_strdup(base64String);
580
581 safeprintf(imagename,"WMFimage%d",idx++);
582 safeprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
583
584 defs += "\n";
585 defs += " <image id=\"";
586 defs += imagename;
587 defs += "\"\n ";
588 defs += xywh;
589 defs += "\n";
590 defs += " xlink:href=\"data:image/png;base64,";
591 defs += base64String;
592 defs += "\"\n";
593 defs += " preserveAspectRatio=\"none\"\n";
594 defs += " />\n";
595
596
597 defs += "\n";
598 defs += " <pattern id=\"";
599 defs += imagename;
600 defs += "_ref\"\n ";
601 defs += xywh;
602 defs += "\n patternUnits=\"userSpaceOnUse\"";
603 defs += " >\n";
604 defs += " <use id=\"";
605 defs += imagename;
606 defs += "_ign\" ";
607 defs += " xlink:href=\"#";
608 defs += imagename;
609 defs += "\" />\n";
610 defs += " </pattern>\n";
611 }
612 g_free(base64String); //wait until this point to free because it might be a duplicate image
613 return(idx-1);
614}
615
616/* Add another 100 blank slots to the clips array.
617*/
619 d->clips.size += 100;
620 d->clips.strings = (char **) realloc(d->clips.strings,d->clips.size * sizeof(char *));
621}
622
623/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
624*/
626 int i;
627 for(i=0; i<d->clips.count; i++){
628 if(strcmp(test,d->clips.strings[i])==0)return(i+1);
629 }
630 return(0);
631}
632
633/* (Conditionally) add a clip.
634 If a matching clip already exists nothing happens
635 If one does exist it is added to the clips list, entered into <defs>.
636*/
637void Wmf::add_clips(PWMF_CALLBACK_DATA d, const char *clippath, unsigned int logic){
638 int op = combine_ops_to_livarot(logic);
639 Geom::PathVector combined_vect;
640 std::string combined;
641 if (op >= 0 && d->dc[d->level].clip_id) {
642 unsigned int real_idx = d->dc[d->level].clip_id - 1;
643 Geom::PathVector old_vect = sp_svg_read_pathv(d->clips.strings[real_idx]);
644 Geom::PathVector new_vect = sp_svg_read_pathv(clippath);
645 combined_vect = sp_pathvector_boolop(new_vect, old_vect, (BooleanOp) op , (FillRule) fill_oddEven, (FillRule) fill_oddEven);
646 combined = sp_svg_write_path(combined_vect);
647 }
648 else {
649 combined = clippath; // COPY operation, erases everything and starts a new one
650 }
651
652 uint32_t idx = in_clips(d, combined.c_str());
653 if(!idx){ // add clip if not already present
654 if(d->clips.count == d->clips.size){ enlarge_clips(d); }
655 d->clips.strings[d->clips.count++] = strdup(combined.c_str());
656 d->dc[d->level].clip_id = d->clips.count; // one more than the slot where it is actually stored
657 SVGOStringStream tmp_clippath;
658 tmp_clippath << "\n<clipPath";
659 tmp_clippath << "\n\tclipPathUnits=\"userSpaceOnUse\" ";
660 tmp_clippath << "\n\tid=\"clipWmfPath" << d->dc[d->level].clip_id << "\"";
661 tmp_clippath << " >";
662 tmp_clippath << "\n\t<path d=\"";
663 tmp_clippath << combined;
664 tmp_clippath << "\"";
665 tmp_clippath << "\n\t/>";
666 tmp_clippath << "\n</clipPath>";
667 d->outdef += tmp_clippath.str().c_str();
668 }
669 else {
670 d->dc[d->level].clip_id = idx;
671 }
672}
673
674
675
676void
678{
679// SVGOStringStream tmp_id;
680 SVGOStringStream tmp_style;
681 char tmp[1024] = {0};
682
683 auto fill = d->dc[d->level].style.fill.getColor();
684 auto stroke = d->dc[d->level].style.stroke.getColor();
685
686 // for U_WMR_BITBLT with no image, try to approximate some of these operations/
687 // Assume src color is "white"
688 if(d->dwRop3){
689 switch(d->dwRop3){
690 case U_PATINVERT: // treat all of these as black
691 case U_SRCINVERT:
692 case U_DSTINVERT:
693 case U_BLACKNESS:
694 case U_SRCERASE:
695 case U_NOTSRCCOPY:
696 fill.set("black");
697 break;
698 case U_SRCCOPY: // treat all of these as white
699 case U_NOTSRCERASE:
700 case U_PATCOPY:
701 case U_WHITENESS:
702 fill.set("white");
703 break;
704 case U_SRCPAINT: // use the existing color
705 case U_SRCAND:
706 case U_MERGECOPY:
707 case U_MERGEPAINT:
708 case U_PATPAINT:
709 default:
710 break;
711 }
712 d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
713 }
714
715 // Implement some of these, the ones where the original screen color does not matter.
716 // The options that merge screen and pen colors cannot be done correctly because we
717 // have no way of knowing what color is already on the screen. For those just pass the
718 // pen color through.
719 switch(d->dwRop2){
720 case U_R2_BLACK:
721 fill.set("black");
722 stroke.set("black");
723 break;
724 case U_R2_NOTMERGEPEN:
725 case U_R2_MASKNOTPEN:
726 break;
727 case U_R2_NOTCOPYPEN:
728 fill.invert();
729 stroke.invert();
730 break;
731 case U_R2_MASKPENNOT:
732 case U_R2_NOT:
733 case U_R2_XORPEN:
734 case U_R2_NOTMASKPEN:
735 case U_R2_NOTXORPEN:
736 case U_R2_NOP:
737 case U_R2_MERGENOTPEN:
738 case U_R2_COPYPEN:
739 case U_R2_MASKPEN:
740 case U_R2_MERGEPENNOT:
741 case U_R2_MERGEPEN:
742 break;
743 case U_R2_WHITE:
744 fill.set("white");
745 stroke.set("white");
746 break;
747 default:
748 break;
749 }
750
751
752// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
753// d->outsvg += tmp_id.str().c_str();
754 d->outsvg += "\n\tstyle=\"";
755 if (!d->dc[d->level].fill_set || ( d->mask & U_DRAW_NOFILL)) { // nofill are lines and arcs
756 tmp_style << "fill:none;";
757 } else {
758 switch(d->dc[d->level].fill_mode){
759 // both of these use the url(#) method
760 case DRAW_PATTERN:
761 snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
762 tmp_style << tmp;
763 break;
764 case DRAW_IMAGE:
765 snprintf(tmp, 1023, "fill:url(#WMFimage%d_ref); ",d->dc[d->level].fill_idx);
766 tmp_style << tmp;
767 break;
768 case DRAW_PAINT:
769 default: // <-- this should never happen, but just in case...
771 tmp_style << "fill:" << fill.toString(false).c_str() << ";";
772 break;
773 }
774 snprintf(
775 tmp, 1023,
776 "fill-rule:%s;",
777 (d->dc[d->level].style.fill_rule.value == SP_WIND_RULE_NONZERO ? "evenodd" : "nonzero")
778 );
779 tmp_style << tmp;
780 tmp_style << "fill-opacity:1;";
781
782 // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately
783 if(
784 (d->dc[d->level].fill_set ) &&
785 (d->dc[d->level].stroke_set ) &&
786 (d->dc[d->level].style.stroke_width.value == 1 ) &&
787 (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) &&
788 (
789 (d->dc[d->level].fill_mode != DRAW_PAINT) ||
790 fill == stroke
791 )
792 ){
793 d->dc[d->level].stroke_set = false;
794 }
795 }
796
797 if (!d->dc[d->level].stroke_set) {
798 tmp_style << "stroke:none;";
799 } else {
800 switch(d->dc[d->level].stroke_mode){
801 // both of these use the url(#) method
802 case DRAW_PATTERN:
803 snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
804 tmp_style << tmp;
805 break;
806 case DRAW_IMAGE:
807 snprintf(tmp, 1023, "stroke:url(#WMFimage%d_ref); ",d->dc[d->level].stroke_idx);
808 tmp_style << tmp;
809 break;
810 case DRAW_PAINT:
811 default: // <-- this should never happen, but just in case...
813 tmp_style << "stroke:" << stroke.toString(false).c_str() << ";";
814 break;
815 }
816 if(d->dc[d->level].style.stroke_width.value){
817 tmp_style << "stroke-width:" <<
818 MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
819 }
820 else { // In a WMF a 0 width pixel means "1 pixel"
821 tmp_style << "stroke-width:" << pix_to_abs_size( d, 1 ) << "px;";
822 }
823
824 tmp_style << "stroke-linecap:" <<
825 (
826 d->dc[d->level].style.stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ? "butt" :
827 d->dc[d->level].style.stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ? "round" :
828 d->dc[d->level].style.stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ? "square" :
829 "unknown"
830 ) << ";";
831
832 tmp_style << "stroke-linejoin:" <<
833 (
834 d->dc[d->level].style.stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ? "miter" :
835 d->dc[d->level].style.stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ? "round" :
836 d->dc[d->level].style.stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ? "bevel" :
837 "unknown"
838 ) << ";";
839
840 // Set miter limit if known, even if it is not needed immediately (not miter)
841 tmp_style << "stroke-miterlimit:" <<
842 MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
843
844 if (d->dc[d->level].style.stroke_dasharray.set &&
845 !d->dc[d->level].style.stroke_dasharray.values.empty())
846 {
847 tmp_style << "stroke-dasharray:";
848 for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) {
849 if (i)
850 tmp_style << ",";
851 tmp_style << d->dc[d->level].style.stroke_dasharray.values[i].value;
852 }
853 tmp_style << ";";
854 tmp_style << "stroke-dashoffset:0;";
855 } else {
856 tmp_style << "stroke-dasharray:none;";
857 }
858 tmp_style << "stroke-opacity:1;";
859 }
860 tmp_style << "\" ";
861 if (d->dc[d->level].clip_id)
862 tmp_style << "\n\tclip-path=\"url(#clipWmfPath" << d->dc[d->level].clip_id << ")\" ";
863
864 d->outsvg += tmp_style.str().c_str();
865}
866
867
868double
870{
871 double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
872 double tmp;
873 tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX;
874 tmp -= d->ulCornerOutX; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
875 return(tmp);
876}
877
878double
880{
881 double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0);
882 double tmp;
883 tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY;
884 tmp -= d->ulCornerOutY; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
885 return(tmp);
886}
887
888
889double
890Wmf::pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double /*py*/)
891{
892 double x = _pix_x_to_point(d, px);
893 return x;
894}
895
896double
897Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double /*px*/, double py)
898{
899 double y = _pix_y_to_point(d, py);
900 return y;
901
902}
903
904double
906{
907 double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d));
908 return ppx;
909}
910
911/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of WMF x,y coordinates
912*/
913std::string Wmf::pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y){
914 SVGOStringStream cxform;
915 cxform << pix_to_x_point(d,x,y);
916 cxform << ",";
917 cxform << pix_to_y_point(d,x,y);
918 return(cxform.str());
919}
920
921
922void
924{
925 int width;
926 char *record = nullptr;
927 U_PEN up;
928
929 if (index < 0 && index >= d->n_obj){ return; }
930 record = d->wmf_obj[index].record;
931 if(!record){ return; }
932 d->dc[d->level].active_pen = index;
933
934 (void) U_WMRCREATEPENINDIRECT_get(record, &up);
935 width = up.Widthw[0]; // width is stored in the first 16 bits of the 32.
936
937 switch (up.Style & U_PS_STYLE_MASK) {
938 case U_PS_DASH:
939 case U_PS_DOT:
940 case U_PS_DASHDOT:
941 case U_PS_DASHDOTDOT:
942 {
943 int penstyle = (up.Style & U_PS_STYLE_MASK);
944 SPILength spilength(1.f);
945 if (!d->dc[d->level].style.stroke_dasharray.values.empty() &&
946 (d->level == 0 || (d->level > 0 && d->dc[d->level].style.stroke_dasharray !=
947 d->dc[d->level - 1].style.stroke_dasharray)))
948 d->dc[d->level].style.stroke_dasharray.values.clear();
949 if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
950 spilength.setDouble(3);
951 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
952 spilength.setDouble(1);
953 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
954 }
955 if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
956 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
957 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
958 }
959 if (penstyle==U_PS_DASHDOTDOT) {
960 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
961 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
962 }
963
964 d->dc[d->level].style.stroke_dasharray.set = true;
965 break;
966 }
967
968 case U_PS_SOLID:
969 default:
970 {
971 d->dc[d->level].style.stroke_dasharray.set = false;
972 break;
973 }
974 }
975
976 switch (up.Style & U_PS_ENDCAP_MASK) {
977 case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_ROUND; break; }
978 case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_SQUARE; break; }
979 case U_PS_ENDCAP_FLAT:
980 default: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_BUTT; break; }
981 }
982
983 switch (up.Style & U_PS_JOIN_MASK) {
984 case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_BEVEL; break; }
985 case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_MITER; break; }
986 case U_PS_JOIN_ROUND:
987 default: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_ROUND; break; }
988 }
989
990
991 double pen_width;
992 if (up.Style == U_PS_NULL) {
993 d->dc[d->level].stroke_set = false;
994 pen_width =0.0;
995 } else if (width) {
996 d->dc[d->level].stroke_set = true;
997 int cur_level = d->level;
998 d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC.
999 pen_width = pix_to_abs_size( d, width );
1000 d->level = cur_level;
1001 } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
1002 d->dc[d->level].stroke_set = true;
1003 int cur_level = d->level;
1004 d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC.
1005 pen_width = pix_to_abs_size( d, 1 );
1006 d->level = cur_level;
1007 }
1008 d->dc[d->level].style.stroke_width.value = pen_width;
1009 d->dc[d->level].style.stroke.setColor(Colors::Color(U_RGB_COMPOSE(up.Color), false));
1010}
1011
1012
1013void
1015{
1016 uint8_t iType;
1017 char *record;
1018 const char *membrush;
1019
1020 if (index < 0 || index >= d->n_obj)return;
1021 record = d->wmf_obj[index].record;
1022 if(!record)return;
1023 d->dc[d->level].active_brush = index;
1024
1025 iType = *(uint8_t *)(record + offsetof(U_METARECORD, iType ) );
1026 if(iType == U_WMR_CREATEBRUSHINDIRECT){
1027 U_WLOGBRUSH lb;
1028 (void) U_WMRCREATEBRUSHINDIRECT_get(record, &membrush);
1029 memcpy(&lb, membrush, U_SIZE_WLOGBRUSH);
1030 if(lb.Style == U_BS_SOLID){
1031 d->dc[d->level].style.fill.setColor(Colors::Color(U_RGB_COMPOSE(lb.Color)));
1032 d->dc[d->level].fill_mode = DRAW_PAINT;
1033 d->dc[d->level].fill_set = true;
1034 }
1035 else if(lb.Style == U_BS_HATCHED){
1036 d->dc[d->level].fill_idx = add_hatch(d, lb.Hatch, lb.Color);
1037 d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
1038 d->dc[d->level].fill_mode = DRAW_PATTERN;
1039 d->dc[d->level].fill_set = true;
1040 }
1041 else if(lb.Style == U_BS_NULL){
1042 d->dc[d->level].fill_mode = DRAW_PAINT; // set it to something
1043 d->dc[d->level].fill_set = false;
1044 }
1045 }
1046 else if(iType == U_WMR_DIBCREATEPATTERNBRUSH){
1047 uint32_t tidx;
1048 uint16_t Style;
1049 uint16_t cUsage;
1050 const char *Bm16h = nullptr; // Pointer to Bitmap16 header (px follows)
1051 const char *dib = nullptr; // Pointer to DIB
1052 (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib);
1053 if(dib || Bm16h){
1054 if(dib){ tidx = add_dib_image(d, dib, cUsage); }
1055 else {
1056 U_BITMAP16 Bm16;
1057 const char *px;
1058 memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16);
1059 px = Bm16h + U_SIZE_BITMAP16;
1060 tidx = add_bm16_image(d, Bm16, px);
1061 }
1062 if(tidx == U_WMR_INVALID){ // Problem with the image, for instance, an unsupported bitmap16 type
1063 d->dc[d->level].style.fill.setColor(Colors::Color(U_RGB_COMPOSE(d->dc[d->level].textColor), false));
1064 d->dc[d->level].fill_mode = DRAW_PAINT;
1065 }
1066 else {
1067 d->dc[d->level].fill_idx = tidx;
1068 d->dc[d->level].fill_mode = DRAW_IMAGE;
1069 }
1070 d->dc[d->level].fill_set = true;
1071 }
1072 else {
1073 g_message("Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled");
1074 }
1075 }
1076 else if(iType == U_WMR_CREATEPATTERNBRUSH){
1077 uint32_t tidx;
1078 int cbPx;
1079 U_BITMAP16 Bm16h;
1080 const char *px;
1081 if(U_WMRCREATEPATTERNBRUSH_get(record, &Bm16h, &cbPx, &px)){
1082 tidx = add_bm16_image(d, Bm16h, px);
1083 if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type
1084 d->dc[d->level].style.fill.setColor(Colors::Color(U_RGB_COMPOSE(d->dc[d->level].textColor), false));
1085 d->dc[d->level].fill_mode = DRAW_PAINT;
1086 }
1087 else {
1088 d->dc[d->level].fill_idx = tidx;
1089 d->dc[d->level].fill_mode = DRAW_IMAGE;
1090 }
1091 d->dc[d->level].fill_set = true;
1092 }
1093 }
1094}
1095
1096
1097void
1099{
1100 char *record = nullptr;
1101 const char *memfont;
1102 const char *facename;
1103 U_FONT font;
1104
1105 if (index < 0 || index >= d->n_obj)return;
1106 record = d->wmf_obj[index].record;
1107 if (!record)return;
1108 d->dc[d->level].active_font = index;
1109
1110
1111 (void) U_WMRCREATEFONTINDIRECT_get(record, &memfont);
1112 memcpy(&font,memfont,U_SIZE_FONT_CORE); //make sure it is in a properly aligned structure before touching it
1113 facename = memfont + U_SIZE_FONT_CORE;
1114
1115 /* The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT
1116 is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
1117 is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
1118 */
1119 int cur_level = d->level;
1120 d->level = d->wmf_obj[index].level;
1121 double font_size = pix_to_abs_size( d, font.Height );
1122 /* snap the font_size to the nearest 1/32nd of a point.
1123 (The size is converted from Pixels to points, snapped, and converted back.)
1124 See the notes where d->D2Pscale[XY] are set for the reason why.
1125 Typically this will set the font to the desired exact size. If some peculiar size
1126 was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
1127 font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8);
1128 d->level = cur_level;
1129 d->dc[d->level].style.font_size.computed = font_size;
1130 d->dc[d->level].style.font_weight.value =
1131 font.Weight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
1132 font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
1133 font.Weight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
1134 font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
1135 font.Weight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
1136 font.Weight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
1137 font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
1138 font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
1139 font.Weight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
1140 font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
1141 font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
1142 font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
1143 font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
1146 d->dc[d->level].style.text_decoration_line.underline = font.Underline;
1147 d->dc[d->level].style.text_decoration_line.line_through = font.StrikeOut;
1148 d->dc[d->level].style.text_decoration_line.set = true;
1149 d->dc[d->level].style.text_decoration_line.inherit = false;
1150
1151 // malformed WMF with empty filename may exist, ignore font change if encountered
1152 if(d->dc[d->level].font_name)free(d->dc[d->level].font_name);
1153 if(*facename){
1154 d->dc[d->level].font_name = strdup(facename);
1155 }
1156 else { // Malformed WMF might specify an empty font name
1157 d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
1158 }
1159 d->dc[d->level].style.baseline_shift.value = round((double)((font.Escapement + 3600) % 3600) / 10.0); // use baseline_shift instead of text_transform to avoid overflow
1160}
1161
1162/* Find the first free hole where an object may be stored.
1163 If there are not any return -1. This is a big error, possibly from a corrupt WMF file.
1164*/
1166{
1167 int index = d->low_water; // Start looking from here, it may already have been filled
1168 while(index < d->n_obj && d->wmf_obj[index].record != nullptr){ index++; }
1169 if(index >= d->n_obj)return(-1); // this is a big problem, percolate it back up so the program can get out of this gracefully
1170 d->low_water = index; // Could probably be index+1
1171 return(index);
1172}
1173
1174void
1176{
1177 if (index >= 0 && index < d->n_obj) {
1178 // If the active object is deleted set default draw values
1179 if(index == d->dc[d->level].active_pen){ // Use default pen: solid, black, 1 pixel wide
1180 d->dc[d->level].active_pen = -1;
1181 d->dc[d->level].style.stroke_dasharray.set = false;
1182 d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_SQUARE; // U_PS_ENDCAP_SQUARE
1183 d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_MITER; // U_PS_JOIN_MITER;
1184 d->dc[d->level].stroke_set = true;
1185 d->dc[d->level].style.stroke_width.value = 1.0;
1186 d->dc[d->level].style.stroke.setColor(Colors::Color(0x000000ff));
1187 }
1188 else if(index == d->dc[d->level].active_brush){
1189 d->dc[d->level].active_brush = -1;
1190 d->dc[d->level].fill_set = false;
1191 }
1192 else if(index == d->dc[d->level].active_font){
1193 d->dc[d->level].active_font = -1;
1194 if(d->dc[d->level].font_name){ free(d->dc[d->level].font_name);}
1195 d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
1196 d->dc[d->level].style.font_size.computed = 16.0;
1199 d->dc[d->level].style.text_decoration_line.underline = false;
1200 d->dc[d->level].style.text_decoration_line.line_through = false;
1201 d->dc[d->level].style.baseline_shift.value = 0;
1202 }
1203
1204
1205 d->wmf_obj[index].type = 0;
1206// We are keeping a copy of the WMR rather than just a structure. Currently that is not necessary as the entire
1207// WMF is read in at once and is stored in a big malloc. However, in past versions it was handled
1208// record by record, and we might need to do that again at some point in the future if we start running into WMF
1209// files too big to fit into memory.
1210 if (d->wmf_obj[index].record)
1211 free(d->wmf_obj[index].record);
1212 d->wmf_obj[index].record = nullptr;
1213 if(index < d->low_water)d->low_water = index;
1214 }
1215}
1216
1217
1218// returns the new index, or -1 on error.
1219int Wmf::insert_object(PWMF_CALLBACK_DATA d, int type, const char *record)
1220{
1221 int index = insertable_object(d);
1222 if(index>=0){
1223 d->wmf_obj[index].type = type;
1224 d->wmf_obj[index].level = d->level;
1225 d->wmf_obj[index].record = wmr_dup(record);
1226 }
1227 return(index);
1228}
1229
1230
1235uint32_t *Wmf::unknown_chars(size_t count){
1236 uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
1237 if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
1238 for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
1239 res[count]=0;
1240 return res;
1241}
1242
1256 double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage){
1257
1258 SVGOStringStream tmp_image;
1259 int dibparams = U_BI_UNKNOWN; // type of image not yet determined
1260
1261 tmp_image << "\n\t <image\n";
1262 if (d->dc[d->level].clip_id){
1263 tmp_image << "\tclip-path=\"url(#clipWmfPath" << d->dc[d->level].clip_id << ")\"\n";
1264 }
1265 tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
1266
1267 MEMPNG mempng; // PNG in memory comes back in this
1268 mempng.buffer = nullptr;
1269
1270 char *rgba_px = nullptr; // RGBA pixels
1271 char *sub_px = nullptr; // RGBA pixels, subarray
1272 const char *px = nullptr; // DIB pixels
1273 const U_RGBQUAD *ct = nullptr; // color table
1274 uint32_t numCt;
1275 int32_t width, height, colortype, invert; // if needed these values will be set in wget_DIB_params
1276 if(iUsage == U_DIB_RGB_COLORS){
1277 // next call returns pointers and values, but allocates no memory
1278 dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert);
1279 if(dibparams == U_BI_RGB){
1280 if(sw == 0 || sh == 0){
1281 sw = width;
1282 sh = height;
1283 }
1284 if(!DIB_to_RGBA(
1285 px, // DIB pixel array
1286 ct, // DIB color table
1287 numCt, // DIB color table number of entries
1288 &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
1289 width, // Width of pixel array
1290 height, // Height of pixel array
1291 colortype, // DIB BitCount Enumeration
1292 numCt, // Color table used if not 0
1293 invert // If DIB rows are in opposite order from RGBA rows
1294 )){
1295 sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
1296 rgba_px, // full pixel array from DIB
1297 width, // Width of pixel array
1298 height, // Height of pixel array
1299 sx,sy, // starting point in pixel array
1300 &sw,&sh // columns/rows to extract from the pixel array (output array size)
1301 );
1302
1303 if(!sub_px)sub_px=rgba_px;
1304 toPNG( // Get the image from the RGBA px into mempng
1305 &mempng,
1306 sw, sh, // size of the extracted pixel array
1307 sub_px
1308 );
1309 free(sub_px);
1310 }
1311 }
1312 }
1313
1314 gchar *base64String=nullptr;
1315 if(dibparams == U_BI_JPEG){ // image was binary jpg in source file
1316 tmp_image << " xlink:href=\"data:image/jpeg;base64,";
1317 base64String = g_base64_encode((guchar*) px, numCt );
1318 }
1319 else if(dibparams==U_BI_PNG){ // image was binary png in source file
1320 tmp_image << " xlink:href=\"data:image/png;base64,";
1321 base64String = g_base64_encode((guchar*) px, numCt );
1322 }
1323 else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
1324 tmp_image << " xlink:href=\"data:image/png;base64,";
1325 base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
1326 free(mempng.buffer);
1327 }
1328 else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
1329 tmp_image << " xlink:href=\"data:image/png;base64,";
1330 base64String = bad_image_png();
1331 }
1332 tmp_image << base64String;
1333 g_free(base64String);
1334
1335 tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
1336 tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
1337 tmp_image << " preserveAspectRatio=\"none\"\n";
1338 tmp_image << "/> \n";
1339
1340 d->outsvg += tmp_image.str().c_str();
1341 d->path = "";
1342}
1343
1358 double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh){
1359
1360 SVGOStringStream tmp_image;
1361
1362 tmp_image << "\n\t <image\n";
1363 if (d->dc[d->level].clip_id){
1364 tmp_image << "\tclip-path=\"url(#clipWmfPath" << d->dc[d->level].clip_id << ")\"\n";
1365 }
1366 tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
1367
1368 MEMPNG mempng; // PNG in memory comes back in this
1369 mempng.buffer = nullptr;
1370
1371 char *rgba_px = nullptr; // RGBA pixels
1372 char *sub_px = nullptr; // RGBA pixels, subarray
1373 const U_RGBQUAD *ct = nullptr; // color table
1374 int32_t width, height, colortype, numCt, invert;
1375
1376 numCt = 0;
1377 width = Bm16.Width; // bitmap width in pixels.
1378 height = Bm16.Height; // bitmap height in scan lines.
1379 colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
1380 invert = 0;
1381
1382 if(sw == 0 || sh == 0){
1383 sw = width;
1384 sh = height;
1385 }
1386
1387 if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
1388
1389 if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works.
1390 px, // DIB pixel array
1391 ct, // DIB color table (always NULL here)
1392 numCt, // DIB color table number of entries (always 0)
1393 &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
1394 width, // Width of pixel array
1395 height, // Height of pixel array
1396 colortype, // DIB BitCount Enumeration
1397 numCt, // Color table used if not 0
1398 invert // If DIB rows are in opposite order from RGBA rows
1399 )){
1400 sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
1401 rgba_px, // full pixel array from DIB
1402 width, // Width of pixel array
1403 height, // Height of pixel array
1404 sx,sy, // starting point in pixel array
1405 &sw,&sh // columns/rows to extract from the pixel array (output array size)
1406 );
1407
1408 if(!sub_px)sub_px=rgba_px;
1409 toPNG( // Get the image from the RGBA px into mempng
1410 &mempng,
1411 sw, sh, // size of the extracted pixel array
1412 sub_px
1413 );
1414 free(sub_px);
1415 }
1416
1417 gchar *base64String=nullptr;
1418 if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine
1419 tmp_image << " xlink:href=\"data:image/png;base64,";
1420 base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
1421 free(mempng.buffer);
1422 }
1423 else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
1424 tmp_image << " xlink:href=\"data:image/png;base64,";
1425 base64String = bad_image_png();
1426 }
1427 tmp_image << base64String;
1428 g_free(base64String);
1429
1430 tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
1431 tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
1432 tmp_image << " preserveAspectRatio=\"none\"\n";
1433 tmp_image << "/> \n";
1434
1435 d->outsvg += tmp_image.str().c_str();
1436 d->path = "";
1437}
1438
1446//THis was a callback, just build it into a normal function
1447int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d)
1448{
1449 uint32_t off=0;
1450 uint32_t wmr_mask;
1451 int OK =1;
1452 int file_status=1;
1453 TCHUNK_SPECS tsp;
1454 uint8_t iType;
1455 int nSize; // size of the current record, in bytes, or an error value if <=0
1456 const char *blimit = contents + length; // 1 byte past the end of the last record
1457
1458 /* variables used to retrieve data from WMF records */
1459 uint16_t utmp16;
1460 U_POINT16 pt16; // any point
1461 U_RECT16 rc; // any rectangle, usually a bounding rectangle
1462 U_POINT16 Dst; // Destination coordinates
1463 U_POINT16 cDst; // Destination w,h, if different from Src
1464 U_POINT16 Src; // Source coordinates
1465 U_POINT16 cSrc; // Source w,h, if different from Dst
1466 U_POINT16 cwh; // w,h, if Src and Dst use the same values
1467 uint16_t cUsage; // colorusage enumeration
1468 uint32_t dwRop3; // raster operations, these are only barely supported here
1469 const char *dib; // DIB style image structure
1470 U_BITMAP16 Bm16; // Bitmap16 style image structure
1471 const char *px; // Image for Bm16
1472 uint16_t cPts; // number of points in the next variable
1473 const char *points; // any list of U_POINT16, may not be aligned
1474 int16_t tlen; // length of returned text, in bytes
1475 const char *text; // returned text, Latin1 encoded
1476 uint16_t Opts;
1477 const int16_t *dx; // character spacing for one text mode, inkscape ignores this
1478 double left, right, top, bottom; // values used, because a bounding rect can have values reversed L<->R, T<->B
1479
1480 uint16_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
1481 U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
1482
1483 // code for end user debugging
1484 int wDbgRecord=0;
1485 int wDbgComment=0;
1486 int wDbgFinal=0;
1487 char const* wDbgString = getenv( "INKSCAPE_DBG_WMF" );
1488 if ( wDbgString != nullptr ) {
1489 if(strstr(wDbgString,"RECORD")){ wDbgRecord = 1; }
1490 if(strstr(wDbgString,"COMMENT")){ wDbgComment = 1; }
1491 if(strstr(wDbgString,"FINAL")){ wDbgFinal = 1; }
1492 }
1493
1494 /* initialize the tsp for text reassembly */
1495 tsp.string = nullptr;
1496 tsp.ori = 0.0; /* degrees */
1497 tsp.fs = 12.0; /* font size */
1498 tsp.x = 0.0;
1499 tsp.y = 0.0;
1500 tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/
1501 tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */
1502 tsp.taln = ALILEFT + ALIBASE;
1503 tsp.ldir = LDIR_LR;
1504 tsp.spaces = 0; // this field is only used for debugging
1505 tsp.color.Red = 0; /* RGB Black */
1506 tsp.color.Green = 0; /* RGB Black */
1507 tsp.color.Blue = 0; /* RGB Black */
1508 tsp.color.Reserved = 0; /* not used */
1509 tsp.italics = 0;
1510 tsp.weight = 80;
1511 tsp.decoration = TXTDECOR_NONE;
1512 tsp.condensed = 100;
1513 tsp.co = 0;
1514 tsp.fi_idx = -1; /* set to an invalid */
1515 tsp.rt_tidx = -1; /* set to an invalid */
1516
1517 SVGOStringStream dbg_str;
1518
1519 /* There is very little information in WMF headers, get what is there. In many cases pretty much everything will have to
1520 default. If there is no placeable header we know pretty much nothing about the size of the page, in which case
1521 assume that it is 1440 WMF pixels/inch and make the page A4 landscape. That is almost certainly the wrong page size
1522 but it has to be set to something, and nothing horrible happens if the drawing goes off the page. */
1523 {
1524
1525 U_WMRPLACEABLE Placeable;
1526 U_WMRHEADER Header;
1527 off = 0;
1528 nSize = wmfheader_get(contents, blimit, &Placeable, &Header);
1529 if (!nSize) {
1530 return(0);
1531 }
1532 if(!Header.nObjects){ Header.nObjects = 256; }// there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway.
1533 d->n_obj = Header.nObjects;
1534 d->wmf_obj = new WMF_OBJECT[d->n_obj];
1535 d->low_water = 0; // completely empty at this point, so start searches at 0
1536
1537 // Init the new wmf_obj list elements to null, provided the
1538 // dynamic allocation succeeded.
1539 if ( d->wmf_obj != nullptr )
1540 {
1541 for( int i=0; i < d->n_obj; ++i )
1542 d->wmf_obj[i].record = nullptr;
1543 } //if
1544
1545 if(!Placeable.Inch){ Placeable.Inch= 1440; }
1546 if(!Placeable.Dst.right && !Placeable.Dst.left){ // no page size has been supplied
1547 // This is gross, scan forward looking for a SETWINDOWEXT record, use the first one found to
1548 // define the page size
1549 int hold_nSize = off = nSize;
1550 Placeable.Dst.left = 0;
1551 Placeable.Dst.top = 0;
1552 while(OK){
1553 nSize = U_WMRRECSAFE_get(contents + off, blimit);
1554 if(nSize){
1555 iType = *(uint8_t *)(contents + off + offsetof(U_METARECORD, iType ) );
1556 if(iType == U_WMR_SETWINDOWEXT){
1557 OK=0;
1558 (void) U_WMRSETWINDOWEXT_get(contents + off, &Dst);
1559 Placeable.Dst.right = Dst.x;
1560 Placeable.Dst.bottom = Dst.y;
1561 }
1562 else if(iType == U_WMR_EOF){
1563 OK=0;
1564 // Really messed up WMF, have to set the page to something, make it A4 horizontal
1565 Placeable.Dst.right = round(((double) Placeable.Inch) * 297.0/25.4);
1566 Placeable.Dst.bottom = round(((double) Placeable.Inch) * 210.0/25.4);
1567 }
1568 else {
1569 off += nSize;
1570 }
1571 }
1572 else {
1573 return(0);
1574 }
1575 }
1576 off=0;
1577 nSize = hold_nSize;
1578 OK=1;
1579 }
1580
1581 // drawing size in WMF pixels
1582 d->PixelsInX = Placeable.Dst.right - Placeable.Dst.left + 1;
1583 d->PixelsInY = Placeable.Dst.bottom - Placeable.Dst.top + 1;
1584
1585 /*
1586 Set values for Window and ViewPort extents to 0 - not defined yet.
1587 */
1588 d->dc[d->level].sizeView.x = d->dc[d->level].sizeWnd.x = 0;
1589 d->dc[d->level].sizeView.y = d->dc[d->level].sizeWnd.y = 0;
1590
1591 /* Upper left corner in device units, usually both 0, but not always.
1592 If a placeable header is used, and later a windoworg/windowext are found, then
1593 the placeable information will be ignored.
1594 */
1595 d->ulCornerInX = Placeable.Dst.left;
1596 d->ulCornerInY = Placeable.Dst.top;
1597
1598 d->E2IdirY = 1.0; // assume MM_ANISOTROPIC, if not, this will be changed later
1599 d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "in", "px")/(double) Placeable.Inch;
1600 trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
1601
1602 // drawing size in Inkscape pixels
1603 d->PixelsOutX = d->PixelsInX * d->D2PscaleX;
1604 d->PixelsOutY = d->PixelsInY * d->D2PscaleY;
1605
1606 // Upper left corner in Inkscape units
1607 d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
1608 d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
1609
1610 d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known
1611 dbg_str << "<!-- U_WMR_HEADER -->\n";
1612
1613 d->outdef += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
1614
1615 SVGOStringStream tmp_outdef;
1616 tmp_outdef << "<svg\n";
1617 tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
1618 tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
1619 tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n";
1620 tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role
1621 tmp_outdef << " version=\"1.0\"\n";
1622
1623 tmp_outdef <<
1624 " width=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutX, "px", "mm") << "mm\"\n" <<
1625 " height=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutY, "px", "mm") << "mm\">\n";
1626 d->outdef += tmp_outdef.str().c_str();
1627 d->outdef += "<defs>"; // temporary end of header
1628
1629 // d->defs holds any defines which are read in.
1630
1631
1632 }
1633
1634
1635
1636 while(OK){
1637 if (off>=length) {
1638 return(0); //normally should exit from while after WMREOF sets OK to false.
1639 }
1640 contents += nSize; // pointer to the start of the next record
1641 off += nSize; // offset from beginning of buffer to the start of the next record
1642
1643 /* Currently this is a weaker check than for EMF, it only checks the size of the constant part
1644 of the record */
1645 nSize = U_WMRRECSAFE_get(contents, blimit);
1646 if(!nSize) {
1647 file_status = 0;
1648 break;
1649 }
1650
1651 iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) );
1652
1653 wmr_mask = U_wmr_properties(iType);
1654 if (wmr_mask == U_WMR_INVALID) {
1655 file_status = 0;
1656 break;
1657 }
1658// At run time define environment variable INKSCAPE_DBG_WMF to include string RECORD.
1659// Users may employ this to track down toxic records
1660 if(wDbgRecord){
1661 std::cout << "record type: " << iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
1662 }
1663
1664 SVGOStringStream tmp_path;
1665 SVGOStringStream tmp_str;
1666
1667/* Uncomment the following to track down text problems */
1668//std::cout << "tri->dirty:"<< d->tri->dirty << " wmr_mask: " << std::hex << wmr_mask << std::dec << std::endl;
1669
1670 // incompatible change to text drawing detected (color or background change) forces out existing text
1671 // OR
1672 // next record is valid type and forces pending text to be drawn immediately
1673 if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != U_WMR_INVALID) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){
1675 if (d->dc[d->level].clip_id){
1676 SVGOStringStream tmp_clip;
1677 tmp_clip << "\n<g\n\tclip-path=\"url(#clipWmfPath" << d->dc[d->level].clip_id << ")\"\n>";
1678 d->outsvg += tmp_clip.str().c_str();
1679 }
1680 TR_layout_2_svg(d->tri);
1682 if (d->tri->out) {
1683 ts << d->tri->out;
1684 d->outsvg += ts.str().c_str();
1685 }
1686 d->tri = trinfo_clear(d->tri);
1687 if (d->dc[d->level].clip_id){
1688 d->outsvg += "\n</g>\n";
1689 }
1690 }
1691 if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
1692 d->dc[d->level].bkMode = tbkMode;
1693 memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF));
1694
1695 if(d->dc[d->level].dirty & DIRTY_TEXT){
1696 // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing...
1697 if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); }
1698 else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque
1699 }
1700
1701 /* It is possible to have a series of EMF records that would result in
1702 the following creating hash patterns which are never used. For instance, if
1703 there were a series of records that changed the background color but did nothing
1704 else.
1705 */
1706 if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){
1707 select_brush(d, d->dc[d->level].fill_recidx);
1708 }
1709
1710 d->dc[d->level].dirty = 0;
1711 }
1712
1713//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl;
1714/*
1715std::cout << "BEFORE DRAW"
1716 << " test0 " << ( d->mask & U_DRAW_VISIBLE)
1717 << " test1 " << ( d->mask & U_DRAW_FORCE)
1718 << " test2 " << (wmr_mask & U_DRAW_ALTERS)
1719 << " test2.5 " << ((d->mask & U_DRAW_NOFILL) != (wmr_mask & U_DRAW_NOFILL) )
1720 << " test3 " << (wmr_mask & U_DRAW_VISIBLE)
1721 << " test4 " << !(d->mask & U_DRAW_ONLYTO)
1722 << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )
1723 << std::endl;
1724*/
1725 /* spurious moveto records should not affect the drawing. However, they set the NOFILL
1726 bit and that messes up the logic about when to emit a path. So prune out any
1727 stray moveto records. That is those which were never followed by a lineto.
1728 */
1729 if((d->mask & U_DRAW_NOFILL) && !(d->mask & U_DRAW_VISIBLE) &&
1730 !(wmr_mask & U_DRAW_ONLYTO) && (wmr_mask & U_DRAW_VISIBLE)){
1731 d->mask ^= U_DRAW_NOFILL;
1732 }
1733
1734 if(
1735 (wmr_mask != U_WMR_INVALID) && // next record is valid type
1736 (d->mask & U_DRAW_VISIBLE) && // This record is drawable
1737 (
1738 (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
1739 (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
1740 ((d->mask & U_DRAW_NOFILL) != (wmr_mask & U_DRAW_NOFILL)) || // Fill<->!Fill requires a draw between
1741 ( (wmr_mask & U_DRAW_VISIBLE) && // Next record is visible...
1742 (
1743 ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible
1744 ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records
1745 )
1746 )
1747 )
1748 ){
1749// std::cout << "PATH DRAW at TOP <<+++++++++++++++++++++++++++++++++++++" << std::endl;
1750 if(!(d->path.empty())){
1751 d->outsvg += " <path "; // this is the ONLY place <path should be used!!!!
1752 output_style(d);
1753 d->outsvg += "\n\t";
1754 d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!!
1755 d->outsvg += d->path;
1756 d->outsvg += " \" /> \n";
1757 d->path = ""; //reset the path
1758 }
1759 // reset the flags
1760 d->mask = 0;
1761 d->drawtype = 0;
1762 }
1763// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl;
1764 switch (iType)
1765 {
1766 case U_WMR_EOF:
1767 {
1768 dbg_str << "<!-- U_WMR_EOF -->\n";
1769
1770 d->outsvg = d->outdef + d->defs + "\n</defs>\n\n" + d->outsvg + "</svg>\n";
1771 OK=0;
1772 break;
1773 }
1774 case U_WMR_SETBKCOLOR:
1775 {
1776 dbg_str << "<!-- U_WMR_SETBKCOLOR -->\n";
1777 nSize = U_WMRSETBKCOLOR_get(contents, &tbkColor);
1778 if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){
1779 d->dc[d->level].dirty |= DIRTY_TEXT;
1780 if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
1781 tbkMode = d->dc[d->level].bkMode;
1782 }
1783 break;
1784 }
1785 case U_WMR_SETBKMODE:{
1786 dbg_str << "<!-- U_WMR_SETBKMODE -->\n";
1787 nSize = U_WMRSETBKMODE_get(contents, &tbkMode);
1788 if(tbkMode != d->dc[d->level].bkMode){
1789 d->dc[d->level].dirty |= DIRTY_TEXT;
1790 if(tbkMode != d->dc[d->level].bkMode){
1791 if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
1792 }
1793 memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF));
1794 }
1795 break;
1796 }
1797 case U_WMR_SETMAPMODE:
1798 {
1799 dbg_str << "<!-- U_WMR_SETMAPMODE -->\n";
1800 nSize = U_WMRSETMAPMODE_get(contents, &utmp16);
1801 switch (utmp16){
1802 case U_MM_TEXT:
1803 default:
1804 // Use all values from the header.
1805 break;
1806 /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
1807 and show up in ScaleIn[XY]
1808 */
1809 case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
1810 case U_MM_HIMETRIC: // 1 LU = 0.01 mm
1811 case U_MM_LOENGLISH: // 1 LU = 0.1 in
1812 case U_MM_HIENGLISH: // 1 LU = 0.01 in
1813 case U_MM_TWIPS: // 1 LU = 1/1440 in
1814 d->E2IdirY = -1.0;
1815 // Use d->D2Pscale[XY] values from the header.
1816 break;
1817 case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
1818 case U_MM_ANISOTROPIC:
1819 break;
1820 }
1821 break;
1822 }
1823 case U_WMR_SETROP2:
1824 {
1825 dbg_str << "<!-- U_WMR_SETROP2 -->\n";
1826 nSize = U_WMRSETROP2_get(contents, &utmp16);
1827 d->dwRop2 = utmp16;
1828 break;
1829 }
1830 case U_WMR_SETRELABS: dbg_str << "<!-- U_WMR_SETRELABS -->\n"; break;
1832 {
1833 dbg_str << "<!-- U_WMR_SETPOLYFILLMODE -->\n";
1834 nSize = U_WMRSETPOLYFILLMODE_get(contents, &utmp16);
1835 d->dc[d->level].style.fill_rule.value =
1836 (utmp16 == U_ALTERNATE ? SP_WIND_RULE_NONZERO
1837 : utmp16 == U_WINDING ? SP_WIND_RULE_INTERSECT : SP_WIND_RULE_NONZERO);
1838 break;
1839 }
1841 {
1842 dbg_str << "<!-- U_WMR_SETSTRETCHBLTMODE -->\n";
1843 nSize = U_WMRSETSTRETCHBLTMODE_get(contents, &utmp16);
1844 BLTmode = utmp16;
1845 break;
1846 }
1847 case U_WMR_SETTEXTCHAREXTRA: dbg_str << "<!-- U_WMR_SETTEXTCHAREXTRA -->\n"; break;
1848 case U_WMR_SETTEXTCOLOR:
1849 {
1850 dbg_str << "<!-- U_WMR_SETTEXTCOLOR -->\n";
1851 nSize = U_WMRSETTEXTCOLOR_get(contents, &(d->dc[d->level].textColor));
1852 if(tbkMode != d->dc[d->level].bkMode){
1853 if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
1854 }
1855 // not text_dirty, because multicolored complex text is supported in libTERE
1856 break;
1857 }
1858 case U_WMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_WMR_SETTEXTJUSTIFICATION -->\n"; break;
1859 case U_WMR_SETWINDOWORG:
1860 {
1861 dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n";
1862 nSize = U_WMRSETWINDOWORG_get(contents, &d->dc[d->level].winorg);
1863 d->ulCornerOutX = 0.0; // In the examples seen to date if this record is used with a placeable header, that header is ignored
1864 d->ulCornerOutY = 0.0;
1865 break;
1866 }
1867 case U_WMR_SETWINDOWEXT:
1868 {
1869 dbg_str << "<!-- U_WMR_SETWINDOWEXT -->\n";
1870
1871 nSize = U_WMRSETWINDOWEXT_get(contents, &d->dc[d->level].sizeWnd);
1872
1873 if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
1874 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1875 if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
1876 d->dc[d->level].sizeWnd.x = d->PixelsOutX;
1877 d->dc[d->level].sizeWnd.y = d->PixelsOutY;
1878 }
1879 }
1880 else {
1881 /* There are a lot WMF files in circulation with the x,y values in the setwindowext reversed. If this is detected, swap them.
1882 There is a remote possibility that the strange scaling this implies was intended, and those will be rendered incorrectly */
1883 double Ox = d->PixelsOutX;
1884 double Oy = d->PixelsOutY;
1885 double Wx = d->dc[d->level].sizeWnd.x;
1886 double Wy = d->dc[d->level].sizeWnd.y;
1887 if(Wx != Wy && Geom::are_near(Ox/Wy, Oy/Wx, 1.01/MIN(Wx,Wy)) ){
1888 int tmp;
1889 tmp = d->dc[d->level].sizeWnd.x;
1890 d->dc[d->level].sizeWnd.x = d->dc[d->level].sizeWnd.y;
1891 d->dc[d->level].sizeWnd.y = tmp;
1892 }
1893 }
1894
1895 if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) {
1896 /* Previously it used sizeWnd, but that always resulted in scale = 1 if no viewport ever appeared, and in most files, it did not */
1897 d->dc[d->level].sizeView.x = d->PixelsInX - 1;
1898 d->dc[d->level].sizeView.y = d->PixelsInY - 1;
1899 }
1900
1901 /* scales logical to WMF pixels, transfer a negative sign on Y, if any */
1902 if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) {
1903 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x;
1904 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y;
1905 if(d->dc[d->level].ScaleInY < 0){
1906 d->dc[d->level].ScaleInY *= -1.0;
1907 d->E2IdirY = -1.0;
1908 }
1909 }
1910 else {
1911 d->dc[d->level].ScaleInX = 1;
1912 d->dc[d->level].ScaleInY = 1;
1913 }
1914 break;
1915 }
1917 {
1918 dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n";
1919 nSize = U_WMRSETVIEWPORTORG_get(contents, &d->dc[d->level].vieworg);
1920 break;
1921 }
1923 {
1924 dbg_str << "<!-- U_WMR_SETVIEWPORTEXTEX -->\n";
1925
1926 nSize = U_WMRSETVIEWPORTEXT_get(contents, &d->dc[d->level].sizeView);
1927
1928 if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) {
1929 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
1930 if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) {
1931 d->dc[d->level].sizeView.x = d->PixelsOutX;
1932 d->dc[d->level].sizeView.y = d->PixelsOutY;
1933 }
1934 }
1935
1936 if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
1937 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1938 }
1939
1940 /* scales logical to WMF pixels, transfer a negative sign on Y, if any */
1941 if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) {
1942 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x;
1943 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y;
1944 if(d->dc[d->level].ScaleInY < 0){
1945 d->dc[d->level].ScaleInY *= -1.0;
1946 d->E2IdirY = -1.0;
1947 }
1948 }
1949 else {
1950 d->dc[d->level].ScaleInX = 1;
1951 d->dc[d->level].ScaleInY = 1;
1952 }
1953 break;
1954 }
1955 case U_WMR_OFFSETWINDOWORG: dbg_str << "<!-- U_WMR_OFFSETWINDOWORG -->\n"; break;
1956 case U_WMR_SCALEWINDOWEXT: dbg_str << "<!-- U_WMR_SCALEWINDOWEXT -->\n"; break;
1957 case U_WMR_OFFSETVIEWPORTORG: dbg_str << "<!-- U_WMR_OFFSETVIEWPORTORG -->\n"; break;
1958 case U_WMR_SCALEVIEWPORTEXT: dbg_str << "<!-- U_WMR_SCALEVIEWPORTEXT -->\n"; break;
1959 case U_WMR_LINETO:
1960 {
1961 dbg_str << "<!-- U_WMR_LINETO -->\n";
1962
1963 nSize = U_WMRLINETO_get(contents, &pt16);
1964
1965 d->mask |= wmr_mask;
1966
1967 tmp_path << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " ";
1968 break;
1969 }
1970 case U_WMR_MOVETO:
1971 {
1972 dbg_str << "<!-- U_WMR_MOVETO -->\n";
1973
1974 nSize = U_WMRLINETO_get(contents, &pt16);
1975
1976 d->mask |= wmr_mask;
1977
1978 d->dc[d->level].cur = pt16;
1979
1980 tmp_path <<
1981 "\n\tM " << pix_to_xy( d, pt16.x, pt16.y ) << " ";
1982 break;
1983 }
1985 {
1986 dbg_str << "<!-- U_WMR_EXCLUDECLIPRECT -->\n";
1987
1988 U_RECT16 rc;
1989 nSize = U_WMREXCLUDECLIPRECT_get(contents, &rc);
1990
1991 SVGOStringStream tmp_path;
1992 float faraway = 10000000; // hopefully well outside any real drawing!
1993 //outer rect, clockwise
1994 tmp_path << "M " << faraway << "," << faraway << " ";
1995 tmp_path << "L " << faraway << "," << -faraway << " ";
1996 tmp_path << "L " << -faraway << "," << -faraway << " ";
1997 tmp_path << "L " << -faraway << "," << faraway << " ";
1998 tmp_path << "z ";
1999 //inner rect, counterclockwise (sign of Y is reversed)
2000 tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " ";
2001 tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " ";
2002 tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " ";
2003 tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " ";
2004 tmp_path << "z";
2005
2006 add_clips(d, tmp_path.str().c_str(), U_RGN_AND);
2007
2008 d->path = "";
2009 d->drawtype = 0;
2010 break;
2011 }
2013 {
2014 dbg_str << "<!-- U_WMR_INTERSECTCLIPRECT -->\n";
2015
2016 nSize = U_WMRINTERSECTCLIPRECT_get(contents, &rc);
2017
2018 SVGOStringStream tmp_path;
2019 tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " ";
2020 tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " ";
2021 tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " ";
2022 tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " ";
2023 tmp_path << "z";
2024
2025 add_clips(d, tmp_path.str().c_str(), U_RGN_AND);
2026
2027 d->path = "";
2028 d->drawtype = 0;
2029 break;
2030 }
2031 case U_WMR_ARC:
2032 {
2033 dbg_str << "<!-- U_WMR_ARC -->\n";
2034 U_POINT16 ArcStart, ArcEnd;
2035 nSize = U_WMRARC_get(contents, &ArcStart, &ArcEnd, &rc);
2036
2037 U_PAIRF center,start,end,size;
2038 int f1;
2039 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2040 int stat = wmr_arc_points(rc, ArcStart, ArcEnd,&f1, f2, &center, &start, &end, &size);
2041 if(!stat){
2042 tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
2043 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
2044 tmp_path << " ";
2045 tmp_path << 180.0 * current_rotation(d)/M_PI;
2046 tmp_path << " ";
2047 tmp_path << " " << f1 << "," << f2 << " ";
2048 tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
2049 d->mask |= wmr_mask;
2050 }
2051 else {
2052 dbg_str << "<!-- ARC record is invalid -->\n";
2053 }
2054 break;
2055 }
2056 case U_WMR_ELLIPSE:
2057 {
2058 dbg_str << "<!-- U_WMR_ELLIPSE -->\n";
2059
2060 nSize = U_WMRELLIPSE_get(contents, &rc);
2061
2062 double cx = pix_to_x_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 );
2063 double cy = pix_to_y_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 );
2064 double rx = pix_to_abs_size( d, std::abs(rc.right - rc.left )/2.0 );
2065 double ry = pix_to_abs_size( d, std::abs(rc.top - rc.bottom)/2.0 );
2066
2067 SVGOStringStream tmp_ellipse;
2068 tmp_ellipse << "cx=\"" << cx << "\" ";
2069 tmp_ellipse << "cy=\"" << cy << "\" ";
2070 tmp_ellipse << "rx=\"" << rx << "\" ";
2071 tmp_ellipse << "ry=\"" << ry << "\" ";
2072
2073 d->mask |= wmr_mask;
2074
2075 d->outsvg += " <ellipse ";
2076 output_style(d);
2077 d->outsvg += "\n\t";
2078 d->outsvg += tmp_ellipse.str().c_str();
2079 d->outsvg += "/> \n";
2080 d->path = "";
2081 break;
2082 }
2083 case U_WMR_FLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break;
2084 case U_WMR_PIE:
2085 {
2086 dbg_str << "<!-- U_WMR_PIE -->\n";
2087 U_POINT16 ArcStart, ArcEnd;
2088 nSize = U_WMRPIE_get(contents, &ArcStart, &ArcEnd, &rc);
2089 U_PAIRF center,start,end,size;
2090 int f1;
2091 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2092 if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, &center, &start, &end, &size)){
2093 tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
2094 tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
2095 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
2096 tmp_path << " ";
2097 tmp_path << 180.0 * current_rotation(d)/M_PI;
2098 tmp_path << " ";
2099 tmp_path << " " << f1 << "," << f2 << " ";
2100 tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
2101 tmp_path << " z ";
2102 d->mask |= wmr_mask;
2103 }
2104 else {
2105 dbg_str << "<!-- PIE record is invalid -->\n";
2106 }
2107 break;
2108 }
2109 case U_WMR_RECTANGLE:
2110 {
2111 dbg_str << "<!-- U_WMR_RECTANGLE -->\n";
2112
2113 nSize = U_WMRRECTANGLE_get(contents, &rc);
2114 U_sanerect16(rc, &left, &top, &right, &bottom);
2115
2116 SVGOStringStream tmp_rectangle;
2117 tmp_rectangle << "\n\tM " << pix_to_xy( d, left , top ) << " ";
2118 tmp_rectangle << "\n\tL " << pix_to_xy( d, right, top ) << " ";
2119 tmp_rectangle << "\n\tL " << pix_to_xy( d, right, bottom ) << " ";
2120 tmp_rectangle << "\n\tL " << pix_to_xy( d, left, bottom ) << " ";
2121 tmp_rectangle << "\n\tz";
2122
2123 d->mask |= wmr_mask;
2124
2125 tmp_path << tmp_rectangle.str().c_str();
2126 break;
2127 }
2128 case U_WMR_ROUNDRECT:
2129 {
2130 dbg_str << "<!-- U_WMR_ROUNDRECT -->\n";
2131
2132 int16_t Height,Width;
2133 nSize = U_WMRROUNDRECT_get(contents, &Width, &Height, &rc);
2134 U_sanerect16(rc, &left, &top, &right, &bottom);
2135 double f = 4.*(sqrt(2) - 1)/3;
2136 double f1 = 1.0 - f;
2137 double cnx = Width/2;
2138 double cny = Height/2;
2139
2140
2141 SVGOStringStream tmp_rectangle;
2142 tmp_rectangle << "\n"
2143 << " M "
2144 << pix_to_xy(d, left , top + cny )
2145 << "\n";
2146 tmp_rectangle << " C "
2147 << pix_to_xy(d, left , top + cny*f1 )
2148 << " "
2149 << pix_to_xy(d, left + cnx*f1 , top )
2150 << " "
2151 << pix_to_xy(d, left + cnx , top )
2152 << "\n";
2153 tmp_rectangle << " L "
2154 << pix_to_xy(d, right - cnx , top )
2155 << "\n";
2156 tmp_rectangle << " C "
2157 << pix_to_xy(d, right - cnx*f1 , top )
2158 << " "
2159 << pix_to_xy(d, right , top + cny*f1 )
2160 << " "
2161 << pix_to_xy(d, right , top + cny )
2162 << "\n";
2163 tmp_rectangle << " L "
2164 << pix_to_xy(d, right , bottom - cny )
2165 << "\n";
2166 tmp_rectangle << " C "
2167 << pix_to_xy(d, right , bottom - cny*f1 )
2168 << " "
2169 << pix_to_xy(d, right - cnx*f1 , bottom )
2170 << " "
2171 << pix_to_xy(d, right - cnx , bottom )
2172 << "\n";
2173 tmp_rectangle << " L "
2174 << pix_to_xy(d, left + cnx , bottom )
2175 << "\n";
2176 tmp_rectangle << " C "
2177 << pix_to_xy(d, left + cnx*f1 , bottom )
2178 << " "
2179 << pix_to_xy(d, left , bottom - cny*f1 )
2180 << " "
2181 << pix_to_xy(d, left , bottom - cny )
2182 << "\n";
2183 tmp_rectangle << " z\n";
2184
2185
2186 d->mask |= wmr_mask;
2187
2188 tmp_path << tmp_rectangle.str().c_str();
2189 break;
2190 }
2191 case U_WMR_PATBLT:
2192 {
2193 dbg_str << "<!-- U_WMR_PATBLT -->\n";
2194 // Treat this like any other rectangle, ie, ignore the dwRop3
2195 nSize = U_WMRPATBLT_get(contents, &Dst, &cwh, &dwRop3);
2196 SVGOStringStream tmp_rectangle;
2197 tmp_rectangle << "\n\tM " << pix_to_xy( d, Dst.x , Dst.y ) << " ";
2198 tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y ) << " ";
2199 tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y + cwh.y ) << " ";
2200 tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x, Dst.y + cwh.y ) << " ";
2201 tmp_rectangle << "\n\tz";
2202
2203 d->mask |= wmr_mask;
2204
2205 tmp_path << tmp_rectangle.str().c_str();
2206 break;
2207 }
2208 case U_WMR_SAVEDC:
2209 {
2210 dbg_str << "<!-- U_WMR_SAVEDC -->\n";
2211
2212 if (d->level < WMF_MAX_DC) {
2213 d->dc[d->level + 1] = d->dc[d->level];
2214 if(d->dc[d->level].font_name){
2215 d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated
2216 }
2217 d->level = d->level + 1;
2218 }
2219 break;
2220 }
2221 case U_WMR_SETPIXEL: dbg_str << "<!-- U_WMR_SETPIXEL -->\n"; break;
2223 {
2224 dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n";
2225 U_POINT16 off;
2226 nSize = U_WMROFFSETCLIPRGN_get(contents,&off);
2227 if (d->dc[d->level].clip_id) { // can only offset an existing clipping path
2228 unsigned int real_idx = d->dc[d->level].clip_id - 1;
2229 Geom::PathVector tmp_vect = sp_svg_read_pathv(d->clips.strings[real_idx]);
2230 double ox = pix_to_x_point(d, off.x, off.y) - pix_to_x_point(d, 0, 0); // take into account all active transforms
2231 double oy = pix_to_y_point(d, off.x, off.y) - pix_to_y_point(d, 0, 0);
2232 Geom::Affine tf = Geom::Translate(ox,oy);
2233 tmp_vect *= tf;
2234 add_clips(d, sp_svg_write_path(tmp_vect).c_str(), U_RGN_COPY);
2235 }
2236 break;
2237 }
2238 // U_WMR_TEXTOUT should be here, but has been moved down to merge with U_WMR_EXTTEXTOUT
2239 case U_WMR_BITBLT:
2240 {
2241 dbg_str << "<!-- U_WMR_BITBLT -->\n";
2242 nSize = U_WMRBITBLT_get(contents,&Dst,&cwh,&Src,&dwRop3,&Bm16,&px);
2243 if(!px){
2244 if(dwRop3 == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
2245 int32_t dx = Dst.x;
2246 int32_t dy = Dst.y;
2247 int32_t dw = cwh.x;
2248 int32_t dh = cwh.y;
2249 SVGOStringStream tmp_rectangle;
2250 tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
2251 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
2252 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
2253 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
2254 tmp_rectangle << "\n\tz";
2255
2256 d->mask |= wmr_mask;
2257 d->dwRop3 = dwRop3; // we will try to approximate SOME of these
2258 d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
2259
2260 tmp_path << tmp_rectangle.str().c_str();
2261 }
2262 else { /* Not done yet, Bm16 image present */ }
2263 double dx = pix_to_x_point( d, Dst.x, Dst.y);
2264 double dy = pix_to_y_point( d, Dst.x, Dst.y);
2265 double dw = pix_to_abs_size( d, cwh.x);
2266 double dh = pix_to_abs_size( d, cwh.y);
2267 //source position within the bitmap, in pixels
2268 int sx = Src.x;
2269 int sy = Src.y;
2270 int sw = 0; // extract all of the image
2271 int sh = 0;
2272 if(sx<0)sx=0;
2273 if(sy<0)sy=0;
2274 common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh);
2275 break;
2276 }
2277 case U_WMR_STRETCHBLT:
2278 {
2279 dbg_str << "<!-- U_WMR_STRETCHBLT -->\n";
2280 nSize = U_WMRSTRETCHBLT_get(contents,&Dst,&cDst,&Src,&cSrc,&dwRop3,&Bm16,&px);
2281 if(!px){
2282 if(dwRop3 == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
2283 int32_t dx = Dst.x;
2284 int32_t dy = Dst.y;
2285 int32_t dw = cDst.x;
2286 int32_t dh = cDst.y;
2287 SVGOStringStream tmp_rectangle;
2288 tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
2289 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
2290 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
2291 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
2292 tmp_rectangle << "\n\tz";
2293
2294 d->mask |= wmr_mask;
2295 d->dwRop3 = dwRop3; // we will try to approximate SOME of these
2296 d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
2297
2298 tmp_path << tmp_rectangle.str().c_str();
2299 }
2300 else { /* Not done yet, Bm16 image present */ }
2301 double dx = pix_to_x_point( d, Dst.x, Dst.y);
2302 double dy = pix_to_y_point( d, Dst.x, Dst.y);
2303 double dw = pix_to_abs_size( d, cDst.x);
2304 double dh = pix_to_abs_size( d, cDst.y);
2305 //source position within the bitmap, in pixels
2306 int sx = Src.x;
2307 int sy = Src.y;
2308 int sw = cSrc.x; // extract the specified amount of the image
2309 int sh = cSrc.y;
2310 if(sx<0)sx=0;
2311 if(sy<0)sy=0;
2312 common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh);
2313 break;
2314 }
2315 case U_WMR_POLYGON:
2316 case U_WMR_POLYLINE:
2317 {
2318 dbg_str << "<!-- U_WMR_POLYGON/POLYLINE -->\n";
2319 nSize = U_WMRPOLYGON_get(contents, &cPts, &points);
2320 uint32_t i;
2321
2322 if (cPts < 2)break;
2323
2324 d->mask |= wmr_mask;
2325 memcpy(&pt16,points,U_SIZE_POINT16); points += U_SIZE_POINT16;
2326
2327 tmp_str << "\n\tM " << pix_to_xy( d, pt16.x, pt16.y) << " ";
2328
2329 for (i=1; i<cPts; i++) {
2330 memcpy(&pt16,points,U_SIZE_POINT16); points+=U_SIZE_POINT16;
2331 tmp_str << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " ";
2332 }
2333
2334 tmp_path << tmp_str.str().c_str();
2335 if(iType==U_WMR_POLYGON){ tmp_path << " z"; }
2336
2337 break;
2338 }
2339 case U_WMR_ESCAPE: // only 3 types of escape are implemented
2340 {
2341 dbg_str << "<!-- U_WMR_ESCAPE -->\n";
2342 uint16_t Escape, elen;
2343 nSize = U_WMRESCAPE_get(contents, &Escape, &elen, &text);
2344 if(elen>=4){
2345 uint32_t utmp4;
2346 memcpy(&utmp4, text ,4);
2347 if(Escape == U_MFE_SETLINECAP){
2348 switch (utmp4 & U_PS_ENDCAP_MASK) {
2349 case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_ROUND; break; }
2350 case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_SQUARE; break; }
2351 case U_PS_ENDCAP_FLAT:
2352 default: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_BUTT; break; }
2353 }
2354 }
2355 else if(Escape == U_MFE_SETLINEJOIN){
2356 switch (utmp4 & U_PS_JOIN_MASK) {
2357 case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_BEVEL; break; }
2358 case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_MITER; break; }
2359 case U_PS_JOIN_ROUND:
2360 default: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_ROUND; break; }
2361 }
2362 }
2363 else if(Escape == U_MFE_SETMITERLIMIT){
2364 //The function takes a float but uses a 32 bit int in the record.
2365 float miterlimit = utmp4;
2366 d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size
2367 if (d->dc[d->level].style.stroke_miterlimit.value < 2)
2368 d->dc[d->level].style.stroke_miterlimit.value = 2.0;
2369 }
2370 }
2371 break;
2372 }
2373 case U_WMR_RESTOREDC:
2374 {
2375 dbg_str << "<!-- U_WMR_RESTOREDC -->\n";
2376
2377 int16_t DC;
2378 nSize = U_WMRRESTOREDC_get(contents, &DC);
2379 int old_level = d->level;
2380 if (DC >= 0) {
2381 if (DC < d->level)
2382 d->level = DC;
2383 }
2384 else {
2385 if (d->level + DC >= 0)
2386 d->level = d->level + DC;
2387 }
2388 while (old_level > d->level) {
2389 if (!d->dc[old_level].style.stroke_dasharray.values.empty() &&
2390 (old_level == 0 || (old_level > 0 && d->dc[old_level].style.stroke_dasharray !=
2391 d->dc[old_level - 1].style.stroke_dasharray))) {
2392 d->dc[old_level].style.stroke_dasharray.values.clear();
2393 }
2394 if(d->dc[old_level].font_name){
2395 free(d->dc[old_level].font_name); // else memory leak
2396 d->dc[old_level].font_name = nullptr;
2397 }
2398 old_level--;
2399 }
2400 break;
2401 }
2402 case U_WMR_FILLREGION: dbg_str << "<!-- U_WMR_FILLREGION -->\n"; break;
2403 case U_WMR_FRAMEREGION: dbg_str << "<!-- U_WMR_FRAMEREGION -->\n"; break;
2404 case U_WMR_INVERTREGION: dbg_str << "<!-- U_WMR_INVERTREGION -->\n"; break;
2405 case U_WMR_PAINTREGION: dbg_str << "<!-- U_WMR_PAINTREGION -->\n"; break;
2407 {
2408 dbg_str << "<!-- U_WMR_EXTSELECTCLIPRGN -->\n";
2409 nSize = U_WMRSELECTCLIPREGION_get(contents, &utmp16);
2410 if (utmp16 == U_RGN_COPY)
2411 clipset = false;
2412 break;
2413 }
2414 case U_WMR_SELECTOBJECT:
2415 {
2416 dbg_str << "<!-- U_WMR_SELECTOBJECT -->\n";
2417
2418 nSize = U_WMRSELECTOBJECT_get(contents, &utmp16);
2419 unsigned int index = utmp16;
2420
2421 // WMF has no stock objects
2422 if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
2423 switch (d->wmf_obj[index].type)
2424 {
2426 select_pen(d, index);
2427 break;
2430 case U_WMR_CREATEPATTERNBRUSH: // <- this one did not display properly on XP, DIBCREATEPATTERNBRUSH works
2431 select_brush(d, index);
2432 break;
2434 select_font(d, index);
2435 break;
2438 case U_WMR_CREATEBITMAP:
2439 case U_WMR_CREATEREGION:
2440 /* these do not do anything, but their objects must be kept in the count */
2441 break;
2442 }
2443 }
2444 break;
2445 }
2446 case U_WMR_SETTEXTALIGN:
2447 {
2448 dbg_str << "<!-- U_WMR_SETTEXTALIGN -->\n";
2449 nSize = U_WMRSETTEXTALIGN_get(contents, &(d->dc[d->level].textAlign));
2450 break;
2451 }
2452 case U_WMR_DRAWTEXT: dbg_str << "<!-- U_WMR_DRAWTEXT -->\n"; break;
2453 case U_WMR_CHORD:
2454 {
2455 dbg_str << "<!-- U_WMR_CHORD -->\n";
2456 U_POINT16 ArcStart, ArcEnd;
2457 nSize = U_WMRCHORD_get(contents, &ArcStart, &ArcEnd, &rc);
2458 U_PAIRF center,start,end,size;
2459 int f1;
2460 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2461 if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, &center, &start, &end, &size)){
2462 tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
2463 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
2464 tmp_path << " ";
2465 tmp_path << 180.0 * current_rotation(d)/M_PI;
2466 tmp_path << " ";
2467 tmp_path << " " << f1 << "," << f2 << " ";
2468 tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
2469 tmp_path << " z ";
2470 d->mask |= wmr_mask;
2471 }
2472 else {
2473 dbg_str << "<!-- CHORD record is invalid -->\n";
2474 }
2475 break;
2476 }
2477 case U_WMR_SETMAPPERFLAGS: dbg_str << "<!-- U_WMR_SETMAPPERFLAGS -->\n"; break;
2478 case U_WMR_TEXTOUT:
2479 case U_WMR_EXTTEXTOUT:
2480 {
2481 if(iType == U_WMR_TEXTOUT){
2482 dbg_str << "<!-- U_WMR_TEXTOUT -->\n";
2483 nSize = U_WMRTEXTOUT_get(contents, &Dst, &tlen, &text);
2484 Opts=0;
2485 }
2486 else {
2487 dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n";
2488 nSize = U_WMREXTTEXTOUT_get(contents, &Dst, &tlen, &Opts, &text, &dx, &rc );
2489 }
2490 uint32_t fOptions = Opts;
2491
2492 double x1,y1;
2493 int cChars;
2494 x1 = Dst.x;
2495 y1 = Dst.y;
2496 cChars = tlen;
2497
2498 if (d->dc[d->level].textAlign & U_TA_UPDATECP) {
2499 x1 = d->dc[d->level].cur.x;
2500 y1 = d->dc[d->level].cur.y;
2501 }
2502
2503 double x = pix_to_x_point(d, x1, y1);
2504 double y = pix_to_y_point(d, x1, y1);
2505
2506 /* Rotation issues are handled entirely in libTERE now */
2507
2508 uint32_t *dup_wt = nullptr;
2509
2510 dup_wt = U_Latin1ToUtf32le(text, cChars, nullptr);
2511 if(!dup_wt)dup_wt = unknown_chars(cChars);
2512
2513 msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
2514
2515 if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){
2516 free(d->dc[d->level].font_name);
2517 d->dc[d->level].font_name = strdup("Times New Roman");
2518 }
2519
2520 char *ansi_text;
2521 ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, nullptr);
2522 free(dup_wt);
2523 // Empty text or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse
2524 if(*((uint8_t *)ansi_text) <= 0x1F){
2525 free(ansi_text);
2526 ansi_text=nullptr;
2527 }
2528
2529 if (ansi_text) {
2530
2532
2533 gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
2534
2535 tsp.x = x*0.8; // TERE expects sizes in points
2536 tsp.y = y*0.8;
2537 tsp.color.Red = d->dc[d->level].textColor.Red;
2538 tsp.color.Green = d->dc[d->level].textColor.Green;
2539 tsp.color.Blue = d->dc[d->level].textColor.Blue;
2540 tsp.color.Reserved = 0;
2541 switch(d->dc[d->level].style.font_style.value){
2543 tsp.italics = FC_SLANT_OBLIQUE; break;
2545 tsp.italics = FC_SLANT_ITALIC; break;
2546 default:
2548 tsp.italics = FC_SLANT_ROMAN; break;
2549 }
2550 switch(d->dc[d->level].style.font_weight.value){
2551 case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
2552 case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
2553 case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
2554 case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
2555 case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
2556 case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
2557 case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
2558 case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
2559 case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
2560 case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
2561 case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
2562 case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
2563 case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
2564 default: tsp.weight = FC_WEIGHT_NORMAL ; break;
2565 }
2566 // WMF only supports two types of text decoration
2567 tsp.decoration = TXTDECOR_NONE;
2568 if(d->dc[d->level].style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; }
2569 if(d->dc[d->level].style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;}
2570
2571 // WMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
2572 tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
2573 (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
2574 ALIRIGHT);
2575 tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
2576 ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
2577 ALITOP));
2578
2579 // language direction can be encoded two ways, U_TA_RTLREADING is preferred
2580 if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; }
2581 else{ tsp.ldir = LDIR_LR; }
2582
2583 tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet)
2584 tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement
2585 // There is no world transform, so ori need not be further rotated
2586 tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear().
2587 tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points
2588 char *fontspec = TR_construct_fontspec(&tsp, d->dc[d->level].font_name);
2589 tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec);
2590 free(fontspec);
2591 // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though
2592 // as the metrics from fontconfig may not match, or the font may not be present.
2593 if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; }
2594 else { tsp.co=0; }
2595
2596 int status;
2597
2598 status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
2599 if(status==-1){ // change of escapement, emit what we have and reset
2601 if (d->dc[d->level].clip_id){
2602 SVGOStringStream tmp_clip;
2603 tmp_clip << "\n<g\n\tclip-path=\"url(#clipWmfPath" << d->dc[d->level].clip_id << ")\"\n>";
2604 d->outsvg += tmp_clip.str().c_str();
2605 }
2606 TR_layout_2_svg(d->tri);
2607 ts << d->tri->out;
2608 d->outsvg += ts.str().c_str();
2609 d->tri = trinfo_clear(d->tri);
2610 (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
2611 if (d->dc[d->level].clip_id){
2612 d->outsvg += "\n</g>\n";
2613 }
2614 }
2615
2616 g_free(escaped_text);
2617 free(ansi_text);
2618 }
2619
2620 break;
2621 }
2622 case U_WMR_SETDIBTODEV: dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n"; break;
2623 case U_WMR_SELECTPALETTE: dbg_str << "<!-- U_WMR_SELECTPALETTE -->\n"; break;
2624 case U_WMR_REALIZEPALETTE: dbg_str << "<!-- U_WMR_REALIZEPALETTE -->\n"; break;
2625 case U_WMR_ANIMATEPALETTE: dbg_str << "<!-- U_WMR_ANIMATEPALETTE -->\n"; break;
2626 case U_WMR_SETPALENTRIES: dbg_str << "<!-- U_WMR_SETPALENTRIES -->\n"; break;
2627 case U_WMR_POLYPOLYGON:
2628 {
2629 dbg_str << "<!-- U_WMR_POLYPOLYGON16 -->\n";
2630 uint16_t nPolys;
2631 const uint16_t *aPolyCounts;
2632 const char *Points;
2633 int cpts; /* total number of points in Points*/
2634 nSize = U_WMRPOLYPOLYGON_get(contents, &nPolys, &aPolyCounts, &Points);
2635 int n, i, j;
2636
2637 d->mask |= wmr_mask;
2638
2639 U_POINT16 apt;
2640 for (n=cpts=0; n < nPolys; n++) { cpts += aPolyCounts[n]; }
2641 i = 0; // offset in BYTES
2642 cpts *= U_SIZE_POINT16; // limit for offset i, in BYTES
2643
2644 for (n=0; n < nPolys && i<cpts; n++) {
2645 SVGOStringStream poly_path;
2646
2647 memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way
2648
2649 poly_path << "\n\tM " << pix_to_xy( d, apt.x, apt.y) << " ";
2650 i += U_SIZE_POINT16;
2651
2652 for (j=1; j < aPolyCounts[n] && i < cpts; j++) {
2653 memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way
2654 poly_path << "\n\tL " << pix_to_xy( d, apt.x, apt.y) << " ";
2655 i += U_SIZE_POINT16;
2656 }
2657
2658 tmp_str << poly_path.str().c_str();
2659 tmp_str << " z";
2660 tmp_str << " \n";
2661 }
2662
2663 tmp_path << tmp_str.str().c_str();
2664
2665 break;
2666 }
2667 case U_WMR_RESIZEPALETTE: dbg_str << "<!-- U_WMR_RESIZEPALETTE -->\n"; break;
2668 case U_WMR_3A:
2669 case U_WMR_3B:
2670 case U_WMR_3C:
2671 case U_WMR_3D:
2672 case U_WMR_3E:
2673 case U_WMR_3F:
2674 {
2675 dbg_str << "<!-- U_WMR_3A..3F -->\n";
2676 break;
2677 }
2678 case U_WMR_DIBBITBLT:
2679 {
2680 dbg_str << "<!-- U_WMR_DIBBITBLT -->\n";
2681 nSize = U_WMRDIBBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &dib);
2682
2683 // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
2684 // least it leaves objects where the operations should have been.
2685 if (!dib) {
2686 // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
2687
2688 if(dwRop3 == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
2689 int32_t dx = Dst.x;
2690 int32_t dy = Dst.y;
2691 int32_t dw = cwh.x;
2692 int32_t dh = cwh.y;
2693 SVGOStringStream tmp_rectangle;
2694 tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
2695 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
2696 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
2697 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
2698 tmp_rectangle << "\n\tz";
2699
2700 d->mask |= wmr_mask;
2701 d->dwRop3 = dwRop3; // we will try to approximate SOME of these
2702 d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
2703
2704 tmp_path << tmp_rectangle.str().c_str();
2705 }
2706 else {
2707 double dx = pix_to_x_point( d, Dst.x, Dst.y);
2708 double dy = pix_to_y_point( d, Dst.x, Dst.y);
2709 double dw = pix_to_abs_size( d, cDst.x);
2710 double dh = pix_to_abs_size( d, cDst.y);
2711 //source position within the bitmap, in pixels
2712 int sx = Src.x;
2713 int sy = Src.y;
2714 int sw = 0; // extract all of the image
2715 int sh = 0;
2716 if(sx<0)sx=0;
2717 if(sy<0)sy=0;
2718 // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS
2719 common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,U_DIB_RGB_COLORS);
2720 }
2721 break;
2722 }
2724 {
2725 dbg_str << "<!-- U_WMR_DIBSTRETCHBLT -->\n";
2726 nSize = U_WMRDIBSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &dib);
2727 // Always grab image, ignore modes.
2728 if (dib) {
2729 double dx = pix_to_x_point( d, Dst.x, Dst.y);
2730 double dy = pix_to_y_point( d, Dst.x, Dst.y);
2731 double dw = pix_to_abs_size( d, cDst.x);
2732 double dh = pix_to_abs_size( d, cDst.y);
2733 //source position within the bitmap, in pixels
2734 int sx = Src.x;
2735 int sy = Src.y;
2736 int sw = cSrc.x; // extract the specified amount of the image
2737 int sh = cSrc.y;
2738 // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS
2739 common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh, U_DIB_RGB_COLORS);
2740 }
2741 break;
2742 }
2744 {
2745 dbg_str << "<!-- U_WMR_DIBCREATEPATTERNBRUSH -->\n";
2747 break;
2748 }
2749 case U_WMR_STRETCHDIB:
2750 {
2751 dbg_str << "<!-- U_WMR_STRETCHDIB -->\n";
2752 nSize = U_WMRSTRETCHDIB_get(contents, &Dst, &cDst, &Src, &cSrc, &cUsage, &dwRop3, &dib);
2753 double dx = pix_to_x_point( d, Dst.x, Dst.y );
2754 double dy = pix_to_y_point( d, Dst.x, Dst.y );
2755 double dw = pix_to_abs_size( d, cDst.x);
2756 double dh = pix_to_abs_size( d, cDst.y);
2757 int sx = Src.x; //source position within the bitmap, in pixels
2758 int sy = Src.y;
2759 int sw = cSrc.x; // extract the specified amount of the image
2760 int sh = cSrc.y;
2761 uint32_t iUsageSrc;
2762 iUsageSrc = cUsage;
2763 common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,iUsageSrc);
2764
2765 break;
2766 }
2767 case U_WMR_44:
2768 case U_WMR_45:
2769 case U_WMR_46:
2770 case U_WMR_47:
2771 {
2772 dbg_str << "<!-- U_WMR_44..47 -->\n";
2773 break;
2774 }
2775 case U_WMR_EXTFLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break;
2776 case U_WMR_49:
2777 case U_WMR_4A:
2778 case U_WMR_4B:
2779 case U_WMR_4C:
2780 case U_WMR_4D:
2781 case U_WMR_4E:
2782 case U_WMR_4F:
2783 case U_WMR_50:
2784 case U_WMR_51:
2785 case U_WMR_52:
2786 case U_WMR_53:
2787 case U_WMR_54:
2788 case U_WMR_55:
2789 case U_WMR_56:
2790 case U_WMR_57:
2791 case U_WMR_58:
2792 case U_WMR_59:
2793 case U_WMR_5A:
2794 case U_WMR_5B:
2795 case U_WMR_5C:
2796 case U_WMR_5D:
2797 case U_WMR_5E:
2798 case U_WMR_5F:
2799 case U_WMR_60:
2800 case U_WMR_61:
2801 case U_WMR_62:
2802 case U_WMR_63:
2803 case U_WMR_64:
2804 case U_WMR_65:
2805 case U_WMR_66:
2806 case U_WMR_67:
2807 case U_WMR_68:
2808 case U_WMR_69:
2809 case U_WMR_6A:
2810 case U_WMR_6B:
2811 case U_WMR_6C:
2812 case U_WMR_6D:
2813 case U_WMR_6E:
2814 case U_WMR_6F:
2815 case U_WMR_70:
2816 case U_WMR_71:
2817 case U_WMR_72:
2818 case U_WMR_73:
2819 case U_WMR_74:
2820 case U_WMR_75:
2821 case U_WMR_76:
2822 case U_WMR_77:
2823 case U_WMR_78:
2824 case U_WMR_79:
2825 case U_WMR_7A:
2826 case U_WMR_7B:
2827 case U_WMR_7C:
2828 case U_WMR_7D:
2829 case U_WMR_7E:
2830 case U_WMR_7F:
2831 case U_WMR_80:
2832 case U_WMR_81:
2833 case U_WMR_82:
2834 case U_WMR_83:
2835 case U_WMR_84:
2836 case U_WMR_85:
2837 case U_WMR_86:
2838 case U_WMR_87:
2839 case U_WMR_88:
2840 case U_WMR_89:
2841 case U_WMR_8A:
2842 case U_WMR_8B:
2843 case U_WMR_8C:
2844 case U_WMR_8D:
2845 case U_WMR_8E:
2846 case U_WMR_8F:
2847 case U_WMR_90:
2848 case U_WMR_91:
2849 case U_WMR_92:
2850 case U_WMR_93:
2851 case U_WMR_94:
2852 case U_WMR_95:
2853 case U_WMR_96:
2854 case U_WMR_97:
2855 case U_WMR_98:
2856 case U_WMR_99:
2857 case U_WMR_9A:
2858 case U_WMR_9B:
2859 case U_WMR_9C:
2860 case U_WMR_9D:
2861 case U_WMR_9E:
2862 case U_WMR_9F:
2863 case U_WMR_A0:
2864 case U_WMR_A1:
2865 case U_WMR_A2:
2866 case U_WMR_A3:
2867 case U_WMR_A4:
2868 case U_WMR_A5:
2869 case U_WMR_A6:
2870 case U_WMR_A7:
2871 case U_WMR_A8:
2872 case U_WMR_A9:
2873 case U_WMR_AA:
2874 case U_WMR_AB:
2875 case U_WMR_AC:
2876 case U_WMR_AD:
2877 case U_WMR_AE:
2878 case U_WMR_AF:
2879 case U_WMR_B0:
2880 case U_WMR_B1:
2881 case U_WMR_B2:
2882 case U_WMR_B3:
2883 case U_WMR_B4:
2884 case U_WMR_B5:
2885 case U_WMR_B6:
2886 case U_WMR_B7:
2887 case U_WMR_B8:
2888 case U_WMR_B9:
2889 case U_WMR_BA:
2890 case U_WMR_BB:
2891 case U_WMR_BC:
2892 case U_WMR_BD:
2893 case U_WMR_BE:
2894 case U_WMR_BF:
2895 case U_WMR_C0:
2896 case U_WMR_C1:
2897 case U_WMR_C2:
2898 case U_WMR_C3:
2899 case U_WMR_C4:
2900 case U_WMR_C5:
2901 case U_WMR_C6:
2902 case U_WMR_C7:
2903 case U_WMR_C8:
2904 case U_WMR_C9:
2905 case U_WMR_CA:
2906 case U_WMR_CB:
2907 case U_WMR_CC:
2908 case U_WMR_CD:
2909 case U_WMR_CE:
2910 case U_WMR_CF:
2911 case U_WMR_D0:
2912 case U_WMR_D1:
2913 case U_WMR_D2:
2914 case U_WMR_D3:
2915 case U_WMR_D4:
2916 case U_WMR_D5:
2917 case U_WMR_D6:
2918 case U_WMR_D7:
2919 case U_WMR_D8:
2920 case U_WMR_D9:
2921 case U_WMR_DA:
2922 case U_WMR_DB:
2923 case U_WMR_DC:
2924 case U_WMR_DD:
2925 case U_WMR_DE:
2926 case U_WMR_DF:
2927 case U_WMR_E0:
2928 case U_WMR_E1:
2929 case U_WMR_E2:
2930 case U_WMR_E3:
2931 case U_WMR_E4:
2932 case U_WMR_E5:
2933 case U_WMR_E6:
2934 case U_WMR_E7:
2935 case U_WMR_E8:
2936 case U_WMR_E9:
2937 case U_WMR_EA:
2938 case U_WMR_EB:
2939 case U_WMR_EC:
2940 case U_WMR_ED:
2941 case U_WMR_EE:
2942 case U_WMR_EF:
2943 {
2944 dbg_str << "<!-- U_WMR_EXTFLOODFILL..EF -->\n";
2945 break;
2946 }
2947 case U_WMR_DELETEOBJECT:
2948 {
2949 dbg_str << "<!-- U_WMR_DELETEOBJECT -->\n";
2950 nSize = U_WMRDELETEOBJECT_get(contents, &utmp16);
2951 delete_object(d, utmp16);
2952 break;
2953 }
2954 case U_WMR_F1:
2955 case U_WMR_F2:
2956 case U_WMR_F3:
2957 case U_WMR_F4:
2958 case U_WMR_F5:
2959 case U_WMR_F6:
2960 {
2961 dbg_str << "<!-- F1..F6 -->\n";
2962 break;
2963 }
2965 {
2966 dbg_str << "<!-- U_WMR_CREATEPALETTE -->\n";
2967 insert_object(d, U_WMR_CREATEPALETTE, contents);
2968 break;
2969 }
2970 case U_WMR_F8: dbg_str << "<!-- F8 -->\n"; break;
2972 {
2973 dbg_str << "<!-- U_WMR_CREATEPATTERNBRUSH -->\n";
2975 break;
2976 }
2978 {
2979 dbg_str << "<!-- U_WMR_EXTCREATEPEN -->\n";
2981 break;
2982 }
2984 {
2985 dbg_str << "<!-- U_WMR_CREATEFONTINDIRECT -->\n";
2987 break;
2988 }
2990 {
2991 dbg_str << "<!-- U_WMR_CREATEBRUSHINDIRECT -->\n";
2993 break;
2994 }
2996 {
2997 dbg_str << "<!-- U_WMR_CREATEBITMAPINDIRECT -->\n";
2999 break;
3000 }
3001 case U_WMR_CREATEBITMAP:
3002 {
3003 dbg_str << "<!-- U_WMR_CREATEBITMAP -->\n";
3004 insert_object(d, U_WMR_CREATEBITMAP, contents);
3005 break;
3006 }
3007 case U_WMR_CREATEREGION:
3008 {
3009 dbg_str << "<!-- U_WMR_CREATEREGION -->\n";
3010 insert_object(d, U_WMR_CREATEREGION, contents);
3011 break;
3012 }
3013 default:
3014 dbg_str << "<!-- U_WMR_??? -->\n";
3015 break;
3016 } //end of switch
3017// At run time define environment variable INKSCAPE_DBG_WMF to include string COMMENT.
3018// Users may employ this to to place a comment for each processed WMR record in the SVG
3019 if(wDbgComment){
3020 d->outsvg += dbg_str.str().c_str();
3021 }
3022 d->path += tmp_path.str().c_str();
3023 if(!nSize){ // There was some problem with the processing of this record, it is not safe to continue
3024 file_status = 0;
3025 break;
3026 }
3027
3028 } //end of while on OK
3029// At run time define environment variable INKSCAPE_DBG_WMF to include string FINAL
3030// Users may employ this to to show the final SVG derived from the WMF
3031 if(wDbgFinal){
3032 std::cout << d->outsvg << std::endl;
3033 }
3034 (void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
3035
3036 return(file_status);
3037}
3038
3040 if(name.count){
3041 for(int i=0; i< name.count; i++){ free(name.strings[i]); }
3042 free(name.strings);
3043 }
3044 name.count = 0;
3045 name.size = 0;
3046}
3047
3048std::unique_ptr<SPDocument> Wmf::open(Inkscape::Extension::Input *, char const *uri, bool)
3049{
3050 if (!uri) {
3051 return nullptr;
3052 }
3053
3054 // ensure usage of dot as decimal separator in scanf/printf functions (indepentendly of current locale)
3055 char *oldlocale = g_strdup(setlocale(LC_NUMERIC, nullptr));
3056 setlocale(LC_NUMERIC, "C");
3057
3059
3060 d.n_obj = 0; //these might not be set otherwise if the input file is corrupt
3061 d.wmf_obj=nullptr;
3062
3063 // Default font, WMF spec says device can pick whatever it wants.
3064 // WMF files that do not specify a font are unlikely to look very good!
3065 d.dc[0].style.font_size.computed = 16.0;
3068 d.dc[0].style.text_decoration_line.underline = false;
3069 d.dc[0].style.text_decoration_line.line_through = false;
3070 d.dc[0].style.baseline_shift.value = 0;
3071
3072 // Default pen, WMF files that do not specify a pen are unlikely to look very good!
3073 d.dc[0].style.stroke_dasharray.set = false;
3074 d.dc[0].style.stroke_linecap.computed = SP_STROKE_LINECAP_SQUARE; // U_PS_ENDCAP_SQUARE;
3075 d.dc[0].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_MITER; // U_PS_JOIN_MITER;
3076 d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF drawing size is known
3077 d.dc[0].style.stroke.setColor(Colors::Color(0x000000ff));
3078 d.dc[0].stroke_set = true;
3079
3080 // Default brush is none - no fill. WMF files that do not specify a brush are unlikely to look very good!
3081 d.dc[0].fill_set = false;
3082
3083 d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there WMF spec says device can pick whatever it wants
3084
3085 // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
3086
3087 d.defs += "\n";
3088 d.defs += " <pattern id=\"WMFhbasepattern\" \n";
3089 d.defs += " patternUnits=\"userSpaceOnUse\"\n";
3090 d.defs += " width=\"6\" \n";
3091 d.defs += " height=\"6\" \n";
3092 d.defs += " x=\"0\" \n";
3093 d.defs += " y=\"0\"> \n";
3094 d.defs += " </pattern> \n";
3095
3096
3097 size_t length;
3098 char *contents;
3099 if(wmf_readdata(uri, &contents, &length))return(nullptr);
3100
3101 // set up the text reassembly system
3102 if(!(d.tri = trinfo_init(nullptr)))return(nullptr);
3103 (void) trinfo_load_ft_opts(d.tri, 1,
3104 FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
3105 FT_KERNING_UNSCALED);
3106
3107 int good = myMetaFileProc(contents,length, &d);
3108 free(contents);
3109
3110// std::cout << "SVG Output: " << std::endl << d.outsvg << std::endl;
3111
3112 std::unique_ptr<SPDocument> doc;
3113 if (good) {
3114 doc = SPDocument::createNewDocFromMem(d.outsvg.raw(), true);
3115 }
3116
3120
3121 if (d.wmf_obj) {
3122 int i;
3123 for (i=0; i<d.n_obj; i++)
3124 delete_object(&d, i);
3125 delete[] d.wmf_obj;
3126 }
3127
3128 d.dc[0].style.stroke_dasharray.values.clear();
3129
3130 for(int i=0; i<=WMF_MAX_DC; i++){
3131 if(d.dc[i].font_name)free(d.dc[i].font_name);
3132 }
3133
3135
3136 // in earlier versions no viewbox was generated and a call to setViewBoxIfMissing() was needed here.
3137
3138 // restore decimal separator used in scanf/printf functions to initial value
3139 setlocale(LC_NUMERIC, oldlocale);
3140 g_free(oldlocale);
3141
3142 return doc;
3143}
3144
3146{
3147 // clang-format off
3148 /* WMF in */
3150 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
3151 "<name>" N_("WMF Input") "</name>\n"
3152 "<id>org.inkscape.input.wmf</id>\n"
3153 "<input>\n"
3154 "<extension>.wmf</extension>\n"
3155 "<mimetype>image/x-wmf</mimetype>\n"
3156 "<filetypename>" N_("Windows Metafiles (*.wmf)") "</filetypename>\n"
3157 "<filetypetooltip>" N_("Windows Metafiles") "</filetypetooltip>\n"
3158 "</input>\n"
3159 "</inkscape-extension>", std::make_unique<Wmf>());
3160
3161 /* WMF out */
3163 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
3164 "<name>" N_("WMF Output") "</name>\n"
3165 "<id>org.inkscape.output.wmf</id>\n"
3166 "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"bool\">true</param>\n"
3167 "<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"bool\">true</param>\n"
3168 "<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"bool\">true</param>\n"
3169 "<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"bool\">true</param>\n"
3170 "<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"bool\">false</param>\n"
3171 "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"bool\">false</param>\n"
3172 "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"bool\">false</param>\n"
3173 "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"bool\">false</param>\n"
3174 "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard WMF hatches") "\" type=\"bool\">false</param>\n"
3175 "<output>\n"
3176 "<extension>.wmf</extension>\n"
3177 "<mimetype>image/x-wmf</mimetype>\n"
3178 "<filetypename>" N_("Windows Metafile (*.wmf)") "</filetypename>\n"
3179 "<filetypetooltip>" N_("Windows Metafile") "</filetypetooltip>\n"
3180 "</output>\n"
3181 "</inkscape-extension>", std::make_unique<Wmf>());
3182 // clang-format on
3183}
3184
3185} // namespace Inkscape::Extension::Internal
3186
3187/*
3188 Local Variables:
3189 mode:c++
3190 c-file-style:"stroustrup"
3191 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3192 indent-tabs-mode:nil
3193 fill-column:99
3194 End:
3195*/
3196// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
int test()
Definition 2junctions.cpp:5
FillRule
Definition LivarotDefs.h:67
@ fill_oddEven
Definition LivarotDefs.h:68
BooleanOp
Definition LivarotDefs.h:76
double scale
Definition aa.cpp:228
3x3 matrix representing an affine transformation.
Definition affine.h:70
Sequence of subpaths.
Definition pathvector.h:122
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
Translation by a vector.
Definition transforms.h:115
void setRoot(DrawingItem *root)
Definition drawing.cpp:64
Extension * get(const gchar *key) const
This function looks up a Inkscape::Extension::Extension by using its unique id. It then returns a ref...
Definition db.cpp:101
The object that is the basis for the Extension system.
Definition extension.h:133
bool set_param_bool(char const *name, bool value)
Sets a parameter identified by name with the boolean in the parameter value.
virtual unsigned fill(Inkscape::Extension::Print *, Geom::PathVector const &, Geom::Affine const &, SPStyle const *, Geom::OptRect const &, Geom::OptRect const &, Geom::OptRect const &)
virtual unsigned text(Inkscape::Extension::Print *, char const *, Geom::Point const &, SPStyle const *)
virtual unsigned stroke(Inkscape::Extension::Print *, Geom::PathVector const &, Geom::Affine const &, SPStyle const *, Geom::OptRect const &, Geom::OptRect const &, Geom::OptRect const &)
static void toPNG(PMEMPNG accum, int width, int height, const char *px)
static int combine_ops_to_livarot(const int op)
static uint32_t sethexcolor(U_COLORREF color)
static int in_images(PWMF_CALLBACK_DATA d, char *test)
static double pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py)
static double pix_to_abs_size(PWMF_CALLBACK_DATA d, double px)
static double _pix_y_to_point(PWMF_CALLBACK_DATA d, double py)
static void select_pen(PWMF_CALLBACK_DATA d, int index)
static uint32_t add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px)
static void enlarge_hatches(PWMF_CALLBACK_DATA d)
static uint32_t add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage)
static void add_clips(PWMF_CALLBACK_DATA d, const char *clippath, unsigned int logic)
std::unique_ptr< SPDocument > open(Inkscape::Extension::Input *mod, char const *uri, bool is_importing) override
Open a file.
static double pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py)
static void select_font(PWMF_CALLBACK_DATA d, int index)
static int myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d)
static void output_style(PWMF_CALLBACK_DATA d)
static void delete_object(PWMF_CALLBACK_DATA d, int index)
static double current_scale(PWMF_CALLBACK_DATA d)
static double current_rotation(PWMF_CALLBACK_DATA d)
static std::string current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset)
static void common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage)
store SVG for an image given the pixmap and various coordinate information
static void enlarge_images(PWMF_CALLBACK_DATA d)
static void common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh)
store SVG for an image given the pixmap and various coordinate information
static int insert_object(PWMF_CALLBACK_DATA d, int type, const char *record)
void save(Inkscape::Extension::Output *mod, SPDocument *doc, char const *filename) override
static double _pix_x_to_point(PWMF_CALLBACK_DATA d, double px)
static uint32_t * unknown_chars(size_t count)
static int in_hatches(PWMF_CALLBACK_DATA d, char *test)
static void free_wmf_strings(WMF_STRINGS name)
bool check(Inkscape::Extension::Extension *module) override
Verify any dependencies.
Definition wmf-inout.cpp:61
static int in_clips(PWMF_CALLBACK_DATA d, const char *test)
static uint32_t add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor)
static void print_document_to_file(SPDocument *doc, const gchar *filename)
Definition wmf-inout.cpp:67
static void enlarge_clips(PWMF_CALLBACK_DATA d)
static std::string pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y)
static int insertable_object(PWMF_CALLBACK_DATA d)
static void select_brush(PWMF_CALLBACK_DATA d, int index)
Generic failure for an undescribed reason.
Definition output.h:34
std::string str() const
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Definition units.cpp:525
Typed SVG document implementation.
Definition document.h:103
static std::unique_ptr< SPDocument > createNewDocFromMem(std::span< char const > buffer, bool keepalive, std::string const &filename="")
Definition document.cpp:718
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:202
int ensureUpToDate(unsigned int object_modified_tag=0)
Repeatedly works on getting the document updated, since sometimes it takes more than one pass to get ...
Length type internal to SPStyle.
void setDouble(double v)
static unsigned int display_key_new(unsigned numkeys)
Allocates unique integer keys.
Definition sp-item.cpp:1233
T< SPAttr::TEXT_DECORATION_LINE, SPITextDecorationLine > text_decoration_line
CSS 3 2.1, 2.2, 2.3.
Definition style.h:191
T< SPAttr::FONT_WEIGHT, SPIEnum< SPCSSFontWeight > > font_weight
Weight of the font.
Definition style.h:112
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::STROKE_DASHARRAY, SPIDashArray > stroke_dasharray
stroke-dasharray
Definition style.h:257
T< SPAttr::STROKE, SPIPaint > stroke
stroke
Definition style.h:247
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Definition style.h:249
T< SPAttr::FILL_RULE, SPIEnum< SPWindRule > > fill_rule
fill-rule: 0 nonzero, 1 evenodd
Definition style.h:244
T< SPAttr::FONT_STYLE, SPIEnum< SPCSSFontStyle > > font_style
Font style.
Definition style.h:108
T< SPAttr::STROKE_LINEJOIN, SPIEnum< SPStrokeJoinType > > stroke_linejoin
stroke-linejoin
Definition style.h:253
T< SPAttr::STROKE_MITERLIMIT, SPIFloat > stroke_miterlimit
stroke-miterlimit
Definition style.h:255
T< SPAttr::STROKE_LINECAP, SPIEnum< SPStrokeCapType > > stroke_linecap
stroke-linecap
Definition style.h:251
T< SPAttr::FONT_SIZE, SPIFontSize > font_size
Size of the font.
Definition style.h:116
T< SPAttr::BASELINE_SHIFT, SPIBaselineShift > baseline_shift
Baseline shift (svg1.1 10.9.2)
Definition style.h:169
A way to clear the N_ macro, which is defined as an inline function.
double inner(valarray< double > const &x, valarray< double > const &y)
RectangularCluster rc
SVG drawing for display.
Geom::Point start
Geom::Point end
constexpr uint32_t U_RGB_COMPOSE(U_COLORREF c)
Metafile printing - common functions.
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
DB db
This is the actual database object.
Definition db.cpp:32
Print * get_print(gchar const *key)
Definition system.cpp:282
void build_from_mem(gchar const *buffer, std::unique_ptr< Implementation::Implementation > in_imp)
Create a module from a buffer holding an XML description.
Definition system.cpp:459
Geom::PathVector sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, BooleanOp bop, FillRule fra, FillRule frb)
Perform a boolean operation on two pathvectors.
Boolean operations.
int off
void invert(const double v[16], double alpha[16])
SPRoot: SVG <svg> implementation.
WMF_DEVICE_CONTEXT dc[WMF_MAX_DC+1]
Definition wmf-inout.h:127
Information for a single text object.
int rt_tidx
index of rectangle that contains it
int decoration
text decorations, ignored during assembly, used during output
int weight
weight, as in FontConfig
int taln
text alignment with respect to x,y
double boff
Y LL corner - boff finds baseline
int spaces
count of spaces converted from wide kerning (1 or 2)
int co
condensed override, if set Font name included narrow
double ori
Orientation, angle of characters with respect to baseline in degrees.
int fi_idx
index of the font it uses
uint8_t * string
UTF-8 text
double fs
font size of text
int ldir
language direction LDIR_*
double vadvance
Line spacing typically 1.25 or 1.2, only set on the first text element in a complex
TRCOLORREF color
RGB
int italics
italics, as in FontConfig
double x
x coordinate, relative to TR_INFO x,y, in points
double y
y coordinate, relative to TR_INFO x,y, in points
int condensed
condensed, as in FontConfig
uint8_t Red
Red color (0-255)
uint8_t Green
Green color (0-255)
uint8_t Reserved
Not used.
uint8_t Blue
Blue color (0-255)
uint8_t * out
buffer to hold formatted output
int dirty
1 if text records are loaded
FT_INFO * fti
Font info storage
Bitmap16 Object WMF manual 2.2.2.1.
Definition uwmf.h:869
int16_t Height
bitmap height in scan lines.
Definition uwmf.h:872
uint8_t BitsPixel
number of adjacent color bits on each plane (R bits + G bits + B bits ????)
Definition uwmf.h:875
int16_t Width
bitmap width in pixels.
Definition uwmf.h:871
WMF manual 2.2.2.8.
Definition uemf.h:474
uint8_t Red
Red color (0-255)
Definition uemf.h:475
uint8_t Blue
Blue color (0-255)
Definition uemf.h:477
uint8_t Green
Green color (0-255)
Definition uemf.h:476
Font Object WMF manual 2.2.1.2 Warning, only pass by pointer, passing by value will will truncate in ...
Definition uwmf.h:783
int16_t Weight
LF_Weight Enumeration.
Definition uwmf.h:788
int16_t Escapement
Angle in 0.1 degrees betweem escapement vector and X axis.
Definition uwmf.h:786
uint8_t Italic
LF_Italic Enumeration.
Definition uwmf.h:789
int16_t Height
Height in Logical units.
Definition uwmf.h:784
uint8_t StrikeOut
LF_StrikeOut Enumeration.
Definition uwmf.h:791
uint8_t Underline
LF_Underline Enumeration.
Definition uwmf.h:790
SizeL Object WMF manual 2.2.2.22 Same as "EMF SIZEL Object" in uemf.h.
Definition uwmf.h:1070
Any generic pair of floats.
Definition uemf.h:1637
float x
X value.
Definition uemf.h:1638
float y
Y value.
Definition uemf.h:1639
Pen Object WMF manual 2.2.1.4.
Definition uwmf.h:826
uint16_t Widthw[2]
reassemble/store the Pen Width in object dimensions using Widthw, the 32 bit value is not aligned
Definition uwmf.h:828
U_COLORREF Color
Pen Color, the 32 bit value is not aligned.
Definition uwmf.h:829
uint16_t Style
PenStyle Enumeration.
Definition uwmf.h:827
WMF manual 2.2.2.16.
Definition uemf.h:563
int16_t y
Y size (16 bit)
Definition uemf.h:565
int16_t x
X size (16 bit)
Definition uemf.h:564
Rect Object WMF manual 2.2.2.18.
Definition uwmf.h:840
int16_t bottom
bottom coordinate
Definition uwmf.h:844
int16_t right
right coordinate
Definition uwmf.h:843
int16_t top
top coordinate
Definition uwmf.h:842
int16_t left
left coordinate
Definition uwmf.h:841
WMF manual 2.2.2.20.
Definition uemf.h:592
BitmapInfoHeader Object WMF manual 2.2.2.3 Same as "EMF BITMAPINFOHEADER Object" in uemf....
Definition uwmf.h:986
uint16_t Style
BrushStyle Enumeration.
Definition uwmf.h:987
U_COLORREF Color
Brush Color value, 32 bit value is not aligned.
Definition uwmf.h:988
uint16_t Hatch
HatchStyle Enumeration.
Definition uwmf.h:989
WMF manual 2.3.2.2 META_HEADER.
Definition uwmf.h:1092
uint16_t nObjects
Total number of brushes, pens, and other graphics objects defined in this file.
Definition uwmf.h:1098
WMF manual 2.3.2.3 META_PLACEABLE If present this must immediately precede the header.
Definition uwmf.h:1081
uint16_t Inch
Logical units/inch (convention if not specified: 1440 logical units/inch)
Definition uwmf.h:1085
U_RECT16 Dst
Destination bounding box in logical units.
Definition uwmf.h:1084
@ SP_WIND_RULE_NONZERO
Definition style-enums.h:24
@ SP_WIND_RULE_INTERSECT
Definition style-enums.h:25
@ SP_STROKE_LINEJOIN_MITER
Definition style-enums.h:34
@ SP_STROKE_LINEJOIN_BEVEL
Definition style-enums.h:36
@ SP_STROKE_LINEJOIN_ROUND
Definition style-enums.h:35
@ SP_CSS_FONT_STYLE_NORMAL
Definition style-enums.h:61
@ SP_CSS_FONT_STYLE_OBLIQUE
Definition style-enums.h:63
@ SP_CSS_FONT_STYLE_ITALIC
Definition style-enums.h:62
@ SP_STROKE_LINECAP_SQUARE
Definition style-enums.h:43
@ SP_STROKE_LINECAP_ROUND
Definition style-enums.h:42
@ SP_STROKE_LINECAP_BUTT
Definition style-enums.h:41
@ SP_CSS_FONT_WEIGHT_LIGHTER
Definition style-enums.h:83
@ SP_CSS_FONT_WEIGHT_NORMAL
Definition style-enums.h:81
@ SP_CSS_FONT_WEIGHT_BOLD
Definition style-enums.h:82
@ SP_CSS_FONT_WEIGHT_400
Definition style-enums.h:75
@ SP_CSS_FONT_WEIGHT_300
Definition style-enums.h:74
@ SP_CSS_FONT_WEIGHT_100
Definition style-enums.h:72
@ SP_CSS_FONT_WEIGHT_200
Definition style-enums.h:73
@ SP_CSS_FONT_WEIGHT_900
Definition style-enums.h:80
@ SP_CSS_FONT_WEIGHT_700
Definition style-enums.h:78
@ SP_CSS_FONT_WEIGHT_800
Definition style-enums.h:79
@ SP_CSS_FONT_WEIGHT_500
Definition style-enums.h:76
@ SP_CSS_FONT_WEIGHT_BOLDER
Definition style-enums.h:84
@ SP_CSS_FONT_WEIGHT_600
Definition style-enums.h:77
Geom::PathVector sp_svg_read_pathv(char const *str)
Definition svg-path.cpp:37
static void sp_svg_write_path(Inkscape::SVG::PathString &str, Geom::Path const &p, bool normalize=false)
Definition svg-path.cpp:109
Enhanced Metafile Input/Output.
int NonToUnicode(uint32_t *text, char *font)
void msdepua(uint32_t *text)
void TableGen(bool symb, bool wing, bool zdng, bool pua)
int index
double height
double width
int trinfo_load_qe(TR_INFO *tri, double qe)
TR_INFO * trinfo_init(TR_INFO *tri)
char * TR_construct_fontspec(const TCHUNK_SPECS *tsp, const char *fontname)
int TR_layout_analyze(TR_INFO *tri)
int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor)
void TR_layout_2_svg(TR_INFO *tri)
TR_INFO * trinfo_clear(TR_INFO *tri)
TR_INFO * trinfo_release_except_FC(TR_INFO *tri)
int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode)
int TR_findcasesub(const char *string, const char *sub)
int trinfo_load_textrec(TR_INFO *tri, const TCHUNK_SPECS *tsp, double escapement, int flags)
int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec)
Glib::ustring name
Definition toolbars.cpp:55
char * U_strdup(const char *s)
uint32_t * U_Latin1ToUtf32le(const char *src, size_t max, size_t *len)
char * U_Utf32leToUtf8(const uint32_t *src, size_t max, size_t *len)
@ U_WMR_PAINTREGION
0x012B U_WMRPAINTREGION record
Definition uwmf.h:124
@ U_WMR_CREATEPATTERNBRUSH
0x01F9 U_WMRCREATEPATTERNBRUSH record
Definition uwmf.h:330
@ U_WMR_C1
0x00C1 U_WMRC1 record
Definition uwmf.h:274
@ U_WMR_POLYGON
0x0324 U_WMRPOLYGON record
Definition uwmf.h:117
@ U_WMR_4F
0x004F U_WMR4F record
Definition uwmf.h:160
@ U_WMR_ED
0x00ED U_WMRED record
Definition uwmf.h:318
@ U_WMR_59
0x0059 U_WMR59 record
Definition uwmf.h:170
@ U_WMR_47
0x0047 U_WMR47 record
Definition uwmf.h:152
@ U_WMR_86
0x0086 U_WMR86 record
Definition uwmf.h:215
@ U_WMR_80
0x0080 U_WMR80 record
Definition uwmf.h:209
@ U_WMR_D4
0x00D4 U_WMRD4 record
Definition uwmf.h:293
@ U_WMR_RECTANGLE
0x041B U_WMRRECTANGLE record
Definition uwmf.h:108
@ U_WMR_INTERSECTCLIPRECT
0x0416 U_WMRINTERSECTCLIPRECT record
Definition uwmf.h:103
@ U_WMR_SETROP2
0x0104 U_WMRSETROP2 record
Definition uwmf.h:85
@ U_WMR_OFFSETCLIPRGN
0x0220 U_WMROFFSETCLIPRGN record
Definition uwmf.h:113
@ U_WMR_AD
0x00AD U_WMRAD record
Definition uwmf.h:254
@ U_WMR_EOF
0x0000 U_WMREOF record
Definition uwmf.h:81
@ U_WMR_91
0x0091 U_WMR91 record
Definition uwmf.h:226
@ U_WMR_3E
0x003E U_WMR3E record
Definition uwmf.h:143
@ U_WMR_DB
0x00DB U_WMRDB record
Definition uwmf.h:300
@ U_WMR_92
0x0092 U_WMR92 record
Definition uwmf.h:227
@ U_WMR_AF
0x00AF U_WMRAF record
Definition uwmf.h:256
@ U_WMR_84
0x0084 U_WMR84 record
Definition uwmf.h:213
@ U_WMR_SCALEVIEWPORTEXT
0x0412 U_WMRSCALEVIEWPORTEXT record
Definition uwmf.h:99
@ U_WMR_B2
0x00B2 U_WMRB2 record
Definition uwmf.h:259
@ U_WMR_DA
0x00DA U_WMRDA record
Definition uwmf.h:299
@ U_WMR_6E
0x006E U_WMR6E record
Definition uwmf.h:191
@ U_WMR_7C
0x007C U_WMR7C record
Definition uwmf.h:205
@ U_WMR_64
0x0064 U_WMR64 record
Definition uwmf.h:181
@ U_WMR_87
0x0087 U_WMR87 record
Definition uwmf.h:216
@ U_WMR_E8
0x00E8 U_WMRE8 record
Definition uwmf.h:313
@ U_WMR_FRAMEREGION
0x0429 U_WMRFRAMEREGION record
Definition uwmf.h:122
@ U_WMR_PATBLT
0x061D U_WMRPATBLT record
Definition uwmf.h:110
@ U_WMR_A2
0x00A2 U_WMRA2 record
Definition uwmf.h:243
@ U_WMR_C8
0x00C8 U_WMRC8 record
Definition uwmf.h:281
@ U_WMR_72
0x0072 U_WMR72 record
Definition uwmf.h:195
@ U_WMR_3A
0x003A U_WMR3A record
Definition uwmf.h:139
@ U_WMR_DIBCREATEPATTERNBRUSH
0x0142 U_WMRDIBCREATEPATTERNBRUSH record
Definition uwmf.h:147
@ U_WMR_F2
0x00F2 U_WMRF2 record
Definition uwmf.h:323
@ U_WMR_C5
0x00C5 U_WMRC5 record
Definition uwmf.h:278
@ U_WMR_9E
0x009E U_WMR9E record
Definition uwmf.h:239
@ U_WMR_53
0x0053 U_WMR53 record
Definition uwmf.h:164
@ U_WMR_67
0x0067 U_WMR67 record
Definition uwmf.h:184
@ U_WMR_A8
0x00A8 U_WMRA8 record
Definition uwmf.h:249
@ U_WMR_51
0x0051 U_WMR51 record
Definition uwmf.h:162
@ U_WMR_EB
0x00EB U_WMREB record
Definition uwmf.h:316
@ U_WMR_SELECTPALETTE
0x0234 U_WMRSELECTPALETTE record
Definition uwmf.h:133
@ U_WMR_6F
0x006F U_WMR6F record
Definition uwmf.h:192
@ U_WMR_7F
0x007F U_WMR7F record
Definition uwmf.h:208
@ U_WMR_C6
0x00C6 U_WMRC6 record
Definition uwmf.h:279
@ U_WMR_55
0x0055 U_WMR55 record
Definition uwmf.h:166
@ U_WMR_F6
0x00F6 U_WMRF6 record
Definition uwmf.h:327
@ U_WMR_5B
0x005B U_WMR5B record
Definition uwmf.h:172
@ U_WMR_AB
0x00AB U_WMRAB record
Definition uwmf.h:252
@ U_WMR_63
0x0063 U_WMR63 record
Definition uwmf.h:180
@ U_WMR_D9
0x00D9 U_WMRD9 record
Definition uwmf.h:298
@ U_WMR_SETMAPPERFLAGS
0x0231 U_WMRSETMAPPERFLAGS record
Definition uwmf.h:130
@ U_WMR_E6
0x00E6 U_WMRE6 record
Definition uwmf.h:311
@ U_WMR_3D
0x003D U_WMR3D record
Definition uwmf.h:142
@ U_WMR_76
0x0076 U_WMR76 record
Definition uwmf.h:199
@ U_WMR_DIBBITBLT
0x0940 U_WMRDIBBITBLT record
Definition uwmf.h:145
@ U_WMR_CE
0x00CE U_WMRCE record
Definition uwmf.h:287
@ U_WMR_9A
0x009A U_WMR9A record
Definition uwmf.h:235
@ U_WMR_EE
0x00EE U_WMREE record
Definition uwmf.h:319
@ U_WMR_44
0x0044 U_WMR44 record
Definition uwmf.h:149
@ U_WMR_7A
0x007A U_WMR7A record
Definition uwmf.h:203
@ U_WMR_70
0x0070 U_WMR70 record
Definition uwmf.h:193
@ U_WMR_4A
0x004A U_WMR4A record
Definition uwmf.h:155
@ U_WMR_B4
0x00B4 U_WMRB4 record
Definition uwmf.h:261
@ U_WMR_D1
0x00D1 U_WMRD1 record
Definition uwmf.h:290
@ U_WMR_E9
0x00E9 U_WMRE9 record
Definition uwmf.h:314
@ U_WMR_56
0x0056 U_WMR56 record
Definition uwmf.h:167
@ U_WMR_8A
0x008A U_WMR8A record
Definition uwmf.h:219
@ U_WMR_A5
0x00A5 U_WMRA5 record
Definition uwmf.h:246
@ U_WMR_EXTTEXTOUT
0x0A32 U_WMREXTTEXTOUT record
Definition uwmf.h:131
@ U_WMR_61
0x0061 U_WMR61 record
Definition uwmf.h:178
@ U_WMR_SETTEXTCOLOR
0x0209 U_WMRSETTEXTCOLOR record
Definition uwmf.h:90
@ U_WMR_8E
0x008E U_WMR8E record
Definition uwmf.h:223
@ U_WMR_71
0x0071 U_WMR71 record
Definition uwmf.h:194
@ U_WMR_88
0x0088 U_WMR88 record
Definition uwmf.h:217
@ U_WMR_6B
0x006B U_WMR6B record
Definition uwmf.h:188
@ U_WMR_8D
0x008D U_WMR8D record
Definition uwmf.h:222
@ U_WMR_C7
0x00C7 U_WMRC7 record
Definition uwmf.h:280
@ U_WMR_83
0x0083 U_WMR83 record
Definition uwmf.h:212
@ U_WMR_SETWINDOWEXT
0x020C U_WMRSETWINDOWEXT record
Definition uwmf.h:93
@ U_WMR_90
0x0090 U_WMR90 record
Definition uwmf.h:225
@ U_WMR_A1
0x00A1 U_WMRA1 record
Definition uwmf.h:242
@ U_WMR_INVERTREGION
0x012A U_WMRINVERTREGION record
Definition uwmf.h:123
@ U_WMR_B9
0x00B9 U_WMRB9 record
Definition uwmf.h:266
@ U_WMR_C3
0x00C3 U_WMRC3 record
Definition uwmf.h:276
@ U_WMR_SETDIBTODEV
0x0D33 U_WMRSETDIBTODEV record
Definition uwmf.h:132
@ U_WMR_D8
0x00D8 U_WMRD8 record
Definition uwmf.h:297
@ U_WMR_SETBKCOLOR
0x0201 U_WMRSETBKCOLOR record
Definition uwmf.h:82
@ U_WMR_ANIMATEPALETTE
0x0436 U_WMRANIMATEPALETTE record
Definition uwmf.h:135
@ U_WMR_3F
0x003F U_WMR3F record
Definition uwmf.h:144
@ U_WMR_SETWINDOWORG
0x020B U_WMRSETWINDOWORG record
Definition uwmf.h:92
@ U_WMR_BF
0x00BF U_WMRBF record
Definition uwmf.h:272
@ U_WMR_SETBKMODE
0x0102 U_WMRSETBKMODE record
Definition uwmf.h:83
@ U_WMR_POLYLINE
0x0325 U_WMRPOLYLINE record
Definition uwmf.h:118
@ U_WMR_9C
0x009C U_WMR9C record
Definition uwmf.h:237
@ U_WMR_SETTEXTALIGN
0x012E U_WMRSETTEXTALIGN record
Definition uwmf.h:127
@ U_WMR_F3
0x00F3 U_WMRF3 record
Definition uwmf.h:324
@ U_WMR_A9
0x00A9 U_WMRA9 record
Definition uwmf.h:250
@ U_WMR_AA
0x00AA U_WMRAA record
Definition uwmf.h:251
@ U_WMR_B6
0x00B6 U_WMRB6 record
Definition uwmf.h:263
@ U_WMR_BA
0x00BA U_WMRBA record
Definition uwmf.h:267
@ U_WMR_SETSTRETCHBLTMODE
0x0107 U_WMRSETSTRETCHBLTMODE record
Definition uwmf.h:88
@ U_WMR_68
0x0068 U_WMR68 record
Definition uwmf.h:185
@ U_WMR_77
0x0077 U_WMR77 record
Definition uwmf.h:200
@ U_WMR_5F
0x005F U_WMR5F record
Definition uwmf.h:176
@ U_WMR_9D
0x009D U_WMR9D record
Definition uwmf.h:238
@ U_WMR_BB
0x00BB U_WMRBB record
Definition uwmf.h:268
@ U_WMR_SETTEXTCHAREXTRA
0x0108 U_WMRSETTEXTCHAREXTRA record
Definition uwmf.h:89
@ U_WMR_E5
0x00E5 U_WMRE5 record
Definition uwmf.h:310
@ U_WMR_58
0x0058 U_WMR58 record
Definition uwmf.h:169
@ U_WMR_CREATEPALETTE
0x00F7 U_WMRCREATEPALETTE record
Definition uwmf.h:328
@ U_WMR_8F
0x008F U_WMR8F record
Definition uwmf.h:224
@ U_WMR_EF
0x00EF U_WMREF record
Definition uwmf.h:320
@ U_WMR_D7
0x00D7 U_WMRD7 record
Definition uwmf.h:296
@ U_WMR_MOVETO
0x0214 U_WMRMOVETO record
Definition uwmf.h:101
@ U_WMR_89
0x0089 U_WMR89 record
Definition uwmf.h:218
@ U_WMR_DF
0x00DF U_WMRDF record
Definition uwmf.h:304
@ U_WMR_6D
0x006D U_WMR6D record
Definition uwmf.h:190
@ U_WMR_STRETCHBLT
0x0B23 U_WMRSTRETCHBLT record
Definition uwmf.h:116
@ U_WMR_CREATEBITMAP
0x06FE U_WMRCREATEBITMAP record
Definition uwmf.h:335
@ U_WMR_E2
0x00E2 U_WMRE2 record
Definition uwmf.h:307
@ U_WMR_SETPOLYFILLMODE
0x0106 U_WMRSETPOLYFILLMODE record
Definition uwmf.h:87
@ U_WMR_85
0x0085 U_WMR85 record
Definition uwmf.h:214
@ U_WMR_4D
0x014D U_WMR4D record
Definition uwmf.h:158
@ U_WMR_4E
0x004E U_WMR4E record
Definition uwmf.h:159
@ U_WMR_FLOODFILL
0x0419 U_WMRFLOODFILL record
Definition uwmf.h:106
@ U_WMR_6C
0x006C U_WMR6C record
Definition uwmf.h:189
@ U_WMR_SETPIXEL
0x041F U_WMRSETPIXEL record
Definition uwmf.h:112
@ U_WMR_D3
0x00D3 U_WMRD3 record
Definition uwmf.h:292
@ U_WMR_5A
0x005A U_WMR5A record
Definition uwmf.h:171
@ U_WMR_79
0x0079 U_WMR79 record
Definition uwmf.h:202
@ U_WMR_49
0x0049 U_WMR49 record
Definition uwmf.h:154
@ U_WMR_DRAWTEXT
0x062F U_WMRDRAWTEXT record
Definition uwmf.h:128
@ U_WMR_OFFSETVIEWPORTORG
0x0211 U_WMROFFSETVIEWPORTORG record
Definition uwmf.h:98
@ U_WMR_C0
0x00C0 U_WMRC0 record
Definition uwmf.h:273
@ U_WMR_D0
0x00D0 U_WMRD0 record
Definition uwmf.h:289
@ U_WMR_AE
0x00AE U_WMRAE record
Definition uwmf.h:255
@ U_WMR_ESCAPE
0x0626 U_WMRESCAPE record
Definition uwmf.h:119
@ U_WMR_DE
0x00DE U_WMRDE record
Definition uwmf.h:303
@ U_WMR_PIE
0x081A U_WMRPIE record
Definition uwmf.h:107
@ U_WMR_TEXTOUT
0x0521 U_WMRTEXTOUT record
Definition uwmf.h:114
@ U_WMR_DELETEOBJECT
0x01F0 U_WMRDELETEOBJECT record
Definition uwmf.h:321
@ U_WMR_SELECTCLIPREGION
0x012C U_WMRSELECTCLIPREGION record
Definition uwmf.h:125
@ U_WMR_E7
0x00E7 U_WMRE7 record
Definition uwmf.h:312
@ U_WMR_EXTFLOODFILL
0x0548 U_WMREXTFLOODFILL record
Definition uwmf.h:153
@ U_WMR_BITBLT
0x0922 U_WMRBITBLT record
Definition uwmf.h:115
@ U_WMR_93
0x0093 U_WMR93 record
Definition uwmf.h:228
@ U_WMR_50
0x0050 U_WMR50 record
Definition uwmf.h:161
@ U_WMR_9F
0x009F U_WMR9F record
Definition uwmf.h:240
@ U_WMR_CF
0x00CF U_WMRCF record
Definition uwmf.h:288
@ U_WMR_DIBSTRETCHBLT
0x0B41 U_WMRDIBSTRETCHBLT record
Definition uwmf.h:146
@ U_WMR_RESTOREDC
0x0127 U_WMRRESTOREDC record
Definition uwmf.h:120
@ U_WMR_95
0x0095 U_WMR95 record
Definition uwmf.h:230
@ U_WMR_STRETCHDIB
0x0F43 U_WMRSTRETCHDIB record
Definition uwmf.h:148
@ U_WMR_5C
0x005C U_WMR5C record
Definition uwmf.h:173
@ U_WMR_SELECTOBJECT
0x012D U_WMRSELECTOBJECT record
Definition uwmf.h:126
@ U_WMR_SETMAPMODE
0x0103 U_WMRSETMAPMODE record
Definition uwmf.h:84
@ U_WMR_99
0x0099 U_WMR99 record
Definition uwmf.h:234
@ U_WMR_DC
0x00DC U_WMRDC record
Definition uwmf.h:301
@ U_WMR_7E
0x007E U_WMR7E record
Definition uwmf.h:207
@ U_WMR_D6
0x00D6 U_WMRD6 record
Definition uwmf.h:295
@ U_WMR_CREATEREGION
0x06FF U_WMRCREATEREGION record
Definition uwmf.h:336
@ U_WMR_7B
0x007B U_WMR7B record
Definition uwmf.h:204
@ U_WMR_BD
0x00BD U_WMRBD record
Definition uwmf.h:270
@ U_WMR_8C
0x008C U_WMR8C record
Definition uwmf.h:221
@ U_WMR_96
0x0096 U_WMR96 record
Definition uwmf.h:231
@ U_WMR_45
0x0045 U_WMR45 record
Definition uwmf.h:150
@ U_WMR_F4
0x00F4 U_WMRF4 record
Definition uwmf.h:325
@ U_WMR_57
0x0057 U_WMR57 record
Definition uwmf.h:168
@ U_WMR_82
0x0082 U_WMR82 record
Definition uwmf.h:211
@ U_WMR_ROUNDRECT
0x061C U_WMRROUNDRECT record
Definition uwmf.h:109
@ U_WMR_5D
0x005D U_WMR5D record
Definition uwmf.h:174
@ U_WMR_97
0x0097 U_WMR97 record
Definition uwmf.h:232
@ U_WMR_D5
0x00D5 U_WMRD5 record
Definition uwmf.h:294
@ U_WMR_6A
0x006A U_WMR6A record
Definition uwmf.h:187
@ U_WMR_CA
0x00CA U_WMRCA record
Definition uwmf.h:283
@ U_WMR_CHORD
0x0830 U_WMRCHORD record
Definition uwmf.h:129
@ U_WMR_60
0x0060 U_WMR60 record
Definition uwmf.h:177
@ U_WMR_A3
0x00A3 U_WMRA3 record
Definition uwmf.h:244
@ U_WMR_C9
0x00C9 U_WMRC9 record
Definition uwmf.h:282
@ U_WMR_SETRELABS
0x0105 U_WMRSETRELABS record
Definition uwmf.h:86
@ U_WMR_A7
0x00A7 U_WMRA7 record
Definition uwmf.h:248
@ U_WMR_73
0x0073 U_WMR73 record
Definition uwmf.h:196
@ U_WMR_POLYPOLYGON
0x0538 U_WMRPOLYPOLYGON record
Definition uwmf.h:137
@ U_WMR_C2
0x00C2 U_WMRC2 record
Definition uwmf.h:275
@ U_WMR_EXCLUDECLIPRECT
0x0415 U_WMREXCLUDECLIPRECT record
Definition uwmf.h:102
@ U_WMR_C4
0x00C4 U_WMRC4 record
Definition uwmf.h:277
@ U_WMR_8B
0x008B U_WMR8B record
Definition uwmf.h:220
@ U_WMR_F5
0x00F5 U_WMRF5 record
Definition uwmf.h:326
@ U_WMR_A4
0x00A4 U_WMRA4 record
Definition uwmf.h:245
@ U_WMR_E4
0x00E4 U_WMRE4 record
Definition uwmf.h:309
@ U_WMR_F8
0x00F8 U_WMRF8 record
Definition uwmf.h:329
@ U_WMR_E3
0x00E3 U_WMRE3 record
Definition uwmf.h:308
@ U_WMR_F1
0x00F1 U_WMRF1 record
Definition uwmf.h:322
@ U_WMR_E1
0x00E1 U_WMRE1 record
Definition uwmf.h:306
@ U_WMR_B0
0x00B0 U_WMRB0 record
Definition uwmf.h:257
@ U_WMR_BE
0x00BE U_WMRBE record
Definition uwmf.h:271
@ U_WMR_SCALEWINDOWEXT
0x0410 U_WMRSCALEWINDOWEXT record
Definition uwmf.h:97
@ U_WMR_D2
0x00D2 U_WMRD2 record
Definition uwmf.h:291
@ U_WMR_CREATEBITMAPINDIRECT
0x02FD U_WMRCREATEBITMAPINDIRECT record
Definition uwmf.h:334
@ U_WMR_DD
0x00DD U_WMRDD record
Definition uwmf.h:302
@ U_WMR_EC
0x00EC U_WMREC record
Definition uwmf.h:317
@ U_WMR_3B
0x003B U_WMR3B record
Definition uwmf.h:140
@ U_WMR_81
0x0081 U_WMR81 record
Definition uwmf.h:210
@ U_WMR_CC
0x00CC U_WMRCC record
Definition uwmf.h:285
@ U_WMR_62
0x0062 U_WMR62 record
Definition uwmf.h:179
@ U_WMR_74
0x0074 U_WMR74 record
Definition uwmf.h:197
@ U_WMR_SETVIEWPORTORG
0x020D U_WMRSETVIEWPORTORG record
Definition uwmf.h:94
@ U_WMR_SETVIEWPORTEXT
0x020E U_WMRSETVIEWPORTEXT record
Definition uwmf.h:95
@ U_WMR_A0
0x00A0 U_WMRA0 record
Definition uwmf.h:241
@ U_WMR_65
0x0065 U_WMR65 record
Definition uwmf.h:182
@ U_WMR_54
0x0054 U_WMR54 record
Definition uwmf.h:165
@ U_WMR_EA
0x00EA U_WMREA record
Definition uwmf.h:315
@ U_WMR_B1
0x00B1 U_WMRB1 record
Definition uwmf.h:258
@ U_WMR_B5
0x00B5 U_WMRB5 record
Definition uwmf.h:262
@ U_WMR_B7
0x00B7 U_WMRB7 record
Definition uwmf.h:264
@ U_WMR_LINETO
0x0213 U_WMRLINETO record
Definition uwmf.h:100
@ U_WMR_98
0x0098 U_WMR98 record
Definition uwmf.h:233
@ U_WMR_SETPALENTRIES
0x0037 U_WMRSETPALENTRIES record
Definition uwmf.h:136
@ U_WMR_BC
0x00BC U_WMRBC record
Definition uwmf.h:269
@ U_WMR_CD
0x00CD U_WMRCD record
Definition uwmf.h:286
@ U_WMR_SAVEDC
0x001E U_WMRSAVEDC record
Definition uwmf.h:111
@ U_WMR_94
0x0094 U_WMR94 record
Definition uwmf.h:229
@ U_WMR_AC
0x00AC U_WMRAC record
Definition uwmf.h:253
@ U_WMR_3C
0x003C U_WMR3C record
Definition uwmf.h:141
@ U_WMR_RESIZEPALETTE
0x0139 U_WMRRESIZEPALETTE record
Definition uwmf.h:138
@ U_WMR_69
0x0069 U_WMR69 record
Definition uwmf.h:186
@ U_WMR_ARC
0x0817 U_WMRARC record
Definition uwmf.h:104
@ U_WMR_52
0x0052 U_WMR52 record
Definition uwmf.h:163
@ U_WMR_75
0x0075 U_WMR75 record
Definition uwmf.h:198
@ U_WMR_7D
0x007D U_WMR7D record
Definition uwmf.h:206
@ U_WMR_9B
0x009B U_WMR9B record
Definition uwmf.h:236
@ U_WMR_CREATEFONTINDIRECT
0x02FB U_WMRCREATEFONTINDIRECT record
Definition uwmf.h:332
@ U_WMR_FILLREGION
0x0228 U_WMRFILLREGION record
Definition uwmf.h:121
@ U_WMR_CREATEBRUSHINDIRECT
0x02FC U_WMRCREATEBRUSHINDIRECT record
Definition uwmf.h:333
@ U_WMR_REALIZEPALETTE
0x0035 U_WMRREALIZEPALETTE record
Definition uwmf.h:134
@ U_WMR_CREATEPENINDIRECT
0x02FA U_WMRCREATEPENINDIRECT record
Definition uwmf.h:331
@ U_WMR_46
0x0046 U_WMR46 record
Definition uwmf.h:151
@ U_WMR_B3
0x00B3 U_WMRB3 record
Definition uwmf.h:260
@ U_WMR_5E
0x005E U_WMR5E record
Definition uwmf.h:175
@ U_WMR_78
0x0078 U_WMR78 record
Definition uwmf.h:201
@ U_WMR_4B
0x004B U_WMR4B record
Definition uwmf.h:156
@ U_WMR_SETTEXTJUSTIFICATION
0x020A U_WMRSETTEXTJUSTIFICATION record
Definition uwmf.h:91
@ U_WMR_ELLIPSE
0x0418 U_WMRELLIPSE record
Definition uwmf.h:105
@ U_WMR_A6
0x00A6 U_WMRA6 record
Definition uwmf.h:247
@ U_WMR_4C
0x014C U_WMR4C record
Definition uwmf.h:157
@ U_WMR_66
0x0066 U_WMR66 record
Definition uwmf.h:183
@ U_WMR_OFFSETWINDOWORG
0x020F U_WMROFFSETWINDOWORG record
Definition uwmf.h:96
@ U_WMR_E0
0x00E0 U_WMRE0 record
Definition uwmf.h:305
@ U_WMR_B8
0x00B8 U_WMRB8 record
Definition uwmf.h:265
@ U_WMR_CB
0x00CB U_WMRCB record
Definition uwmf.h:284
constexpr auto PRINT_WMF
Definition wmf-inout.cpp:50
Windows Metafile Input/Output.