README revision 1df6105803c4c56c020a56301c7c9c4890fd4158
107N/AlibUEMF is a portable C99 implementation for reading/writing Enhanced Metafile (EMF)
107N/Afor each WMR/EMR record type, and each object type incorporated into such a record, it provides
107N/Acorresponding *_set, *_print, and *_swap functions. (For WMF there are also *_get functions, see below.)
107N/AU_EMRBITBLT_set, U_EMRBITBLT_print, and U_EMRBITBLT_swap. A few additional functions are provided for
107N/Aassembling the EMF in memory, debugging, and converting the EMF file to/from Little Endian representation.
107N/AThis code has been tested on 32 bit Ubuntu (LE), 32 bit Mingw, 64 bit Manriva, and 64 bit Solaris (BE).
107N/AEMF+ file Record structure is from many helpful responses from Microsoft documentation support
107N/Atestbuild.sh Small bash script to build all programs. Modify as needed for target platform.
107N/Auemf_print.c Contains the *_print functions needed to print the contents of EMF records and objects.
181N/Auemf_print.h Prototypes for *_print functions.
107N/Auemf_endian.c Contains the *_swap functions needed to rearrange bytes between Big and Little Endian.
107N/Auemf_endian.h Prototype for U_emf_endian() and definitions for Endian type of the local machine.
upmf.c Contains the *_set and *_get functions needed to construct or read an EMF+ file.
upmf.h Definitions and structures for EMF+ records and objects.
upmf_print.c Contains the *_print functions needed to print the contents of EMF+ records and objects.
upmf_print.h Prototypes for *_print functions.
uwmf.c Contains the *_set and *_get functions needed to construct or read a WMF file.
uwmf.h Definitions and structures for WMF records and objects.
uwmf_print.c Contains the *_print functions needed to print the contents of WMF records and objects.
uwmf_print.h Prototypes for *_print functions.
uwmf_endian.c Contains the *_swap functions needed to rearrange bytes between Big and Little Endian.
uwmf_endian.h Prototype for U_wmf_endian() and definitions for Endian type of the local machine.
testbed_emf.c Program used for testing emf functions in libUEMF. Run it like: testbed_emf flags.
It creates a test file "test_libuemf.emf" which should be identical to
test_libuemf_ref.emf. (This file cannot be imported from EMF into PowerPoint
testbed_pmf.c Program used for testing EMF+ functions in libUEMF. Similar to testbed_emf.
testbed_wmf.c Program used for testing wmf functions in libUEMF. Similar to testbed_emf.
reademf.c Utility that that reads an EMF file and emits its contents in text form.
Run it like: reademf target_file.emf
readwmf.c Utility that that reads an WMF file and emits its contents in text form.
Run it like: reademf target_file.wmf
cutemf.c Utility for removing specific records from an EMF file.
pmfdual2single.c Utility for reducing dual-mode EMF+ file to single mode. Removes all
Example output from: reademf test_libuemf_ref.emf
Example output from: readwmf test_libuemf_ref.wmf
test_mm_<modes>_ref.emf
emf-inout.cpp,example
In Linux/Unix like environments (omit -g flag for production versions):
gcc -std=c99 -pedantic -Wall -fPIC -g -c uemf.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c uemf_print.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c uemf_endian.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c uemf_utf.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c uwmf.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c uwmf_print.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c uwmf_endian.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c upmf.c
gcc -std=c99 -pedantic -Wall -fPIC -g -c upmf_print.c
gcc -shared -Wl,-soname,libuemf.so.0 \
-o libuemf.so.0.0.3 uemf.o uemf_utf.o uemf_print.o uemf_endian.o uwmf.o uwmf_print.o uwmf_endian.o upmf.o upmf_print.o -lc
gcc -std=c99 -pedantic -Wall -g -o cutemf cutemf.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o pmfdual2single pmfdual2single.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o reademf reademf.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o readwmf readwmf.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o testbed_emf testbed_emf.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o testbed_emf testbed_wmf.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o test_mapmodes_emf test_mapmodes_emf.c -luemf -lm
gcc -std=c99 -pedantic -Wall -g -o pmfdual2single pmfdual2single.c uemf.c uemf_endian.c uemf_utf.c upmf.c -lm
gcc -std=c99 -pedantic -Wall -g -o reademf reademf.c uemf.c uemf_endian.c uemf_utf.c uemf_print.c upmf.c upmf_print.c -lm
gcc -std=c99 -pedantic -Wall -g -o readwmf readwmf.c uemf.c uemf_endian.c uemf_utf.c uemf_print.c uwmf.c uwmf_endian.c uwmf_print.c upmf.c upmf_print.c -lm
gcc -std=c99 -pedantic -Wall -g -o testbed_pmf testbed_pmf.c uemf.c uemf_endian.c uemf_utf.c upmf.c upmf.h -lm
gcc -std=c99 -pedantic -Wall -g -o testbed_wmf testbed_wmf.c uemf.c uemf_endian.c uemf_utf.c uwmf.c uwmf_endian.c -lm
gcc -std=c99 -pedantic -Wall -g -o test_mapmodes_emf test_mapmodes_emf.c uemf.c uemf_endian.c uemf_utf.c -lm
Extra debugging on linux may be enabled in testbed for use under Valgrind. To build that way do instead:
gcc -std=c99 -pedantic -Wall -g -DU_VALGRIND -o testbed_emf testbed_emf.c uemf.c uemf_endian.c uemf_print.c uemf_utf.c -lm
Sparc Solaris 8 and 9 are Big Endian, and to work around some minor incompatibilities with more recent systems,
assuming gcc is installed in /opt/csw and PATH is set correctly to use it:
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o cutemf cutemf.c uemf.c uemf_endian.c uemf_utf.c -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o pmfdual2single pmfdual2single.c uemf.c uemf_endian.c uemf_utf.c upmf.c -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o reademf reademf.c uemf.c uemf_endian.c uemf_utf.c uemf_print.c upmf.c upmf_print.c -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o readwmf readwmf.c uemf.c uemf_endian.c uemf_utf.c uemf_print.c uwmf.c uwmf_endian.c uwmf_print.c upmf.c upmf_print.c -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o testbed_emf testbed_emf.c uemf.c uemf_endian.c uemf_utf.c -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o testbed_pmf testbed_pmf.c uemf.c uemf_endian.c uemf_utf.c upmf.c upmf.h -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o testbed_wmf testbed_wmf.c uemf.c uemf_endian.c uemf_utf.c uwmf.c uwmf_endian.c -lm -L/opt/csw/lib -liconv
gcc -DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g -o test_mapmodes_emf test_mapmodes_emf.c uemf.c uemf_endian.c uemf_utf.c -lm -L/opt/csw/lib -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o cutemf cutemf.c uemf.c uemf_endian.c uemf_utf.c -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o pmfdual2single pmfdual2single.c uemf.c uemf_endian.c uemf_utf.c upmf.c -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o reademf reademf.c uemf.c uemf_endian.c uemf_utf.c uemf_print.c upmf.c upmf_print.c -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o readwmf readwmf.c uemf.c uemf_endian.c uemf_utf.c uemf_print.c uwmf.c uwmf_endian.c uwmf_print.c upmf.c upmf_print.c -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o testbed_emf testbed_emf.c uemf.c uemf_endian.c uemf_utf.c -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o testbed_pmf testbed_pmf.c uemf.c uemf_endian.c uemf_utf.c upmf.c upmf.h -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o testbed_wmf testbed_wmf.c uemf.c uemf_endian.c uemf_utf.c uwmf.c uwmf_endian.c -lm -liconv
gcc -DWIN32 -std=c99 -pedantic -Wall -g -o test_mapmodes_emf test_mapmodes_emf.c uemf.c uemf_endian.c uemf_utf.c -lm -liconv
| extract -fmt 'gcc -Werror=format-security -Wall -Wformat -Wformat-security -W -Wno-pointer-sign -O2 -c -o deleteme.o [1,]' \
To write an EMF file the code first runs two initialization functions: emf_start() and htable_create().
Then a U_EMRHEADER record is created. This and all subsequent records are appended to the EMF file in
memory with emf_append(). Whichever other EMR records are desired are also added. The last EMR record
To input an EMF file it is is opened and the data read into a buffer in memory with emf_readdata(). On a
Big Endian machine this will also swap machine dependent byte orders as needed. At that point end user code
generally has to do something with the data in each record. The simplest case is to just print it, as shown
in reademf.c. More typically it must map the operations into its own graphics model, as shown in the
emf32*.*.example files from Inkscape. Basically the processing program needs to enter a loop, processing
one record at a time, pulling the record size and type from the first two uint32_t values present in each
record. It then enters a switch statement with one case for each EMR record type. Each case: statement
will generally define a pointer to that type of data object. Accessing the data from that pointer is
While libUEMF implements _print and _swap functions for all supported EMR records, end user code would
to U_emf_onerec_print() (see reademf.c) or the entire completed EMF file in memory buffer to U_emf_endian()
(see testbed.c).
WMF support is similar, except the functions are wmf_start(), wmf_readdata(), and so forth. It is a good
idea to separate end user WMF and EMF generating code into different modules, in order to avoid accidentally
writing EMR records to a WMF file and vice versa. WHile EMF objects are aligned in memory and so may be
accessed using the supplied structs, the ones for WMF files are not usually aligned and so must be accessed
using the supplied *_get functions. (The difference may not be evident on an x86 platform, but on RISC directly
The usual idea when employing a graphics file type like EMF is to copy a description of the objects in a
drawing from one program to another. Many of the record types in an EMF file can be thought of as objects,
they are lines or shapes or bitmaps or text. However, Microsoft's GDI implements binary and ternary raster
operations (see the descriptions in uemf.h) and most of these operations are not object like, instead they
combine things on the drawing surface. (There is in each case a copy operation which is object like.)
Consequently, EMF files which use these other raster operations are not particularly easy to import as
graphic objects. For instance, when PowerPoint rotates an image and saves it in an EMF the result is not
a single rotated image object. Instead there is an image containing the rotated image, which is followed by
masking operations to make the regions outside of the image transparent. There appears to be no standard
"begin path" and "end path" to delineate the start and end of such a compound operation. So a program
reading such a file has no easy way of figuring out which previous object is being modified by a subsequent
binary raster operations in vertical slices to two images. The expected result appears in Windows "Preview",
but if that region is imported into PowerPoint and converted to objects within that program the result looks
Support for U_EMREXTTEXTOUTW is much more common than for U_EMRSMALLTEXT. The latter is easier to use,
since it does not require a Dx array for each text string, but the objects will not import into PowerPoint,
There are two types of dotted/dashed lines. The first uses a set of predefined flags to set the pattern
and the latter is end user user defined. Both are restricted to lines of width 1. These built in types are
problematic as key applications cannot handle them properly. PowerPoint cannot convert either type to its
internal object format. The first form loses the pattern and comes through as solid lines. The second type
is toxic - even a single dotted line of the second type will prevent the entire EMF from being converted.
The safest choice is to avoid these patterned line styles entirely. Convert all dots and dashes to separate
line draws before writing those into the EMF file. libUEMF has no problem reading these records, so code
As with most graphics file formats there is no single object representation of a complex text string (varying
font size, super/sub script, bold, italic,.etc.). Such text must be decomposed into multiple text strings,
each with its own formatting. It is unlikely that a subsequent program reading these records from the EMF
If a font used in an EMF file is not present on both the sending and receiving systems text will not look the
same on both. Font substitution is usually silent in most programs, so it may not be evident why the text looks
a little odd. However, if text is simple, that is, consists of just one line of text without size, color,
WMF graphics are quite limited when compared to EMF graphics. When reading a WMF file it is essential that
end user code always create a specified object, even if that object is just a placeholder with no real
function. If any "create" operation presented by the WMF file is not handled then the object indices used
further along in the WMF file will be off, with very bad results! WMF "regions" are not supported by libUEMF,
files in the other modes were produced. With no positive control there was no way to verify that they
EMF+ files are usually stored in files with an ".emf" file extension. In this package EMF+ programs,
functions, and definitions use PMF or PMR to distinguish them from the EMF and WMF material. ("EMF+"
representations, or which are missing in one representation. The example file generated by this library
Text in EMF+ is placed not from the baseline, as in EMF, but from the upper left corner of the Em square.
substitutions result in badly placed text because even fonts that look similar on the screen may have
Consequently the text representation within an EMF+ file is not very portable between systems - it will
only render correctly if the second system has all of the fonts used in the document. The testbed_pmf.c
Slight changes in documentation for uemf.h.
Fixed typo in uemf_endian.c.
Fixed a tiny bug in uemf.c (if memory allocation failed a struct would have
Added U_PMF_DASHEDLINEDATA_set3 (dot/dash pattern from bits in a uint32_t).
testbed_emf.c to include that.
Fixed error in test_mapmodes_emf.c where truncation float to integer was used where round
Slight modification to testit.sh.
Added missing parameter for WMF RESTOREDC_set/get.
Replaced all sizeof() in uwmf.c that referred to UWMF structures with their
needed, sometimes flipped direction for arcs/chords.
Modified uemf_endian.c to suppress some compiler warnings.
Fixed a typo in uwmf_print.c.
0.1.2 2013-01-25 Fixed bug revealed by newer gcc on Solaris, assignment of aligned 32 bit to unaligned
0.0.11 2012-12-04 Moved UTF and related functions out of uemf.c uemf.h and into uemf_utf.c uemf_utf.h.
0.0.10 2012-11-28 Discovered that not enough space was being allocated for some UTF conversions. To be
Fixed header related print/swap functions - depending on what type of header there
Added test_mm_(mode)_ref.emf files. These are reference for:
0.0.7 2012-08-30 Added/fixed tests for hatched, DIB, and mono strokes.
0.0.6 2012-08-21 Added/fixed tests for hatched, DIB, and mono fills.
0.0.5 2012-08-08 Minor changes to uemf.c to suppress compiler warnings. Fixed
0.0.4 2012-07-25 More tests in testbed.c. Found and fixed bugs in