Графический файл WMF

Also Known As: WMF, Enhanced Metafile, EMF, APM

Type Metafile
Colors 24-bit
Compression None
Maximum Image Size NA
Multiple Images Per File Yes
Numerical Format Little-endian
Originator Microsoft Corporation
Platform Microsoft Windows
Supporting Applications Numerous Microsoft Windows-based graphics applications
Usage Storage of vector drawings and bitmaps.

Comments
A widely used format associated with Microsoft Windows,
although many applications on other platforms provide support.

Microsoft Windows Metafile Format (WMF) files are used to store both
vector and bitmap-format graphical data in memory or in disk files.
The vector data stored in WMF files is described as Microsoft Windows
Graphics Device Interface (GDI) commands. In the Window environment
these commands are interpreted and played back on an output device
using the Windows API PlayMetaFile() function. Bitmap data stored in
a WMF file may be stored in the form of a Microsoft Device Dependent
Bitmap (DDB), or Device Independent Bitmap (DIB).

Contents:
File Organization
File Details

In the Windows environment, metafiles are typically created and
played back in memory. If the metafile data grows too large to be
stored in memory, or needs to be saved before an application
terminates, the data can be written to disk in the form of a WMF or
EMF file and played back from disk. The maximum size of a Windows
metafile is four gigabytes.

WMF is the original 16-bit Windows metafile format that appeared with
Windows 2.0. EMF files are the 32-bit revision of the WMF format.
EMF files have extended functionality over WMF files, including a
color palette and full support for all 32-bit GDI commands. The Win32
API (Windows 95 and Windows NT) and 32-bit OLE support both WMF and
EMF files. The Win16 and Win32s APIs (Windows 3.x) and 16-bit OLE
only supports WMF files.

Although the Windows Metafile format is specific to Microsoft
Windows, many non-Windows-based applications support this format as a
method for interchanging graphical data with Windows applications.
Because of the widespread popularity of the Microsoft Windows GUI,
the Windows Metafile format has become a staple format for graphical
applications and is therefore supported on most platforms. For
example, Adobe’s Encapsulated PostScript (EPS) supports the use of an
included Windows Metafile when required to store vector-based data.

If you are using metafiles in the Windows or OS/2 operating systems
you will not write code to parse them directly, but instead call a
set of Windows API functions used to manipulate metafiles. Because
there is ample documentation from Microsoft and IBM on how to use
metafiles under Windows and OS/2, this article will look at the
structure and direct parsing of Microsoft metafiles without the
benefit of the Windows API.

If you have access to the Win16 Software Development Kit, then you
will find all of the data structures and data type definitions
associated with WMF files in the WINDOWS.H header file. For the Win32
SDK you will find WMF and EMF definitions in the WINUSER.H and
WINGDI.H header files. Both of these SDKs are available with all C
and C++ compilers that support Windows application development.

File Organization

A metafile is comprised of one or two information headers and an
array of variable-length records that store the GDI function call
information.

There are four flavors of Windows metafiles: standard, placeable,
clipboard, and enhanced. A standard metafile contains an 18-byte WMF
header followed by one or more records of GDI commands. A placeable
metafile contains a 22-byte header followed by the standard 18-byte
WMF header and GDI command records. Clipboard metafiles contains a
8-byte (Win16) or 16-byte (Win32) header that precedes the standard
metafile header. Enhanced metafiles contain only EMF records, with
the first record storing the header information. EMF files are not
compatible in design with the other types of WMF metafiles.

Windows Metafiles (Figure Microsoft Windows Metafile-1)
contain a header, followed by one or
more records of data. The header contains a description of the record
data stored in the metafile. Each record is a binary-encoded
Microsoft Windows Graphics Device Interface (GDI) function call. The
GDI is used by Windows to perform all output to a window, printer, or
other output device. When the metafile data is rendered (or played
back, in Microsoft terminology), the data from each record is used to
perform the appropriate GDI function call to render each object
stored in the file. The last record in the file contains information
indicating that the end of the record data has been reached.
Figure Microsoft Windows Metafile-1: Standard metafile format

Placeable metafiles (Figure Microsoft Windows Metafile-2)
are WMF files with an 18-byte header
prepended. This preheader contain information used to describe the
position of the metafile drawing on the printed page (something that
the original WMF file designers did not think of).
Figure Microsoft Windows Metafile-2: Placeable metafile format

Clipboard metafiles (Figure Microsoft Windows Metafile-3)
are similar to placeable metafiles in
that that also contain an extra header prepended to a WMF file. The
Clipboard preheader contains information used to describe the position
of the metafile on the Windows Clipboard and the mapping mode used to
playback the data.
Figure Microsoft Windows Metafile-3: Clipboard metafile format

Enhanced metafiles (Figure Microsoft Windows Metafile-4)
have the same basic format of WMF
files: a header followed by one or more records of drawing objects
stored as GDI commands. Unlike WMF, the header is also stored in a
record which appears as the first record in each EMF file. The EMF
header now contains additional information, including the position
and mapping information stored in the placeable and clipboard
metafile preheaders. EMF also adds the features of a file description
string and a programmable color palette to the metafile format.
Figure Microsoft Windows Metafile-4: Enhanced metafile format

