[cairo] SVG to EMF quality

Adrian Johnson ajohnson at redneon.com
Wed Sep 9 07:07:35 PDT 2009

Shixin Zeng wrote:
> Hi,
> I've produced some pictures with matplotlib for my paper, which
> prefers enhanced MetaFile (EMF). However, current maplotlib doesn't
> support EMF output, but svg. So I tried to convert svg to emf via
> cairo, as mentioned in this
> thread:http://lists.cairographics.org/archives/cairo/2009-January/016215.html
> But the problem is that the quality of the output emf file is pretty
> low. Is this caused by my badly programming or the limitation of this
> method itself? Thanks

After discovering EMFexplorer [1] and examining some different EMF files 
I have found the cause of the low quality EMF output from the 
win32-printing surface.

In GDI all path functions use integer coordinates. For small drawings 
this causes rounding problems. Using EMFexplorer I could see that other 
applications were scaling down the GDI current transformation matrix and 
scaling up path coordinates to increase the precision.

This was something I previously tried with the win32-printing surface 
without success. Using EMFexplorer to check the output I could 
immediately see what the problem is. The win32-print surface is 
resetting the GDI CTM to identity to preventing rounding errors when 
printing where the GDI units are in dpi.

The patch on my emf branch [2] is an initial attempt at fixing this. It 
needs further testing to ensure I have not caused any regressions when 
printing. With this patch it is possible to get good EMF output with the 
following code:

void create_emf (char *filename)
     HDC dc;
     HDC ref_dc;
     XFORM xform;
     cairo_surface_t *surface;
     cairo_t *cr;

     ref_dc = GetDC (NULL);
     dc = CreateEnhMetaFile (ref_dc, filename, NULL, NULL);
     ReleaseDC (NULL, dc);

     /* Scale the GDI CTM by 1/16. This allows all coordinates to
      * be scaled up by 16 to increase precision */
     SetGraphicsMode (dc, GM_ADVANCED);
     xform.eM11 = 1.0/16;
     xform.eM12 = 0;
     xform.eM21 = 0;
     xform.eM22 = 1.0/16;
     xform.eDx = 0;
     xform.eDy = 0;
     SetWorldTransform (dc, &xform);

     surface = cairo_win32_printing_surface_create (dc);
     cr = cairo_create (surface);

     /* Undo the scale applied to the GDI CTM */
     cairo_scale (cr, 16, 16);

     draw (cr);
     cairo_destroy (cr);
     cairo_surface_destroy (surface);
     CloseEnhMetaFile (dc);

[1] http://frazmitic.free.fr/emfexplorer/
[2] http://cgit.freedesktop.org/~ajohnson/cairo/log/?h=emf

More information about the cairo mailing list