Overview: libUEMF is a portable C99 implementation for reading/writing Enhanced Metafile (EMF), Enhanced Metafile Format Plus (PMF), and Windows Metafile (WMF) files. libUEMF avoids collisions with Microsoft defined functions and values, so portable programs which use it and have a Windows version, do not require any conditional logic to separate the native GDI support from the WMF/EMF/PMF support proviced by libUEMF. To accomplish this libUEMF does not implement GDI calls. Instead, for each WMR/EMR/PMR record type, and each object type incorporated into such a record, it provides corresponding *_set, *_print, and *_swap functions. For PMF and WMF there are also *_get functions, see below. For example, for the U_EMRBITBLT record there are corresponding functions: U_EMRBITBLT_set, U_EMRBITBLT_print, and U_EMRBITBLT_swap. A few additional functions are provided for assembling the EMF in memory, debugging, and converting the EMF file to/from Little Endian representation. (EMF files' internal data representation is always Little Endian.) This code has been tested on 32 bit Ubuntu (LE), 32 bit Mingw, 64 bit CentOS, and 64 bit Solaris (BE). libUEMF is released under the GPL 2 license, read the file 'COPYING' for more information Version 0.2.8, released May 13, 2020. To report bugs or provide feedback send email to David Mathog, mathog@caltech.edu. -------------------------------------------------------------------------------------------- Sources: EMF file Record structure information has been derived from Mingw, Wine, and libEMF header files, and from Microsoft's EMF Information pdf, release date March 28,2012, link from here: http://msdn2.microsoft.com/en-us/library/cc230514.aspx If the direct link fails the document may be found by searching the web for: "[MS-EMF]: Enhanced Metafile Format". WMF file Record structure information is from some of the same sources, as well as: http://msdn2.microsoft.com/en-us/library/250370.aspx If the direct link fails the document may be found by searching the web for: "[MS-WMF]: Windows Metafile Format" EMF+ file Record structure is from many helpful responses from Microsoft documentation support and from: http://msdn.microsoft.com/en-us/library/cc230724.aspx If the direct link fails the document may be found by searching the web for: "[MS-EMFPLUS]: Enhanced Metafile Format Plus Extensions" Files: README This file. CMakeLists.txt Build instructions for cmake on linux. Not tested on OS X or Windows. COPYING GPL V2 license file. DOXYFILE Doxygen configuration file, for generating documentation from the source files. testbuild.sh Small bash script to build all programs. Modify as needed for target platform. testit.sh Small bash script that generates all test files and compares them with referencess supplied. This script should be edited to match your test system before it is run! uemf.c Contains the *_set functions needed to construct an EMF file. Also contains auxilliary functions for debugging and constructing EMF files in memory. uemf.h Definitions and structures for EMF records and objects. Prototypes for *_set and construction functions. uemf_print.c Contains the *_print functions needed to print the contents of EMF records and objects. uemf_print.h Prototypes for *_print functions. uemf_endian.c Contains the *_swap functions needed to rearrange bytes between Big and Little Endian. U_emf_endian() is the only function here that user could should call. uemf_endian.h Prototype for U_emf_endian() and definitions for Endian type of the local machine. uemf_safe.c Contains the *_safe functions for EMF records, which verify that all offsets and counts stay within the declared size of a record. Also checks that core record sizes are sane. U_emf_record_safe() is the only _safe function which user code should call directly, and then ONLY after a previous call to U_emf_record_sizeok(), which is in the endian file. uemf_safe.h Prototype for U_emf_record_safe(). . upmf.c Contains the *_set and *_get functions needed to construct or read an EMF+ file. Also contains auxilliary functions for debugging and constructing EMF+ files in memory. upmf.h Definitions and structures for EMF+ records and objects. Prototypes for *_set, *_get and construction functions. 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. Also contains auxilliary functions for debugging and constructing WMF files in memory. uwmf.h Definitions and structures for WMF records and objects. Prototypes for *_set, *_get and construction functions. 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. U_wmf_endian() is the only function here that user could should call. 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. Run with no argument to see what the bit flag values are. 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 because it contains dotted lines. Use "testbed_emf 1" to generate a file without any dotted lines. ) 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. test_mapmodes_emf.c Program used for testing emf functions in libUEMF. Generates one test file in each MAPMODE, MM_TEXT through MM_ANISOTROPIC, optionally with offsets to the bounds and with particular Viewport origin. (Bounds offset + Viewport Origin sets the Window origin.) test_mapmodes_wmf.c Program used for testing wmf functions in libUEMF. Similar to test_mapmodes_emf. reademf.c Utility that that reads an EMF file and emits its contents in text form. Also processes EMF+ files. 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. Run it like: cutemf '2,10,12...13' src_file.emf dst_file.emf pmfdual2single.c Utility for reducing dual-mode EMF+ file to single mode. Removes all nonessential EMF records. Run it like: pmfdual2single dual_mode.emf single_mode.emf test_libuemf_ref.emf Example output from: testbed_emf 0 test_libuemf_p_ref.emf Example output from: testbed_pmf 0 test_libuemf_ref30.emf Example output from: testbed_emf 4 test_libuemf_ref.wmf Example output from: testbed_wmf 0 test_libuemf_ref_emf.txt Example output from: reademf test_libuemf_ref.emf test_libuemf_ref_wmf.txt Example output from: readwmf test_libuemf_ref.wmf test_mm__ref.emf Example output from: test_mapmodes_emf -vX 2000 -vY 1000 emf-inout.cpp,example emf-inout.h.example emf-print.cpp.example emf-print.h.example Example code from Inkscape, demonstrates how to integrate libUEMF with another program. -------------------------------------------------------------------------------------------- How to Build: In Linux/Unix like environments build and install a shared library and the test and tool programs: cd #modify the destination in CMakeLists.txt if /usr/local is not acceptable mkdir build cd build make make install cd .. ./testit.sh rm -rf build For simple development work use testbuild.sh to make debug versions without the shared library. (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] export CLIBS="-lm -L/opt/csw/lib -liconv" export CFLAGS="-DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g" (win32) [This uses _wfopen() instead of fopen(), with filename translation from UTF-8 to UTF-16LE. This will allow file opens to utilize unicode names. If WIN32 is omitted on Windows file names must be all ASCII. This works in mingw.] Then compile with: export CLIBS="-lm -liconv" export CFLAGS="-DWIN32 -std=c99 -pedantic -Wall -g" gcc $CFLAGS -o cutemf cutemf.c uemf.c uemf_endian.c uemf_utf.c $CLIBS gcc $CFLAGS -o pmfdual2single pmfdual2single.c uemf.c uemf_endian.c uemf_utf.c upmf.c $CLIBS gcc $CFLAGS -o reademf reademf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c $CLIBS gcc $CFLAGS -o readwmf readwmf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c uwmf.c uwmf_endian.c uwmf_print.c $CLIBS gcc $CFLAGS -o testbed_emf testbed_emf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c $CLIBS gcc $CFLAGS -o testbed_pmf testbed_pmf.c uemf.c uemf_endian.c uemf_safe.c uemf_utf.c upmf.c $CLIBS gcc $CFLAGS -o testbed_wmf testbed_wmf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c uwmf.c uwmf_endian.c $CLIBS gcc $CFLAGS -o test_mapmodes_emf test_mapmodes_emf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c $CLIBS 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 and then compile as above for linux. Dependencies: libiconv (if not built into your compiler) libpng (in the Inkscape examples) -------------------------------------------------------------------------------------------- Testing All modules must also compile without warning under the more restrictive: ls -1 *.c \ | extract -fmt 'gcc -Werror=format-security -Wall -Wformat -Wformat-security -W -Wno-pointer-sign -O2 -c -o deleteme.o [1,]' \ | execinput -------------------------------------------------------------------------------------------- Using libUEMF: 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 added must be the single instance of U_EMREOF. Then the code calls emf_finish(), emf_free(), and htable_free(). Conversion of byte order on Big Endian machines to Little Endian is carried out automatically in emf_finish(), if it is required. 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 illustrated in the code for the corresponding *_print function. While libUEMF implements _print and _swap functions for all supported EMR records, end user code would never call any of these directly. Instead it should either pass a single EMR record 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 trying to access objects in memory will result in access violations.) Things to be aware of in EMF files: 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 for when and where these subsequent operations will be applied. That is, there is no equivalent of "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 raster operation. The testbed program provided in this package generates a region which applies all 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 nothing like what Preview shows. 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, for instance. 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 should accept them for input. 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 will be able to reassemble them back into a single complex text string. 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, or other changes, then it will look approximately correct after font substitution. Things to be aware of in WMF files: 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, however, if an operation creates regions, this type of placeholder must still be created. In theory WMF supports mapmodes other than Anisotropic. However, since many programs do not handle these other modes it is strongly suggested that any WMF files generated use Anisotropic. For this reason there is no test_mapmodes_wmf program - windows XP preview did not show anything when WMF files in the other modes were produced. With no positive control there was no way to verify that they were valid. Things to be aware of in EMF+ files: 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+" is not an allowed variable or function name in C.) Dual mode EMF+ files contain both EMF and EMF+ records. HOWEVER, those generated by PowerPoint are defective in that they drop all text information from the drawing in the EMF+ representation. There is no simple way to line up the EMF and EMF+ records in their representations to determine which ones correspond to which drawing object. So it is generally not possible to see which elements are represented in both representations, or which are missing in one representation. The example file generated by this library has only EMF+ records plus the few EMF records needed to wrap them. Text in EMF+ is placed not from the baseline, as in EMF, but from the upper left corner of the Em square. Use the utility function U_PMR_drawstring() to draw text onto a baseline. Font substitutions result in badly placed text because even fonts that look similar on the screen may have different font metrics. Specifically, font substitutions look worse in EMF+ files than they do in EMF files. There is no way to embed fonts, or their font information in the EMF+ file. 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 program contains some metrics for common fonts which may be used with U_PMR_drawstring() to accurately place text. -------------------------------------------------------------------------------------------- History (Note, version numbers in files represent the libUEMF release where it was last modified, so not all files will show the same version numbers in each release.) 0.2.8 2020-05-13 Fixed warnings from newer compilers. Fixed truncation of one string in testbed outputs files, from 32 to 31 bytes (seen on CentOS 8 with gcc 8.3.1 but not CentOS 7 with gcc 4.8.5) 0.2.7 2019-10-10 Added CMakeLists.txt for linux. Added cmake instructions in README. Fixed typo in README build instructions. Error checking added to testit.sh. Increased max records in cutemf from 10K to 10M. 0.2.6 2019-03-21 Fixed typo in upmf.c discovered by David Binderman. 0.2.5 2017-01-03 Fixed a misplaced paren in uemf.h (thanks to Tavmjong Bah for noticing it) Added more U_SIZE_* definitions in uemf.h for "cores" of record types with final variable length arrays, such as U_SIZE_EMRNAMEDESCAPE Removed redundant U_SIZE_BITMAPINFOHEADER definition from uwmf.h 0.2.4 2016-01-26 Record EXTSELECTCLIPRGN is supposed to be valid when the RgnDataSize is 0 if the RegionMode is "COPY". Modified safe and print routines so that they would handle this situation. U_PMR_DrawDriverstring seen for the first time and it crashed reademf. Reason, there was a spurious "Tension" value in the structure, which offset values in the record. 0.2.3 2015-05-28 Fixed an assortment of warnings and a couple of bugs flagged by clang static analysis. 0.2.2 2015-04-28 Added lu_crc32 sums to record information in print statements. Affects only reademf and readwmf. The point of this exercise is to enable the detection of differences in binary fields which are not expanded by the print functions. This (re)uses code from Alexander Peslyak. lu_ in name because crc32 conflicts with other libraries, like png. Minor changes to some wmf function parameter types. Minor changes to upmf.c so that it compiles cleanly with clang. Restrict IS_MEM_UNSAFE 2nd parameter to be int or larger and test for negative values. Updated the examples from Inkscape. 0.2.1 2015-04-23 Bug in safety check on EMREXTCREATEFONTINDIRECTW because it had alternative "standard" record sizes. Changed warnings on unimplemented EMF record types encounterd in swap or safe from stdout to stderr. Added memory checking for WMF polyline and polygon records, for the variable part and some others. Note: U_WMRCREATEREGION_get does not check that the variable part stays within the record. Current implementation seems to be broken since it does not show up in XP preview. 0.2.0 2015-03-20 Added UEMF _safe functions to better handle corrupt records, where variable sizes fields might have been specified to read past the end of memory. These are records with offsets, arrays with counts, and bitmaps. Also any record which specifies a size smaller than the minimum for that record type. Added similar code for EMF+. These changed the API so the minor version number was bumped by 1. 0.1.18 2015-01-15 Pierre-Francois Carpentier sent some EMF examples which used U_EMR_EXTSELECTCLIPRGN, which had not previously been encountered and showed that the handling of regions was broken. Added tests for U_EMRFILLRGN, U_EMRFRAMERGN, U_EMRFRAMERGN, U_EMREXTSELECTCLIPRGN to testbed_emf. 0.1.18 2014-04-28 Fixed typo in testbed_wmf.c. "include,include" in one place should have been "exclude,exclude". 0.1.17 2014-04-25 Added text clipping tests to testbed_emf.c, testbed_wmf.c, and testbed_pmf.c. Added option to omit clipping tests in testbed's. 0.1.16 2014-04-14 Fixed bug in U_WMRRESTOREDC_set. Added clipping tests to testbed_wmf.c. 0.1.15 2014-04-04 Changed record flags for U_EMRSELECTCLIPPATH record, it consumes a path but does not ALTER (which forced a premature draw.) Added U_EMROFFSETCLIPRGN test to testbed_emf.c. Changed location on dist drawing where clipping appears. 0.1.14 2014-03-27 Fixed bug, in U_PMF_RECTN_set() in upmf.c. Never tested. Fixed a few potential bugs in upmf.c if a null pointer was passed for certain function arguments. (Previously unhandled cases.) Fixed bug, operations setting variables that are never read along those execution paths: upmf_print.c, uemf.c, uwmf.c, uemf_endian.cm upmf.c. Fixed potential (but very unlikely) memory leaks in upmf.c and uemf_utf.c. Added test of U_PMF_RECTN_set to testbed_pmf.c. Changed U_wmr_names() and U_wmr_escnames() to const char* (from char*). Changed method for suppressing unused parameter warnings. 0.1.13 2014-03-21 Fixed bug, cutemf was messing up the object count (pens, brushes, etc.). Added cutemf can now take ranges of lines. Added testbed_emf generates clipping records for rect and path (but not region). 0.1.12 2014-02-14 Documentation change, U_WMRCREATEPATTERNBRUSH is obsolete. Changed wmf_finish() so that it accurately reflects the largest number of objects used, previously it showed the number of appends, which was much larger. 0.1.11 2014-01-29 Fixed bug in uwmf.c (wrong minimum record size on U_WMRTEXTOUT) Fixed bug in uwmf.c (U_WMRCREATEPATTERNBRUSH not right) Fixed bug in uwmf_print.c (U_WMRTEXTOUT_print, x,y were reversed) Added error handling to uemf_utf.c for cases where src is a null pointer. Added a test of createpatternbrush to testlib_wmf 0.1.10 2014-01-14 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 been deleted before the struct itself. 0.1.9 2013-12-02 Added U_PMF_DASHEDLINEDATA_set3 (dot/dash pattern from bits in a uint32_t). Finally was able to make linear gradient gradientfill records work. Updated testbed_emf.c to include that. 0.1.8 2013-11-28 Fixed a bug in U_PMF_REGIONNODEPATH_print(), returned size was 4 too small. Changed formatting of U_PMF_REGIONNODECHILDNODES_print() output to improve readability of nested region structures in reademf. 0.1.7 2013-11-20 Added EMF+ support. Converted U_RGA and similar from defines to functions, because the method being used in the define (from C99) was not exactly compatible with C++ compilation. Fixed error in test_mapmodes_emf.c where truncation float to integer was used where round have been, resulting in an off by 1 error on some platforms. Eliminated PU_W* pointers. Cleaned up Doxygen comments. 0.1.6. 2013-04-18 Added tests which vary background mode, background color, and text color. Slight modification to testit.sh. Updated example files. 0.1.5. 2013-02-13 Added missing parameter for WMF RESTOREDC_set/get. Replaced all sizeof() in uwmf.c that referred to UWMF structures with their U_SIZE_* equivalents. Added DIB related WMF _get functions. (Which were missing). These are U_BITMAPCOREHEADER_get, U_BITMAPINFOHEADER_get, wget_dib_params Added const where appropriate to wmf _get functions. Added comprehensive cap,join,miter tests to testbeds. Fixed bug in gradient4_swap(). Fixed bug in emr_arc_points_common(), used vector where unit vectors were needed, sometimes flipped direction for arcs/chords. Fixed bug in U_WMFTEXTOUT_get(). Changed all dst->Dst and src->Src as call variables in WMF code. Denigrated htable_*() for emf, these become emf_htable_*(), to match naming convention used for wmf_table_*(). 0.1.4 2013-02-04 Added code to handle DIB formats that use clrUsed=0 to mean "maximum number of color entries", this showed up in several places, including uemf.c and uemf_print.c. Added some labels to test drawings, slightly rearranged image section, added PNG and JPG image tests and clrUsed=0 images. Modified uemf_endian.c to suppress some compiler warnings. Changed get_DIB_params to return the Compression enumeration. Fixed a typo in uwmf_print.c. 0.1.3 2013-01-29 Add modes to EMF test programs that changes worldtransform, so that the resulting test files will exercise rotation transforms. Added flags indication for testbed programs. Added test for ROUNDRECT records. Swapped argument orders for those _get/_set operations. 0.1.2 2013-01-25 Fixed bug revealed by newer gcc on Solaris, assignment of aligned 32 bit to unaligned 16 bit segfaulted. 0.1.1 2013-01-24 Fixed a few compiler warnings under g++, mostly having to do with signed unsigned comparisons. Eliminated an unused variable from wmf_finish and two stray lines from U_WMRHEADER_set. Cleaned up doxygen comments. 0.1.0 2013-01-09 Added WMF functions. Simplified print functions. Changed output format of reademf slightly, from U_EMRXXX to U_EMR_XXX - easier to read the new way. 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 safe need 4 bytes per glyph + 1 for UTF-8. 0.0.9 2012-09-26 Some "uninitialized variable warnings" for certain versions of gcc. These were, as far as I could tell, all spurious, but to quiet them the variables in question were all initialized to 0. Fixed header related print/swap functions - depending on what type of header there could be an access violation. Fixed U_Utf16leToUtf8, could leak memory if the conversion failed. Fixed sections which were not testing for all types of EMF headers. Added RGBA_to_RGBA() so that extractions of subsets of bitmaps (offset, different size) can be handled. Added cutemf. Utility to remove records from an EMF file. Added test_mapmodes. Program to generate test files in each MAPMODE. Added test_mm_(mode)_ref.emf files. These are reference for: test_mapmodes -vX 2000 -vY 1000 0.0.8 2012-09-10 Fixed bug in htable_insert, failed to celear newly added table slots. Fixed test for EMR_GRADIENTFILL triangle mode (rectangle still produces toxic EMF files.) Fixed bug in gradientfill_swap on Solaris. 0.0.7 2012-08-30 Added/fixed tests for hatched, DIB, and mono strokes. Corrected error in U_EMREXTCREATEPEN_set. 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 one bug in SET_CB_FROM_PXBMI macro (which was not triggered in testbed because all images were the same size). 0.0.4 2012-07-25 More tests in testbed.c. Found and fixed bugs in U_POLYPOLYLINE and U_POLYPOLYGON related code. 0.0.3 2012-07-24 Warnings related to printing size_t on 64 bit Linux. Correct fix is to use "zd", but gcc -std=c99 does not support that on Solaris 9, the only available big endian system. So use cast or the size_t to (int) and stick with %d format specifier. This should be OK as the sizes involved should not be all that large. Bug in core9 affecting U_EMRARC_swap(), and related, on Big Endian. 0.0.2 2012-07-12 first release