File Details

The standard Windows metafile header is 18 bytes in length and is
structured as follows:

typedef struct _WindowsMetaHeader
{
  WORD  FileType;       /* Type of metafile (0=memory, 1=disk) */
  WORD  HeaderSize;     /* Size of header in WORDS (always 9) */
  WORD  Version;        /* Version of Microsoft Windows used */
  DWORD FileSize;       /* Total size of the metafile in WORDs */
  WORD  NumOfObjects;   /* Number of objects in the file */
  DWORD MaxRecordSize;  /* The size of largest record in WORDs */
  WORD  NumOfParams;    /* Not Used (always 0) */
} WMFHEAD;

FileType contains a value which indicates the location of the metafile
data. A value of 0 indicates that the metafile is stored in memory,
while a 1 indicates that it is stored on disk.

HeaderSize contains the size of the metafile header in 16-bit WORDs.
This value is always 9.

Version stores the version number of Microsoft Windows that created
the metafile. This value is always read in hexadecimal format. For
example, in a metafile created by Windows 3.0 and 3.1, this item
would have the value 0x0300.

FileSize specifies the total size of the metafile in 16-bit WORDs.

NumOfObjects specifies the number of objects that are in the metafile.

MaxRecordSize specifies the size of the largest record in the metafile
in WORDs.

NumOfParams is not used and is set to a value of 0.

Aldus Placeable Metafiles

Placeable Metafiles (file extension .APM) were created by Aldus
Corporation as a non-standard way of specifying how a metafile is
mapped and scaled on an output device. Placeable metafiles are quite
wide-spread, but not directly supported by the Windows API. To
playback a placeable metafile using the Windows API, you will first
need to strip the placeable metafile header from the file. This is
typically performed by copying the metafile to a temporary file
starting at file offset 0x16. The contents of the temporary file may
then be used as input to the Windows GetMetaFile(), PlayMetaFile(),
CopyMetaFile(), etc. GDI functions. Placeable Metafiles are limited
to 64K in length.

Each placeable metafile begins with a 22-byte header followed by a
standard metafile:

typedef struct _PlaceableMetaHeader
{
  DWORD Key;           /* Magic number (always 9AC6CDD7h) */
  WORD  Handle;        /* Metafile HANDLE number (always 0) */
  SHORT Left;          /* Left coordinate in metafile units */
  SHORT Top;           /* Top coordinate in metafile units */
  SHORT Right;         /* Right coordinate in metafile units */
  SHORT Bottom;        /* Bottom coordinate in metafile units */
  WORD  Inch;          /* Number of metafile units per inch */
  DWORD Reserved;      /* Reserved (always 0) */
  WORD  Checksum;      /* Checksum value for previous 10 WORDs */
} PLACEABLEMETAHEADER;

Key contains a special identification value that indicates the
presence of a placeable metafile header and is always 9AC6CDD7h.

Handle is used to stored the handle of the metafile in memory. When
written to disk, this field is not used and will always contains the
value 0.

Left, Top, Right, and Bottom contain the coordinates of the
upper-left and lower-right corners of the image on the output device.
These are measured in twips[1]. These four fields also
correspond to the RECT structure used in Microsoft Windows and
defined in the file WINDOWS.H.

[1] A twip (meaning «twentieth of a point») is the logical unit of
measurement used in Windows Metafiles. A twip is equal to 1/1440 of
an inch. Thus 720 twips equal 1/2 inch, while 32,768 twips is 22.75
inches.

Inch contains the number of twips per inch used to represent the
image. Normally, there are 1440 twips per inch; however, this number
may be changed to scale the image. A value of 720 indicates that the
image is double its normal size, or scaled to a factor of 2:1. A
value of 360 indicates a scale of 4:1, while a value of 2880
indicates that the image is scaled down in size by a factor of two. A
value of 1440 indicates a 1:1 scale ratio.

Reserved is not used and is always set to 0.

Checksum contains a checksum value for the previous 10 WORDs in the
header. This value can be in an attempt to detect if the metafile has
become corrupted. The checksum is calculated by XORing each WORD value
to an initial value of 0:

PLACEABLEMETAHEADER pmh;
pmh.Checksum = 0;
pmh.Checksum ^= (pmh.Key & 0x0000FFFFUL);
pmh.Checksum ^= ((pmh.Key & 0xFFFF0000UL) >> 16);
pmh.Checksum ^= pmh.Handle;
pmh.Checksum ^= pmh.Left;
pmh.Checksum ^= pmh.Top;
pmh.Checksum ^= pmh.Right;
pmh.Checksum ^= pmh.Bottom;
pmh.Checksum ^= pmh.Inch;
pmh.Checksum ^= (pmh.Reserved & 0x0000FFFFUL);
pmh.Checksum ^= ((pmh.Reserved & 0xFFFF0000UL) >> 16);

An alternative way to step through the header structure one WORD at a
time is to use a pointer as shown below:

PLACEABLEMETAHEADER *pmh;
WORD *ptr;
pmh->Checksum = 0;
for (ptr = (WORD *) pmh; ptr < (WORD *)pmh->Checksum; ptr++)
    pmh->Checksum ^= *ptr;

