MS EMF (Enhanced Metafile) to SVG conversion library.
By themselves, EMF/EMF+ files are rare in the wild. However, they are frequently embedded inside other MS file formats.
This project was started to properly convert Visio stencils (.VSS) to svg and be able to reuse public stencils in other environments than MS Visio (see libvisio2svg).
However this project could be use beyond its original motivations to handle emf blobs in any MS formats.
Installing the dependencies on Debian:
# compiler
apt-get install gcc g++
# or
apt-get install clang
# build deps
apt-get install cmake pkg-config
# library deps with their headers
apt-get install libpng-dev libc6-dev libfontconfig1-dev libfreetype6-dev zlib1g-dev
Installing the dependencies on OS X:
$ brew install argp-standalone
Installing the dependencies on RHEL/CentOS/Fedora:
yum install cmake libpng-devel freetype-devel fontconfig-devel gcc-c++ gcc
Also note that in some rare cases, to properly handle text fields (ETO_GLYPH_INDEX flag), the ttf font used by the documents must be present and indexed (fontconfig) on your system.
Commands to build this project:
# options:
# * [-DUSE_CLANG=on]: use clang instead of gcc
# * [-DSTATIC=on]: build static library
# * [-DDEBUG=on]: compile with debugging symbols
#
# CMAKE_INSTALL_PREFIX is optional, default is /usr/local/
$ cmake . -DCMAKE_INSTALL_PREFIX=/usr/
# compilation
$ make
# installation
$ make install
$ ./emf2svg-conv --help
Usage: emf2svg-conv [OPTION...] -i FILE -o FILE
emf2svg -- Enhanced Metafile to SVG converter
-h, --height=HEIGHT Max height in px
-i, --input=FILE Input EMF file
-o, --output=FILE Output SVG file
-p, --emfplus Handle EMF+ records
-v, --verbose Produce verbose output
-w, --width=WIDTH Max width in px
-?, --help Give this help list
--usage Give a short usage message
--version Print program version
-V, --version Print emf2svg version
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Report bugs to https://github.com/kakwa/libemf2svg/issues.
# usage example:
$ ./emf2svg-conv -i ./tests/resources/emf/test-037.emf -o example.svg -v
Shorten examples:
Conversion from EMF to SVG (complete example here):
#include <emf2svg.h>
//[...]
int main(int argc, char *argv[]){
/* emf content size */
size_t emf_size;
/* emf content */
char * emf_content;
/* svg output string */
char *svg_out = NULL;
/* svg output length */
size_t svg_out_len = 0;
//[...]
/*************************** options settings **************************/
/* allocate the options structure) */
generatorOptions *options = (generatorOptions *)calloc(1, \
sizeof(generatorOptions));
/* debugging flag (prints the emf record in stdout if true) */
options->verbose = true;
/* emf+ flag (handles emf+ records if true) */
options->emfplus = true;
/* if a custom xml/svg namespace is needed (keep empty in doubt) */
options->nameSpace = (char *)"svg";
/* includes the svg start and stop tags (set to false if the result
* of this call is meant to be used inside another svg) */
options->svgDelimiter = true;
/* image width in px (set to 0 to use the original emf device width) */
options->imgWidth = 0;
/* image height in px (set to 0 to use the original emf device height) */
options->imgHeight = 0;
/***************************** conversion ******************************/
int ret = emf2svg(emf_content, emf_size, &svg_out, &svg_out_len, options);
/***********************************************************************/
//[...]
}
Check document for EMF+ record presence (complete example here):
int main(int argc, char *argv[]){
/* emf content size */
size_t emf_size;
/* emf content */
char * emf_content;
/* svg output string */
char *svg_out = NULL;
/* svg output length */
size_t svg_out_len = 0;
bool emfplus;
int ret = emf2svg_is_emfplus(emf_content, emf_size, &emfplus);
if(emfplus)
fprintf(stdout,"%s contains EMF+ records\n", file_name);
}
See ./src/conv/emf2svg.cpp for a real life example.
EMF RECORDS:
Status | Count | Percent |
---|---|---|
Supported | 37 | [ 35%] |
Partial | 33 | [ 31%] |
Unused | 2 | [ 1%] |
Ignored | 33 | [ 31%] |
Total | 105 |
EMF+ RECORDS:
Status | Count | Percent |
---|---|---|
Supported | 0 | [ 0%] |
Partial | 0 | [ 0%] |
Unused | 0 | [ 0%] |
Ignored | 85 | [ 100%] |
Total | 85 |
1.1.0:
1.0.3:
1.0.2:
1.0.1:
1.0.0:
size_t svg_out_len;
/********* options settings **********/
@@ -44,7 +46,7 @@ int main(int argc, char *argv[]){
/***************************** conversion ******************************/
int ret = emf2svg(emf_content, emf_size, &svg_out, &svg_out_len, options);
/***************************/ ```
0.5.1:
0.5.0:
0.4.0:
0.3.0:
0.2.0:
0.1.0:
General source code organisation:
Useful links:
$ ./tests/resources/coverage.sh
Using American Fuzzy Lop:
# remove big files from test pool
$ mkdir ./tmp
$ find tests/resources/emf -size +1M -name "*.emf" -exec mv {} ./tmp \;
# compile with afl compiler
$ cmake -DCMAKE_CXX_COMPILER=afl-clang++ -DCMAKE_C_COMPILER=afl-clang .
$ make
# run afl (see man for more advanced usage)
$ afl-fuzz -i tests/resources/emf -o out/ -t 10000 -- ./emf2svg-conv -i '@@' -o out/
# restore the files
mv ./tmp/* tests/resources/emf
# options: -n to disable valgrind tests, -v for verbose output
# see -h for complete list of options
$ ./tests/resources/check_correctness.sh #[-n] [-v]
# generated svg:
$ ls tests/out/test-*
tests/out/test-000.emf.svg tests/out/test-051.emf.svg
[...]
The emf files used for these checks are located in ./tests/resources/emf/.
To build, run on emf test files and visualize (with geeqie):
$ cmake .&& \
make &&\
"./tests/resources/check_correctness.sh" -n &&\
geeqie "tests/out"
To check against corrupted emf:
$ cmake -DDEBUG=ON . &&\
make &&\
"./tests/resources/check_correctness.sh" -sxN \
-e "./tests/resources/emf-corrupted/"
To print records index in svg as comments:
$ cmake -DINDEX=ON . && make
To reformat/reindent the code (clang-format):
$ ./goodies/format
Contribution are welcomed.
Nothing special here, it’s the usual “fork; commit(s); pull request”.
Only one thing however, run ./goodies/format
(clang-format) before the pull request.