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