Clipboard Metafile

Clipboard metafiles are stored in Microsoft Clipboard Viewer files
(file extension .CLP) and Microsoft Windows Write files (file
extension .WRI). Clipboard metafiles are also based on the standard
metafile format, but are preceded by an additional 8- or 16-byte
header that allows the position of the metafile on the Clipboard
viewer. If the Clipboard metafile was created using a 16-bit version
of Windows (Windows and Windows for Workgroups) this header will
contain 2-byte fields arranged in the following structure:

typedef struct _Clipboard16MetaHeader
{
  SHORT MappingMode; /* Units used to playback metafile */
  SHORT Width;       /* Width of the metafile */
  SHORT Height;      /* Height of the metafile */
  WORD  Handle;      /* Handle to the metafile in memory */
} CLIPBOARD16METAHEADER;

MappingMode specifies the type of Windows coordinate mapping units
used to store and playback the metafile data. This field will contain
one of the following values:

Value
Mapping Mode
One Unit Maps To

1
Text
One pixel

2
Low Metric
0.1 millimeter

3
High Metric
0.01 millimeter

4
Low English
0.01 inch

5
High English
0.001 inch

6
Twips
1/1440th of an inch

7
Isotropic
Application specific (aspect ratio preserved)

8
Anisotropic
Application specific (aspect ratio not preserved)

Width and Height are the size of the metafile in the units specified
in the MappingMode field.

Handle is used to stored the handle of the metafile in memory. When
written to disk, this field is not used and will always contains the
value 0.

If the clipboard metafile was created under a 32-bit Windows
environment (Windows NT and Windows 95) this header will contain the
same fields as the Win16 WMF header, but the fields are 32 bytes in
length:

typedef struct _Clipboard32MetaHeader
{
  LONG  MappingMode; /* Units used to playback metafile */
  LONG  Width;       /* Width of the metafile */
  LONG  Height;      /* Height of the metafile */
  DWORD Handle;      /* Handle to the metafile in memory */
} CLIPBOARD32METAHEADER;

Enhanced Metafiles

Enhanced metafile files are a «new and improved» 32-bit revision of
the standard metafile. Only the 32-bit Windows API (Win32) supports
EMF files and the 16-bit Windows APIs (Win16 and Win32s) do not. It is also
recommended that WMF files not be used by applications running the
Window 32-bit environments (Windows 95 and Windows NT). Enhanced
metafiles are typically saved to disk using the file extension
«.EMF».

The string data found in EMF files uses the Unicode character set.
Each Unicode character is 2-bytes in size. The first 256 (of the over
36000) characters of the Unicode characters set are also the 256
characters of the ANSI character set used by Windows. The low byte of
each Unicode character will contain the ANSI character value and the
high byte will be zero. You will recognize Unicode strings in data
dumps when you see a byte pattern such as » S u m m a r y I n f o»
rather than the more common ANSI or ASCII pattern of «SummaryInfo».

EMF files have a header that is 80 bytes in length and contains the
same features as found in placeable and Clipboard metafiles. Although
the header is considered to be just another EMF record, it must
appear as the first record in every EMF file.

typedef struct _EnhancedMetaHeader
{
    DWORD RecordType;       /* Record type */
    DWORD RecordSize;       /* Size of the record in bytes */
    LONG  BoundsLeft;       /* Left inclusive bounds */
    LONG  BoundsRight;      /* Right inclusive bounds */
    LONG  BoundsTop;        /* Top inclusive bounds */
    LONG  BoundsBottom;     /* Bottom inclusive bounds */
    LONG  FrameLeft;        /* Left side of inclusive picture frame */
    LONG  FrameRight;       /* Right side of inclusive picture frame */
    LONG  FrameTop;         /* Top side of inclusive picture frame */
    LONG  FrameBottom;      /* Bottom side of inclusive picture frame */
    DWORD Signature;        /* Signature ID (always 0x464D4520) */
    DWORD Version;          /* Version of the metafile */
    DWORD Size;             /* Size of the metafile in bytes */
    DWORD NumOfRecords;     /* Number of records in the metafile */
    WORD  NumOfHandles;     /* Number of handles in the handle table */
    WORD  Reserved;         /* Not used (always 0) */
    DWORD SizeOfDescrip;    /* Size of description string in WORDs */
    DWORD OffsOfDescrip;    /* Offset of description string in metafile */
    DWORD NumPalEntries;    /* Number of color palette entries */
    LONG  WidthDevPixels;   /* Width of reference device in pixels */
    LONG  HeightDevPixels;  /* Height of reference device in pixels */
    LONG  WidthDevMM;       /* Width of reference device in millimeters */
    LONG  HeightDevMM;      /* Height of reference device in millimeters */
} ENHANCEDMETAHEADER;

RecordType identifies the type of EMF record. For the EMF header
record this value is always 00000001h.

RecordSize is the size of the header in bytes.

BoundsLeft, BoundsRight, BoundsTop, and BoundsBottom specify the size
of the metafile drawing using X, Y, width, and length coordinate
system. BoundsTop and BoundsBottom must have greater values than
BoundsLeft and BoundsRight.

