EMF for Office and report tools¶
Word, Excel, PowerPoint and most Delphi report tools only take vector pictures as Windows Enhanced Metafiles (EMF). This page shows how to export a drawing to EMF, so it stays sharp at any zoom and in print, and keeps its text selectable where the font allows it.
EMF export is VCL only.
Requirements¶
The export is written by the GDI+ backend, whatever your application renders
with on screen. Enable GDI+ and the GDI font system in
Common\Vcl\ContextSettingsVCL.inc, in addition to the render context
your application uses:
This does not change what your application renders with: Direct2D stays the default. GDI+ only has to be available for the export to switch to it. A project can also set these symbols in its own project options instead of in the shared file; see setting this per project.
Without the two defines the export routines still compile, and raise an exception naming them when called.
Exporting¶
Add BVE.SVG2ExportEMF.VCL to the uses clause. From a file:
From a document you already loaded, for example the one in a component after your application has changed it:
The document itself is not changed. For the duration of the call it renders through GDI+; afterwards it is back on the backend it had, also when the export raises an exception.
Size¶
Both routines take a width and a height in pixels. The default, 0 for both, uses the drawing's own size:
Text¶
The next parameter decides how text is written:
| Value | Result |
|---|---|
etmStringsWithPlacedCharacters |
Each run of text is one piece of text, with every character placed. The default, and the best choice for selectable text. |
etmStrings |
Every placed character starts a new piece of text. |
etmPaths |
Text is converted to outlines. Nothing to select, but it looks the same on every computer, with or without the font. |
Text is written as text only for installed TrueType fonts, and the computer
that opens the file needs the same fonts to show it as drawn. Choose
etmPaths when the file goes to people who may not have them.
Filters and clip paths¶
The render options default to none, on purpose. Filters and clip paths make parts of the output bitmaps, which defeats the point of a vector file. Pass them only when the drawing needs them:
SVGRenderToEmfFile(Root, 'drawing.emf', 0, 0,
etmStringsWithPlacedCharacters, [sroFilters, sroClippath]);
Using the EMF¶
- In Office: insert the file as a picture, or put it on the clipboard and
paste it. Loading the file into a VCL
TMetafileand assigning that to theClipboardgives Office a vector picture to paste. - In a report tool: FastReport, ReportBuilder and similar tools accept EMF in their picture components. Export the drawing to a file or a stream before the report runs and load it there.
Many files, several threads, or a DLL¶
GDI+ has to be started once per process. The export routines do this themselves, counted under a lock, so two threads exporting at the same time cannot shut GDI+ down under each other.
When exporting many files, keep GDI+ running across all of them to save a start and stop per file:
SVGEmfGraphicsAcquire;
try
for FileName in FileNames do
SVGFileRenderToEmfFile(FileName, ChangeFileExt(FileName, '.emf'));
finally
SVGEmfGraphicsRelease;
end;
Every SVGEmfGraphicsAcquire needs a matching SVGEmfGraphicsRelease.
The routines are safe to call from a DLL: GDI+ is started on the first export rather than when the unit is initialised, because a DLL's initialisation runs where GDI+ may not be started.
Doing it by hand¶
To write into a GDI+ metafile you create yourself, create the render context yourself as well. The document must then use the matching resource factory for the duration of the render, which you set and restore:
SaveFactory := Root.ResourceFactory;
Root.ResourceFactory :=
TSVGRenderContextManager.CreateResourceFactory(rcGDIPlus, fsGDI);
try
RCGP := TSVGContextGP.Create(FileName, W, H);
RC := RCGP;
RCGP.TextFormattingOptions := [tfoStringsWithPlacedCharacters];
RC.BeginScene;
try
SVGRenderToRenderContext(Root, RC, W, H, []);
finally
RC.EndScene;
end;
RC := nil; // the metafile is written when the context is released
finally
if SaveFactory = TSVGRenderContextManager.ResourceFactory then
Root.ResourceFactory := nil
else
Root.ResourceFactory := SaveFactory;
end;
The factory and the context must match
The resource factory decides what kind of path data and text the document
creates; it does not create the render context. A mismatch fails without a
clear message: GDI+ path data on a Direct2D context is an access violation
inside d2d1.dll, and Direct2D path data on the GDI+ metafile writer gives
an empty file.
Examples\RenderToEMF in the
examples repository
shows both routes side by side.