Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
emf-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 <cstdio>
27#include <cstdlib>
28#include <cstdint>
30
31#include "emf-inout.h"
32
33#include "clear-n_.h"
34#include "colors/color.h"
36#include "display/drawing.h"
37#include "document.h"
38#include "extension/db.h"
39#include "extension/input.h"
40#include "extension/output.h"
41#include "extension/print.h"
42#include "extension/system.h"
43#include "object/sp-root.h"
44#include "path/path-boolop.h"
45#include "print.h"
46#include "svg/svg.h"
47#include "util/safe-printf.h"
48#include "util/units.h"
49
50#include "emf-print.h"
51
52constexpr auto PRINT_EMF = "org.inkscape.print.emf";
53
54#ifndef U_PS_JOIN_MASK
55#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND)
56#endif
57
59
60static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented
61static uint32_t BLTmode = 0;
62constexpr float faraway = 10000000; // used in "exclude" clips, hopefully well outside any real drawing!
63
68
69void
70Emf::print_document_to_file(SPDocument *doc, const gchar *filename)
71{
73 SPPrintContext context;
74 const gchar *oldconst;
75 gchar *oldoutput;
76 unsigned int ret;
77
78 doc->ensureUpToDate();
79
81 oldconst = mod->get_param_string("destination");
82 oldoutput = g_strdup(oldconst);
83 mod->set_param_string("destination", filename);
84
85/* Start */
86 context.module = mod;
87 /* fixme: This has to go into module constructor somehow */
88 /* Create new arena */
89 mod->base = doc->getRoot();
90 Inkscape::Drawing drawing;
91 mod->dkey = SPItem::display_key_new(1);
92 mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY);
93 drawing.setRoot(mod->root);
94 /* Print document */
95 ret = mod->begin(doc);
96 if (ret) {
97 g_free(oldoutput);
99 }
100 mod->base->invoke_print(&context);
101 (void) mod->finish();
102 /* Release arena */
103 mod->base->invoke_hide(mod->dkey);
104 mod->base = nullptr;
105 mod->root = nullptr; // deleted by invoke_hide
106/* end */
107
108 mod->set_param_string("destination", oldoutput);
109 g_free(oldoutput);
110
111 return;
112}
113
114
115void
116Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
117{
119
121 if (ext == nullptr)
122 return;
123
124 bool new_val = mod->get_param_bool("textToPath");
125 bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug
126 // reserve FixPPT2 for opacity bug. Currently EMF does not export opacity values
127 bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug
128 bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug
129 bool new_FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad"); // allow native rectangular linear gradient
130 bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard EMF hatch
131 bool new_FixImageRot = mod->get_param_bool("FixImageRot"); // remove rotations on images
132
133 TableGen( //possibly regenerate the unicode-convert tables
134 mod->get_param_bool("TnrToSymbol"),
135 mod->get_param_bool("TnrToWingdings"),
136 mod->get_param_bool("TnrToZapfDingbats"),
137 mod->get_param_bool("UsePUA")
138 );
139
140 ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result!
141 ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine);
142 ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys);
143 ext->set_param_bool("FixPPTLinGrad",new_FixPPTLinGrad);
144 ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch);
145 ext->set_param_bool("FixImageRot",new_FixImageRot);
146 ext->set_param_bool("textToPath", new_val);
147
148 // ensure usage of dot as decimal separator in scanf/printf functions (independently of current locale)
149 char *oldlocale = g_strdup(setlocale(LC_NUMERIC, nullptr));
150 setlocale(LC_NUMERIC, "C");
151
152 print_document_to_file(doc, filename);
153
154 // restore decimal separator used in scanf/printf functions to initial value
155 setlocale(LC_NUMERIC, oldlocale);
156 g_free(oldlocale);
157
158 return;
159}
160
161
162/* given the transformation matrix from worldTransform return the scale in the matrix part. Assumes that the
163 matrix is not used to skew, invert, or make another distorting transformation. */
165 double scale =
168 if(scale <= 0.0)scale=1.0; /* something is dreadfully wrong with the matrix, but do not crash over it */
169 scale=sqrt(scale);
170 return(scale);
171}
172
173/* given the transformation matrix from worldTransform and the current x,y position in inkscape coordinates,
174 generate an SVG transform that gives the same amount of rotation, no scaling, and maps x,y back onto x,y. This is used for
175 rotating objects when the location of at least one point in that object is known. Returns:
176 "matrix(a,b,c,d,e,f)" (WITH the double quotes)
177*/
178std::string Emf::current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset){
179 SVGOStringStream cxform;
180 double scale = current_scale(d);
181 cxform << "\"matrix(";
182 cxform << d->dc[d->level].worldTransform.eM11/scale; cxform << ",";
183 cxform << d->dc[d->level].worldTransform.eM12/scale; cxform << ",";
184 cxform << d->dc[d->level].worldTransform.eM21/scale; cxform << ",";
185 cxform << d->dc[d->level].worldTransform.eM22/scale; cxform << ",";
186 if(useoffset){
187 /* for the "new" coordinates drop the worldtransform translations, not used here */
188 double newx = x * d->dc[d->level].worldTransform.eM11/scale + y * d->dc[d->level].worldTransform.eM21/scale;
189 double newy = x * d->dc[d->level].worldTransform.eM12/scale + y * d->dc[d->level].worldTransform.eM22/scale;
190 cxform << x - newx; cxform << ",";
191 cxform << y - newy;
192 }
193 else {
194 cxform << "0,0";
195 }
196 cxform << ")\"";
197 return(cxform.str());
198}
199
200/* given the transformation matrix from worldTransform return the rotation angle in radians.
201 counter clockwise from the x axis. */
203 return -std::atan2(d->dc[d->level].worldTransform.eM12, d->dc[d->level].worldTransform.eM11);
204}
205
206/* Add another 100 blank slots to the hatches array.
207*/
209 d->hatches.size += 100;
210 d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *));
211}
212
213/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
214*/
216 int i;
217 for(i=0; i<d->hatches.count; i++){
218 if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
219 }
220 return(0);
221}
222
223/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one
224 does not exist it is added to the hatches list and also entered into <defs>.
225 This is also used to add the path part of the hatches, which they reference with a xlink:href
226*/
227uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){
228 char hatchname[64]; // big enough
229 char hpathname[64]; // big enough
230 char hbkname[64]; // big enough
231 char tmpcolor[8];
232 char bkcolor[8];
233 uint32_t idx;
234
235 switch(hatchType){
236 case U_HS_SOLIDTEXTCLR:
237 case U_HS_DITHEREDTEXTCLR:
238 safeprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
239 break;
240 case U_HS_SOLIDBKCLR:
241 case U_HS_DITHEREDBKCLR:
242 safeprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
243 break;
244 default:
245 safeprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
246 break;
247 }
248
249 /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch.
250 This will be used late to compose, or recompose the transparent or opaque final hatch.*/
251
252 std::string refpath; // used to reference later the path pieces which are about to be created
253 safeprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor);
254 idx = in_hatches(d,hpathname);
255 auto & defs = d->defs;
256 if(!idx){ // add path/color if not already present
257 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
258 d->hatches.strings[d->hatches.count++]=strdup(hpathname);
259
260 defs += "\n";
261 switch(hatchType){
262 case U_HS_HORIZONTAL:
263 defs += " <path id=\"";
264 defs += hpathname;
265 defs += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
266 defs += tmpcolor;
267 defs += "\" />\n";
268 break;
269 case U_HS_VERTICAL:
270 defs += " <path id=\"";
271 defs += hpathname;
272 defs += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
273 defs += tmpcolor;
274 defs += "\" />\n";
275 break;
276 case U_HS_FDIAGONAL:
277 defs += " <line id=\"sub";
278 defs += hpathname;
279 defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
280 defs += tmpcolor;
281 defs += "\"/>\n";
282 break;
283 case U_HS_BDIAGONAL:
284 defs += " <line id=\"sub";
285 defs += hpathname;
286 defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
287 defs += tmpcolor;
288 defs += "\"/>\n";
289 break;
290 case U_HS_CROSS:
291 defs += " <path id=\"";
292 defs += hpathname;
293 defs += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
294 defs += tmpcolor;
295 defs += "\" />\n";
296 break;
297 case U_HS_DIAGCROSS:
298 defs += " <line id=\"subfd";
299 defs += hpathname;
300 defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
301 defs += tmpcolor;
302 defs += "\"/>\n";
303 defs += " <line id=\"subbd";
304 defs += hpathname;
305 defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
306 defs += tmpcolor;
307 defs += "\"/>\n";
308 break;
309 case U_HS_SOLIDCLR:
310 case U_HS_DITHEREDCLR:
311 case U_HS_SOLIDTEXTCLR:
312 case U_HS_DITHEREDTEXTCLR:
313 case U_HS_SOLIDBKCLR:
314 case U_HS_DITHEREDBKCLR:
315 default:
316 defs += " <path id=\"";
317 defs += hpathname;
318 defs += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
319 defs += tmpcolor;
320 defs += ";stroke:none";
321 defs += "\" />\n";
322 break;
323 }
324 }
325
326 // References to paths possibly just created above. These will be used in the actual patterns.
327 switch(hatchType){
328 case U_HS_HORIZONTAL:
329 case U_HS_VERTICAL:
330 case U_HS_CROSS:
331 case U_HS_SOLIDCLR:
332 case U_HS_DITHEREDCLR:
333 case U_HS_SOLIDTEXTCLR:
334 case U_HS_DITHEREDTEXTCLR:
335 case U_HS_SOLIDBKCLR:
336 case U_HS_DITHEREDBKCLR:
337 default:
338 refpath += " <use xlink:href=\"#";
339 refpath += hpathname;
340 refpath += "\" />\n";
341 break;
342 case U_HS_FDIAGONAL:
343 case U_HS_BDIAGONAL:
344 refpath += " <use xlink:href=\"#sub";
345 refpath += hpathname;
346 refpath += "\" />\n";
347 refpath += " <use xlink:href=\"#sub";
348 refpath += hpathname;
349 refpath += "\" transform=\"translate(6,0)\" />\n";
350 refpath += " <use xlink:href=\"#sub";
351 refpath += hpathname;
352 refpath += "\" transform=\"translate(-6,0)\" />\n";
353 break;
354 case U_HS_DIAGCROSS:
355 refpath += " <use xlink:href=\"#subfd";
356 refpath += hpathname;
357 refpath += "\" />\n";
358 refpath += " <use xlink:href=\"#subfd";
359 refpath += hpathname;
360 refpath += "\" transform=\"translate(6,0)\"/>\n";
361 refpath += " <use xlink:href=\"#subfd";
362 refpath += hpathname;
363 refpath += "\" transform=\"translate(-6,0)\"/>\n";
364 refpath += " <use xlink:href=\"#subbd";
365 refpath += hpathname;
366 refpath += "\" />\n";
367 refpath += " <use xlink:href=\"#subbd";
368 refpath += hpathname;
369 refpath += "\" transform=\"translate(6,0)\"/>\n";
370 refpath += " <use xlink:href=\"#subbd";
371 refpath += hpathname;
372 refpath += "\" transform=\"translate(-6,0)\"/>\n";
373 break;
374 }
375
376 if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){
377 safeprintf(hatchname,"EMFhatch%d_%s",hatchType,tmpcolor);
378 safeprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor);
379 idx = in_hatches(d,hatchname);
380 if(!idx){ // add it if not already present
381 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
382 d->hatches.strings[d->hatches.count++]=strdup(hatchname);
383 defs += "\n";
384 defs += " <pattern id=\"";
385 defs += hatchname;
386 defs += "\" xlink:href=\"#EMFhbasepattern\">\n";
387 defs += refpath;
388 defs += " </pattern>\n";
389 idx = d->hatches.count;
390 }
391 }
392 else { // bkMode==U_OPAQUE
393 /* Set up an object in the defs for this background, if there is not one already there */
394 safeprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
395 safeprintf(hbkname,"EMFhbkclr_%s",bkcolor);
396 idx = in_hatches(d,hbkname);
397 if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name.
398 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
399 d->hatches.strings[d->hatches.count++]=strdup(hbkname);
400
401 defs += "\n";
402 defs += " <rect id=\"";
403 defs += hbkname;
404 defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
405 defs += bkcolor;
406 defs += "\" />\n";
407 }
408
409 // this is the pattern, its name will show up in Inkscape's pattern selector
410 safeprintf(hatchname,"EMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor);
411 idx = in_hatches(d,hatchname);
412 if(!idx){ // add it if not already present
413 if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
414 d->hatches.strings[d->hatches.count++]=strdup(hatchname);
415 defs += "\n";
416 defs += " <pattern id=\"";
417 defs += hatchname;
418 defs += "\" xlink:href=\"#EMFhbasepattern\">\n";
419 defs += " <use xlink:href=\"#";
420 defs += hbkname;
421 defs += "\" />\n";
422 defs += refpath;
423 defs += " </pattern>\n";
424 idx = d->hatches.count;
425 }
426 }
427 return(idx-1);
428}
429
430/* Add another 100 blank slots to the images array.
431*/
433 d->images.size += 100;
434 d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *));
435}
436
437/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
438*/
440 int i;
441 for(i=0; i<d->images.count; i++){
442 if(strcmp(test,d->images.strings[i])==0)return(i+1);
443 }
444 return(0);
445}
446
447/* (Conditionally) add an image. If a matching image already exists nothing happens. If one
448 does not exist it is added to the images list and also entered into <defs>.
449
450 U_EMRCREATEMONOBRUSH records only work when the bitmap is monochrome. If we hit one that isn't
451 set idx to 2^32-1 and let the caller handle it.
452*/
453uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi,
454 uint32_t iUsage, uint32_t offBits, uint32_t offBmi){
455
456 uint32_t idx;
457 char imagename[64]; // big enough
458 char imrotname[64]; // big enough
459 char xywh[64]; // big enough
460 int dibparams = U_BI_UNKNOWN; // type of image not yet determined
461
462 MEMPNG mempng; // PNG in memory comes back in this
463 mempng.buffer = nullptr;
464
465 char *rgba_px = nullptr; // RGBA pixels
466 const char *px = nullptr; // DIB pixels
467 const U_RGBQUAD *ct = nullptr; // DIB color table
468 U_RGBQUAD ct2[2];
469 uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params
470 if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)){
471 // next call returns pointers and values, but allocates no memory
472 dibparams = get_DIB_params((const char *)pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
473 &numCt, &width, &height, &colortype, &invert);
474 if(dibparams ==U_BI_RGB){
475 // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map.
476 if(((PU_EMR)pEmr)->iType == U_EMR_CREATEMONOBRUSH){
477 if(numCt==2){
478 ct2[0] = U_RGB2BGR(d->dc[d->level].textColor);
479 ct2[1] = U_RGB2BGR(d->dc[d->level].bkColor);
480 ct = &ct2[0];
481 }
482 else { // This record is invalid, nothing more to do here, let caller handle it
483 return(U_EMR_INVALID);
484 }
485 }
486
487 if(!DIB_to_RGBA(
488 px, // DIB pixel array
489 ct, // DIB color table
490 numCt, // DIB color table number of entries
491 &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
492 width, // Width of pixel array in record
493 height, // Height of pixel array in record
494 colortype, // DIB BitCount Enumeration
495 numCt, // Color table used if not 0
496 invert // If DIB rows are in opposite order from RGBA rows
497 )){
498 toPNG( // Get the image from the RGBA px into mempng
499 &mempng,
500 width, height, // of the SRC bitmap
501 rgba_px
502 );
503 free(rgba_px);
504 }
505 }
506 }
507
508 gchar *base64String=nullptr;
509 if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ // image was binary png or jpg in source file
510 base64String = g_base64_encode((guchar*) px, numCt );
511 }
512 else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
513 base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
514 free(mempng.buffer);
515 }
516 else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
517 width = 3;
518 height = 4;
519 base64String = bad_image_png();
520 }
521
522 idx = in_images(d, (char *) base64String);
523 auto & defs = d->defs;
524 if(!idx){ // add it if not already present - we looked at the actual data for comparison
525 if(d->images.count == d->images.size){ enlarge_images(d); }
526 idx = d->images.count;
527 d->images.strings[d->images.count++]=strdup(base64String);
528
529 safeprintf(imagename,"EMFimage%d",idx++);
530 safeprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
531
532 defs += "\n";
533 defs += " <image id=\"";
534 defs += imagename;
535 defs += "\"\n ";
536 defs += xywh;
537 defs += "\n";
538 if(dibparams == U_BI_JPEG){ defs += " xlink:href=\"data:image/jpeg;base64,"; }
539 else { defs += " xlink:href=\"data:image/png;base64,"; }
540 defs += base64String;
541 defs += "\"\n";
542 defs += " preserveAspectRatio=\"none\"\n";
543 defs += " />\n";
544
545
546 defs += "\n";
547 defs += " <pattern id=\"";
548 defs += imagename;
549 defs += "_ref\"\n ";
550 defs += xywh;
551 defs += "\n patternUnits=\"userSpaceOnUse\"";
552 defs += " >\n";
553 defs += " <use id=\"";
554 defs += imagename;
555 defs += "_ign\" ";
556 defs += " xlink:href=\"#";
557 defs += imagename;
558 defs += "\" />\n";
559 defs += " ";
560 defs += " </pattern>\n";
561 }
562 g_free(base64String);//wait until this point to free because it might be a duplicate image
563
564 /* image allows the inner image to be rotated nicely, load this one second only if needed
565 imagename retained from above
566 Here comes a dreadful hack. How do we determine if this rotation of the base image has already
567 been loaded? The image names contain no identifying information, they are just numbered sequentially.
568 So the rotated name is EMFrotimage###_XXXXXX, where ### is the number of the referred to image, and
569 XXXX is the rotation in radians x 1000000 and truncated. That is then stored in BASE64 as the "image".
570 The corresponding SVG generated though is not for an image, but a reference to an image.
571 The name of the pattern MUST still be EMFimage###_ref or output_style() will not be able to use it.
572 */
573 if(current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001){ /* some rotation, allow a little rounding error around 0 degrees */
574 int tangle = round(current_rotation(d)*1000000.0);
575 safeprintf(imrotname,"EMFrotimage%d_%d",idx-1,tangle);
576 base64String = g_base64_encode((guchar*) imrotname, strlen(imrotname) );
577 idx = in_images(d, (char *) base64String); // scan for this "image"
578 if(!idx){
579 if(d->images.count == d->images.size){ enlarge_images(d); }
580 idx = d->images.count;
581 d->images.strings[d->images.count++]=strdup(base64String);
582 safeprintf(imrotname,"EMFimage%d",idx++);
583
584 defs += "\n";
585 defs += " <pattern\n";
586 defs += " id=\"";
587 defs += imrotname;
588 defs += "_ref\"\n";
589 defs += " xlink:href=\"#";
590 defs += imagename;
591 defs += "_ref\"\n";
592 defs += " patternTransform=";
593 defs += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
594 defs += " />\n";
595 }
596 g_free(base64String);
597 }
598
599 return(idx-1);
600}
601
602/* Add another 100 blank slots to the gradients array.
603*/
605 d->gradients.size += 100;
606 d->gradients.strings = (char **) realloc(d->gradients.strings,d->gradients.size * sizeof(char *));
607}
608
609/* See if the gradient name is already in the list. If it is return its position (1->n, not 1-n-1)
610*/
612 int i;
613 for(i=0; i<d->gradients.count; i++){
614 if(strcmp(test,d->gradients.strings[i])==0)return(i+1);
615 }
616 return(0);
617}
618
620 U_COLORREF uc;
621 uc.Red = tv.Red >> 8;
622 uc.Green = tv.Green >> 8;
623 uc.Blue = tv.Blue >> 8;
624 uc.Reserved = tv.Alpha >> 8; // Not used
625 return(uc);
626}
627
628/* (Conditionally) add a gradient. If a matching gradient already exists nothing happens. If one
629 does not exist it is added to the gradients list and also entered into <defs>.
630 Only call this with H or V gradient, not a triangle.
631*/
632uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2){
633 char hgradname[64]; // big enough
634 char tmpcolor1[8];
635 char tmpcolor2[8];
636 char gradc;
637 uint32_t idx;
638 std::string x2,y2;
639
640 U_COLORREF gradientColor1 = trivertex_to_colorref(tv1);
641 U_COLORREF gradientColor2 = trivertex_to_colorref(tv2);
642
643
644 safeprintf(tmpcolor1,"%6.6X",sethexcolor(gradientColor1));
645 safeprintf(tmpcolor2,"%6.6X",sethexcolor(gradientColor2));
646 switch(gradientType){
647 case U_GRADIENT_FILL_RECT_H:
648 gradc='H';
649 x2="100";
650 y2="0";
651 break;
652 case U_GRADIENT_FILL_RECT_V:
653 gradc='V';
654 x2="0";
655 y2="100";
656 break;
657 default: // this should never happen, but fill these in to avoid compiler warnings
658 gradc='!';
659 x2="0";
660 y2="0";
661 break;
662 }
663
664 /* Even though the gradient was defined as Horizontal or Vertical if the rectangle is rotated it needs to
665 be at some other alignment, and that needs gradienttransform. Set the name using the same sort of hack
666 as for add_image.
667 */
668 int tangle = round(current_rotation(d)*1000000.0);
669 safeprintf(hgradname,"LinGrd%c_%s_%s_%d",gradc,tmpcolor1,tmpcolor2,tangle);
670
671 idx = in_gradients(d,hgradname);
672 if(!idx){ // gradient does not yet exist
674 d->gradients.strings[d->gradients.count++]=strdup(hgradname);
675 idx = d->gradients.count;
676 SVGOStringStream stmp;
677 stmp << " <linearGradient id=\"";
678 stmp << hgradname;
679 stmp << "\" x1=\"";
680 stmp << pix_to_x_point(d, tv1.x , tv1.y);
681 stmp << "\" y1=\"";
682 stmp << pix_to_y_point(d, tv1.x , tv1.y);
683 stmp << "\" x2=\"";
684 if(gradc=='H'){ // UR corner
685 stmp << pix_to_x_point(d, tv2.x , tv1.y);
686 stmp << "\" y2=\"";
687 stmp << pix_to_y_point(d, tv2.x , tv1.y);
688 }
689 else { // LL corner
690 stmp << pix_to_x_point(d, tv1.x , tv2.y);
691 stmp << "\" y2=\"";
692 stmp << pix_to_y_point(d, tv1.x , tv2.y);
693 }
694 stmp << "\" gradientTransform=\"(1,0,0,1,0,0)\"";
695 stmp << " gradientUnits=\"userSpaceOnUse\"\n";
696 stmp << ">\n";
697 stmp << " <stop offset=\"0\" style=\"stop-color:#";
698 stmp << tmpcolor1;
699 stmp << ";stop-opacity:1\" />\n";
700 stmp << " <stop offset=\"1\" style=\"stop-color:#";
701 stmp << tmpcolor2;
702 stmp << ";stop-opacity:1\" />\n";
703 stmp << " </linearGradient>\n";
704 d->defs += stmp.str().c_str();
705 }
706
707 return(idx-1);
708}
709
710/* Add another 100 blank slots to the clips array.
711*/
713 d->clips.size += 100;
714 d->clips.strings = (char **) realloc(d->clips.strings,d->clips.size * sizeof(char *));
715}
716
717/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
718*/
720 int i;
721 for(i=0; i<d->clips.count; i++){
722 if(strcmp(test,d->clips.strings[i])==0)return(i+1);
723 }
724 return(0);
725}
726
727/* (Conditionally) add a clip.
728 If a matching clip already exists nothing happens
729 If one does exist it is added to the clips list, entered into <defs>.
730*/
731void Emf::add_clips(PEMF_CALLBACK_DATA d, const char *clippath, unsigned int logic){
732 int op = combine_ops_to_livarot(logic);
733 Geom::PathVector combined_vect;
734 std::string combined;
735 if (op >= 0 && d->dc[d->level].clip_id) {
736 unsigned int real_idx = d->dc[d->level].clip_id - 1;
737 Geom::PathVector old_vect = sp_svg_read_pathv(d->clips.strings[real_idx]);
738 Geom::PathVector new_vect = sp_svg_read_pathv(clippath);
739 combined_vect = sp_pathvector_boolop(new_vect, old_vect, (BooleanOp) op , (FillRule) fill_oddEven, (FillRule) fill_oddEven);
740 combined = sp_svg_write_path(combined_vect);
741 }
742 else {
743 combined = clippath; // COPY operation, erases everything and starts a new one
744 }
745
746 uint32_t idx = in_clips(d, combined.c_str());
747 if(!idx){ // add clip if not already present
748 if(d->clips.count == d->clips.size){ enlarge_clips(d); }
749 d->clips.strings[d->clips.count++] = strdup(combined.c_str());
750 d->dc[d->level].clip_id = d->clips.count; // one more than the slot where it is actually stored
751 SVGOStringStream tmp_clippath;
752 tmp_clippath << "\n<clipPath";
753 tmp_clippath << "\n\tclipPathUnits=\"userSpaceOnUse\" ";
754 tmp_clippath << "\n\tid=\"clipEmfPath" << d->dc[d->level].clip_id << "\"";
755 tmp_clippath << " >";
756 tmp_clippath << "\n\t<path d=\"";
757 tmp_clippath << combined;
758 tmp_clippath << "\"";
759 tmp_clippath << "\n\t/>";
760 tmp_clippath << "\n</clipPath>";
761 d->outdef += tmp_clippath.str().c_str();
762 }
763 else {
764 d->dc[d->level].clip_id = idx;
765 }
766}
767
768
769
770void
772{
773// SVGOStringStream tmp_id;
774 SVGOStringStream tmp_style;
775 char tmp[1024] = {0};
776
777 auto fill = d->dc[d->level].style.fill.getColor();
778 auto stroke = d->dc[d->level].style.stroke.getColor();
779
780 // for U_EMR_BITBLT with no image, try to approximate some of these operations/
781 // Assume src color is "white"
782 if(d->dwRop3){
783 switch(d->dwRop3){
784 case U_PATINVERT: // invert pattern
785 fill.set("black");
786 break;
787 case U_SRCINVERT: // treat all of these as black
788 case U_DSTINVERT:
789 case U_BLACKNESS:
790 case U_SRCERASE:
791 case U_NOTSRCCOPY:
792 fill.set("black");
793 break;
794 case U_SRCCOPY: // treat all of these as white
795 case U_NOTSRCERASE:
796 case U_WHITENESS:
797 fill.set("white");
798 break;
799 case U_SRCPAINT: // use the existing color
800 case U_SRCAND:
801 case U_MERGECOPY:
802 case U_MERGEPAINT:
803 case U_PATPAINT:
804 case U_PATCOPY:
805 default:
806 break;
807 }
808 d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
809 }
810
811 // Implement some of these, the ones where the original screen color does not matter.
812 // The options that merge screen and pen colors cannot be done correctly because we
813 // have no way of knowing what color is already on the screen. For those just pass the
814 // pen color through.
815 switch(d->dwRop2){
816 case U_R2_BLACK:
817 fill.set("black");
818 stroke.set("black");
819 break;
820 case U_R2_NOTMERGEPEN:
821 case U_R2_MASKNOTPEN:
822 break;
823 case U_R2_NOTCOPYPEN:
824 fill.invert();
825 stroke.invert();
826 break;
827 case U_R2_MASKPENNOT:
828 case U_R2_NOT:
829 case U_R2_XORPEN:
830 case U_R2_NOTMASKPEN:
831 case U_R2_NOTXORPEN:
832 case U_R2_NOP:
833 case U_R2_MERGENOTPEN:
834 case U_R2_COPYPEN:
835 case U_R2_MASKPEN:
836 case U_R2_MERGEPENNOT:
837 case U_R2_MERGEPEN:
838 break;
839 case U_R2_WHITE:
840 fill.set("white");
841 stroke.set("white");
842 break;
843 default:
844 break;
845 }
846
847
848// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
849// d->outsvg += tmp_id.str().c_str();
850 d->outsvg += "\n\tstyle=\"";
851 if (iType == U_EMR_STROKEPATH || !d->dc[d->level].fill_set) {
852 tmp_style << "fill:none;";
853 } else {
854 switch(d->dc[d->level].fill_mode){
855 // both of these use the url(#) method
856 case DRAW_PATTERN:
857 snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
858 tmp_style << tmp;
859 break;
860 case DRAW_IMAGE:
861 snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx);
862 tmp_style << tmp;
863 break;
865 case DRAW_PAINT:
866 default: // <-- this should never happen, but just in case...
868 tmp_style << "fill:" << fill.toString(false).c_str() << ";";
869 break;
870 }
871 snprintf(
872 tmp, 1023,
873 "fill-rule:%s;",
874 (d->dc[d->level].style.fill_rule.value == SP_WIND_RULE_NONZERO ? "evenodd" : "nonzero")
875 );
876 tmp_style << tmp;
877 tmp_style << "fill-opacity:1;";
878
879 // 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
880 if(
881 (d->dc[d->level].fill_set ) &&
882 (d->dc[d->level].stroke_set ) &&
883 (d->dc[d->level].style.stroke_width.value == 1 ) &&
884 (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) &&
885 (
886 (d->dc[d->level].fill_mode != DRAW_PAINT) ||
887 fill == stroke
888 )
889 ){
890 d->dc[d->level].stroke_set = false;
891 }
892 }
893
894 if (iType == U_EMR_FILLPATH || !d->dc[d->level].stroke_set) {
895 tmp_style << "stroke:none;";
896 } else {
897 switch(d->dc[d->level].stroke_mode){
898 // both of these use the url(#) method
899 case DRAW_PATTERN:
900 snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
901 tmp_style << tmp;
902 break;
903 case DRAW_IMAGE:
904 snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx);
905 tmp_style << tmp;
906 break;
908 case DRAW_PAINT:
909 default: // <-- this should never happen, but just in case...
911 tmp_style << "stroke:" << stroke.toString(false).c_str() << ";";
912 break;
913 }
914 tmp_style << "stroke-width:" <<
915 MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
916
917 tmp_style << "stroke-linecap:" <<
918 (
919 d->dc[d->level].style.stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ? "butt" :
920 d->dc[d->level].style.stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ? "round" :
921 d->dc[d->level].style.stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ? "square" :
922 "unknown"
923 ) << ";";
924
925 tmp_style << "stroke-linejoin:" <<
926 (
927 d->dc[d->level].style.stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ? "miter" :
928 d->dc[d->level].style.stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ? "round" :
929 d->dc[d->level].style.stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ? "bevel" :
930 "unknown"
931 ) << ";";
932
933 // Set miter limit if known, even if it is not needed immediately (not miter)
934 tmp_style << "stroke-miterlimit:" <<
935 MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";";
936
937 if (d->dc[d->level].style.stroke_dasharray.set &&
938 !d->dc[d->level].style.stroke_dasharray.values.empty() )
939 {
940 tmp_style << "stroke-dasharray:";
941 for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) {
942 if (i)
943 tmp_style << ",";
944 tmp_style << d->dc[d->level].style.stroke_dasharray.values[i].value;
945 }
946 tmp_style << ";";
947 tmp_style << "stroke-dashoffset:0;";
948 } else {
949 tmp_style << "stroke-dasharray:none;";
950 }
951 tmp_style << "stroke-opacity:1;";
952 }
953 tmp_style << "\" ";
954 if (d->dc[d->level].clip_id)
955 tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\" ";
956
957 d->outsvg += tmp_style.str().c_str();
958}
959
960
961double
963{
964 double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0);
965 double tmp;
966 tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX;
967 tmp -= d->ulCornerOutX; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
968 return(tmp);
969}
970
971double
973{
974 double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0);
975 double tmp;
976 tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY;
977 tmp -= d->ulCornerOutY; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
978 return(tmp);
979}
980
981
982double
984{
985 double wpx = px * d->dc[d->level].worldTransform.eM11 + py * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx;
986 double x = _pix_x_to_point(d, wpx);
987
988 return x;
989}
990
991double
993{
994
995 double wpy = px * d->dc[d->level].worldTransform.eM12 + py * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy;
996 double y = _pix_y_to_point(d, wpy);
997
998 return y;
999
1000}
1001
1002double
1004{
1005 double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d));
1006 return ppx;
1007}
1008
1009/* snaps coordinate pairs made up of values near +/-faraway, +/-faraway to exactly faraway.
1010 This eliminates coordinate drift on repeated clipping cycles which use exclude.
1011 It should not affect internals of normal drawings because the value of faraway is so large.
1012*/
1013void
1014Emf::snap_to_faraway_pair(double *x, double *y)
1015{
1016 if((std::abs(std::abs(*x) - faraway)/faraway <= 1e-4) && (std::abs(std::abs(*y) - faraway)/faraway <= 1e-4)){
1017 *x = (*x > 0 ? faraway : -faraway);
1018 *y = (*y > 0 ? faraway : -faraway);
1019 }
1020}
1021
1022/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates.
1023 Since exclude clip can go through here, it calls snap_to_faraway_pair for numerical stability.
1024*/
1025std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){
1026 SVGOStringStream cxform;
1027 double tx = pix_to_x_point(d,x,y);
1028 double ty = pix_to_y_point(d,x,y);
1029 snap_to_faraway_pair(&tx,&ty);
1030 cxform << tx;
1031 cxform << ",";
1032 cxform << ty;
1033 return(cxform.str());
1034}
1035
1036
1037void
1039{
1040 PU_EMRCREATEPEN pEmr = nullptr;
1041
1042 if (index >= 0 && index < d->n_obj){
1043 pEmr = (PU_EMRCREATEPEN) d->emf_obj[index].lpEMFR;
1044 }
1045
1046 if (!pEmr){ return; }
1047
1048 switch (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK) {
1049 case U_PS_DASH:
1050 case U_PS_DOT:
1051 case U_PS_DASHDOT:
1052 case U_PS_DASHDOTDOT:
1053 {
1054 SPILength spilength(1.f);
1055 int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK);
1056 if (!d->dc[d->level].style.stroke_dasharray.values.empty() &&
1057 (d->level == 0 || (d->level > 0 && d->dc[d->level].style.stroke_dasharray !=
1058 d->dc[d->level - 1].style.stroke_dasharray)))
1059 d->dc[d->level].style.stroke_dasharray.values.clear();
1060 if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
1061 spilength.setDouble(3);
1062 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1063 spilength.setDouble(1);
1064 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1065 }
1066 if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
1067 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1068 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1069 }
1070 if (penstyle==U_PS_DASHDOTDOT) {
1071 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1072 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1073 }
1074
1075 d->dc[d->level].style.stroke_dasharray.set = true;
1076 break;
1077 }
1078
1079 case U_PS_SOLID:
1080 default:
1081 {
1082 d->dc[d->level].style.stroke_dasharray.set = false;
1083 break;
1084 }
1085 }
1086
1087 switch (pEmr->lopn.lopnStyle & U_PS_ENDCAP_MASK) {
1088 case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_ROUND; break; }
1089 case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_SQUARE; break; }
1090 case U_PS_ENDCAP_FLAT:
1091 default: { d->dc[d->level].style.stroke_linecap.computed = SP_STROKE_LINECAP_BUTT; break; }
1092 }
1093
1094 switch (pEmr->lopn.lopnStyle & U_PS_JOIN_MASK) {
1095 case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_BEVEL; break; }
1096 case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_MITER; break; }
1097 case U_PS_JOIN_ROUND:
1098 default: { d->dc[d->level].style.stroke_linejoin.computed = SP_STROKE_LINEJOIN_ROUND; break; }
1099 }
1100
1101 d->dc[d->level].stroke_set = true;
1102
1103 if (pEmr->lopn.lopnStyle == U_PS_NULL) {
1104 d->dc[d->level].style.stroke_width.value = 0;
1105 d->dc[d->level].stroke_set = false;
1106 } else if (pEmr->lopn.lopnWidth.x) {
1107 int cur_level = d->level;
1108 d->level = d->emf_obj[index].level;
1109 double pen_width = pix_to_abs_size( d, pEmr->lopn.lopnWidth.x );
1110 d->level = cur_level;
1111 d->dc[d->level].style.stroke_width.value = pen_width;
1112 } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
1113 //d->dc[d->level].style.stroke_width.value = 1.0;
1114 int cur_level = d->level;
1115 d->level = d->emf_obj[index].level;
1116 double pen_width = pix_to_abs_size( d, 1 );
1117 d->level = cur_level;
1118 d->dc[d->level].style.stroke_width.value = pen_width;
1119 }
1120 d->dc[d->level].style.stroke.setColor(Colors::Color(U_RGB_COMPOSE(pEmr->lopn.lopnColor), false));
1121}
1122
1123void
1125{
1126 PU_EMREXTCREATEPEN pEmr = nullptr;
1127
1128 if (index >= 0 && index < d->n_obj)
1130
1131 if (!pEmr)
1132 return;
1133
1134 switch (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK) {
1135 case U_PS_USERSTYLE:
1136 {
1137 if (pEmr->elp.elpNumEntries) {
1138 if (!d->dc[d->level].style.stroke_dasharray.values.empty() &&
1139 (d->level == 0 || (d->level > 0 && d->dc[d->level].style.stroke_dasharray !=
1140 d->dc[d->level - 1].style.stroke_dasharray)))
1141 d->dc[d->level].style.stroke_dasharray.values.clear();
1142 for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
1143 double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] );
1144 d->dc[d->level].style.stroke_dasharray.values.emplace_back(dash_length);
1145 }
1146 d->dc[d->level].style.stroke_dasharray.set = true;
1147 } else {
1148 d->dc[d->level].style.stroke_dasharray.set = false;
1149 }
1150 break;
1151 }
1152
1153 case U_PS_DASH:
1154 case U_PS_DOT:
1155 case U_PS_DASHDOT:
1156 case U_PS_DASHDOTDOT:
1157 {
1158 int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK);
1159 if (!d->dc[d->level].style.stroke_dasharray.values.empty() &&
1160 (d->level == 0 || (d->level > 0 && d->dc[d->level].style.stroke_dasharray !=
1161 d->dc[d->level - 1].style.stroke_dasharray)))
1162 d->dc[d->level].style.stroke_dasharray.values.clear();
1163 SPILength spilength;
1164 if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
1165 spilength.setDouble(3);
1166 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1167 spilength.setDouble(2);
1168 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1169 }
1170 if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) {
1171 spilength.setDouble(1);
1172 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1173 spilength.setDouble(2);
1174 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1175 }
1176 if (penstyle==U_PS_DASHDOTDOT) {
1177 spilength.setDouble(1);
1178 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1179 spilength.setDouble(2);
1180 d->dc[d->level].style.stroke_dasharray.values.push_back(spilength);
1181 }
1182
1183 d->dc[d->level].style.stroke_dasharray.set = true;
1184 break;
1185 }
1186 case U_PS_SOLID:
1187/* includes these for now, some should maybe not be in here
1188 case U_PS_NULL:
1189 case U_PS_INSIDEFRAME:
1190 case U_PS_ALTERNATE:
1191 case U_PS_STYLE_MASK:
1192*/
1193 default:
1194 {
1195 d->dc[d->level].style.stroke_dasharray.set = false;
1196 break;
1197 }
1198 }
1199
1200 switch (pEmr->elp.elpPenStyle & U_PS_ENDCAP_MASK) {
1201 case U_PS_ENDCAP_ROUND:
1202 {
1204 break;
1205 }
1206 case U_PS_ENDCAP_SQUARE:
1207 {
1209 break;
1210 }
1211 case U_PS_ENDCAP_FLAT:
1212 default:
1213 {
1215 break;
1216 }
1217 }
1218
1219 switch (pEmr->elp.elpPenStyle & U_PS_JOIN_MASK) {
1220 case U_PS_JOIN_BEVEL:
1221 {
1223 break;
1224 }
1225 case U_PS_JOIN_MITER:
1226 {
1228 break;
1229 }
1230 case U_PS_JOIN_ROUND:
1231 default:
1232 {
1234 break;
1235 }
1236 }
1237
1238 d->dc[d->level].stroke_set = true;
1239
1240 if (pEmr->elp.elpPenStyle == U_PS_NULL) { // draw nothing, but fill out all the values with something
1241 d->dc[d->level].style.stroke.setColor(Colors::Color(U_RGB_COMPOSE(d->dc[d->level].textColor), false));
1242 d->dc[d->level].style.stroke_width.value = 0;
1243 d->dc[d->level].stroke_set = false;
1244 d->dc[d->level].stroke_mode = DRAW_PAINT;
1245 }
1246 else {
1247 if (pEmr->elp.elpWidth) {
1248 int cur_level = d->level;
1249 d->level = d->emf_obj[index].level;
1250 double pen_width = pix_to_abs_size( d, pEmr->elp.elpWidth );
1251 d->level = cur_level;
1252 d->dc[d->level].style.stroke_width.value = pen_width;
1253 } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
1254 //d->dc[d->level].style.stroke_width.value = 1.0;
1255 int cur_level = d->level;
1256 d->level = d->emf_obj[index].level;
1257 double pen_width = pix_to_abs_size( d, 1 );
1258 d->level = cur_level;
1259 d->dc[d->level].style.stroke_width.value = pen_width;
1260 }
1261
1262 if( pEmr->elp.elpBrushStyle == U_BS_SOLID){
1263 d->dc[d->level].style.stroke.setColor(Colors::Color(U_RGB_COMPOSE(pEmr->elp.elpColor), false));
1264 d->dc[d->level].stroke_mode = DRAW_PAINT;
1265 d->dc[d->level].stroke_set = true;
1266 }
1267 else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){
1268 d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor);
1269 d->dc[d->level].stroke_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
1271 d->dc[d->level].stroke_set = true;
1272 }
1273 else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){
1274 d->dc[d->level].stroke_idx = add_image(d, (void *)pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi);
1275 d->dc[d->level].stroke_mode = DRAW_IMAGE;
1276 d->dc[d->level].stroke_set = true;
1277 }
1278 else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor
1279 d->dc[d->level].style.stroke.setColor(Colors::Color(U_RGB_COMPOSE(d->dc[d->level].textColor)));
1280 d->dc[d->level].stroke_mode = DRAW_PAINT;
1281 d->dc[d->level].stroke_set = true;
1282 }
1283 }
1284}
1285
1286
1287void
1289{
1290 uint32_t tidx;
1291 uint32_t iType;
1292
1293 if (index >= 0 && index < d->n_obj){
1294 iType = ((PU_EMR) (d->emf_obj[index].lpEMFR))->iType;
1295 if(iType == U_EMR_CREATEBRUSHINDIRECT){
1297 if( pEmr->lb.lbStyle == U_BS_SOLID){
1298 d->dc[d->level].style.fill.setColor(Colors::Color(U_RGB_COMPOSE(pEmr->lb.lbColor), false));
1299 d->dc[d->level].fill_mode = DRAW_PAINT;
1300 d->dc[d->level].fill_set = true;
1301 }
1302 else if(pEmr->lb.lbStyle == U_BS_HATCHED){
1303 d->dc[d->level].fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor);
1304 d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
1305 d->dc[d->level].fill_mode = DRAW_PATTERN;
1306 d->dc[d->level].fill_set = true;
1307 }
1308 }
1309 else if(iType == U_EMR_CREATEDIBPATTERNBRUSHPT || iType == U_EMR_CREATEMONOBRUSH){
1311 tidx = add_image(d, (void *) pEmr, pEmr->cbBits, pEmr->cbBmi, pEmr->iUsage, pEmr->offBits, pEmr->offBmi);
1312 if(tidx == U_EMR_INVALID){ // This happens if createmonobrush has a DIB that isn't monochrome
1313 d->dc[d->level].style.fill.setColor(Colors::Color(U_RGB_COMPOSE(d->dc[d->level].textColor), false));
1314 d->dc[d->level].fill_mode = DRAW_PAINT;
1315 }
1316 else {
1317 d->dc[d->level].fill_idx = tidx;
1318 d->dc[d->level].fill_mode = DRAW_IMAGE;
1319 }
1320 d->dc[d->level].fill_set = true;
1321 }
1322 }
1323}
1324
1325
1326void
1328{
1329 PU_EMREXTCREATEFONTINDIRECTW pEmr = nullptr;
1330
1331 if (index >= 0 && index < d->n_obj)
1333
1334 if (!pEmr)return;
1335
1336
1337 /* The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW
1338 is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
1339 is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
1340 */
1341 int cur_level = d->level;
1342 d->level = d->emf_obj[index].level;
1343 double font_size = pix_to_abs_size( d, pEmr->elfw.elfLogFont.lfHeight );
1344 /* snap the font_size to the nearest 1/32nd of a point.
1345 (The size is converted from Pixels to points, snapped, and converted back.)
1346 See the notes where d->D2Pscale[XY] are set for the reason why.
1347 Typically this will set the font to the desired exact size. If some peculiar size
1348 was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
1349 font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8);
1350 d->level = cur_level;
1351 d->dc[d->level].style.font_size.computed = font_size;
1352 d->dc[d->level].style.font_weight.value =
1353 pEmr->elfw.elfLogFont.lfWeight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 :
1354 pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 :
1355 pEmr->elfw.elfLogFont.lfWeight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 :
1356 pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 :
1357 pEmr->elfw.elfLogFont.lfWeight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 :
1358 pEmr->elfw.elfLogFont.lfWeight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 :
1359 pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 :
1360 pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 :
1361 pEmr->elfw.elfLogFont.lfWeight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 :
1362 pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL :
1363 pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD :
1364 pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER :
1365 pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER :
1368 d->dc[d->level].style.text_decoration_line.underline = pEmr->elfw.elfLogFont.lfUnderline;
1369 d->dc[d->level].style.text_decoration_line.line_through = pEmr->elfw.elfLogFont.lfStrikeOut;
1370 d->dc[d->level].style.text_decoration_line.set = true;
1371 d->dc[d->level].style.text_decoration_line.inherit = false;
1372 // malformed EMF with empty filename may exist, ignore font change if encountered
1373 char *ctmp = U_Utf16leToUtf8((uint16_t *) (pEmr->elfw.elfLogFont.lfFaceName), U_LF_FACESIZE, nullptr);
1374 if(ctmp){
1375 if (d->dc[d->level].font_name){ free(d->dc[d->level].font_name); }
1376 if(*ctmp){
1377 d->dc[d->level].font_name = ctmp;
1378 }
1379 else { // Malformed EMF might specify an empty font name
1380 free(ctmp);
1381 d->dc[d->level].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
1382 }
1383 }
1384 d->dc[d->level].style.baseline_shift.value = round((double)((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600)) / 10.0; // use baseline_shift instead of text_transform to avoid overflow
1385}
1386
1387void
1389{
1390 if (index >= 0 && index < d->n_obj) {
1391 d->emf_obj[index].type = 0;
1392// We are keeping a copy of the EMR rather than just a structure. Currently that is not necessary as the entire
1393// EMF is read in at once and is stored in a big malloc. However, in past versions it was handled
1394// record by record, and we might need to do that again at some point in the future if we start running into EMF
1395// files too big to fit into memory.
1396 if (d->emf_obj[index].lpEMFR)
1397 free(d->emf_obj[index].lpEMFR);
1398 d->emf_obj[index].lpEMFR = nullptr;
1399 }
1400}
1401
1402
1403void
1405{
1406 if (index >= 0 && index < d->n_obj) {
1407 delete_object(d, index);
1408 d->emf_obj[index].type = type;
1409 d->emf_obj[index].level = d->level;
1410 d->emf_obj[index].lpEMFR = emr_dup((char *) pObj);
1411 }
1412}
1413
1414/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling.
1415 The few so far observed all had this format.
1416*/
1418 int ret=0;
1419 char *ptr;
1420 ptr = (char *)pEmr;
1421 PU_EMRSETMAPMODE nEmr = (PU_EMRSETMAPMODE) (ptr + pEmr->emr.nSize);
1422 char *string = nullptr;
1423 if(pEmr->nDescription)string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, nullptr);
1424 if(string){
1425 if((pEmr->nDescription >= 13) &&
1426 (0==strcmp("Adobe Systems",string)) &&
1427 (nEmr->emr.iType == U_EMR_SETMAPMODE) &&
1428 (nEmr->iMode == U_MM_ANISOTROPIC)){ ret=1; }
1429 free(string);
1430 }
1431 return(ret);
1432}
1433
1438uint32_t *Emf::unknown_chars(size_t count){
1439 uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
1440 if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
1441 for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
1442 res[count]=0;
1443 return res;
1444}
1445
1463 double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh,
1464 uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){
1465
1466 SVGOStringStream tmp_image;
1467 int dibparams = U_BI_UNKNOWN; // type of image not yet determined
1468
1469 tmp_image << "\n\t <image\n";
1470 if (d->dc[d->level].clip_id){
1471 tmp_image << "\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n";
1472 }
1473 tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
1474
1475 MEMPNG mempng; // PNG in memory comes back in this
1476 mempng.buffer = nullptr;
1477
1478 char *rgba_px = nullptr; // RGBA pixels
1479 char *sub_px = nullptr; // RGBA pixels, subarray
1480 const char *px = nullptr; // DIB pixels
1481 const U_RGBQUAD *ct = nullptr; // DIB color table
1482 uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params
1483 if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)){
1484 // next call returns pointers and values, but allocates no memory
1485 dibparams = get_DIB_params((const char *)pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
1486 &numCt, &width, &height, &colortype, &invert);
1487 if(dibparams ==U_BI_RGB){
1488 if(sw == 0 || sh == 0){
1489 sw = width;
1490 sh = height;
1491 }
1492
1493 if(!DIB_to_RGBA(
1494 px, // DIB pixel array
1495 ct, // DIB color table
1496 numCt, // DIB color table number of entries
1497 &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
1498 width, // Width of pixel array
1499 height, // Height of pixel array
1500 colortype, // DIB BitCount Enumeration
1501 numCt, // Color table used if not 0
1502 invert // If DIB rows are in opposite order from RGBA rows
1503 )){
1504 sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
1505 rgba_px, // full pixel array from DIB
1506 width, // Width of pixel array
1507 height, // Height of pixel array
1508 sx,sy, // starting point in pixel array
1509 &sw,&sh // columns/rows to extract from the pixel array (output array size)
1510 );
1511
1512 if(!sub_px)sub_px=rgba_px;
1513 toPNG( // Get the image from the RGBA px into mempng
1514 &mempng,
1515 sw, sh, // size of the extracted pixel array
1516 sub_px
1517 );
1518 free(sub_px);
1519 }
1520 }
1521 }
1522
1523 gchar *base64String=nullptr;
1524 if(dibparams == U_BI_JPEG){ // image was binary jpg in source file
1525 tmp_image << " xlink:href=\"data:image/jpeg;base64,";
1526 base64String = g_base64_encode((guchar*) px, numCt );
1527 }
1528 else if(dibparams==U_BI_PNG){ // image was binary png in source file
1529 tmp_image << " xlink:href=\"data:image/png;base64,";
1530 base64String = g_base64_encode((guchar*) px, numCt );
1531 }
1532 else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine
1533 tmp_image << " xlink:href=\"data:image/png;base64,";
1534 base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
1535 free(mempng.buffer);
1536 }
1537 else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
1538 tmp_image << " xlink:href=\"data:image/png;base64,";
1539 base64String = bad_image_png();
1540 }
1541 tmp_image << base64String;
1542 g_free(base64String);
1543
1544 tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
1545
1546 tmp_image << " transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset
1547 tmp_image << " preserveAspectRatio=\"none\"\n";
1548 tmp_image << "/> \n";
1549
1550 d->outsvg += tmp_image.str().c_str();
1551 d->path = "";
1552}
1553
1560//THis was a callback, just build it into a normal function
1561int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d)
1562{
1563 uint32_t off=0;
1564 uint32_t emr_mask;
1565 int OK =1;
1566 int file_status=1;
1567 uint32_t nSize;
1568 uint32_t iType;
1569 const char *blimit = contents + length;
1570 PU_ENHMETARECORD lpEMFR;
1571 TCHUNK_SPECS tsp;
1572 uint32_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
1573 U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
1574
1575 // code for end user debugging
1576 int eDbgRecord=0;
1577 int eDbgComment=0;
1578 int eDbgFinal=0;
1579 char const* eDbgString = getenv( "INKSCAPE_DBG_EMF" );
1580 if ( eDbgString != nullptr ) {
1581 if(strstr(eDbgString,"RECORD")){ eDbgRecord = 1; }
1582 if(strstr(eDbgString,"COMMENT")){ eDbgComment = 1; }
1583 if(strstr(eDbgString,"FINAL")){ eDbgFinal = 1; }
1584 }
1585
1586 /* initialize the tsp for text reassembly */
1587 tsp.string = nullptr;
1588 tsp.ori = 0.0; /* degrees */
1589 tsp.fs = 12.0; /* font size */
1590 tsp.x = 0.0;
1591 tsp.y = 0.0;
1592 tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/
1593 tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */
1594 tsp.taln = ALILEFT + ALIBASE;
1595 tsp.ldir = LDIR_LR;
1596 tsp.spaces = 0; // this field is only used for debugging
1597 tsp.color.Red = 0; /* RGB Black */
1598 tsp.color.Green = 0; /* RGB Black */
1599 tsp.color.Blue = 0; /* RGB Black */
1600 tsp.color.Reserved = 0; /* not used */
1601 tsp.italics = 0;
1602 tsp.weight = 80;
1603 tsp.decoration = TXTDECOR_NONE;
1604 tsp.condensed = 100;
1605 tsp.co = 0;
1606 tsp.fi_idx = -1; /* set to an invalid */
1607
1608 while(OK){
1609 if(off>=length)return(0); //normally should exit from while after EMREOF sets OK to false.
1610
1611 // check record sizes and types thoroughly
1612 int badrec = 0;
1613 if (!U_emf_record_sizeok(contents + off, blimit, &nSize, &iType, 1) ||
1614 !U_emf_record_safe(contents + off)){
1615 badrec = 1;
1616 }
1617 else {
1618 emr_mask = emr_properties(iType);
1619 if (emr_mask == U_EMR_INVALID) { badrec = 1; }
1620 }
1621 if (badrec) {
1622 file_status = 0;
1623 break;
1624 }
1625
1626 lpEMFR = (PU_ENHMETARECORD)(contents + off);
1627
1628// At run time define environment variable INKSCAPE_DBG_EMF to include string RECORD.
1629// Users may employ this to track down toxic records
1630 if(eDbgRecord){
1631 std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
1632 }
1633 off += nSize;
1634
1635 SVGOStringStream tmp_outsvg;
1636 SVGOStringStream tmp_path;
1637 SVGOStringStream tmp_str;
1638 SVGOStringStream dbg_str;
1639
1640/* Uncomment the following to track down text problems */
1641//std::cout << "tri->dirty:"<< d->tri->dirty << " emr_mask: " << std::hex << emr_mask << std::dec << std::endl;
1642
1643 // incompatible change to text drawing detected (color or background change) forces out existing text
1644 // OR
1645 // next record is valid type and forces pending text to be drawn immediately
1646 if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((emr_mask != U_EMR_INVALID) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){
1648 if (d->dc[d->level].clip_id){
1649 SVGOStringStream tmp_clip;
1650 tmp_clip << "\n<g\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n>";
1651 d->outsvg += tmp_clip.str().c_str();
1652 }
1653 TR_layout_2_svg(d->tri);
1655 ts << d->tri->out;
1656 d->outsvg += ts.str().c_str();
1657 d->tri = trinfo_clear(d->tri);
1658 if (d->dc[d->level].clip_id){
1659 d->outsvg += "\n</g>\n";
1660 }
1661 }
1662 if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
1663 d->dc[d->level].bkMode = tbkMode;
1664 memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF));
1665
1666 if(d->dc[d->level].dirty & DIRTY_TEXT){
1667 // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing...
1668 if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); }
1669 else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque
1670 }
1671
1672 /* It is possible to have a series of EMF records that would result in
1673 the following creating hash patterns which are never used. For instance, if
1674 there were a series of records that changed the background color but did nothing
1675 else.
1676 */
1677 if((d->dc[d->level].stroke_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_STROKE)){
1679 }
1680
1681 if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){
1682 select_brush(d, d->dc[d->level].fill_recidx);
1683 }
1684
1685 d->dc[d->level].dirty = 0;
1686 }
1687
1688// std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl;
1689/*
1690std::cout << "BEFORE DRAW"
1691 << " test0 " << ( d->mask & U_DRAW_VISIBLE)
1692 << " test1 " << ( d->mask & U_DRAW_FORCE)
1693 << " test2 " << (emr_mask & U_DRAW_ALTERS)
1694 << " test3 " << (emr_mask & U_DRAW_VISIBLE)
1695 << " test4 " << !(d->mask & U_DRAW_ONLYTO)
1696 << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )
1697 << std::endl;
1698*/
1699
1700 if(
1701 (emr_mask != U_EMR_INVALID) && // next record is valid type
1702 (d->mask & U_DRAW_VISIBLE) && // Current set of objects are drawable
1703 (
1704 (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
1705 (emr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
1706 (
1707 (emr_mask & U_DRAW_VISIBLE) && // Next record is visible...
1708 (
1709 ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible
1710 ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records
1711 )
1712 )
1713 )
1714 ){
1715// std::cout << "PATH DRAW at TOP path" << *(d->path) << std::endl;
1716 if(!(d->path.empty())){
1717 d->outsvg += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill.
1718 if(d->drawtype){ // explicit draw type EMR record
1719 output_style(d, d->drawtype);
1720 }
1721 else if(d->mask & U_DRAW_CLOSED){ // implicit draw type
1722 output_style(d, U_EMR_STROKEANDFILLPATH);
1723 }
1724 else {
1725 output_style(d, U_EMR_STROKEPATH);
1726 }
1727 d->outsvg += "\n\t";
1728 d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill.
1729 d->outsvg += d->path;
1730 d->outsvg += " \" /> \n";
1731 d->path = "";
1732 }
1733 // reset the flags
1734 d->mask = 0;
1735 d->drawtype = 0;
1736 }
1737// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl;
1738
1739 switch (iType)
1740 {
1741 case U_EMR_HEADER:
1742 {
1743 dbg_str << "<!-- U_EMR_HEADER -->\n";
1744
1745 d->outdef += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
1746
1747 if (d->pDesc) {
1748 d->outdef += "<!-- ";
1749 d->outdef += d->pDesc;
1750 d->outdef += " -->\n";
1751 }
1752
1753 PU_EMRHEADER pEmr = (PU_EMRHEADER) lpEMFR;
1754 SVGOStringStream tmp_outdef;
1755 tmp_outdef << "<svg\n";
1756 tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
1757 tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
1758 tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n";
1759 tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role
1760 tmp_outdef << " version=\"1.0\"\n";
1761
1762
1763 /* inclusive-inclusive, so the size is 1 more than the difference */
1764 d->MM100InX = pEmr->rclFrame.right - pEmr->rclFrame.left + 1;
1765 d->MM100InY = pEmr->rclFrame.bottom - pEmr->rclFrame.top + 1;
1766 d->PixelsInX = pEmr->rclBounds.right - pEmr->rclBounds.left + 1;
1767 d->PixelsInY = pEmr->rclBounds.bottom - pEmr->rclBounds.top + 1;
1768
1769 /*
1770 calculate ratio of Inkscape dpi/EMF device dpi
1771 This can cause problems later due to accuracy limits in the EMF. A high resolution
1772 EMF might have a final D2Pscale[XY] of 0.074998, and adjusting the (integer) device size
1773 by 1 will still not get it exactly to 0.075. Later when the font size is calculated it
1774 can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by
1775 snapping font sizes to the nearest .01. The best estimate is made by using both values.
1776 */
1777 if ((pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy) && ( pEmr->szlDevice.cx + pEmr->szlDevice.cy)){
1778 d->E2IdirY = 1.0; // assume MM_TEXT, if not, this will be changed later
1779 d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "mm", "px") *
1780 (double)(pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/
1781 (double)( pEmr->szlDevice.cx + pEmr->szlDevice.cy);
1782 }
1783 trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
1784
1785 /* Adobe Illustrator files set mapmode to MM_ANISOTROPIC and somehow or other this
1786 converts the rclFrame values from MM_HIMETRIC to MM_HIENGLISH, with another factor of 3 thrown
1787 in for good measure. Ours not to question why...
1788 */
1789 if(AI_hack(pEmr)){
1790 d->MM100InX *= 25.4/(10.0*3.0);
1791 d->MM100InY *= 25.4/(10.0*3.0);
1792 d->D2PscaleX *= 25.4/(10.0*3.0);
1793 d->D2PscaleY *= 25.4/(10.0*3.0);
1794 }
1795
1796 d->MMX = d->MM100InX / 100.0;
1797 d->MMY = d->MM100InY / 100.0;
1798
1801
1802 // Upper left corner, from header rclBounds, in device units, usually both 0, but not always
1803 d->ulCornerInX = pEmr->rclBounds.left;
1804 d->ulCornerInY = pEmr->rclBounds.top;
1805 d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
1806 d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
1807
1808 tmp_outdef <<
1809 " width=\"" << d->MMX << "mm\"\n" <<
1810 " height=\"" << d->MMY << "mm\">\n";
1811 d->outdef += tmp_outdef.str().c_str();
1812 d->outdef += "<defs>"; // temporary end of header
1813
1814 // d->defs holds any defines which are read in.
1815
1816 tmp_outsvg << "\n</defs>\n\n"; // start of main body
1817
1818 if (pEmr->nHandles) {
1819 d->n_obj = pEmr->nHandles;
1820 d->emf_obj = new EMF_OBJECT[d->n_obj];
1821
1822 // Init the new emf_obj list elements to null, provided the
1823 // dynamic allocation succeeded.
1824 if ( d->emf_obj != nullptr )
1825 {
1826 for( int i=0; i < d->n_obj; ++i )
1827 d->emf_obj[i].lpEMFR = nullptr;
1828 } //if
1829
1830 } else {
1831 d->emf_obj = nullptr;
1832 }
1833
1834 break;
1835 }
1836 case U_EMR_POLYBEZIER:
1837 {
1838 dbg_str << "<!-- U_EMR_POLYBEZIER -->\n";
1839
1840 PU_EMRPOLYBEZIER pEmr = (PU_EMRPOLYBEZIER) lpEMFR;
1841 uint32_t i,j;
1842
1843 if (pEmr->cptl<4)
1844 break;
1845
1846 d->mask |= emr_mask;
1847
1848 tmp_str <<
1849 "\n\tM " <<
1850 pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " ";
1851
1852 for (i=1; i<pEmr->cptl; ) {
1853 tmp_str << "\n\tC ";
1854 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
1855 tmp_str << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y) << " ";
1856 }
1857 }
1858
1859 tmp_path << tmp_str.str().c_str();
1860
1861 break;
1862 }
1863 case U_EMR_POLYGON:
1864 {
1865 dbg_str << "<!-- U_EMR_POLYGON -->\n";
1866
1867 PU_EMRPOLYGON pEmr = (PU_EMRPOLYGON) lpEMFR;
1868 uint32_t i;
1869
1870 if (pEmr->cptl < 2)
1871 break;
1872
1873 d->mask |= emr_mask;
1874
1875 tmp_str <<
1876 "\n\tM " <<
1877 pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
1878
1879 for (i=1; i<pEmr->cptl; i++) {
1880 tmp_str <<
1881 "\n\tL " <<
1882 pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
1883 }
1884
1885 tmp_path << tmp_str.str().c_str();
1886 tmp_path << " z";
1887
1888 break;
1889 }
1890 case U_EMR_POLYLINE:
1891 {
1892 dbg_str << "<!-- U_EMR_POLYLINE -->\n";
1893
1894 PU_EMRPOLYLINE pEmr = (PU_EMRPOLYLINE) lpEMFR;
1895 uint32_t i;
1896
1897 if (pEmr->cptl<2)
1898 break;
1899
1900 d->mask |= emr_mask;
1901
1902 tmp_str <<
1903 "\n\tM " <<
1904 pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " ";
1905
1906 for (i=1; i<pEmr->cptl; i++) {
1907 tmp_str <<
1908 "\n\tL " <<
1909 pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
1910 }
1911
1912 tmp_path << tmp_str.str().c_str();
1913
1914 break;
1915 }
1916 case U_EMR_POLYBEZIERTO:
1917 {
1918 dbg_str << "<!-- U_EMR_POLYBEZIERTO -->\n";
1919
1920 PU_EMRPOLYBEZIERTO pEmr = (PU_EMRPOLYBEZIERTO) lpEMFR;
1921 uint32_t i,j;
1922
1923 d->mask |= emr_mask;
1924
1925 for (i=0; i<pEmr->cptl;) {
1926 tmp_path << "\n\tC ";
1927 for (j=0; j<3 && i<pEmr->cptl; j++,i++) {
1928 tmp_path <<
1929 pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
1930 }
1931 }
1932
1933 break;
1934 }
1935 case U_EMR_POLYLINETO:
1936 {
1937 dbg_str << "<!-- U_EMR_POLYLINETO -->\n";
1938
1939 PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) lpEMFR;
1940 uint32_t i;
1941
1942 d->mask |= emr_mask;
1943
1944 for (i=0; i<pEmr->cptl;i++) {
1945 tmp_path <<
1946 "\n\tL " <<
1947 pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " ";
1948 }
1949
1950 break;
1951 }
1952 case U_EMR_POLYPOLYLINE:
1953 case U_EMR_POLYPOLYGON:
1954 {
1955 if (lpEMFR->iType == U_EMR_POLYPOLYLINE)
1956 dbg_str << "<!-- U_EMR_POLYPOLYLINE -->\n";
1957 if (lpEMFR->iType == U_EMR_POLYPOLYGON)
1958 dbg_str << "<!-- U_EMR_POLYPOLYGON -->\n";
1959
1960 PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) lpEMFR;
1961 unsigned int n, i, j;
1962
1963 d->mask |= emr_mask;
1964
1965 U_POINTL *aptl = (PU_POINTL) &pEmr->aPolyCounts[pEmr->nPolys];
1966
1967 i = 0;
1968 for (n=0; n<pEmr->nPolys && i<pEmr->cptl; n++) {
1969 SVGOStringStream poly_path;
1970
1971 poly_path << "\n\tM " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " ";
1972 i++;
1973
1974 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cptl; j++) {
1975 poly_path << "\n\tL " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " ";
1976 i++;
1977 }
1978
1979 tmp_str << poly_path.str().c_str();
1980 if (lpEMFR->iType == U_EMR_POLYPOLYGON)
1981 tmp_str << " z";
1982 tmp_str << " \n";
1983 }
1984
1985 tmp_path << tmp_str.str().c_str();
1986
1987 break;
1988 }
1989 case U_EMR_SETWINDOWEXTEX:
1990 {
1991 dbg_str << "<!-- U_EMR_SETWINDOWEXTEX -->\n";
1992
1994
1995 d->dc[d->level].sizeWnd = pEmr->szlExtent;
1996
1997 if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
1998 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
1999 if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
2000 d->dc[d->level].sizeWnd.cx = d->PixelsOutX;
2001 d->dc[d->level].sizeWnd.cy = d->PixelsOutY;
2002 }
2003 }
2004
2005 if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
2006 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
2007 }
2008
2009 /* scales logical to EMF pixels, transfer a negative sign on Y, if any */
2010 if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) {
2011 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx;
2012 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy;
2013 if(d->dc[d->level].ScaleInY < 0){
2014 d->dc[d->level].ScaleInY *= -1.0;
2015 d->E2IdirY = -1.0;
2016 }
2017 }
2018 else {
2019 d->dc[d->level].ScaleInX = 1;
2020 d->dc[d->level].ScaleInY = 1;
2021 }
2022 break;
2023 }
2024 case U_EMR_SETWINDOWORGEX:
2025 {
2026 dbg_str << "<!-- U_EMR_SETWINDOWORGEX -->\n";
2027
2029 d->dc[d->level].winorg = pEmr->ptlOrigin;
2030 break;
2031 }
2032 case U_EMR_SETVIEWPORTEXTEX:
2033 {
2034 dbg_str << "<!-- U_EMR_SETVIEWPORTEXTEX -->\n";
2035
2037
2038 d->dc[d->level].sizeView = pEmr->szlExtent;
2039
2040 if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
2041 d->dc[d->level].sizeView = d->dc[d->level].sizeWnd;
2042 if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) {
2043 d->dc[d->level].sizeView.cx = d->PixelsOutX;
2044 d->dc[d->level].sizeView.cy = d->PixelsOutY;
2045 }
2046 }
2047
2048 if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
2049 d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
2050 }
2051
2052 /* scales logical to EMF pixels, transfer a negative sign on Y, if any */
2053 if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) {
2054 d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx;
2055 d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy;
2056 if( d->dc[d->level].ScaleInY < 0){
2057 d->dc[d->level].ScaleInY *= -1.0;
2058 d->E2IdirY = -1.0;
2059 }
2060 }
2061 else {
2062 d->dc[d->level].ScaleInX = 1;
2063 d->dc[d->level].ScaleInY = 1;
2064 }
2065 break;
2066 }
2067 case U_EMR_SETVIEWPORTORGEX:
2068 {
2069 dbg_str << "<!-- U_EMR_SETVIEWPORTORGEX -->\n";
2070
2072 d->dc[d->level].vieworg = pEmr->ptlOrigin;
2073 break;
2074 }
2075 case U_EMR_SETBRUSHORGEX: dbg_str << "<!-- U_EMR_SETBRUSHORGEX -->\n"; break;
2076 case U_EMR_EOF:
2077 {
2078 dbg_str << "<!-- U_EMR_EOF -->\n";
2079
2080 tmp_outsvg << "</svg>\n";
2081 d->outsvg = d->outdef + d->defs + d->outsvg;
2082 OK=0;
2083 break;
2084 }
2085 case U_EMR_SETPIXELV: dbg_str << "<!-- U_EMR_SETPIXELV -->\n"; break;
2086 case U_EMR_SETMAPPERFLAGS: dbg_str << "<!-- U_EMR_SETMAPPERFLAGS -->\n"; break;
2087 case U_EMR_SETMAPMODE:
2088 {
2089 dbg_str << "<!-- U_EMR_SETMAPMODE -->\n";
2090 PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE) lpEMFR;
2091 switch (pEmr->iMode){
2092 case U_MM_TEXT:
2093 default:
2094 // Use all values from the header.
2095 break;
2096 /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
2097 and show up in ScaleIn[XY]
2098 */
2099 case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
2100 case U_MM_HIMETRIC: // 1 LU = 0.01 mm
2101 case U_MM_LOENGLISH: // 1 LU = 0.1 in
2102 case U_MM_HIENGLISH: // 1 LU = 0.01 in
2103 case U_MM_TWIPS: // 1 LU = 1/1440 in
2104 d->E2IdirY = -1.0;
2105 // Use d->D2Pscale[XY] values from the header.
2106 break;
2107 case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
2108 case U_MM_ANISOTROPIC:
2109 break;
2110 }
2111 break;
2112 }
2113 case U_EMR_SETBKMODE:
2114 {
2115 dbg_str << "<!-- U_EMR_SETBKMODE -->\n";
2116 PU_EMRSETBKMODE pEmr = (PU_EMRSETBKMODE) lpEMFR;
2117 tbkMode = pEmr->iMode;
2118 if(tbkMode != d->dc[d->level].bkMode){
2119 d->dc[d->level].dirty |= DIRTY_TEXT;
2120 if(tbkMode != d->dc[d->level].bkMode){
2121 if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
2122 if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
2123 }
2124 memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF));
2125 }
2126 break;
2127 }
2128 case U_EMR_SETPOLYFILLMODE:
2129 {
2130 dbg_str << "<!-- U_EMR_SETPOLYFILLMODE -->\n";
2131
2133 d->dc[d->level].style.fill_rule.value =
2134 (pEmr->iMode == U_ALTERNATE
2136 : (pEmr->iMode == U_WINDING ? SP_WIND_RULE_INTERSECT : SP_WIND_RULE_NONZERO));
2137 break;
2138 }
2139 case U_EMR_SETROP2:
2140 {
2141 dbg_str << "<!-- U_EMR_SETROP2 -->\n";
2142 PU_EMRSETROP2 pEmr = (PU_EMRSETROP2) lpEMFR;
2143 d->dwRop2 = pEmr->iMode;
2144 break;
2145 }
2146 case U_EMR_SETSTRETCHBLTMODE:
2147 {
2148 PU_EMRSETSTRETCHBLTMODE pEmr = (PU_EMRSETSTRETCHBLTMODE) lpEMFR; // from wingdi.h
2149 BLTmode = pEmr->iMode;
2150 dbg_str << "<!-- U_EMR_SETSTRETCHBLTMODE -->\n";
2151 break;
2152 }
2153 case U_EMR_SETTEXTALIGN:
2154 {
2155 dbg_str << "<!-- U_EMR_SETTEXTALIGN -->\n";
2156
2157 PU_EMRSETTEXTALIGN pEmr = (PU_EMRSETTEXTALIGN) lpEMFR;
2158 d->dc[d->level].textAlign = pEmr->iMode;
2159 break;
2160 }
2161 case U_EMR_SETCOLORADJUSTMENT:
2162 dbg_str << "<!-- U_EMR_SETCOLORADJUSTMENT -->\n";
2163 break;
2164 case U_EMR_SETTEXTCOLOR:
2165 {
2166 dbg_str << "<!-- U_EMR_SETTEXTCOLOR -->\n";
2167
2168 PU_EMRSETTEXTCOLOR pEmr = (PU_EMRSETTEXTCOLOR) lpEMFR;
2169 d->dc[d->level].textColor = pEmr->crColor;
2170 if(tbkMode != d->dc[d->level].bkMode){
2171 if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
2172 if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
2173 }
2174 // not text_dirty, because multicolored complex text is supported in libTERE
2175 break;
2176 }
2177 case U_EMR_SETBKCOLOR:
2178 {
2179 dbg_str << "<!-- U_EMR_SETBKCOLOR -->\n";
2180
2181 PU_EMRSETBKCOLOR pEmr = (PU_EMRSETBKCOLOR) lpEMFR;
2182 tbkColor = pEmr->crColor;
2183 if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){
2184 d->dc[d->level].dirty |= DIRTY_TEXT;
2185 if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
2186 if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
2187 tbkMode = d->dc[d->level].bkMode;
2188 }
2189 break;
2190 }
2191 case U_EMR_OFFSETCLIPRGN:
2192 {
2193 dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n";
2194 if (d->dc[d->level].clip_id) { // can only offsetan existing clipping path
2196 U_POINTL off = pEmr->ptlOffset;
2197 unsigned int real_idx = d->dc[d->level].clip_id - 1;
2198 Geom::PathVector tmp_vect = sp_svg_read_pathv(d->clips.strings[real_idx]);
2199 double ox = pix_to_x_point(d, off.x, off.y) - pix_to_x_point(d, 0, 0); // take into account all active transforms
2200 double oy = pix_to_y_point(d, off.x, off.y) - pix_to_y_point(d, 0, 0);
2201 Geom::Affine tf = Geom::Translate(ox,oy);
2202 tmp_vect *= tf;
2203 add_clips(d, sp_svg_write_path(tmp_vect).c_str(), U_RGN_COPY);
2204 }
2205 break;
2206 }
2207 case U_EMR_MOVETOEX:
2208 {
2209 dbg_str << "<!-- U_EMR_MOVETOEX -->\n";
2210
2211 PU_EMRMOVETOEX pEmr = (PU_EMRMOVETOEX) lpEMFR;
2212
2213 d->mask |= emr_mask;
2214
2215 d->dc[d->level].cur = pEmr->ptl;
2216
2217 tmp_path <<
2218 "\n\tM " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " ";
2219 break;
2220 }
2221 case U_EMR_SETMETARGN: dbg_str << "<!-- U_EMR_SETMETARGN -->\n"; break;
2222 case U_EMR_EXCLUDECLIPRECT:
2223 {
2224 dbg_str << "<!-- U_EMR_EXCLUDECLIPRECT -->\n";
2225
2227 U_RECTL rc = pEmr->rclClip;
2228
2229 SVGOStringStream tmp_path;
2230 //outer rect, clockwise
2231 tmp_path << "M " << faraway << "," << faraway << " ";
2232 tmp_path << "L " << faraway << "," << -faraway << " ";
2233 tmp_path << "L " << -faraway << "," << -faraway << " ";
2234 tmp_path << "L " << -faraway << "," << faraway << " ";
2235 tmp_path << "z ";
2236 //inner rect, counterclockwise (sign of Y is reversed)
2237 tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " ";
2238 tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " ";
2239 tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " ";
2240 tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " ";
2241 tmp_path << "z";
2242
2243 add_clips(d, tmp_path.str().c_str(), U_RGN_AND);
2244
2245 d->path = "";
2246 d->drawtype = 0;
2247 break;
2248 }
2249 case U_EMR_INTERSECTCLIPRECT:
2250 {
2251 dbg_str << "<!-- U_EMR_INTERSECTCLIPRECT -->\n";
2252
2254 U_RECTL rc = pEmr->rclClip;
2255
2256 SVGOStringStream tmp_path;
2257 tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " ";
2258 tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " ";
2259 tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " ";
2260 tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " ";
2261 tmp_path << "z";
2262
2263 add_clips(d, tmp_path.str().c_str(), U_RGN_AND);
2264
2265 d->path = "";
2266 d->drawtype = 0;
2267 break;
2268 }
2269 case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "<!-- U_EMR_SCALEVIEWPORTEXTEX -->\n"; break;
2270 case U_EMR_SCALEWINDOWEXTEX: dbg_str << "<!-- U_EMR_SCALEWINDOWEXTEX -->\n"; break;
2271 case U_EMR_SAVEDC:
2272 dbg_str << "<!-- U_EMR_SAVEDC -->\n";
2273
2274 if (d->level < EMF_MAX_DC) {
2275 d->dc[d->level + 1] = d->dc[d->level];
2276 if(d->dc[d->level].font_name){
2277 d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated
2278 }
2279 d->level = d->level + 1;
2280 }
2281 break;
2282 case U_EMR_RESTOREDC:
2283 {
2284 dbg_str << "<!-- U_EMR_RESTOREDC -->\n";
2285
2286 PU_EMRRESTOREDC pEmr = (PU_EMRRESTOREDC) lpEMFR;
2287 int old_level = d->level;
2288 if (pEmr->iRelative >= 0) {
2289 if (pEmr->iRelative < d->level)
2290 d->level = pEmr->iRelative;
2291 }
2292 else {
2293 if (d->level + pEmr->iRelative >= 0)
2294 d->level = d->level + pEmr->iRelative;
2295 }
2296 while (old_level > d->level) {
2297 if (!d->dc[old_level].style.stroke_dasharray.values.empty() &&
2298 (old_level == 0 || (old_level > 0 && d->dc[old_level].style.stroke_dasharray !=
2299 d->dc[old_level - 1].style.stroke_dasharray))) {
2300 d->dc[old_level].style.stroke_dasharray.values.clear();
2301 }
2302 if(d->dc[old_level].font_name){
2303 free(d->dc[old_level].font_name); // else memory leak
2304 d->dc[old_level].font_name = nullptr;
2305 }
2306 old_level--;
2307 }
2308 break;
2309 }
2310 case U_EMR_SETWORLDTRANSFORM:
2311 {
2312 dbg_str << "<!-- U_EMR_SETWORLDTRANSFORM -->\n";
2313
2315 d->dc[d->level].worldTransform = pEmr->xform;
2316 break;
2317 }
2318 case U_EMR_MODIFYWORLDTRANSFORM:
2319 {
2320 dbg_str << "<!-- U_EMR_MODIFYWORLDTRANSFORM -->\n";
2321
2323 switch (pEmr->iMode)
2324 {
2325 case U_MWT_IDENTITY:
2326 d->dc[d->level].worldTransform.eM11 = 1.0;
2327 d->dc[d->level].worldTransform.eM12 = 0.0;
2328 d->dc[d->level].worldTransform.eM21 = 0.0;
2329 d->dc[d->level].worldTransform.eM22 = 1.0;
2330 d->dc[d->level].worldTransform.eDx = 0.0;
2331 d->dc[d->level].worldTransform.eDy = 0.0;
2332 break;
2333 case U_MWT_LEFTMULTIPLY:
2334 {
2335// d->dc[d->level].worldTransform = pEmr->xform * worldTransform;
2336
2337 float a11 = pEmr->xform.eM11;
2338 float a12 = pEmr->xform.eM12;
2339 float a13 = 0.0;
2340 float a21 = pEmr->xform.eM21;
2341 float a22 = pEmr->xform.eM22;
2342 float a23 = 0.0;
2343 float a31 = pEmr->xform.eDx;
2344 float a32 = pEmr->xform.eDy;
2345 float a33 = 1.0;
2346
2347 float b11 = d->dc[d->level].worldTransform.eM11;
2348 float b12 = d->dc[d->level].worldTransform.eM12;
2349 //float b13 = 0.0;
2350 float b21 = d->dc[d->level].worldTransform.eM21;
2351 float b22 = d->dc[d->level].worldTransform.eM22;
2352 //float b23 = 0.0;
2353 float b31 = d->dc[d->level].worldTransform.eDx;
2354 float b32 = d->dc[d->level].worldTransform.eDy;
2355 //float b33 = 1.0;
2356
2357 float c11 = a11*b11 + a12*b21 + a13*b31;;
2358 float c12 = a11*b12 + a12*b22 + a13*b32;;
2359 //float c13 = a11*b13 + a12*b23 + a13*b33;;
2360 float c21 = a21*b11 + a22*b21 + a23*b31;;
2361 float c22 = a21*b12 + a22*b22 + a23*b32;;
2362 //float c23 = a21*b13 + a22*b23 + a23*b33;;
2363 float c31 = a31*b11 + a32*b21 + a33*b31;;
2364 float c32 = a31*b12 + a32*b22 + a33*b32;;
2365 //float c33 = a31*b13 + a32*b23 + a33*b33;;
2366
2367 d->dc[d->level].worldTransform.eM11 = c11;;
2368 d->dc[d->level].worldTransform.eM12 = c12;;
2369 d->dc[d->level].worldTransform.eM21 = c21;;
2370 d->dc[d->level].worldTransform.eM22 = c22;;
2371 d->dc[d->level].worldTransform.eDx = c31;
2372 d->dc[d->level].worldTransform.eDy = c32;
2373
2374 break;
2375 }
2376 case U_MWT_RIGHTMULTIPLY:
2377 {
2378// d->dc[d->level].worldTransform = worldTransform * pEmr->xform;
2379
2380 float a11 = d->dc[d->level].worldTransform.eM11;
2381 float a12 = d->dc[d->level].worldTransform.eM12;
2382 float a13 = 0.0;
2383 float a21 = d->dc[d->level].worldTransform.eM21;
2384 float a22 = d->dc[d->level].worldTransform.eM22;
2385 float a23 = 0.0;
2386 float a31 = d->dc[d->level].worldTransform.eDx;
2387 float a32 = d->dc[d->level].worldTransform.eDy;
2388 float a33 = 1.0;
2389
2390 float b11 = pEmr->xform.eM11;
2391 float b12 = pEmr->xform.eM12;
2392 //float b13 = 0.0;
2393 float b21 = pEmr->xform.eM21;
2394 float b22 = pEmr->xform.eM22;
2395 //float b23 = 0.0;
2396 float b31 = pEmr->xform.eDx;
2397 float b32 = pEmr->xform.eDy;
2398 //float b33 = 1.0;
2399
2400 float c11 = a11*b11 + a12*b21 + a13*b31;;
2401 float c12 = a11*b12 + a12*b22 + a13*b32;;
2402 //float c13 = a11*b13 + a12*b23 + a13*b33;;
2403 float c21 = a21*b11 + a22*b21 + a23*b31;;
2404 float c22 = a21*b12 + a22*b22 + a23*b32;;
2405 //float c23 = a21*b13 + a22*b23 + a23*b33;;
2406 float c31 = a31*b11 + a32*b21 + a33*b31;;
2407 float c32 = a31*b12 + a32*b22 + a33*b32;;
2408 //float c33 = a31*b13 + a32*b23 + a33*b33;;
2409
2410 d->dc[d->level].worldTransform.eM11 = c11;;
2411 d->dc[d->level].worldTransform.eM12 = c12;;
2412 d->dc[d->level].worldTransform.eM21 = c21;;
2413 d->dc[d->level].worldTransform.eM22 = c22;;
2414 d->dc[d->level].worldTransform.eDx = c31;
2415 d->dc[d->level].worldTransform.eDy = c32;
2416
2417 break;
2418 }
2419// case MWT_SET:
2420 default:
2421 d->dc[d->level].worldTransform = pEmr->xform;
2422 break;
2423 }
2424 break;
2425 }
2426 case U_EMR_SELECTOBJECT:
2427 {
2428 dbg_str << "<!-- U_EMR_SELECTOBJECT -->\n";
2429
2430 PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT) lpEMFR;
2431 unsigned int index = pEmr->ihObject;
2432
2433 if (index & U_STOCK_OBJECT) {
2434 switch (index) {
2435 case U_NULL_BRUSH:
2436 d->dc[d->level].fill_mode = DRAW_PAINT;
2437 d->dc[d->level].fill_set = false;
2438 break;
2439 case U_BLACK_BRUSH:
2440 case U_DKGRAY_BRUSH:
2441 case U_GRAY_BRUSH:
2442 case U_LTGRAY_BRUSH:
2443 case U_WHITE_BRUSH:
2444 {
2445 float val = 0;
2446 switch (index) {
2447 case U_BLACK_BRUSH:
2448 val = 0.0 / 255.0;
2449 break;
2450 case U_DKGRAY_BRUSH:
2451 val = 64.0 / 255.0;
2452 break;
2453 case U_GRAY_BRUSH:
2454 val = 128.0 / 255.0;
2455 break;
2456 case U_LTGRAY_BRUSH:
2457 val = 192.0 / 255.0;
2458 break;
2459 case U_WHITE_BRUSH:
2460 val = 255.0 / 255.0;
2461 break;
2462 }
2463 d->dc[d->level].style.fill.setColor(Colors::Color(SP_RGBA32_F_COMPOSE(val, val, val, 1.0), false));
2464 d->dc[d->level].fill_mode = DRAW_PAINT;
2465 d->dc[d->level].fill_set = true;
2466 break;
2467 }
2468 case U_NULL_PEN:
2469 d->dc[d->level].stroke_mode = DRAW_PAINT;
2470 d->dc[d->level].stroke_set = false;
2471 break;
2472 case U_BLACK_PEN:
2473 case U_WHITE_PEN:
2474 {
2475 float val = index == U_BLACK_PEN ? 0 : 1;
2476 d->dc[d->level].style.stroke_dasharray.set = false;
2477 d->dc[d->level].style.stroke_width.value = 1.0;
2478 d->dc[d->level].style.stroke.setColor(Colors::Color(SP_RGBA32_F_COMPOSE(val, val, val, 1.0), false));
2479
2480 d->dc[d->level].stroke_mode = DRAW_PAINT;
2481 d->dc[d->level].stroke_set = true;
2482
2483 break;
2484 }
2485 }
2486 } else {
2487 if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) {
2488 switch (d->emf_obj[index].type)
2489 {
2490 case U_EMR_CREATEPEN:
2491 select_pen(d, index);
2492 break;
2493 case U_EMR_CREATEBRUSHINDIRECT:
2494 case U_EMR_CREATEDIBPATTERNBRUSHPT:
2495 case U_EMR_CREATEMONOBRUSH:
2496 select_brush(d, index);
2497 break;
2498 case U_EMR_EXTCREATEPEN:
2499 select_extpen(d, index);
2500 break;
2501 case U_EMR_EXTCREATEFONTINDIRECTW:
2502 select_font(d, index);
2503 break;
2504 }
2505 }
2506 }
2507 break;
2508 }
2509 case U_EMR_CREATEPEN:
2510 {
2511 dbg_str << "<!-- U_EMR_CREATEPEN -->\n";
2512
2513 PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN) lpEMFR;
2514 insert_object(d, pEmr->ihPen, U_EMR_CREATEPEN, lpEMFR);
2515 break;
2516 }
2517 case U_EMR_CREATEBRUSHINDIRECT:
2518 {
2519 dbg_str << "<!-- U_EMR_CREATEBRUSHINDIRECT -->\n";
2520
2522 insert_object(d, pEmr->ihBrush, U_EMR_CREATEBRUSHINDIRECT, lpEMFR);
2523 break;
2524 }
2525 case U_EMR_DELETEOBJECT:
2526 dbg_str << "<!-- U_EMR_DELETEOBJECT -->\n";
2527 // Objects here are not deleted until the draw completes, new ones may write over an existing one.
2528 break;
2529 case U_EMR_ANGLEARC:
2530 dbg_str << "<!-- U_EMR_ANGLEARC -->\n";
2531 break;
2532 case U_EMR_ELLIPSE:
2533 {
2534 dbg_str << "<!-- U_EMR_ELLIPSE -->\n";
2535
2536 PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE) lpEMFR;
2537 U_RECTL rclBox = pEmr->rclBox;
2538
2539 double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 );
2540 double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 );
2541 double rx = pix_to_abs_size( d, std::abs(rclBox.right - rclBox.left )/2.0 );
2542 double ry = pix_to_abs_size( d, std::abs(rclBox.top - rclBox.bottom)/2.0 );
2543
2544 SVGOStringStream tmp_ellipse;
2545 tmp_ellipse << "cx=\"" << cx << "\" ";
2546 tmp_ellipse << "cy=\"" << cy << "\" ";
2547 tmp_ellipse << "rx=\"" << rx << "\" ";
2548 tmp_ellipse << "ry=\"" << ry << "\" ";
2549
2550 d->mask |= emr_mask;
2551
2552 d->outsvg += " <ellipse ";
2553 output_style(d, lpEMFR->iType); //
2554 d->outsvg += "\n\t";
2555 d->outsvg += tmp_ellipse.str().c_str();
2556 d->outsvg += "/> \n";
2557 d->path = "";
2558 break;
2559 }
2560 case U_EMR_RECTANGLE:
2561 {
2562 dbg_str << "<!-- U_EMR_RECTANGLE -->\n";
2563
2564 PU_EMRRECTANGLE pEmr = (PU_EMRRECTANGLE) lpEMFR;
2565 U_RECTL rc = pEmr->rclBox;
2566
2567 SVGOStringStream tmp_rectangle;
2568 tmp_rectangle << "\n\tM " << pix_to_xy( d, rc.left , rc.top ) << " ";
2569 tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.top ) << " ";
2570 tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.bottom ) << " ";
2571 tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.left, rc.bottom ) << " ";
2572 tmp_rectangle << "\n\tz";
2573
2574 d->mask |= emr_mask;
2575
2576 tmp_path << tmp_rectangle.str().c_str();
2577 break;
2578 }
2579 case U_EMR_ROUNDRECT:
2580 {
2581 dbg_str << "<!-- U_EMR_ROUNDRECT -->\n";
2582
2583 PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT) lpEMFR;
2584 U_RECTL rc = pEmr->rclBox;
2585 U_SIZEL corner = pEmr->szlCorner;
2586 double f = 4.*(sqrt(2) - 1)/3;
2587 double f1 = 1.0 - f;
2588 double cnx = corner.cx/2;
2589 double cny = corner.cy/2;
2590
2591 // clang-format off
2592 SVGOStringStream tmp_rectangle;
2593 tmp_rectangle << "\n"
2594 << " M "
2595 << pix_to_xy(d, rc.left , rc.top + cny )
2596 << "\n";
2597 tmp_rectangle << " C "
2598 << pix_to_xy(d, rc.left , rc.top + cny*f1 )
2599 << " "
2600 << pix_to_xy(d, rc.left + cnx*f1 , rc.top )
2601 << " "
2602 << pix_to_xy(d, rc.left + cnx , rc.top )
2603 << "\n";
2604 tmp_rectangle << " L "
2605 << pix_to_xy(d, rc.right - cnx , rc.top )
2606 << "\n";
2607 tmp_rectangle << " C "
2608 << pix_to_xy(d, rc.right - cnx*f1 , rc.top )
2609 << " "
2610 << pix_to_xy(d, rc.right , rc.top + cny*f1 )
2611 << " "
2612 << pix_to_xy(d, rc.right , rc.top + cny )
2613 << "\n";
2614 tmp_rectangle << " L "
2615 << pix_to_xy(d, rc.right , rc.bottom - cny )
2616 << "\n";
2617 tmp_rectangle << " C "
2618 << pix_to_xy(d, rc.right , rc.bottom - cny*f1 )
2619 << " "
2620 << pix_to_xy(d, rc.right - cnx*f1 , rc.bottom )
2621 << " "
2622 << pix_to_xy(d, rc.right - cnx , rc.bottom )
2623 << "\n";
2624 tmp_rectangle << " L "
2625 << pix_to_xy(d, rc.left + cnx , rc.bottom )
2626 << "\n";
2627 tmp_rectangle << " C "
2628 << pix_to_xy(d, rc.left + cnx*f1 , rc.bottom )
2629 << " "
2630 << pix_to_xy(d, rc.left , rc.bottom - cny*f1 )
2631 << " "
2632 << pix_to_xy(d, rc.left , rc.bottom - cny )
2633 << "\n";
2634 tmp_rectangle << " z\n";
2635 // clang-format on
2636
2637 d->mask |= emr_mask;
2638
2639 tmp_path << tmp_rectangle.str().c_str();
2640 break;
2641 }
2642 case U_EMR_ARC:
2643 {
2644 dbg_str << "<!-- U_EMR_ARC -->\n";
2645 U_PAIRF center,start,end,size;
2646 int f1;
2647 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2648 int stat = emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size);
2649 if(!stat){
2650 tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
2651 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
2652 tmp_path << " ";
2653 tmp_path << 180.0 * current_rotation(d)/M_PI;
2654 tmp_path << " ";
2655 tmp_path << " " << f1 << "," << f2 << " ";
2656 tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
2657 d->mask |= emr_mask;
2658 }
2659 else {
2660 dbg_str << "<!-- ARC record is invalid -->\n";
2661 }
2662 break;
2663 }
2664 case U_EMR_CHORD:
2665 {
2666 dbg_str << "<!-- U_EMR_CHORD -->\n";
2667 U_PAIRF center,start,end,size;
2668 int f1;
2669 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2670 if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
2671 tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
2672 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
2673 tmp_path << " ";
2674 tmp_path << 180.0 * current_rotation(d)/M_PI;
2675 tmp_path << " ";
2676 tmp_path << " " << f1 << "," << f2 << " ";
2677 tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
2678 tmp_path << " z ";
2679 d->mask |= emr_mask;
2680 }
2681 else {
2682 dbg_str << "<!-- CHORD record is invalid -->\n";
2683 }
2684 break;
2685 }
2686 case U_EMR_PIE:
2687 {
2688 dbg_str << "<!-- U_EMR_PIE -->\n";
2689 U_PAIRF center,start,end,size;
2690 int f1;
2691 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2692 if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
2693 tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
2694 tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
2695 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
2696 tmp_path << " ";
2697 tmp_path << 180.0 * current_rotation(d)/M_PI;
2698 tmp_path << " ";
2699 tmp_path << " " << f1 << "," << f2 << " ";
2700 tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
2701 tmp_path << " z ";
2702 d->mask |= emr_mask;
2703 }
2704 else {
2705 dbg_str << "<!-- PIE record is invalid -->\n";
2706 }
2707 break;
2708 }
2709 case U_EMR_SELECTPALETTE: dbg_str << "<!-- U_EMR_SELECTPALETTE -->\n"; break;
2710 case U_EMR_CREATEPALETTE: dbg_str << "<!-- U_EMR_CREATEPALETTE -->\n"; break;
2711 case U_EMR_SETPALETTEENTRIES: dbg_str << "<!-- U_EMR_SETPALETTEENTRIES -->\n"; break;
2712 case U_EMR_RESIZEPALETTE: dbg_str << "<!-- U_EMR_RESIZEPALETTE -->\n"; break;
2713 case U_EMR_REALIZEPALETTE: dbg_str << "<!-- U_EMR_REALIZEPALETTE -->\n"; break;
2714 case U_EMR_EXTFLOODFILL: dbg_str << "<!-- U_EMR_EXTFLOODFILL -->\n"; break;
2715 case U_EMR_LINETO:
2716 {
2717 dbg_str << "<!-- U_EMR_LINETO -->\n";
2718
2719 PU_EMRLINETO pEmr = (PU_EMRLINETO) lpEMFR;
2720
2721 d->mask |= emr_mask;
2722
2723 tmp_path <<
2724 "\n\tL " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y) << " ";
2725 break;
2726 }
2727 case U_EMR_ARCTO:
2728 {
2729 dbg_str << "<!-- U_EMR_ARCTO -->\n";
2730 U_PAIRF center,start,end,size;
2731 int f1;
2732 int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
2733 if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
2734 // draw a line from current position to start, arc from there
2735 tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
2736 tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0;
2737 tmp_path << " ";
2738 tmp_path << 180.0 * current_rotation(d)/M_PI;
2739 tmp_path << " ";
2740 tmp_path << " " << f1 << "," << f2 << " ";
2741 tmp_path << pix_to_xy(d, end.x, end.y)<< " ";
2742
2743 d->mask |= emr_mask;
2744 }
2745 else {
2746 dbg_str << "<!-- ARCTO record is invalid -->\n";
2747 }
2748 break;
2749 }
2750 case U_EMR_POLYDRAW: dbg_str << "<!-- U_EMR_POLYDRAW -->\n"; break;
2751 case U_EMR_SETARCDIRECTION:
2752 {
2753 dbg_str << "<!-- U_EMR_SETARCDIRECTION -->\n";
2755 if(d->arcdir == U_AD_CLOCKWISE || d->arcdir == U_AD_COUNTERCLOCKWISE){ // EMF file could be corrupt
2756 d->arcdir = pEmr->iArcDirection;
2757 }
2758 break;
2759 }
2760 case U_EMR_SETMITERLIMIT:
2761 {
2762 dbg_str << "<!-- U_EMR_SETMITERLIMIT -->\n";
2763
2765
2766 //The function takes a float but saves a 32 bit int in the U_EMR_SETMITERLIMIT record.
2767 float miterlimit = *((int32_t *) &(pEmr->eMiterLimit));
2768 d->dc[d->level].style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size
2769 if (d->dc[d->level].style.stroke_miterlimit.value < 2)
2770 d->dc[d->level].style.stroke_miterlimit.value = 2.0;
2771 break;
2772 }
2773 case U_EMR_BEGINPATH:
2774 {
2775 dbg_str << "<!-- U_EMR_BEGINPATH -->\n";
2776 // The next line should never be needed, should have been handled before main switch
2777 // qualifier added because EMF's encountered where moveto preceded beginpath followed by lineto
2778 if(d->mask & U_DRAW_VISIBLE){
2779 d->path = "";
2780 }
2781 d->mask |= emr_mask;
2782 break;
2783 }
2784 case U_EMR_ENDPATH:
2785 {
2786 dbg_str << "<!-- U_EMR_ENDPATH -->\n";
2787 d->mask &= (0xFFFFFFFF - U_DRAW_ONLYTO); // clear the OnlyTo bit (it might not have been set), prevents any further path extension
2788 break;
2789 }
2790 case U_EMR_CLOSEFIGURE:
2791 {
2792 dbg_str << "<!-- U_EMR_CLOSEFIGURE -->\n";
2793 // EMF may contain multiple closefigures on one path
2794 tmp_path << "\n\tz";
2795 d->mask |= U_DRAW_CLOSED;
2796 break;
2797 }
2798 case U_EMR_FILLPATH:
2799 {
2800 dbg_str << "<!-- U_EMR_FILLPATH -->\n";
2801 if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
2802 if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
2803 tmp_path << "\n\tz";
2804 d->mask |= U_DRAW_CLOSED;
2805 }
2806 d->mask |= emr_mask;
2807 d->drawtype = U_EMR_FILLPATH;
2808 }
2809 break;
2810 }
2811 case U_EMR_STROKEANDFILLPATH:
2812 {
2813 dbg_str << "<!-- U_EMR_STROKEANDFILLPATH -->\n";
2814 if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
2815 if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
2816 tmp_path << "\n\tz";
2817 d->mask |= U_DRAW_CLOSED;
2818 }
2819 d->mask |= emr_mask;
2820 d->drawtype = U_EMR_STROKEANDFILLPATH;
2821 }
2822 break;
2823 }
2824 case U_EMR_STROKEPATH:
2825 {
2826 dbg_str << "<!-- U_EMR_STROKEPATH -->\n";
2827 if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
2828 d->mask |= emr_mask;
2829 d->drawtype = U_EMR_STROKEPATH;
2830 }
2831 break;
2832 }
2833 case U_EMR_FLATTENPATH: dbg_str << "<!-- U_EMR_FLATTENPATH -->\n"; break;
2834 case U_EMR_WIDENPATH: dbg_str << "<!-- U_EMR_WIDENPATH -->\n"; break;
2835 case U_EMR_SELECTCLIPPATH:
2836 {
2837 dbg_str << "<!-- U_EMR_SELECTCLIPPATH -->\n";
2839 int logic = pEmr->iMode;
2840
2841 if ((logic < U_RGN_MIN) || (logic > U_RGN_MAX)){ break; }
2842 add_clips(d, d->path.c_str(), logic); // finds an existing one or stores this, sets clip_id
2843 d->path = "";
2844 d->drawtype = 0;
2845 break;
2846 }
2847 case U_EMR_ABORTPATH:
2848 {
2849 dbg_str << "<!-- U_EMR_ABORTPATH -->\n";
2850 d->path = "";
2851 d->drawtype = 0;
2852 break;
2853 }
2854 case U_EMR_UNDEF69: dbg_str << "<!-- U_EMR_UNDEF69 -->\n"; break;
2855 case U_EMR_COMMENT:
2856 {
2857 dbg_str << "<!-- U_EMR_COMMENT -->\n";
2858
2859 PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT) lpEMFR;
2860
2861 char *szTxt = (char *) pEmr->Data;
2862
2863 for (uint32_t i = 0; i < pEmr->cbData; i++) {
2864 if ( *szTxt) {
2865 if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) {
2866 tmp_str << *szTxt;
2867 }
2868 szTxt++;
2869 }
2870 }
2871
2872 if (false && strlen(tmp_str.str().c_str())) {
2873 tmp_outsvg << " <!-- \"";
2874 tmp_outsvg << tmp_str.str().c_str();
2875 tmp_outsvg << "\" -->\n";
2876 }
2877
2878 break;
2879 }
2880 case U_EMR_FILLRGN: dbg_str << "<!-- U_EMR_FILLRGN -->\n"; break;
2881 case U_EMR_FRAMERGN: dbg_str << "<!-- U_EMR_FRAMERGN -->\n"; break;
2882 case U_EMR_INVERTRGN: dbg_str << "<!-- U_EMR_INVERTRGN -->\n"; break;
2883 case U_EMR_PAINTRGN: dbg_str << "<!-- U_EMR_PAINTRGN -->\n"; break;
2884 case U_EMR_EXTSELECTCLIPRGN:
2885 {
2886 dbg_str << "<!-- U_EMR_EXTSELECTCLIPRGN -->\n";
2887
2889 // the only mode we implement - this clears the clipping region
2890 if (pEmr->iMode == U_RGN_COPY) {
2891 d->dc[d->level].clip_id = 0;
2892 }
2893 break;
2894 }
2895 case U_EMR_BITBLT:
2896 {
2897 dbg_str << "<!-- U_EMR_BITBLT -->\n";
2898
2899 PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR;
2900 // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
2901 // least it leaves objects where the operations should have been.
2902 if (!pEmr->cbBmiSrc) {
2903 // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
2904
2905 if(pEmr->dwRop == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
2906 int32_t dx = pEmr->Dest.x;
2907 int32_t dy = pEmr->Dest.y;
2908 int32_t dw = pEmr->cDest.x;
2909 int32_t dh = pEmr->cDest.y;
2910 SVGOStringStream tmp_rectangle;
2911 tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " ";
2912 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " ";
2913 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " ";
2914 tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " ";
2915 tmp_rectangle << "\n\tz";
2916
2917 d->mask |= emr_mask;
2918 d->dwRop3 = pEmr->dwRop; // we will try to approximate SOME of these
2919 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
2920
2921 tmp_path << tmp_rectangle.str().c_str();
2922 }
2923 else {
2924 double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y);
2925 double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y);
2926 double dw = pix_to_abs_size( d, pEmr->cDest.x);
2927 double dh = pix_to_abs_size( d, pEmr->cDest.y);
2928 //source position within the bitmap, in pixels
2929 int sx = pEmr->Src.x + pEmr->xformSrc.eDx;
2930 int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
2931 int sw = 0; // extract all of the image
2932 int sh = 0;
2933 if(sx<0)sx=0;
2934 if(sy<0)sy=0;
2935 common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
2936 pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
2937 }
2938 break;
2939 }
2940 case U_EMR_STRETCHBLT:
2941 {
2942 dbg_str << "<!-- U_EMR_STRETCHBLT -->\n";
2943 PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) lpEMFR;
2944 // Always grab image, ignore modes.
2945 if (pEmr->cbBmiSrc) {
2946 double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y);
2947 double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y);
2948 double dw = pix_to_abs_size( d, pEmr->cDest.x);
2949 double dh = pix_to_abs_size( d, pEmr->cDest.y);
2950 //source position within the bitmap, in pixels
2951 int sx = pEmr->Src.x + pEmr->xformSrc.eDx;
2952 int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
2953 int sw = pEmr->cSrc.x; // extract the specified amount of the image
2954 int sh = pEmr->cSrc.y;
2955 common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
2956 pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
2957 }
2958 break;
2959 }
2960 case U_EMR_MASKBLT:
2961 {
2962 dbg_str << "<!-- U_EMR_MASKBLT -->\n";
2963 PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) lpEMFR;
2964 // Always grab image, ignore masks and modes.
2965 if (pEmr->cbBmiSrc) {
2966 double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y);
2967 double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y);
2968 double dw = pix_to_abs_size( d, pEmr->cDest.x);
2969 double dh = pix_to_abs_size( d, pEmr->cDest.y);
2970 int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels
2971 int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
2972 int sw = 0; // extract all of the image
2973 int sh = 0;
2974 common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
2975 pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
2976 }
2977 break;
2978 }
2979 case U_EMR_PLGBLT: dbg_str << "<!-- U_EMR_PLGBLT -->\n"; break;
2980 case U_EMR_SETDIBITSTODEVICE: dbg_str << "<!-- U_EMR_SETDIBITSTODEVICE -->\n"; break;
2981 case U_EMR_STRETCHDIBITS:
2982 {
2983 // Some applications use multiple EMF operations, including multiple STRETCHDIBITS to create
2984 // images with transparent regions. PowerPoint does this with rotated images, for instance.
2985 // Parsing all of that to derive a single resultant image object is left for a later version
2986 // of this code. In the meantime, every STRETCHDIBITS goes directly to an image. The Inkscape
2987 // user can sort out transparency later using Gimp, if need be.
2988
2990 double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y );
2991 double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y );
2992 double dw = pix_to_abs_size( d, pEmr->cDest.x);
2993 double dh = pix_to_abs_size( d, pEmr->cDest.y);
2994 int sx = pEmr->Src.x; //source position within the bitmap, in pixels
2995 int sy = pEmr->Src.y;
2996 int sw = pEmr->cSrc.x; // extract the specified amount of the image
2997 int sh = pEmr->cSrc.y;
2998 common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
2999 pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
3000
3001 dbg_str << "<!-- U_EMR_STRETCHDIBITS -->\n";
3002 break;
3003 }
3004 case U_EMR_EXTCREATEFONTINDIRECTW:
3005 {
3006 dbg_str << "<!-- U_EMR_EXTCREATEFONTINDIRECTW -->\n";
3007
3009 insert_object(d, pEmr->ihFont, U_EMR_EXTCREATEFONTINDIRECTW, lpEMFR);
3010 break;
3011 }
3012 case U_EMR_EXTTEXTOUTA:
3013 case U_EMR_EXTTEXTOUTW:
3014 case U_EMR_SMALLTEXTOUT:
3015 {
3016 dbg_str << "<!-- U_EMR_EXTTEXTOUTA/W -->\n";
3017
3018 PU_EMREXTTEXTOUTW pEmr = (PU_EMREXTTEXTOUTW) lpEMFR;
3019 PU_EMRSMALLTEXTOUT pEmrS = (PU_EMRSMALLTEXTOUT) lpEMFR;
3020
3021 double x1,y1;
3022 int roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields, only used with U_EMR_SMALLTEXTOUT
3023 int cChars;
3024 if(lpEMFR->iType==U_EMR_SMALLTEXTOUT){
3025 x1 = pEmrS->Dest.x;
3026 y1 = pEmrS->Dest.y;
3027 cChars = pEmrS->cChars;
3028 if(!(pEmrS->fuOptions & U_ETO_NO_RECT)){ roff += sizeof(U_RECTL); }
3029 }
3030 else {
3031 x1 = pEmr->emrtext.ptlReference.x;
3032 y1 = pEmr->emrtext.ptlReference.y;
3033 cChars = 0;
3034 }
3035 uint32_t fOptions = pEmr->emrtext.fOptions;
3036
3037 if (d->dc[d->level].textAlign & U_TA_UPDATECP) {
3038 x1 = d->dc[d->level].cur.x;
3039 y1 = d->dc[d->level].cur.y;
3040 }
3041
3042 double x = pix_to_x_point(d, x1, y1);
3043 double y = pix_to_y_point(d, x1, y1);
3044
3045 /* Rotation issues are handled entirely in libTERE now */
3046
3047 uint32_t *dup_wt = nullptr;
3048
3049 if( lpEMFR->iType==U_EMR_EXTTEXTOUTA){
3050 /* These should be JUST ASCII, but they might not be...
3051 If it holds Utf-8 or plain ASCII the first call will succeed.
3052 If not, assume that it holds Latin1.
3053 If that fails then something is really screwed up!
3054 */
3055 dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, nullptr);
3056 if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, nullptr);
3057 if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
3058 }
3059 else if( lpEMFR->iType==U_EMR_EXTTEXTOUTW){
3060 dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, nullptr);
3061 if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
3062 }
3063 else { // U_EMR_SMALLTEXTOUT
3064 if(pEmrS->fuOptions & U_ETO_SMALL_CHARS){
3065 dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, nullptr);
3066 }
3067 else {
3068 dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmrS + roff), cChars, nullptr);
3069 }
3070 if(!dup_wt)dup_wt = unknown_chars(cChars);
3071 }
3072
3073 msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
3074
3075 if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){
3076 free(d->dc[d->level].font_name);
3077 d->dc[d->level].font_name = strdup("Times New Roman");
3078 }
3079
3080 char *ansi_text;
3081 ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, nullptr);
3082 free(dup_wt);
3083 // Empty string or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse
3084 if(*((uint8_t *)ansi_text) <= 0x1F){
3085 free(ansi_text);
3086 ansi_text=nullptr;
3087 }
3088
3089 if (ansi_text) {
3090
3092
3093 gchar *escaped_text = g_markup_escape_text(ansi_text, -1);
3094
3095 tsp.x = x*0.8; // TERE expects sizes in points.
3096 tsp.y = y*0.8;
3097 tsp.color.Red = d->dc[d->level].textColor.Red;
3098 tsp.color.Green = d->dc[d->level].textColor.Green;
3099 tsp.color.Blue = d->dc[d->level].textColor.Blue;
3100 tsp.color.Reserved = 0;
3101 switch(d->dc[d->level].style.font_style.value){
3103 tsp.italics = FC_SLANT_OBLIQUE; break;
3105 tsp.italics = FC_SLANT_ITALIC; break;
3106 default:
3108 tsp.italics = FC_SLANT_ROMAN; break;
3109 }
3110 switch(d->dc[d->level].style.font_weight.value){
3111 case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
3112 case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
3113 case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
3114 case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
3115 case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
3116 case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
3117 case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
3118 case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
3119 case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
3120 case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
3121 case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
3122 case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
3123 case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
3124 default: tsp.weight = FC_WEIGHT_NORMAL ; break;
3125 }
3126 // EMF only supports two types of text decoration
3127 tsp.decoration = TXTDECOR_NONE;
3128 if(d->dc[d->level].style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; }
3129 if(d->dc[d->level].style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;}
3130
3131 // EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
3132 tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
3133 (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
3134 ALIRIGHT);
3135 tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
3136 ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
3137 ALITOP));
3138
3139 // language direction can be encoded two ways, U_TA_RTLREADING is preferred
3140 if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; }
3141 else{ tsp.ldir = LDIR_LR; }
3142
3143 tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet)
3144 tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement
3145 tsp.ori += 180.0 * current_rotation(d)/ M_PI; // radians to degrees
3146 tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear().
3147 tsp.fs = d->dc[d->level].style.font_size.computed * 0.8; // Font size in points
3148 char *fontspec = TR_construct_fontspec(&tsp, d->dc[d->level].font_name);
3149 tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec);
3150 free(fontspec);
3151 // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though
3152 // as the metrics from fontconfig may not match, or the font may not be present.
3153 if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; }
3154 else { tsp.co=0; }
3155
3156 int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
3157 if(status==-1){ // change of escapement, emit what we have and reset
3159 if (d->dc[d->level].clip_id){
3160 SVGOStringStream tmp_clip;
3161 tmp_clip << "\n<g\n\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n>";
3162 d->outsvg += tmp_clip.str().c_str();
3163 }
3164 TR_layout_2_svg(d->tri);
3165 ts << d->tri->out;
3166 d->outsvg += ts.str().c_str();
3167 d->tri = trinfo_clear(d->tri);
3168 (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
3169 if (d->dc[d->level].clip_id){
3170 d->outsvg += "\n</g>\n";
3171 }
3172 }
3173
3174 g_free(escaped_text);
3175 free(ansi_text);
3176 }
3177
3178 break;
3179 }
3180 case U_EMR_POLYBEZIER16:
3181 {
3182 dbg_str << "<!-- U_EMR_POLYBEZIER16 -->\n";
3183
3184 PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) lpEMFR;
3185 PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
3186 uint32_t i,j;
3187
3188 if (pEmr->cpts<4)
3189 break;
3190
3191 d->mask |= emr_mask;
3192
3193 tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " ";
3194
3195 for (i=1; i<pEmr->cpts; ) {
3196 tmp_str << "\n\tC ";
3197 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
3198 tmp_str << pix_to_xy( d, apts[i].x, apts[i].y ) << " ";
3199 }
3200 }
3201
3202 tmp_path << tmp_str.str().c_str();
3203
3204 break;
3205 }
3206 case U_EMR_POLYGON16:
3207 {
3208 dbg_str << "<!-- U_EMR_POLYGON16 -->\n";
3209
3210 PU_EMRPOLYGON16 pEmr = (PU_EMRPOLYGON16) lpEMFR;
3211 PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
3212 SVGOStringStream tmp_poly;
3213 unsigned int i;
3214 unsigned int first = 0;
3215
3216 d->mask |= emr_mask;
3217
3218 // skip the first point?
3219 tmp_poly << "\n\tM " << pix_to_xy( d, apts[first].x, apts[first].y ) << " ";
3220
3221 for (i=first+1; i<pEmr->cpts; i++) {
3222 tmp_poly << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " ";
3223 }
3224
3225 tmp_path << tmp_poly.str().c_str();
3226 tmp_path << "\n\tz";
3227 d->mask |= U_DRAW_CLOSED;
3228
3229 break;
3230 }
3231 case U_EMR_POLYLINE16:
3232 {
3233 dbg_str << "<!-- U_EMR_POLYLINE16 -->\n";
3234
3235 PU_EMRPOLYLINE16 pEmr = (PU_EMRPOLYLINE16) lpEMFR;
3236 PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
3237 uint32_t i;
3238
3239 if (pEmr->cpts<2)
3240 break;
3241
3242 d->mask |= emr_mask;
3243
3244 tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " ";
3245
3246 for (i=1; i<pEmr->cpts; i++) {
3247 tmp_str << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " ";
3248 }
3249
3250 tmp_path << tmp_str.str().c_str();
3251
3252 break;
3253 }
3254 case U_EMR_POLYBEZIERTO16:
3255 {
3256 dbg_str << "<!-- U_EMR_POLYBEZIERTO16 -->\n";
3257
3259 PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
3260 uint32_t i,j;
3261
3262 d->mask |= emr_mask;
3263
3264 for (i=0; i<pEmr->cpts;) {
3265 tmp_path << "\n\tC ";
3266 for (j=0; j<3 && i<pEmr->cpts; j++,i++) {
3267 tmp_path << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
3268 }
3269 }
3270
3271 break;
3272 }
3273 case U_EMR_POLYLINETO16:
3274 {
3275 dbg_str << "<!-- U_EMR_POLYLINETO16 -->\n";
3276
3277 PU_EMRPOLYLINETO16 pEmr = (PU_EMRPOLYLINETO16) lpEMFR;
3278 PU_POINT16 apts = (PU_POINT16) pEmr->apts; // Bug in MinGW wingdi.h ?
3279 uint32_t i;
3280
3281 d->mask |= emr_mask;
3282
3283 for (i=0; i<pEmr->cpts;i++) {
3284 tmp_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
3285 }
3286
3287 break;
3288 }
3289 case U_EMR_POLYPOLYLINE16:
3290 case U_EMR_POLYPOLYGON16:
3291 {
3292 if (lpEMFR->iType == U_EMR_POLYPOLYLINE16)
3293 dbg_str << "<!-- U_EMR_POLYPOLYLINE16 -->\n";
3294 if (lpEMFR->iType == U_EMR_POLYPOLYGON16)
3295 dbg_str << "<!-- U_EMR_POLYPOLYGON16 -->\n";
3296
3298 unsigned int n, i, j;
3299
3300 d->mask |= emr_mask;
3301
3302 PU_POINT16 apts = (PU_POINT16) &pEmr->aPolyCounts[pEmr->nPolys];
3303
3304 i = 0;
3305 for (n=0; n<pEmr->nPolys && i<pEmr->cpts; n++) {
3306 SVGOStringStream poly_path;
3307
3308 poly_path << "\n\tM " << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
3309 i++;
3310
3311 for (j=1; j<pEmr->aPolyCounts[n] && i<pEmr->cpts; j++) {
3312 poly_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " ";
3313 i++;
3314 }
3315
3316 tmp_str << poly_path.str().c_str();
3317 if (lpEMFR->iType == U_EMR_POLYPOLYGON16)
3318 tmp_str << " z";
3319 tmp_str << " \n";
3320 }
3321
3322 tmp_path << tmp_str.str().c_str();
3323
3324 break;
3325 }
3326 case U_EMR_POLYDRAW16: dbg_str << "<!-- U_EMR_POLYDRAW16 -->\n"; break;
3327 case U_EMR_CREATEMONOBRUSH:
3328 {
3329 dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n";
3330
3332 insert_object(d, pEmr->ihBrush, U_EMR_CREATEMONOBRUSH, lpEMFR);
3333 break;
3334 }
3335 case U_EMR_CREATEDIBPATTERNBRUSHPT:
3336 {
3337 dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n";
3338
3340 insert_object(d, pEmr->ihBrush, U_EMR_CREATEDIBPATTERNBRUSHPT, lpEMFR);
3341 break;
3342 }
3343 case U_EMR_EXTCREATEPEN:
3344 {
3345 dbg_str << "<!-- U_EMR_EXTCREATEPEN -->\n";
3346
3347 PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN) lpEMFR;
3348 insert_object(d, pEmr->ihPen, U_EMR_EXTCREATEPEN, lpEMFR);
3349 break;
3350 }
3351 case U_EMR_POLYTEXTOUTA: dbg_str << "<!-- U_EMR_POLYTEXTOUTA -->\n"; break;
3352 case U_EMR_POLYTEXTOUTW: dbg_str << "<!-- U_EMR_POLYTEXTOUTW -->\n"; break;
3353 case U_EMR_SETICMMODE:
3354 {
3355 dbg_str << "<!-- U_EMR_SETICMMODE -->\n";
3356 PU_EMRSETICMMODE pEmr = (PU_EMRSETICMMODE) lpEMFR;
3357 ICMmode= pEmr->iMode;
3358 break;
3359 }
3360 case U_EMR_CREATECOLORSPACE: dbg_str << "<!-- U_EMR_CREATECOLORSPACE -->\n"; break;
3361 case U_EMR_SETCOLORSPACE: dbg_str << "<!-- U_EMR_SETCOLORSPACE -->\n"; break;
3362 case U_EMR_DELETECOLORSPACE: dbg_str << "<!-- U_EMR_DELETECOLORSPACE -->\n"; break;
3363 case U_EMR_GLSRECORD: dbg_str << "<!-- U_EMR_GLSRECORD -->\n"; break;
3364 case U_EMR_GLSBOUNDEDRECORD: dbg_str << "<!-- U_EMR_GLSBOUNDEDRECORD -->\n"; break;
3365 case U_EMR_PIXELFORMAT: dbg_str << "<!-- U_EMR_PIXELFORMAT -->\n"; break;
3366 case U_EMR_DRAWESCAPE: dbg_str << "<!-- U_EMR_DRAWESCAPE -->\n"; break;
3367 case U_EMR_EXTESCAPE: dbg_str << "<!-- U_EMR_EXTESCAPE -->\n"; break;
3368 case U_EMR_UNDEF107: dbg_str << "<!-- U_EMR_UNDEF107 -->\n"; break;
3369 // U_EMR_SMALLTEXTOUT is handled with U_EMR_EXTTEXTOUTA/W above
3370 case U_EMR_FORCEUFIMAPPING: dbg_str << "<!-- U_EMR_FORCEUFIMAPPING -->\n"; break;
3371 case U_EMR_NAMEDESCAPE: dbg_str << "<!-- U_EMR_NAMEDESCAPE -->\n"; break;
3372 case U_EMR_COLORCORRECTPALETTE: dbg_str << "<!-- U_EMR_COLORCORRECTPALETTE -->\n"; break;
3373 case U_EMR_SETICMPROFILEA: dbg_str << "<!-- U_EMR_SETICMPROFILEA -->\n"; break;
3374 case U_EMR_SETICMPROFILEW: dbg_str << "<!-- U_EMR_SETICMPROFILEW -->\n"; break;
3375 case U_EMR_ALPHABLEND: dbg_str << "<!-- U_EMR_ALPHABLEND -->\n"; break;
3376 case U_EMR_SETLAYOUT: dbg_str << "<!-- U_EMR_SETLAYOUT -->\n"; break;
3377 case U_EMR_TRANSPARENTBLT: dbg_str << "<!-- U_EMR_TRANSPARENTBLT -->\n"; break;
3378 case U_EMR_UNDEF117: dbg_str << "<!-- U_EMR_UNDEF117 -->\n"; break;
3379 case U_EMR_GRADIENTFILL:
3380 {
3381 /* Gradient fill is doable for rectangles because those correspond to linear gradients. However,
3382 the general case for the triangle fill, with a different color in each corner of the triangle,
3383 has no SVG equivalent and cannot be easily emulated with SVG gradients. So the linear gradient
3384 is implemented, and the triangle fill just paints with the color of the first corner.
3385
3386 This record can hold a series of gradients so we are forced to add path elements directly here,
3387 it cannot wait for the top of the main loop. Any existing path is erased.
3388
3389 */
3390 dbg_str << "<!-- U_EMR_GRADIENTFILL -->\n";
3391 PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL) lpEMFR;
3392 int nV = pEmr->nTriVert; // Number of TriVertex objects
3393 int nG = pEmr->nGradObj; // Number of gradient triangle/rectangle objects
3394 U_TRIVERTEX *tv = (U_TRIVERTEX *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL));
3395 if( pEmr->ulMode == U_GRADIENT_FILL_RECT_H ||
3396 pEmr->ulMode == U_GRADIENT_FILL_RECT_V
3397 ){
3398 SVGOStringStream tmp_rectangle;
3399 int i,fill_idx;
3400 U_GRADIENT4 *rcs = (U_GRADIENT4 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV);
3401 for(i=0;i<nG;i++){
3402 tmp_rectangle << "\n<path d=\"";
3403 fill_idx = add_gradient(d, pEmr->ulMode, tv[rcs[i].UpperLeft], tv[rcs[i].LowerRight]);
3404 tmp_rectangle << "\n\tM " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].UpperLeft ].y ) << " ";
3405 tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].UpperLeft ].y ) << " ";
3406 tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].LowerRight].y ) << " ";
3407 tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].LowerRight].y ) << " ";
3408 tmp_rectangle << "\n\tz\"";
3409 tmp_rectangle << "\n\tstyle=\"stroke:none;fill:url(#";
3410 tmp_rectangle << d->gradients.strings[fill_idx];
3411 tmp_rectangle << ");\"\n";
3412 if (d->dc[d->level].clip_id){
3413 tmp_rectangle << "\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n";
3414 }
3415 tmp_rectangle << "/>\n";
3416 }
3417 d->outsvg += tmp_rectangle.str().c_str();
3418 }
3419 else if(pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){
3420 SVGOStringStream tmp_triangle;
3421 char tmpcolor[8];
3422 int i;
3423 U_GRADIENT3 *tris = (U_GRADIENT3 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV);
3424 for(i=0;i<nG;i++){
3425 tmp_triangle << "\n<path d=\"";
3426 safeprintf(tmpcolor,"%6.6X",sethexcolor(trivertex_to_colorref(tv[tris[i].Vertex1])));
3427 tmp_triangle << "\n\tM " << pix_to_xy( d, tv[tris[i].Vertex1].x , tv[tris[i].Vertex1].y ) << " ";
3428 tmp_triangle << "\n\tL " << pix_to_xy( d, tv[tris[i].Vertex2].x , tv[tris[i].Vertex2].y ) << " ";
3429 tmp_triangle << "\n\tL " << pix_to_xy( d, tv[tris[i].Vertex3].x , tv[tris[i].Vertex3].y ) << " ";
3430 tmp_triangle << "\n\tz\"";
3431 tmp_triangle << "\n\tstyle=\"stroke:none;fill:#";
3432 tmp_triangle << tmpcolor;
3433 tmp_triangle << ";\"\n/>\n";
3434 }
3435 d->outsvg += tmp_triangle.str().c_str();
3436 }
3437 d->path = "";
3438 // if it is anything else the record is bogus, so ignore it
3439 break;
3440 }
3441 case U_EMR_SETLINKEDUFIS: dbg_str << "<!-- U_EMR_SETLINKEDUFIS -->\n"; break;
3442 case U_EMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_EMR_SETTEXTJUSTIFICATION -->\n"; break;
3443 case U_EMR_COLORMATCHTOTARGETW: dbg_str << "<!-- U_EMR_COLORMATCHTOTARGETW -->\n"; break;
3444 case U_EMR_CREATECOLORSPACEW: dbg_str << "<!-- U_EMR_CREATECOLORSPACEW -->\n"; break;
3445 default:
3446 dbg_str << "<!-- U_EMR_??? -->\n";
3447 break;
3448 } //end of switch
3449// At run time define environment variable INKSCAPE_DBG_EMF to include string COMMENT.
3450// Users may employ this to to place a comment for each processed EMR record in the SVG
3451 if(eDbgComment){
3452 d->outsvg += dbg_str.str().c_str();
3453 }
3454 d->outsvg += tmp_outsvg.str().c_str();
3455 d->path += tmp_path.str().c_str();
3456
3457 } //end of while
3458// At run time define environment variable INKSCAPE_DBG_EMF to include string FINAL
3459// Users may employ this to to show the final SVG derived from the EMF
3460 if(eDbgFinal){
3461 std::cout << d->outsvg << std::endl;
3462 }
3463 (void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
3464
3465 return(file_status);
3466}
3467
3469 if(name.count){
3470 for(int i=0; i< name.count; i++){ free(name.strings[i]); }
3471 free(name.strings);
3472 }
3473 name.count = 0;
3474 name.size = 0;
3475}
3476
3477std::unique_ptr<SPDocument> Emf::open(Inkscape::Extension::Input *, char const *uri, bool)
3478{
3479 if (!uri) {
3480 return nullptr;
3481 }
3482
3483 // ensure usage of dot as decimal separator in scanf/printf functions (indepentendly of current locale)
3484 char *oldlocale = g_strdup(setlocale(LC_NUMERIC, nullptr));
3485 setlocale(LC_NUMERIC, "C");
3486
3488
3489 d.n_obj = 0; //these might not be set otherwise if the input file is corrupt
3490 d.emf_obj = nullptr;
3491 d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there EMF spec says device can pick whatever it wants
3492
3493 // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
3494
3495 d.defs += "\n";
3496 d.defs += " <pattern id=\"EMFhbasepattern\" \n";
3497 d.defs += " patternUnits=\"userSpaceOnUse\"\n";
3498 d.defs += " width=\"6\" \n";
3499 d.defs += " height=\"6\" \n";
3500 d.defs += " x=\"0\" \n";
3501 d.defs += " y=\"0\"> \n";
3502 d.defs += " </pattern> \n";
3503
3504
3505 size_t length;
3506 char *contents;
3507 if(emf_readdata(uri, &contents, &length))return(nullptr);
3508
3509 d.pDesc = nullptr;
3510
3511 // set up the text reassembly system
3512 if(!(d.tri = trinfo_init(nullptr)))return(nullptr);
3513 (void) trinfo_load_ft_opts(d.tri, 1,
3514 FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
3515 FT_KERNING_UNSCALED);
3516
3517 int good = myEnhMetaFileProc(contents,length, &d);
3518 free(contents);
3519
3520 if (d.pDesc){ free( d.pDesc ); }
3521
3522// std::cout << "SVG Output: " << std::endl << d.outsvg << std::endl;
3523
3524 std::unique_ptr<SPDocument> doc;
3525 if (good) {
3526 doc = SPDocument::createNewDocFromMem(d.outsvg.raw(), true);
3527 }
3528
3533
3534 if (d.emf_obj) {
3535 int i;
3536 for (i=0; i<d.n_obj; i++)
3537 delete_object(&d, i);
3538 delete[] d.emf_obj;
3539 }
3540
3541 d.dc[0].style.stroke_dasharray.values.clear();
3542
3543 for(int i=0; i<=EMF_MAX_DC; i++){
3544 if(d.dc[i].font_name)free(d.dc[i].font_name);
3545 }
3546
3548
3549 // in earlier versions no viewbox was generated and a call to setViewBoxIfMissing() was needed here.
3550
3551 // restore decimal separator used in scanf/printf functions to initial value
3552 setlocale(LC_NUMERIC, oldlocale);
3553 g_free(oldlocale);
3554
3555 return doc;
3556}
3557
3559{
3560 /* EMF in */
3561 // clang-format off
3563 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
3564 "<name>" N_("EMF Input") "</name>\n"
3565 "<id>org.inkscape.input.emf</id>\n"
3566 "<input>\n"
3567 "<extension>.emf</extension>\n"
3568 "<mimetype>image/x-emf</mimetype>\n"
3569 "<filetypename>" N_("Enhanced Metafiles (*.emf)") "</filetypename>\n"
3570 "<filetypetooltip>" N_("Enhanced Metafiles") "</filetypetooltip>\n"
3571 "</input>\n"
3572 "</inkscape-extension>", std::make_unique<Emf>());
3573 // clang-format on
3574
3575 /* EMF out */
3576 // clang-format off
3578 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
3579 "<name>" N_("EMF Output") "</name>\n"
3580 "<id>org.inkscape.output.emf</id>\n"
3581 "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"bool\">true</param>\n"
3582 "<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"bool\">true</param>\n"
3583 "<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"bool\">true</param>\n"
3584 "<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"bool\">true</param>\n"
3585 "<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"bool\">false</param>\n"
3586 "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"bool\">false</param>\n"
3587 "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"bool\">false</param>\n"
3588 "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"bool\">false</param>\n"
3589 "<param name=\"FixPPTLinGrad\" gui-text=\"" N_("Use native rectangular linear gradients") "\" type=\"bool\">false</param>\n"
3590 "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard EMF hatches") "\" type=\"bool\">false</param>\n"
3591 "<param name=\"FixImageRot\" gui-text=\"" N_("Ignore image rotations") "\" type=\"bool\">false</param>\n"
3592 "<output>\n"
3593 "<extension>.emf</extension>\n"
3594 "<mimetype>image/x-emf</mimetype>\n"
3595 "<filetypename>" N_("Enhanced Metafile (*.emf)") "</filetypename>\n"
3596 "<filetypetooltip>" N_("Enhanced Metafile") "</filetypetooltip>\n"
3597 "</output>\n"
3598 "</inkscape-extension>", std::make_unique<Emf>());
3599 // clang-format on
3600}
3601
3602} // namespace Inkscape::Extension::Internal
3603
3604/*
3605 Local Variables:
3606 mode:c++
3607 c-file-style:"stroustrup"
3608 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3609 indent-tabs-mode:nil
3610 fill-column:99
3611 End:
3612*/
3613// 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 stroke(Inkscape::Extension::Print *, Geom::PathVector const &, Geom::Affine const &, SPStyle const *, Geom::OptRect const &, Geom::OptRect const &, Geom::OptRect const &)
static void enlarge_clips(PEMF_CALLBACK_DATA d)
static void free_emf_strings(EMF_STRINGS name)
static int myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d)
static int in_clips(PEMF_CALLBACK_DATA d, const char *test)
static void add_clips(PEMF_CALLBACK_DATA d, const char *clippath, unsigned int logic)
static double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py)
static void select_pen(PEMF_CALLBACK_DATA d, int index)
static uint32_t add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2)
static double current_scale(PEMF_CALLBACK_DATA d)
static uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi, uint32_t iUsage, uint32_t offBits, uint32_t offBmi)
static void delete_object(PEMF_CALLBACK_DATA d, int index)
static void enlarge_hatches(PEMF_CALLBACK_DATA d)
static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py)
static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset)
static int AI_hack(PU_EMRHEADER pEmr)
static void enlarge_images(PEMF_CALLBACK_DATA d)
static uint32_t add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor)
bool check(Inkscape::Extension::Extension *module) override
Verify any dependencies.
Definition emf-inout.cpp:64
static void insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD pObj)
static void select_font(PEMF_CALLBACK_DATA d, int index)
static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y)
static void print_document_to_file(SPDocument *doc, const gchar *filename)
Definition emf-inout.cpp:70
static void enlarge_gradients(PEMF_CALLBACK_DATA d)
static void snap_to_faraway_pair(double *x, double *y)
std::unique_ptr< SPDocument > open(Inkscape::Extension::Input *mod, char const *uri, bool is_importing) override
Open a file.
static void output_style(PEMF_CALLBACK_DATA d, int iType)
static uint32_t * unknown_chars(size_t count)
static int in_hatches(PEMF_CALLBACK_DATA d, char *test)
static void select_extpen(PEMF_CALLBACK_DATA d, int index)
static double current_rotation(PEMF_CALLBACK_DATA d)
static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px)
static double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px)
void save(Inkscape::Extension::Output *mod, SPDocument *doc, char const *filename) override
static int in_gradients(PEMF_CALLBACK_DATA d, const char *test)
static void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi)
static int in_images(PEMF_CALLBACK_DATA d, const char *test)
static void select_brush(PEMF_CALLBACK_DATA d, int index)
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)
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.
constexpr uint32_t SP_RGBA32_F_COMPOSE(double r, double g, double b, double a)
Definition utils.h:63
RectangularCluster rc
Canvas item belonging to an SVG drawing element.
SVG drawing for display.
constexpr auto PRINT_EMF
Definition emf-inout.cpp:52
Enhanced Metafile Input/Output.
Enhanced Metafile printing - implementation.
Geom::Point start
Geom::Point end
constexpr uint32_t U_RGB_COMPOSE(U_COLORREF c)
U_COLORREF trivertex_to_colorref(U_TRIVERTEX tv)
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.
EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]
Definition emf-inout.h:132
Information for a single text object.
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
WMF manual 2.2.2.8.
Definition uemf.h:474
uint8_t Red
Red color (0-255)
Definition uemf.h:475
uint8_t Reserved
Not used.
Definition uemf.h:478
uint8_t Blue
Blue color (0-255)
Definition uemf.h:477
uint8_t Green
Green color (0-255)
Definition uemf.h:476
EMF manual 2.3.1.2
Definition uemf.h:2771
U_OFFBITSSRC offBitsSrc
Offset in bytes to the bitmap (within bitmapbuffer)
Definition uemf.h:2783
U_OFFBMISRC offBmiSrc
Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
Definition uemf.h:2781
U_POINTL Dest
Destination UL corner in logical units.
Definition uemf.h:2774
U_XFORM xformSrc
Source bitmap transform (world to page coordinates)
Definition uemf.h:2778
uint32_t dwRop
Ternary Raster Operation enumeration.
Definition uemf.h:2776
U_POINTL cDest
Destination width in logical units.
Definition uemf.h:2775
U_CBBITS cbBitsSrc
Size in bytes of bitmap Record may include optional bitmapbuffer.
Definition uemf.h:2784
uint32_t iUsageSrc
DIBcolors Enumeration.
Definition uemf.h:2780
U_CBBMISRC cbBmiSrc
Size in bytes of U_BITMAPINFO.
Definition uemf.h:2782
U_POINTL Src
Source retangle UL corner in logical units.
Definition uemf.h:2777
EMF manual 2.3.3.1.
Definition uemf.h:2669
uint8_t Data[1]
Comment (any binary data, interpretation is program specific)
Definition uemf.h:2672
U_CBDATA cbData
Number of bytes in comment.
Definition uemf.h:2671
EMF manual 2.3.7.1
Definition uemf.h:2473
uint32_t ihBrush
Index to place object in EMF object table (this entry must not yet exist)
Definition uemf.h:2475
U_LOGBRUSH lb
Brush properties.
Definition uemf.h:2476
EMF manual 2.3.7.4
Definition uemf.h:3024
U_OFFBITS offBits
Offset in bytes to the DIB bitmap data (within DIB bitmapbuffer.
Definition uemf.h:3030
uint32_t ihBrush
Index to place object in EMF object table (this entry must not yet exist)
Definition uemf.h:3026
U_OFFBMI offBmi
Offset in bytes to U_BITMAPINFO (within DIB bitmapbuffer)
Definition uemf.h:3028
uint32_t iUsage
DIBcolors Enumeration.
Definition uemf.h:3027
U_CBBITS cbBits
Size in bytes of DIB bitmap Record may include optional DIB bitmapbuffer.
Definition uemf.h:3031
U_CBBMI cbBmi
Size in bytes of U_BITMAPINFO.
Definition uemf.h:3029
EMF manual 2.3.7.5
Definition uemf.h:3008
uint32_t ihBrush
Index to place object in EMF object table (this entry must not yet exist)
Definition uemf.h:3010
EMF manual 2.3.7.7
Definition uemf.h:2462
U_LOGPEN lopn
Pen properties.
Definition uemf.h:2465
uint32_t ihPen
Index to place object in EMF object table (this entry must not yet exist)
Definition uemf.h:2464
EMF manual 2.3.8.3
Definition uemf.h:2449
uint32_t ihObject
Number of a stock or created object.
Definition uemf.h:2451
EMF manual 2.3.5.5
Definition uemf.h:2499
U_RECTL rclBox
bounding rectangle in logical units
Definition uemf.h:2501
EMF manual 2.3.2.1
Definition uemf.h:2387
U_RECTL rclClip
Clipping Region.
Definition uemf.h:2389
EMF manual 2.3.7.8
Definition uemf.h:2913
U_LOGFONT_PANOSE elfw
Font parameters, either U_LOGFONT or U_LOGFONT_PANOSE, the latter is bigger so use that type here.
Definition uemf.h:2916
uint32_t ihFont
Index of the font in the EMF object table.
Definition uemf.h:2915
EMF manual 2.3.7.9
Definition uemf.h:3040
U_CBBITS cbBits
Size in bytes of DIB bitmap.
Definition uemf.h:3046
uint32_t ihPen
Index to place object in EMF object table (this entry must not yet exist)
Definition uemf.h:3042
U_EXTLOGPEN elp
Pen parameters (Size is Variable!!!!) Record may include optional DIB bitmap.
Definition uemf.h:3047
EMF manual 2.3.2.2
Definition uemf.h:2759
uint32_t iMode
RegionMode Enumeration
Definition uemf.h:2762
EMF manual 2.3.5.7
Definition uemf.h:2933
U_EMRTEXT emrtext
Text parameters.
Definition uemf.h:2939
EMF manual 2.3.5.12
Definition uemf.h:3254
U_NUM_GRADOBJ nGradObj
Number of gradient triangle/rectangle objects.
Definition uemf.h:3258
uint32_t ulMode
Gradientfill Enumeration (determines Triangle/Rectangle)
Definition uemf.h:3259
U_NUM_TRIVERTEX nTriVert
Number of TriVertex objects.
Definition uemf.h:3257
The first U_ENHMETARECORD record in the metafile.
Definition uemf.h:2127
uint32_t offDescription
Offset in bytes to optional UTF-16BE string Description field.
Definition uemf.h:2138
uint32_t nDescription
Characters in the Description field, 0 if no description
Definition uemf.h:2137
U_EMR emr
U_EMR
Definition uemf.h:2128
U_SIZEL szlMillimeters
Reference device size in 0.01 mm.
Definition uemf.h:2141
U_SIZEL szlDevice
Reference device size in pixels
Definition uemf.h:2140
uint16_t nHandles
Number of graphics objects used in the Metafile
Definition uemf.h:2135
U_RECTL rclFrame
Bounding rectangle in 0.01 mm units.
Definition uemf.h:2130
U_RECTL rclBounds
Bounding rectangle in device units.
Definition uemf.h:2129
EMF manual 2.3.1.3
Definition uemf.h:2816
U_OFFBMISRC offBmiSrc
Offset in bytes to U_BITMAPINFO (within srcbitmapbuffer)
Definition uemf.h:2826
U_POINTL Src
Source UL corner in logical units.
Definition uemf.h:2822
uint32_t iUsageSrc
DIBcolors Enumeration.
Definition uemf.h:2825
U_POINTL Dest
Destination UL corner in logical units.
Definition uemf.h:2819
U_XFORM xformSrc
Transform to apply to source.
Definition uemf.h:2823
U_POINTL cDest
Destination width in logical units.
Definition uemf.h:2820
U_OFFBITSSRC offBitsSrc
Offset in bytes to the src bitmap (within srcbitmapbuffer)
Definition uemf.h:2828
U_CBBITS cbBitsSrc
Size in bytes of src bitmap.
Definition uemf.h:2829
U_CBBMISRC cbBmiSrc
Size in bytes of U_BITMAPINFO.
Definition uemf.h:2827
EMF manual 2.3.12.1
Definition uemf.h:2438
U_XFORM xform
Transform.
Definition uemf.h:2440
uint32_t iMode
ModifyWorldTransformMode Enumeration.
Definition uemf.h:2441
EMF manual 2.3.11.4 EMF manual 2.3.5.13
Definition uemf.h:2340
U_POINTL ptl
Point coordinates.
Definition uemf.h:2342
EMF manual 2.3.2.4
Definition uemf.h:2328
U_POINTL ptlOffset
Clipping region.
Definition uemf.h:2330
EMF manual 2.3.5.17
Definition uemf.h:2950
U_POINT16 apts[1]
Array of POINT16.
Definition uemf.h:2954
U_NUM_POINT16 cpts
Number of POINT16 in array.
Definition uemf.h:2953
EMF manual 2.3.5.16.
Definition uemf.h:2156
U_NUM_POINTL cptl
Number of points to draw.
Definition uemf.h:2159
U_POINTL aptl[1]
array of points
Definition uemf.h:2160
EMF manual 2.3.5.31
Definition uemf.h:2976
U_NUM_POINT16 cpts
Total number of points (over all poly)
Definition uemf.h:2980
U_NUM_POLYCOUNTS nPolys
Number of elements in aPolyCounts.
Definition uemf.h:2979
U_POLYCOUNTS aPolyCounts[1]
Number of points in each poly (sequential)
Definition uemf.h:2981
EMF manual 2.3.5.30.
Definition uemf.h:2183
U_POLYCOUNTS aPolyCounts[1]
Number of points in each poly (sequential)
Definition uemf.h:2188
U_NUM_POINTL cptl
Total number of points (over all poly)
Definition uemf.h:2187
U_NUM_POLYCOUNTS nPolys
Number of elements in aPolyCounts.
Definition uemf.h:2186
EMF manual 2.3.11.6
Definition uemf.h:2418
int32_t iRelative
DC to restore. -1 is preceding.
Definition uemf.h:2420
EMF manual 2.3.5.35
Definition uemf.h:2512
U_RECTL rclBox
bounding rectangle in logical units
Definition uemf.h:2514
U_SIZEL szlCorner
W & H in logical units of ellipse used to round corner.
Definition uemf.h:2515
EMF manual 2.3.11.9
Definition uemf.h:2622
uint32_t iArcDirection
ArcDirection Enumeration.
Definition uemf.h:2624
EMF manual 2.3.11.19 MapMode enumeration.
Definition uemf.h:2270
uint32_t iMode
enumeration varies with type
Definition uemf.h:2272
U_EMR emr
U_EMR.
Definition uemf.h:2271
EMF manual 2.3.11.21
Definition uemf.h:2635
uint32_t eMiterLimit
Miter limit (max value of mitered length / line width)
Definition uemf.h:2637
EMF manual 2.3.11.26
Definition uemf.h:2315
U_COLORREF crColor
Color.
Definition uemf.h:2317
EMF manual 2.3.11.30.
Definition uemf.h:2199
U_SIZEL szlExtent
H & V extent in logical units.
Definition uemf.h:2201
EMF manual 2.3.11.31.
Definition uemf.h:2212
U_POINTL ptlOrigin
H & V origin in logical units.
Definition uemf.h:2214
EMF manual 2.3.12.2
Definition uemf.h:2428
U_XFORM xform
Transform.
Definition uemf.h:2430
EMF manual 2.3.5.37
Definition uemf.h:3157
U_POINTL Dest
Where to draw the text.
Definition uemf.h:3159
U_NUM_STR cChars
Characters in TextString (not null terminated)
Definition uemf.h:3160
uint32_t fuOptions
ExtTextOutOptions Enumeration.
Definition uemf.h:3161
EMF manual 2.3.1.6
Definition uemf.h:2793
U_CBBITS cbBitsSrc
Size in bytes of bitmap.
Definition uemf.h:2806
U_OFFBMISRC offBmiSrc
Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
Definition uemf.h:2803
U_POINTL cSrc
Src W & H in logical units Record may include optional bitmapbuffer.
Definition uemf.h:2807
U_OFFBITSSRC offBitsSrc
Offset in bytes to the bitmap (within bitmapbuffer)
Definition uemf.h:2805
uint32_t iUsageSrc
DIBcolors Enumeration.
Definition uemf.h:2802
U_XFORM xformSrc
Transform to apply to source.
Definition uemf.h:2800
U_POINTL Src
Source UL corner in logical units.
Definition uemf.h:2799
U_CBBMISRC cbBmiSrc
Size in bytes of U_BITMAPINFO.
Definition uemf.h:2804
U_POINTL Dest
Destination UL corner in logical units.
Definition uemf.h:2796
U_POINTL cDest
Destination width in logical units.
Definition uemf.h:2797
EMF manual 2.3.1.7
Definition uemf.h:2892
U_POINTL cDest
Destination W & H in logical units Record may includes optional bitmapbuffer.
Definition uemf.h:2904
U_POINTL Src
Source UL corner in logical units.
Definition uemf.h:2896
U_POINTL Dest
Destination UL corner in logical units.
Definition uemf.h:2895
U_OFFBITSSRC offBitsSrc
Offset in bytes to bitmap.
Definition uemf.h:2900
U_CBBITS cbBitsSrc
Size in bytes of bitmap.
Definition uemf.h:2901
U_CBBMISRC cbBmiSrc
Size in bytes of U_BITMAPINFO.
Definition uemf.h:2899
U_OFFBMISRC offBmiSrc
Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
Definition uemf.h:2898
U_POINTL cSrc
Source W & H in logical units.
Definition uemf.h:2897
uint32_t iUsageSrc
DIBColors Enumeration.
Definition uemf.h:2902
uint32_t fOptions
ExtTextOutOptions Enumeration.
Definition uemf.h:1733
U_POINTL ptlReference
String start coordinates.
Definition uemf.h:1730
U_OFFSTR offString
Offset in bytes to the string from the start of the RECORD.
Definition uemf.h:1732
U_NUM_STR nChars
Number of characters in the string.
Definition uemf.h:1731
First two fields of all EMF records, First two fields of all EMF+ records (1 or more within an EMF co...
Definition uemf.h:2084
uint32_t iType
Type of EMR record.
Definition uemf.h:2085
uint32_t nSize
Size of entire record in bytes (multiple of 4).
Definition uemf.h:2086
General form of an EMF record.
Definition uemf.h:2071
uint32_t iType
Type of EMR record.
Definition uemf.h:2072
U_NUM_STYLEENTRY elpNumEntries
Count of StyleEntry array.
Definition uemf.h:2032
U_STYLEENTRY elpStyleEntry[1]
Array of StyleEntry (For user specified dot/dash patterns)
Definition uemf.h:2033
uint32_t elpWidth
Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel)
Definition uemf.h:2028
uint32_t elpPenStyle
PenStyle Enumeration.
Definition uemf.h:2027
U_COLORREF elpColor
Pen color.
Definition uemf.h:2030
uint32_t elpBrushStyle
LB_Style Enumeration.
Definition uemf.h:2029
uint32_t elpHatch
HatchStyle Enumeration.
Definition uemf.h:2031
For U_EMRGRADIENTFILL GradObj field.
Definition uemf.h:1797
For U_EMRGRADIENTFILL GradObj field.
Definition uemf.h:1781
uint32_t UpperLeft
Index of UL corner in an array of U_TRIVERTEX objects.
Definition uemf.h:1782
uint32_t LowerRight
Index of LR corner in an array of U_TRIVERTEX objects.
Definition uemf.h:1783
U_COLORREF lbColor
Brush color.
Definition uemf.h:1815
uint32_t lbHatch
HatchStyle Enumeration.
Definition uemf.h:1816
uint32_t lbStyle
< In MS documentation this is LogBrushEx Object
Definition uemf.h:1814
U_LOGFONT elfLogFont
Basic font attributes.
Definition uemf.h:1877
uint8_t lfUnderline
LF_Underline Enumeration.
Definition uemf.h:1834
uint8_t lfItalic
LF_Italic Enumeration.
Definition uemf.h:1833
uint8_t lfStrikeOut
LF_StrikeOut Enumeration.
Definition uemf.h:1835
int32_t lfEscapement
Angle in 0.1 degrees betweem escapement vector and X axis.
Definition uemf.h:1830
int32_t lfHeight
Height in Logical units.
Definition uemf.h:1828
uint16_t lfFaceName[U_LF_FACESIZE]
Name of font. If <U_LF_FACESIZE chars must be null terminated.
Definition uemf.h:1841
int32_t lfWeight
LF_Weight Enumeration.
Definition uemf.h:1832
uint32_t lopnStyle
PenStyle Enumeration.
Definition uemf.h:1927
U_POINT lopnWidth
Width of pen set by X, Y is ignored.
Definition uemf.h:1928
U_COLORREF lopnColor
Pen color value.
Definition uemf.h:1929
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
WMF manual 2.2.2.15.
Definition uemf.h:546
int32_t x
X value.
Definition uemf.h:547
int32_t y
Y value.
Definition uemf.h:548
WMF manual 2.2.2.16.
Definition uemf.h:563
WMF manual 2.2.2.19.
Definition uemf.h:576
int32_t left
left coordinate
Definition uemf.h:577
int32_t right
right coordinate
Definition uemf.h:579
int32_t bottom
bottom coordinate
Definition uemf.h:580
int32_t top
top coordinate
Definition uemf.h:578
WMF manual 2.2.2.20.
Definition uemf.h:592
WMF manual 2.2.2.22.
Definition uemf.h:608
int32_t cy
Y size.
Definition uemf.h:610
int32_t cx
X size.
Definition uemf.h:609
For GRADIENT_[TRIANGLE|U_RECT].
Definition uemf.h:1766
uint16_t Green
Green component.
Definition uemf.h:1770
int32_t y
Y coord.
Definition uemf.h:1768
uint16_t Red
Red component.
Definition uemf.h:1769
int32_t x
X coord.
Definition uemf.h:1767
uint16_t Alpha
Alpha Transparency.
Definition uemf.h:1772
uint16_t Blue
Bule component.
Definition uemf.h:1771
U_FLOAT eDx
X offset in logical units.
Definition uemf.h:2016
U_FLOAT eM12
Matrix element M12.
Definition uemf.h:2013
U_FLOAT eM21
Matrix element M21.
Definition uemf.h:2014
U_FLOAT eM11
Matrix element M11.
Definition uemf.h:2012
U_FLOAT eDy
Y offset in logical units.
Definition uemf.h:2017
U_FLOAT eM22
Matrix element M22.
Definition uemf.h:2015
@ 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
struct U_EMREXCLUDECLIPRECT * PU_EMREXCLUDECLIPRECT
EMF manual 2.3.2.1.
struct U_EMRSETWINDOWORGEX * PU_EMRSETWINDOWORGEX
EMF manual 2.3.11.31.
struct U_RECT U_RECTL
WMF manual 2.2.2.19.
struct U_EMRMODIFYWORLDTRANSFORM * PU_EMRMODIFYWORLDTRANSFORM
EMF manual 2.3.12.1.
struct U_EMRSETMITERLIMIT * PU_EMRSETMITERLIMIT
EMF manual 2.3.11.21
struct U_EMRPOLYPOLYLINE * PU_EMRPOLYPOLYGON
EMF manual 2.3.5.28.
struct U_EMRSETMAPMODE * PU_EMRSETTEXTALIGN
EMF manual 2.3.11.25 TextAlignment enumeration.
struct U_EMRSETWINDOWORGEX * PU_EMRSETVIEWPORTORGEX
EMF manual 2.3.11.29.
struct U_EMRMOVETOEX * PU_EMRMOVETOEX
EMF manual 2.3.11.4.
struct U_EMRSTRETCHBLT * PU_EMRSTRETCHBLT
EMF manual 2.3.1.6.
struct U_EMRPOLYBEZIER * PU_EMRPOLYGON
EMF manual 2.3.5.22.
struct U_EMRSETWINDOWEXTEX * PU_EMRSETWINDOWEXTEX
EMF manual manual 2.3.11.30.
struct U_EMRSETMAPMODE * PU_EMRSETMAPMODE
EMF manual 2.3.11.19 MapMode enumeration.
struct U_EMRSTRETCHDIBITS * PU_EMRSTRETCHDIBITS
EMF manual 2.3.1.7.
struct U_POINT16 * PU_POINT16
WMF manual 2.2.2.16.
struct U_EMRSETWORLDTRANSFORM * PU_EMRSETWORLDTRANSFORM
EMF manual 2.3.12.2.
struct U_EMRSETMAPMODE * PU_EMRSETPOLYFILLMODE
EMF manual 2.3.11.22 PolygonFillMode Enumeration.
struct U_EMRSETMAPMODE * PU_EMRSETBKMODE
EMF manual 2.3.11.11 BackgroundMode Enumeration.
struct U_EMRSETTEXTCOLOR * PU_EMRSETTEXTCOLOR
EMF manual 2.3.11.26.
struct U_EMRSETMAPMODE * PU_EMRSELECTCLIPPATH
EMF manual 2.3.2.5 RegionMode Enumeration.
struct U_EMRMOVETOEX * PU_EMRLINETO
EMF manual 2.3.5.13.
struct U_EMRBITBLT * PU_EMRBITBLT
EMF manual 2.3.1.2.
struct U_EMRPOLYBEZIER * PU_EMRPOLYBEZIERTO
EMF manual 2.3.5.18.
struct U_EMRCOMMENT * PU_EMRCOMMENT
EMF manual 2.3.3.1, AKA GDICOMMENT.
struct U_EMREXTCREATEPEN * PU_EMREXTCREATEPEN
EMF manual 2.3.7.9.
struct U_EMRPOLYBEZIER16 * PU_EMRPOLYLINETO16
EMF manual 2.3.5.27.
struct U_ENHMETARECORD * PU_ENHMETARECORD
General form of an EMF record.
struct U_EMROFFSETCLIPRGN * PU_EMROFFSETCLIPRGN
EMF manual 2.3.2.4.
struct U_EMRHEADER * PU_EMRHEADER
EMF manual 2.2.9.
struct U_EMRSETARCDIRECTION * PU_EMRSETARCDIRECTION
EMF manual 2.3.11.9.
struct U_EMRSMALLTEXTOUT * PU_EMRSMALLTEXTOUT
EMF manual 2.3.5.37.
struct U_EMRCREATEBRUSHINDIRECT * PU_EMRCREATEBRUSHINDIRECT
EMF manual 2.3.7.1
struct U_EMRSETMAPMODE * PU_EMRSETICMMODE
EMF manual 2.3.11.14 ICMMode Enumeration.
struct U_EMRROUNDRECT * PU_EMRROUNDRECT
EMF manual 2.3.5.35
struct U_EMRPOLYBEZIER * PU_EMRPOLYBEZIER
EMF manual 2.3.5.16.
struct U_EMRRESTOREDC * PU_EMRRESTOREDC
EMF manual 2.3.11.6.
struct U_EMREXTTEXTOUTA * PU_EMREXTTEXTOUTW
EMF manual 2.3.5.8.
struct U_EMRPOLYBEZIER16 * PU_EMRPOLYGON16
EMF manual 2.3.5.23.
struct U_EMRPOLYBEZIER * PU_EMRPOLYLINE
EMF manual 2.3.5.24.
struct U_EMRDELETEOBJECT * PU_EMRSELECTOBJECT
EMF manual 2.3.8.5.
struct U_EMR * PU_EMR
First two fields of all EMF records,.
struct U_EMRCREATEDIBPATTERNBRUSHPT * PU_EMRCREATEDIBPATTERNBRUSHPT
EMF manual 2.3.7.4.
struct U_EMRCREATEMONOBRUSH * PU_EMRCREATEMONOBRUSH
EMF manual 2.3.7.5.
struct U_EMRELLIPSE * PU_EMRELLIPSE
EMF manual 2.3.5.5.
struct U_EMRSETWINDOWEXTEX * PU_EMRSETVIEWPORTEXTEX
EMF manual manual 2.3.11.28.
struct U_EMRPOLYPOLYLINE16 * PU_EMRPOLYPOLYGON16
EMF manual 2.3.5.29.
struct U_EMRSETMAPMODE * PU_EMRSETSTRETCHBLTMODE
EMF manual 2.3.11.24 StretchMode Enumeration.
struct U_EMRELLIPSE * PU_EMRRECTANGLE
EMF manual 2.3.5.34.
struct U_EMRCREATEPEN * PU_EMRCREATEPEN
EMF manual 2.3.7.7.
struct U_PAIR * PU_POINTL
WMF manual 2.2.2.15.
struct U_EMRPOLYBEZIER * PU_EMRPOLYLINETO
EMF manual 2.3.5.26.
struct U_EMREXCLUDECLIPRECT * PU_EMRINTERSECTCLIPRECT
EMF manual 2.3.2.3.
struct U_EMRPOLYBEZIER16 * PU_EMRPOLYLINE16
EMF manual 2.3.5.25.
struct U_EMRSETTEXTCOLOR * PU_EMRSETBKCOLOR
EMF manual 2.3.11.10.
struct U_EMRMASKBLT * PU_EMRMASKBLT
EMF manual 2.3.1.3.
struct U_EMRSETMAPMODE * PU_EMRSETROP2
EMF manual 2.3.11.23 Binary Raster Operation Enumeration.
struct U_EMREXTSELECTCLIPRGN * PU_EMREXTSELECTCLIPRGN
EMF manual 2.3.2.2.
struct U_EMRPOLYBEZIER16 * PU_EMRPOLYBEZIER16
EMF manual 2.3.5.17.
struct U_EMRGRADIENTFILL * PU_EMRGRADIENTFILL
EMF manual 2.3.5.12.
struct U_EMRPOLYBEZIER16 * PU_EMRPOLYBEZIERTO16
EMF manual 2.3.5.19.
struct U_EMREXTCREATEFONTINDIRECTW * PU_EMREXTCREATEFONTINDIRECTW
EMF manual 2.3.7.8.
int U_emf_record_safe(const char *record)
uint32_t * U_Utf8ToUtf32le(const char *src, size_t max, size_t *len)
char * U_Utf16leToUtf8(const uint16_t *src, size_t max, size_t *len)
char * U_strdup(const char *s)
uint32_t * U_Latin1ToUtf32le(const char *src, size_t max, size_t *len)
uint32_t * U_Utf16leToUtf32le(const uint16_t *src, size_t max, size_t *len)
char * U_Utf32leToUtf8(const uint32_t *src, size_t max, size_t *len)