FrameLeft, FrameRight, FrameTop, and FrameBottom specify the size of
the frame or border that encloses the metafile using X, Y, width, and
length coordinate system. FrameTop and FrameBottom must have greater
values than FrameLeft and FrameRight.

Signature is a file identification value and is always set to
the value of 0x464D4520.

Version is the version number of the EMF file format. The current
version is 1.0 and is stored as the value 0x00000100.

Size is the size of the entire metafile in bytes.

NumOfRecords is the total number of records in the metafile,
including the header record.

NumOfHandles is the number of handles currently stored in the memory
handle table. This value is always 0 for metafile data stored to
disk.

Reserved is not used and is always zero.

SizeOfDescrip is the number of 16-bit Unicode characters contained in
the description string, including all NULL characters. If this value
is 0 then no description string is present in the file.

OffsOfDescrip is the location of the description string calculated as
the number of bytes from the beginning of the file. If this value is 0
then no description string is present in the file.

NumPalEntries indicates the number of entries in the color palette.
The color palette, if present, will be located in the End-Of-File
records. If this value is 0 then no color palette is present.

WidthDevPixels and HeightDevPixels are the width and height of the
display device in pixels.

WidthDevMM and HeightDevMM are the width and height of the
display device in millimeters.

EMF Description String

A Unicode description string may be stored in an EMF file. If the
SizeOfDescrip and OffsOfDescrip header fields are not zero, then a
description string is present in the file. It will be located
OffsOfDescrip bytes from the beginning of the file and will contain
SizeOfDescrip Unicode characters.

Although not limited in practical size (unless you want a description
longer than two billion characters), the description string is
expected to have a specific format. The format is the name of the
application that created the picture, a NULL, the name or description
of the picture, and finally two NULLs. A typical EMF creator/title
Unicode description string may therefore appear as such:

"Pain Paint 1.5Eating at Polly's"

Adhering to this «double NULL-terminated format» guarantees that
standard information may be obtained form an EMF file and also allows
the description string to be easily read using Windows GDI function calls.

Standard Metafile Records

Following the standard header in all WMF metafiles is a series of
data records. This record is defined by the METARECORD data type
definition in WINDOWS.H and has the following format:

typedef struct _StandardMetaRecord
{
    DWORD Size;          /* Total size of the record in WORDs */
    WORD  Function;      /* Function number (defined in WINDOWS.H) */
    WORD  Parameters[];  /* Parameter values passed to function */
} WMFRECORD;

Size is the total size of the records in 16-bit WORDs, including the
Size field itself. The minimum possible size for a record is 3.

Function is the GDI number of the function called to playback this
record. The low-byte of this value identifies the specific GDI
function to call. The high-byte is the number of WORDs passed to this
function, and is also the number of elements in the Parameters array.
For example, a value of 0x0213 indicates the LineTo() function (0x13)
and that this function is passed two WORD values.

Parameters is an array of the parameters used by the GDI function
specified by this record. The parameters are stored in the reverse
order in which they are passed to the function. For example, the two
parameter values of the LineTo record are passed to the LineTo()
function in the order of X and Y, but store in the record as Y and X.

Although each record parameter is stored as a WORD, the exact data
type of the parameter is determined by the function it is passed to.
Parameter values that change, such as device context handles, are
never stored in metafile records.

The last record in every metafile always has a function number of
0000h, a Size of 0003h, and no Parameters array. This record is used
to indicate the end of the record data in the metafile. The use of
this terminator record is missing from the original WMF description
found in the Windows SDK and is now documented in article Q99334 of
the Microsoft Knowledge Base.

When a Windows Metafile format file is played back in the Windows
environment, each record is read and the function call it contains is
executed in the sequence in which it is stored in the file. Windows
creates a table of object handles used by the functions called in the
metafile records. The maximum size of this object handle table is
indicated by the value of the NumOfObjects field in the header.
Windows inserts new objects into the table using the SelectObject()
API call. The object handle table is only created and used during the
access of the metafile in memory and is never stored in a WMF file.

There are several important considerations that must be observed when
reading metafile record data.

Not all of the records in a Windows Metafile have the above format,
although most do. The metafile records that do follow this basic
record format are the following:

Record Name
Function Number

AbortDoc
0x0052

Arc
0x0817

Chord
0x0830

DeleteObject
0x01f0

Ellipse
0x0418

EndDoc
0x005E

EndPage
0x0050

ExcludeClipRect
0x0415

ExtFloodFill
0x0548

FillRegion
0x0228

FloodFill
0x0419

FrameRegion
0x0429

IntersectClipRect
0x0416

InvertRegion
0x012A

LineTo
0x0213

MoveTo
0x0214

OffsetClipRgn
0x0220

OffsetViewportOrg
0x0211

OffsetWindowOrg
0x020F

PaintRegion
0x012B

PatBlt
0x061D

Pie
0x081A

RealizePalette
0x0035

Rectangle
0x041B

ResetDc
0x014C

ResizePalette
0x0139

RestoreDC
0x0127

RoundRect
0x061C

SaveDC
0x001E

ScaleViewportExt
0x0412

ScaleWindowExt
0x0410

SelectClipRegion
0x012C

SelectObject
0x012D

SelectPalette
0x0234

SetTextAlign
0x012E

SetBkColor
0x0201

SetBkMode
0x0102

SetDibToDev
0x0d33

SetMapMode
0x0103

SetMapperFlags
0x0231

SetPalEntries
0x0037

SetPixel
0x041F

SetPolyFillMode
0x0106

SetRelabs
0x0105

SetROP2
0x0104

SetStretchBltMode
0x0107

SetTextAlign
0x012E

SetTextCharExtra
0x0108

SetTextColor
0x0209

SetTextJustification
0x020A

SetViewportExt
0x020E

SetViewportOrg
0x020D

SetWindowExt
0x020C

SetWindowOrg
0x020B

StartDoc
0x014D

StartPage
0x004F

For example, the LineTo record stores information that is passed to
the LineTo() GDI function. The LineTo() function draws a line from
the current point to the coordinates specified in the record data.
Assuming the line is to be drawn to location 100,50, the data in the
LineTo record would appear as follows:

Size           5        /* Five WORDs in the file */
Function       0x0213   /* LineTo function number */
Parameters[0]  50       /* Y Coordinate */
Parameters[1]  100      /* X Coordinate */

This data would be read from the metafile and passed to the LineTo()
GDI functions as such (the hDC handle is not stored in the metafile):

LineTo(hDC, 100, 5);

Several record formats deviate from the basic record format by
containing a data structure, rather than a data array, in the
Parameters field. These records are:

Record Name
Function Number
</tr>

AnimatePalette
0x0436

BitBlt
0x0922

CreateBitmap
0x06FE

CreateBitmapIndirect
0x02FD

CreateBrush
0x00F8

CreateBrushIndirect
0x02FC

CreateFontIndirect
0x02FB

CreatePalette
0x00F7

CreatePatternBrush
0x01F9

CreatePenIndirect
0x02FA

CreateRegion
0x06FF

DeleteObject
0x01F0

DibBitblt
0x0940

DibCreatePatternBrush
0x0142

DibStretchBlt
0x0B41

DrawText
0x062F

Escape
0x0626

ExtTextOut
0x0A32

Polygon
0x0324

PolyPolygon
0x0538

Polyline
0x0325

TextOut
0x0521

StretchBlt
0x0B23

StretchDIBits
0x0F43

For example, the BitBlt record is used to store bitmap data in a
metafile. The BitBlt record stores a Device Dependent Bitmap (DDB) in
its Parameters field. A DDB is a simple header followed by
uncompressed bitmap data. The entire BitBlt record in a Windows 2.x
metafile will have the following format:

typedef struct _BitBltRecord
{
    DWORD     Size;             /* Total size of the record in WORDs */
    WORD      Function;         /* Function number (0x0922) */
    WORD      RasterOp;         /* High-order word for the raster operation */
    WORD      YSrcOrigin;       /* Y-coordinate of the source origin */
    WORD      XSrcOrigin;       /* X-coordinate of the source origin */
    WORD      YDest;            /* Destination width */
    WORD      XDest;            /* Destination height */
    WORD      YDestOrigin;      /* Y-coordinate of the destination origin */
    WORD      XDestOrigin;      /* X-coordinate of the destination origin */
    /* DDB Bitmap */
    DWORD     Width;            /* Width of bitmap in pixels */
    DWORD     Height;           /* Height of bitmap in scan lines */
    DWORD     BytesPerLine;     /* Number of bytes in each scan line */
    WORD      NumColorPlanes;   /* Number of color planes in the bitmap */
    WORD      BitsPerPixel;     /* Number of bits in each pixel */
    RGBTRIPLE Bitmap[];         /* Bitmap data */
} BITBLTRECORD;

The bitmap data itself is stored as an array of RGBTRIPLE structures:

typedef struct _RGBTriple
{
    BYTE Red;
    BYTE Green;
    BYTE Blue;
} RGBTRIPLE;

Note that DDB bitmap found in Windows 2.x WMF BitBlt records is not
compatible with Windows 3.0 and later. Windows 3.0 created the
DibBitBlt record to store a Device Independent Bitmap (DIB) rather
than a DDB. A DibBitBlt record has the following format:

typedef struct _DibBitBltRecord
{
    DWORD   Size;             /* Total size of the record in WORDs */
    WORD    Function;         /* Function number (0x0940) */
    WORD    RasterOp;         /* High-order word for the raster operation */
    WORD    YSrcOrigin;       /* Y-coordinate of the source origin */
    WORD    XSrcOrigin;       /* X-coordinate of the source origin */
    WORD    YDest;            /* Destination width */
    WORD    XDest;            /* Destination height */
    WORD    YDestOrigin;      /* Y-coordinate of the destination origin */
    WORD    XDestOrigin;      /* X-coordinate of the destination origin */
    /* DIB Bitmap */
    DWORD   Width;            /* Width of bitmap in pixels */
    DWORD   Height;           /* Height of bitmap in scan lines */
    DWORD   BytesPerLine;     /* Number of bytes in each scan line */
    WORD    NumColorPlanes;   /* Number of color planes in the bitmap */
    WORD    BitsPerPixel;     /* Number of bits in each pixel */
    DWORD   Compression;      /* Compression type */
    DWORD   SizeImage;        /* Size of bitmap in bytes */
    LONG    XPelsPerMeter;    /* Width of image in pixels per meter */
    LONG    YPelsPerMeter;    /* Height of image in pixels per meter */
    DWORD   ClrUsed;          /* Number of colors used */
    DWORD   ClrImportant;     /* Number of important colors */
    RGBQUAD Bitmap[];         /* Bitmap data */
} DIBBITBLTRECORD;

The bitmap data itself is stored as an array of RGBQUAD structures:

typedef struct _RGBQuad
{
    BYTE Red;
    BYTE Green;
    BYTE Blue;
    BYTE Reserved;
} RGBQUAD;

One other function-specific metafile record that deserves attention
is Escape. The Windows 3.x API supports 64 different printer escape
sequences that may be embedded into a WMF metafile. The actual
sequences available will vary depending upon the printer driver(s)
currently installed it the Windows environment. The use of printer
escapes is discouraged, as including one or more Escape records in
the WMF file makes the metafile data device-dependent.

One of the most common Escape records is MFCOMMENT. The WMF format
does not directly support the insertion of human-readable text. The
MFCOMMENT printer sequence is therefore used insert a string (or
other private data) up to 32K in size into a metafile. There may be
multiple Escape records stored in a metafile.

Consult the Microsoft Windows Programmer’s Reference, Volume 2, for
the internal structure of each function-specific metafile records.

Several GDI function calls were added or had their parameters changed
with the release of Microsoft Windows 3.0. GDI function calls in this
category include:

AnimatePalette
BitBlt
CreatePalette
CreatePatternBrush
DeleteObject
DibBitBlt
DibCreatePatternBrush
DibStretchBlt
RealizePalette
ResizePalette
StretchBlt

Note that not all GDI function calls can appear in a metafile. The
only calls that are valid are those that take a handle to a device
context as their first parameter. A complete list of all of the GDI
function calls is documented in Microsoft Windows Programmer’s
Reference, Volume 2. They are also found in the WINDOWS.H header
file. These GDI function calls are the directives that begin with the
characters META. There are more than 70 different GDI function calls
defined for Windows 3.x.

Enhanced Metafile Records

Enhanced metafiles also have an enhanced metafile record structure.
When compared to standard metafile records you will see that all
three fields are now 32-bit DWORDs and the positions of the Size and
Function fields are exchanged:

typedef struct _EnhancedMetaRecord
{
    DWORD Function;      /* Function number (defined in WINGDI.H) */
    DWORD Size;          /* Total size of the record in WORDs */
    DWORD Parameters[];   /* Parameter values passed to GDI function */
} EMFRECORD;

Function is the GDI number of the function called to playback this
record. In the Win32 SDK these values identified by the EMR_*
definitions in the WINDOWS.H header file.

Size is the total size of the records in BYTEs, including the Size
and Function fields. The minimum possible size for a record is 8.

Parameters is an array of the parameters used by the GDI function
specified by this record. The parameters are stored in the reverse
order in which they are passed to the function. For example, the two
parameter values of the LineTo record are passed to the LineTo()
function in the order of X and Y, but stored in the record as Y and X.

An EMF file is composed entirely of EMF records. Of the 97 record
types presently defined for EMF files, at least two records must be
present in every file. These are the header record (record type 1)
and the End Of File record (record type 14).

Here are the function identifiers for all 97 EMF records. If you need
to add EMF file capability to your software, then you must obtain a
copy of the Microsoft documents that describe these Win32 API
functions.

Record
Value
Record
Value

EMR_ABORTPATH
68
EMR_POLYLINE
4

EMR_ANGLEARC
41
EMR_POLYLINE16
87

EMR_ARC
45
EMR_POLYLINETO
6

EMR_ARCTO
55
EMR_POLYLINETO16
89

EMR_BEGINPATH
59
EMR_POLYPOLYGON
8

EMR_BITBLT
76
EMR_POLYPOLYGON16
91

EMR_CHORD
46
EMR_POLYPOLYLINE
7

EMR_CLOSEFIGURE
61
EMR_POLYPOLYLINE16
90

EMR_CREATEBRUSHINDIRECT
39
EMR_POLYTEXTOUTA
96

EMR_CREATEDIBPATTERNBRUSHPT
94
EMR_POLYTEXTOUTW
97

EMR_CREATEMONOBRUSH
93
EMR_REALIZEPALETTE
52

EMR_CREATEPALETTE
49
EMR_RECTANGLE
43

EMR_CREATEPEN
38
EMR_RESIZEPALETTE
51

EMR_DELETEOBJECT
40
EMR_RESTOREDC
34

EMR_ELLIPSE
42
EMR_ROUNDRECT
44

EMR_ENDPATH
60
EMR_SAVEDC
33

EMR_EOF
14
EMR_SCALEVIEWPORTEXTEX
31

EMR_EXCLUDECLIPRECT
29
EMR_SCALEWINDOWEXTEX
32

EMR_EXTCREATEFONTINDIRECTW
82
EMR_SELECTCLIPPATH
67

EMR_EXTCREATEPEN
95
EMR_SELECTOBJECT
37

EMR_EXTFLOODFILL
53
EMR_SELECTPALETTE
48

EMR_EXTSELECTCLIPRGN
75
EMR_SETARCDIRECTION
57

EMR_EXTTEXTOUTA
83
EMR_SETBKCOLOR
25

EMR_EXTTEXTOUTW
84
EMR_SETBKMODE
18

EMR_FILLPATH
62
EMR_SETBRUSHORGEX
13

EMR_FILLRGN
71
EMR_SETCOLORADJUSTMENT
23

EMR_FLATTENPATH
65
EMR_SETDIBITSTODEVICE
80

EMR_FRAMERGN
72
EMR_SETMAPMODE
17

EMR_GDICOMMENT
70
EMR_SETMAPPERFLAGS
16

EMR_HEADER
1
EMR_SETMETARGN
28

EMR_INTERSECTCLIPRECT
30
EMR_SETMITERLIMIT
58

EMR_INVERTRGN
73
EMR_SETPALETTEENTRIES
50

EMR_LINETO
54
EMR_SETPIXELV
15

EMR_MASKBLT
78
EMR_SETPOLYFILLMODE
19

EMR_MODIFYWORLDTRANSFORM
36
EMR_SETROP2
20

EMR_MOVETOEX
27
EMR_SETSTRETCHBLTMODE
21

EMR_OFFSETCLIPRGN
26
EMR_SETTEXTALIGN
22

EMR_PAINTRGN
74
EMR_SETTEXTCOLOR
24

EMR_PIE
47
EMR_SETVIEWPORTEXTEX
11

EMR_PLGBLT
79
EMR_SETVIEWPORTORGEX
12

EMR_POLYBEZIER
2
EMR_SETWINDOWEXTEX
9

EMR_POLYBEZIER16
85
EMR_SETWINDOWORGEX
10

EMR_POLYBEZIERTO
5
EMR_SETWORLDTRANSFORM
35

EMR_POLYBEZIERTO16
88
EMR_STRETCHBLT
77

EMR_POLYDRAW
56
EMR_STRETCHDIBITS
81

EMR_POLYDRAW16
92
EMR_STROKEANDFILLPATH
63

EMR_POLYGON
3
EMR_STROKEPATH
64

EMR_POLYGON16
86
EMR_WIDENPATH
66

Color Palette

EMF files may also contain an optional color palette used to render
the EMF drawing. By comparison, WMF files do not store a color
palette and instead use the default Windows foreground palette.

The NumPalEntries field in the EMF header will indicate the number of
entries in the palette and will have a value of zero if no palette is
present. The color palette, if present, will be stored in the End Of
File record. The EOF record is always the last record stores in an
EMF file and has the following format:

typedef struct _EndOfRecord
{
    DWORD  Function;        /* End Of Record ID (14) */
    DWORD  Size;            /* Total size of the record in WORDs */
    DWORD  NumPalEntries;   /* Number of color palette entries */
    DWORD  OffPalEntries;   /* Offset of color palette entries */
    PALENT Palette[];       /* The color palette data */
    DWORD  OffToEOF;        /* Offset to beginning of this record */
} ENDOFRECORD;

Function is the function number of this record. For EOF records this
value is always 14.

Size is the total size of this record in bytes. For an EOF record that
does not contain a color palette this value will be 20.

NumPalEntries is the number of color palette entries. This value will
correspond the value of the NumPalEntries field in the EMF header. A
value of zero indicates no color palette is present.

OffPalEntries indicates the position of the first color palette entry.
The offset is measured from the beginning of the EOF record.

Palette is the color palette data stored as an array of PALENT
structures. This field is not present in the EOF record if a color
palette is not present.

OffToEOF indicates the byte offset back to the beginning of the EOF
record. This field is located after the color palette data (if any)
and always contains the same value as the Size field.

Each entry in the color palette is four bytes in size and has the
following format:

typedef struct _PaletteEntry
{
    BYTE Red;       /* Red component value */
    BYTE Green;     /* Green component value */
    BYTE Blue;      /* Blue component value */
    BYTE Flags;     /* Flag values */
} PALENT;

Red, Green, and Blue contain the color component values for the
24-bit color palette entry.

Flags contains a bitfield of flags use to indicate the usage of the
palette entry. Values for this field are:

0x01
Palette index used for animation

0x02
Palette index is explicit to device

0x04
Do not match color to system palette

GDI Comment

One very nice feature of the EMF format is the ability to embed
private data within an EMF file. Unlike the WMF printer escape
comment, the GDI comment may contain any type of data and is
completely device independent.

The GDICOMMENT record has the following format:

typedef struct _GdiCommentRecord
{
    DWORD   Function;      /* GDI Comment ID (70) */
    DWORD   Size;          /* Total size of the record in WORDs */
    DWORD   SizeOfData;    /* Size of comment data in bytes */
    BYTE    Data[];        /* Comment data */
} GDICOMMENTRECORD;

Function is the function number of this record. For GDI Comment
records this value is always 70.

Size is the total size of this record in bytes. For an GDI comment
record that does not contain any data this value will be 12.

SizeOfData is the number of bytes in the Data field.

Data is the GDI Comment data. The data may be strings, Encapsulated
PostScipt, or an enhanced metafile.

Each GDI Comment record may store one or more types of comment data.
The Metafile comment stores a single metafile. The BeginGroup and
EndGroup comments store a collection of enhanced metafile objects and
description strings. And the Multiformats comment stores multiple
enhanced metafiles and Encapsulated PostScript data.

GDI Comments should never contain any application-specific data, as
this would make the enhanced metafile device dependent. Comment data
should also not store the offset position of any other data in the
file. It is possible that records will be added or removed to the
metafile causing the offset values to then be invalid.

The Metafile comment is a header followed by an enhanced metafile.
The header has the following format:

typedef struct _GdiCommentMetafile
{
    DWORD Identifier;       /* Comment ID (0x43494447) */
    DWORD Comment;          /* Metafile ID (0x80000001) */
    DWORD Version;          /* Version of the metafile */
    DWORD Checksum;         /* Checksum value of the metafile */
    DWORD Flags;            /* Flags (always 0) */
    DWORD Size;             /* Size of the metafile data in bytes */
} GDICOMMENTMETAFILE;

Identifier contains a value of 0x43494447 identifying this
structure as a GDI public comment.

Comment contains a value of 0x80000001 identifying this
structure as a metafile comment.

Version is the version of the metafile. This value is typically
0x00000001.

Checksum is the checksum value of the metafile data.

Flags is not presently used and is always 0.

Size is the number of bytes in the metafile data.

The BeginGroup and EndGroup comments contain one or more EMF drawing
objects. The BeginGroup comment starts the list, followed by all
EMF records, and is completed by the EndGroup comment. Such groups
may be nested. The format of the BeginGroup header is as follows:

typedef struct _GdiCommentBeginGroup
{
    DWORD Identifier;       /* Comment ID (0x43494447) */
    DWORD Comment;          /* BeginGroup ID (0x00000002) */
    LONG  BoundsLeft;       /* Left side of bounding rectangle */
    LONG  BoundsRight;      /* Right side of bounding rectangle */
    LONG  BoundsTop;        /* Top side of bounding rectangle */
    LONG  BoundsBottom;     /* Bottom side of bounding rectangle */
    DWORD SizeOfDescrip;    /* Number of characters in the description */
} GDICOMMENTBEGINGROUP;

Identifier contains a value of 0x43494447 identifying this structure
as a GDI public comment.

Comment contains a value of 0x00000002 identifying this structure as
a BeginGroup comment.

BoundsLeft, BoundsRight, BoundsTop, and BoundsBottom define the
bounding rectangle of the picture.

SizeOfDescrip is the number of Unicode characters in the description
string. This string, if present, will always immediately follow this
header. If this value is zero then there is no description string
present.

The EndGroup comment contains only a header and no data. The header
has the following format:

typedef struct _GdiCommentEndGroup
{
    DWORD Identifier;       /* Comment ID (0x43494447) */
    DWORD Comment;          /* EndGroup ID (0x00000003) */
} GDICOMMENTENDGROUP;

Identifier contains a value of 0x43494447 identifying this structure
as a GDI public comment.

Comment contains a value of 0x00000003 identifying this structure as
a EndGroup comment.

The Multiformats comment is used to store metafile and Encapsulated
PostScript (EPS) picture data. This comment begins with a header
followed by one or more pictures. The format of a Multiformats
comments header is as follows:

typedef struct _GdiCommentMultiFormats
{
    DWORD Identifier;       /* Comment ID (0x43494447) */
    DWORD Comment;          /* Multiformats ID (0x40000004) */
    LONG  BoundsLeft;       /* Left side of bounding rectangle */
    LONG  BoundsRight;      /* Right side of bounding rectangle */
    LONG  BoundsTop;        /* Top side of bounding rectangle */
    LONG  BoundsBottom;     /* Bottom side of bounding rectangle */
    DWORD NumFormats;       /* Number of formats in comment */
    EMRFORMAT Data[];       /* Array of comment data */
} GDICOMMENTMULTIFORMATS

Identifier contains a value of 0x43494447 identifying this structure
as a GDI public comment.

Comment contains a value of 0x40000004 identifying this structure as
a Multiformats comment.

BoundsLeft, BoundsRight, BoundsTop, and BoundsBottom define the
bounding rectangle of the picture.

NumFormats is the number of EMRFORMAT structures in the data.

Data contains one or more EMRFORMAT structures followed their
associated data. Each structure identifies the type of comment data,
its size and location in the record.

typedef struct _EmrFormat
{
    DWORD Signature;    /* Format signature */
    DWORD Version;      /* Format version number */
    DWORD Data;         /* Size of data in bytes */
    DWORD OffsetToData; /* Offset to data */
} EMRFORMAT;

Signature is the data format identifier. A value of 0x464D4520
indicates an enhanced metafile, and a value of 0x46535045 indicates
an Encapsulated PostScript file.

Version is the version level of the data. For EPS data this field
will hold the EPS version number. For an enhanced metafile this
value of this field will be 0x00000001.

Data is the size of the data associated with this structure in bytes.

OffsetToData is the byte offset of the beginning of the data. The
offset is measured from the beginning of the Comments field in the
GDICOMMENTMULTIFORMATS record structure.